← 게임 포트폴리오MONSTER TAMING / ENGINEERING기술문서구현 근거
PERSONAL ENGINEERING PORTFOLIO

플레이를 만드는 구조,
콘텐츠를 만드는 환경.

전찬우 · 구조 설계, 제작 도구, 공용 실행과 통합

실제 게임 시연과 함께, 선택한 설계의 이유·구현·검증 범위·남은 과제를 기록했습니다.

검증 기록 읽는 법 ↗
전체 구조 설계 / Assembly 경계 / 책임과 소유권 / 단일 조립 지점

프로젝트 전체 구조의 설계

Bootstrap 조립, Core·Shared·Framework·기능·콘텐츠의 의존 방향을 기준으로 팀의 작업 경계를 만들었습니다.

기초 구조부터 설계한 범위

최종 구조도 9차는 폴더뿐 아니라 의존 방향, 앱·씬 수명, 데이터 변경, 담당 소유권과 통합 절차를 함께 정의합니다. 전찬우는 프로젝트 기초 구조와 공용 계약을 설계하고 팀 기능을 연결하는 통합을 맡았습니다.

공용 코드가 개별 콘텐츠를 알지 않도록

Core는 실행 기반, Shared는 게임 데이터·공용 전투, Content Framework는 콘텐츠 입장·종료 계약을 담당합니다. Features와 개별 콘텐츠가 이 기반을 사용하며, Framework는 개별 콘텐츠 Controller에 의존하지 않는 방향입니다.

문서와 실제 Assembly 경계

현재 Core asmdef에는 다른 프로젝트 어셈블리 참조가 없고, Shared는 Core를, Framework는 Core·Shared를 참조합니다. Features와 FoodRiot는 Core·Shared·Framework를 참조하며 Bootstrap은 이 계약들을 조립합니다.

각 계층에서 결정하는 것

공통 피해 계산과 Actor는 Shared에, 목표·Spawner·AI·승리 조건은 각 콘텐츠에 둡니다. 제작 도구는 Editor에서 실행 자산을 생산하며 Runtime 의존 계층과 별도로 다룹니다.

설계 이유

공용 기능의 중복과 팀원 간 직접 의존을 줄이고, 새 콘텐츠를 기존 콘텐츠의 내부 수정 없이 연결하기 위한 구조입니다.

적용 범위와 한계

9차 구조도의 핵심 경계를 현재 코드맵과 관련 asmdef 6개로 대조했습니다. 메인 도식은 주요 의존 방향을 축약한 것으로 모든 클래스·직접 참조를 표시하지 않습니다. 사각 CastleRaid는 현재 실행 경로에서 제외합니다.

ENGINEERING DEEP DIVE

구현을 한 단계 더 깊이.

기술문서 내려받기 ↓전체 기술 주제 · Markdown

전체 구조는 폴더 정리뿐 아니라 누가 무엇을 수정하고, 어떤 계약으로 실행하며, 어느 수명에서 정리할지를 함께 정한 설계입니다. 팀 프로젝트에서 독립 작업과 통합을 가능하게 하는 경계를 중심으로 설명합니다.

책임과 데이터 계약

표를 좌우로 밀어 전체 항목을 확인하세요 ↔

영역소유하는 책임상위 기능과의 연결
BootstrapAppRoot와 서비스 조립, 접속·씬 진입의 순서Core·Shared·Features·Framework 계약을 조립
CoreSceneFlow·SaveIO·Time·Contracts구체 게임 콘텐츠를 알지 않는 기반
SharedGameData·Unit·Combat·Reward·공용 UICore를 사용하고 여러 기능의 공통 데이터·계산 제공
Content FrameworkContentFlow·StartData·ResultAdapterCore·Shared를 사용해 입장·종료·정산 계약 제공
Features / Contents성장·편성·UI / 개별 목표·AI·승리 조건공용 계약을 사용하고 개별 구현은 자기 영역에 유지
실제 실행 순서
  1. 01
    의존 방향을 먼저 고정

    Core ← Shared ← Framework ← Features·Contents의 주요 의존 방향을 정하고, Bootstrap을 조립 지점으로 둡니다. Features와 Contents가 Core·Shared를 직접 사용하는 참조도 있으며 메인 도식은 이를 축약했습니다.

  2. 02
    실행 입력과 결과로 연결

    콘텐츠별 StartData와 타입 Result가 개별 플레이를 공통 실행 흐름에 연결합니다. 콘텐츠가 진행 저장과 메인 화면 복귀를 각자 구현하는 대신, Adapter와 ContentFlow가 경계를 담당합니다.

  3. 03
    DEV와 Main의 원본을 공유

    성장 던전은 같은 원본 Prefab·Controller를 DEV와 Main에서 사용합니다. 개발용 Dummy 입력과 정상 게임의 실제 입력을 구분하고, 제작 원본과 통합 반영의 소유권을 명확히 합니다.

  4. 04
    수명에 맞춰 정리

    AppRoot 서비스는 앱 수명, MainBattle의 Hosted Runner와 Prefab 인스턴스는 씬 수명, 선택한 콘텐츠의 유닛·투사체·VFX는 한 판의 실행 수명으로 구분합니다.

코드에서 확인한 구현
의존 경계는 실제 Assembly 참조로 표현ProjectMT.Contents.Framework.asmdef · 프로젝트 참조 항목 발췌
"name": "ProjectMT.Contents.Framework",
"references": [
  "ProjectMT.Core",
  "ProjectMT.Shared",
  "UnityEngine.UI",
  "Unity.TextMeshPro"
]
실패와 처리 경계

표를 좌우로 밀어 전체 항목을 확인하세요 ↔

설계에서 다룬 상황구조적 대응확인할 경계
여러 팀원이 공용 파일을 수정담당 영역과 통합 Catalog의 소유권 분리참조 경계만으로 모든 협업 충돌이 사라지는 것은 아님
DEV에서는 되지만 Main에서 다르게 동작같은 원본 Prefab·Controller, 입력만 분리DEV 더미가 정상 게임 입력에 섞이지 않는지
콘텐츠가 종료 중 결과를 다시 보냄단일 ActiveRun과 첫 Exit 접수, 정산 중 재진입 가드늦은 비동기 완료가 다른 실행에 적용되지 않는지
후속 기능을 위해 계층이 계속 증가실제 사용처와 교체 필요가 있는 경계만 추가가정뿐인 Queue·서버·Repository를 현재 구현처럼 소개하지 않기
선택의 비용과 후속 개선
공통 계약은 통합 비용도 갖습니다

각 콘텐츠를 자유롭게 만드는 대신 StartData·Result와 수명 계약을 맞춰야 합니다. 공통 계약 변경은 여러 기능에 영향을 주므로 소유권과 검증 범위를 함께 관리합니다.

현재 구조와 목표 구조를 구분합니다

9차 문서 일부에는 과거 사각 CastleRaid 경로가 남아 있습니다. 포트폴리오의 메인 구조는 현재 코드맵과 10번 마스터를 우선해 Hosted 성장 콘텐츠와 별도 Hex Scene으로 표현합니다.

근거와 확인 범위구조 근거: 9차 구조도·설계 이유 문서, 현행 코드맵·공통 런타임 마스터와 asmdef 6개. 주요 경계를 대조한 범위이며 전체 클래스 의존성 분석은 포함하지 않습니다.

참고한 구현과 문서
  • TeamDocs/02_최종구조도_9차.md · 2.1 전체 구조 / 2.2 의존 방향
  • Docs/01_코드맵.md / Docs/10_공통런타임시스템_마스터.md
  • ProjectMT.Core / Shared / Contents.Framework / Features / Contents.FoodRiot / Bootstrap.asmdef
Draft 저장 / GUID 유지 / 소유권 검사 / 파일·메타 복구

안전한 자산 생성과 기존 참조 보존

수정 대상을 제한하고 파일 백업과 GUID 확인으로 기존 연결을 보호합니다

ENGINEERING CASE

팀의 제작 편차를 공통 생산 흐름으로

문제와 제약

팀원마다 달랐던 몬스터 제작 방식을 하나로 묶고, 내부 구조를 직접 구현하지 않아도 콘텐츠 제작에 참여할 수 있는 환경이 필요했습니다. 콘텐츠가 늘어날 때 개발자가 연결·등록 작업을 반복하는 부담도 줄이고자 했습니다.

설계 판단

작업 순서를 설명하는 문서에 더해, Draft를 입력 계약으로 삼고 Preview·Validator·Writer를 같은 도구에 연결했습니다. 제작자가 설정할 데이터와 공용 실행기가 책임질 동작을 분리했습니다.

구현의 핵심

생산 전 소유권과 출력 범위를 검사하고 변경 대상 파일을 보관합니다. 생산 후 실제 저장된 Definition과 Catalog를 다시 확인하고, 기존 GUID가 유지된 경우에만 완료합니다. 예외는 복구 경로로 연결했습니다.

확인한 결과

2026.09.07 자료에서 44종의 Catalog·Draft 편입을 대조했고, 판고 제작 시연으로 입력·미리보기·생산 흐름을 보여줍니다. 44종은 적용 범위의 근거이며 제작 속도 개선율은 아닙니다.

남은 한계

Writer가 확보한 파일 범위만 복구합니다. 파일 잠금 등으로 복구도 실패할 수 있어, 실패 지점별 회귀 검증과 Writer 책임 분리가 후속 과제입니다.

초안 저장과 생산

미완성 설정은 Draft로 보관합니다. 게임용 자산 생산은 검증을 통과한 설정에 대해 실행합니다.

기존 연결 보호

기존 자산의 GUID를 갱신 전후로 대조합니다. 다른 자산에서 참조한 연결이 유지되는지 확인하고, 제작 원본의 소유권과 출력 대상을 검사합니다.

오류 처리

변경 대상 파일과 .meta를 미리 백업합니다. 생성·등록 중 오류가 나면 기존 파일을 되돌리고 새로 만든 대상은 정리합니다. 복구도 실패하면 생성 오류와 복구 오류를 함께 보고합니다.

설계 이유

작업을 반복해도 기존 몬스터의 자산 참조와 다른 제작물의 소유권을 지킵니다.

적용 범위와 한계

복구 대상은 Writer가 백업한 생성물과 등록 자산 범위입니다. 파일 접근 오류 등에 따른 복구 실패 가능성은 남아 있습니다.

ENGINEERING DEEP DIVE

구현을 한 단계 더 깊이.

기술문서 내려받기 ↓전체 기술 주제 · Markdown

Monster Maker의 생산 버튼은 파일 생성 한 번이 아닙니다. 팀원이 같은 제작 입력을 사용하도록 하고, 이미 게임에서 참조하는 자산을 갱신하면서 등록 상태와 기존 연결을 지키는 일련의 생산 절차입니다.

책임과 데이터 계약

표를 좌우로 밀어 전체 항목을 확인하세요 ↔

데이터역할생산 시 확인
Draft팀원이 편집하는 제작 원본입력 오류·소유권·출력 대상
Definition / RuntimeAssetSet / Profile게임이 사용하는 산출물필수 참조와 실행 데이터의 유효성
Monster / Rarity / AI CatalogID와 정식 실행 자산 연결실제 등록 대상·등급·AI 설정 일치
파일·메타 백업 + GUID 전후 값갱신 전 상태와 참조 식별 보존기존 GUID 유지 및 실패 시 복구 범위
실제 실행 순서
  1. 01
    사전 검증과 소유권 확인

    Draft 동기화와 Validator 검사 뒤 필요한 Catalog와 출력 경로를 결정합니다. ValidateProductionDraftOwnership으로 다른 제작물의 영역을 잘못 덮지 않는지 확인합니다.

  2. 02
    변경 범위를 먼저 확보

    생성물, 등록 Catalog와 생산용 AI Catalog 경로를 transactionPaths에 모읍니다. 파일·메타와 새로 만들 수 있는 폴더 범위를 Capture한 뒤 실제 쓰기를 시작합니다.

  3. 03
    생성물을 다시 읽어 검사

    Definition과 관련 프로필을 생성·갱신하고 저장한 뒤 Definition을 AssetDatabase에서 다시 불러옵니다. MonsterDefinitionValidator로 실제 저장된 생성물을 재검증합니다.

  4. 04
    등록 확인 후에 완료

    Catalog에 등록한 대상과 등급·AI 설정을 읽어 확인하고 GUID 전후 값을 대조합니다. 통과한 뒤 transaction.Commit()을 호출하며, 예외 경로는 Rollback으로 연결합니다.

코드에서 확인한 구현
생성 후 다시 로드해 검사MonsterMakerAssetWriter.cs:415–420 · 발췌
definition = AssetDatabase.LoadAssetAtPath<MonsterDefinition>(paths[0]);
var outputValidation = MonsterDefinitionValidator.Validate(definition, true);
if (outputValidation.HasErrors)
{
    throw new InvalidOperationException(BuildRuntimeIssueText(outputValidation.Issues));
}
기존 자산의 참조 식별을 보존MonsterMakerAssetWriter.cs:451–459 · 발췌
var guidAfter = outputPaths.ToDictionary(path => path, AssetDatabase.AssetPathToGUID);
for (var index = 0; index < outputPaths.Length; index++)
{
    var before = guidBefore[outputPaths[index]];
    if (!string.IsNullOrEmpty(before) && !string.Equals(before, guidAfter[outputPaths[index]], StringComparison.Ordinal))
    {
        throw new InvalidOperationException("기존 Asset GUID가 변경되었습니다: " + outputPaths[index]);
    }
}
실패와 처리 경계

표를 좌우로 밀어 전체 항목을 확인하세요 ↔

실패 지점처리보존하려는 것
사전 입력·소유권 오류생산 진입을 차단기존 자산과 다른 제작물
생성물 검증·Catalog 등록 불일치예외를 통해 Rollback 경로 진입생산 전 파일·등록 상태
기존 GUID 변경완료 전에 실패로 처리기존 Prefab·Definition 등의 참조
생성과 복구가 모두 실패원래 예외와 복구 예외를 AggregateException으로 보고복구 실패를 성공으로 숨기지 않는 진단 정보
선택의 비용과 후속 개선
파일 수준 복구이며 데이터베이스 트랜잭션은 아닙니다

Rollback은 Capture한 파일·메타와 폴더 범위를 대상으로 합니다. 전체 Unity 프로젝트를 원자적으로 되돌린다는 의미가 아니며 파일 권한·잠금 등으로 복구 자체도 실패할 수 있습니다.

검증과 생산의 책임이 커집니다

참조 보존·파생 자산·Catalog까지 다루므로 Writer는 단순 생성 코드보다 복잡합니다. 출력 단위별 책임 분리와 실패 지점별 회귀 검증이 후속 개선 기준입니다.

근거와 확인 범위소스 확인 범위: 사전 검사·Capture, 생성물 재검증, Catalog/GUID 확인, Commit·Rollback과 복구 예외 처리. 실패 처리 경로의 구현 근거이며 실제 실패 주입 테스트 결과와는 구분합니다.

참고한 구현과 문서
  • MonsterMakerAssetWriter.ValidateProductionDraftOwnership
  • MonsterMakerAssetWriter.BuildAndRegister
  • MonsterMakerWriteTransaction.Capture / Rollback
  • MonsterMakerWriteResult.GuidAfter
역방향 Dijkstra / 최소 힙 / 정책 + 실행 분리 / 7상태 FSM · BFS

공성 길 찾기와 AI 상태 전환

공격 병력의 역할 정책과 수비대 FSM을 육각 셀 위에서 실행합니다

ENGINEERING CASE

부술 수 있는 성벽까지 경로 비용으로

문제와 제약

절차적으로 달라지는 성에서는 성벽이 장애물이면서 돌파 대상입니다. 병력의 역할과 공격력에 따라 우회와 파괴 중 유리한 선택이 달라지고, 성벽 파괴 후에는 전장 연결도 바뀝니다.

설계 판단

단순 거리 대신 이동 시간과 파괴 비용을 결합했습니다. 병력별로 같은 목적지까지 탐색하는 비용을 줄이기 위해 왕궁 접근 셀에서 역방향 비용 지도를 만들고 조건이 같은 요청끼리 공유하도록 했습니다.

구현의 핵심

최소 힙으로 비용을 완화하며 역할·방어층·공격력 구간·속도 구간·전장 버전을 키로 사용합니다. 통행 구조가 바뀌면 캐시를 무효화합니다. 대표값 구간은 개별 최적 경로의 정밀도와 재사용 사이의 절충입니다.

확인한 결과

공성 시연에서 배치→접근→성벽 파괴→내부 진입 흐름을 보여줍니다. 소스에서는 비용 결합과 캐시 재사용·무효화 조건을 확인할 수 있습니다. 기존 Hex 테스트 집계는 아래 검증 기록에 범위를 구분해 적었습니다.

남은 한계

개별 병력 능력치를 구간 대표값으로 근사합니다. 병력 수에 따른 프레임 시간·캐시 적중률 측정은 남아 있으며, 현재 자료로 성능 개선율을 주장하지 않습니다.

공격 병력 · 우선순위 정책

돌파 경로를 먼저 구한 뒤 위협 대응, 지원, 유지 중인 목표를 확인하고 역할별 목표와 장애물을 고릅니다. 일곱 역할 프로필을 사용하며, 기존 목표를 기억해 위협 대응 후에도 유효하면 복귀합니다.

왕궁 경로 · 역방향 다익스트라

왕궁 접근 칸을 비용 0으로 최소 힙에 넣고, 누적 비용이 작은 칸부터 주변으로 비용 지도를 만듭니다. 빈 셀은 이동 시간만 계산하고, 막힌 셀은 파괴 시간에 역할 가중치를 곱해 더합니다.

공유와 갱신

공격력·속도를 구간별 대표값으로 묶고, 이동 정책·방어층·전장 버전이 같은 병력끼리 비용 지도를 공유합니다. 파괴·통행 변경 시 캐시를 비우며, 전략 재판단은 프레임당 한 유닛씩 분산합니다.

수비대 · enum FSM

Idle → Patrol에서 적을 감지하면 반응 지연과 대응 위치 예약을 거쳐 Chase로 이동합니다. 공격 가능하면 Attack, 범위를 벗어나면 Chase로 돌아갑니다. 목표 사망·추적 한계 초과 시 목표를 해제하고 본거지 복귀 또는 순찰을 선택합니다.

수비대 이동 · BFS와 도약

통행 가능한 셀을 BFS로 탐색합니다. 기사는 허용된 장애물 한 칸을 넘는 탐색 연결을 추가하고 실제 도약 중 Jump 상태를 사용합니다. 전체 상태는 Idle·Patrol·Chase·Attack·Return·Jump·Dead입니다.

설계 이유

병력마다 같은 경로 계산을 반복하는 비용을 줄이고, 역할과 파괴된 성벽에 따라 다른 행동을 선택합니다.

적용 범위와 한계

공격 병력은 조건 기반 행동 실행, 수비대는 명시적인 7상태 enum FSM입니다. 두 AI의 구현 방식을 구분합니다.

ENGINEERING DEEP DIVE

구현을 한 단계 더 깊이.

기술문서 내려받기 ↓전체 기술 주제 · Markdown

공성의 길 찾기는 성벽을 단순한 통행 불가 칸으로 취급하지 않습니다. 이동 시간과 파괴 시간을 같은 비용으로 평가하고, 공통 목적지를 향하는 병력끼리 역방향 비용 지도를 재사용합니다.

책임과 데이터 계약

표를 좌우로 밀어 전체 항목을 확인하세요 ↔

입력·캐시 항목의미구현에서의 처리
policy병력의 경로·파괴 선호ResourceRaider·TurretHunter·WallBreaker 등
expectedDefenseLayer현재 탐색에서 사용할 방어층 조건CanUseCell 조건과 캐시 키에 사용
damageBand / speedBand공격력·속도의 대표값 구간공격력은 10 단위, 속도는 0.25 단위로 재구성
topologyVersion파괴·통행 구조의 버전키에 포함, IncrementTopology에서 캐시 무효화
실제 실행 순서
  1. 01
    왕궁 접근 칸에서 시작

    사용 가능한 왕궁 접근 칸을 비용 0으로 최소 힙에 넣습니다. 병력 각각에서 목적지를 찾기보다 공통 목적지에서 역방향 비용 지도를 만듭니다.

  2. 02
    낮은 비용부터 역방향 완화

    최소 비용 노드를 Pop하고, 더 좋은 비용이 이미 기록된 오래된 항목은 건너뜁니다. 현재 칸에 들어오는 비용을 이웃 predecessor의 누적 후보에 더해 작은 값이면 갱신합니다.

  3. 03
    이동 시간과 파괴 시간을 결합

    빈 칸 비용은 이동 거리/속도입니다. 막힌 칸은 현재 체력/초당 공격력에 역할 가중치를 곱해 더합니다. 사용할 수 없는 칸은 무한대 비용으로 제외합니다.

  4. 04
    같은 조건의 병력끼리 공유

    정책·방어층·공격력 구간·속도 구간·전장 버전이 같은 요청은 fields에서 비용 지도를 재사용합니다. 전장 구조가 달라지면 무효화하고 병력의 전략 재판단을 요청합니다.

코드에서 확인한 구현
캐시 키를 만드는 대표값 구간HexCastleAssaultNavigation.cs:229–236 · 발췌
var damageBand = Mathf.Max(1, Mathf.RoundToInt(Mathf.Max(1f, damagePerSecond) / 10f));
var speedBand = Mathf.Max(1, Mathf.RoundToInt(Mathf.Max(0.1f, moveSpeed) * 4f));
var key = new FieldKey(
    policy,
    Mathf.Max(0, expectedDefenseLayer),
    damageBand,
    speedBand,
    topologyVersion);
막힌 셀에도 유한한 돌파 비용 부여HexCastleAssaultNavigation.cs:552–560 · 발췌
var travel = cellTravelDistance / Mathf.Max(0.1f, moveSpeed);
var cell = cells[coordinates];
if (!cell.IsBlocked)
{
    return travel;
}
var destruction = cell.CurrentHealth / Mathf.Max(1f, damagePerSecond);
return travel + destruction * ResolveDestructionWeight(cell, policy);
실패와 처리 경계

표를 좌우로 밀어 전체 항목을 확인하세요 ↔

상황처리·판단의미
시작 칸이 없거나 왕궁 내부경로 요청 실패유효 탐색 영역 밖 입력을 실행하지 않음
시작 칸에 역방향 비용이 없음도달 경로 없음으로 반환모든 병력이 반드시 도달한다고 가정하지 않음
성벽 파괴·통행 변경Topology 증가와 navigation.Invalidate()이전 전장의 비용 지도 재사용 방지
병력 능력치가 조금씩 다름구간별 대표값으로 공유정확한 개별 비용과 재사용 효율 사이의 근사
선택의 비용과 후속 개선
역할 가중치는 이동 속도와 다른 설계 값입니다

예를 들어 WallBreaker의 성벽 가중치는 0.45, ResourceRaider의 성벽 가중치는 1.35입니다. 같은 성벽도 역할에 따라 다른 비용으로 평가해 우회와 돌파의 선택을 달리합니다.

비용 계산 예시

설명용으로 이동 비용 1, 성벽 체력 100, DPS 50을 가정하면 WallBreaker는 1+(100/50)×0.45=1.9, ResourceRaider는 3.7입니다. 이는 공식의 이해를 위한 예시이며 측정된 클리어 시간이나 실제 특정 스테이지 수치가 아닙니다.

최적화의 범위와 다음 검증

대표값 근사와 캐시 갱신 조건이 실제 판단 품질에 미치는 영향을 함께 봐야 합니다. 비용 지도 재사용은 코드에서 확인했지만 FPS 향상률·프레임 시간 절감 수치는 측정하지 않았습니다.

근거와 확인 범위소스 확인 범위: TryResolveRoute, FieldKey, BuildReverseField, ResolveEntryCost와 전장 변경에 따른 무효화. 공격 병력의 비용 지도와 수비대 FSM은 별도 책임입니다. 성능 개선율은 측정하지 않았습니다.

참고한 구현과 문서
  • HexCastleAssaultWorld.TryResolveDecision
  • HexCastleAssaultNavigation.BuildReverseField
  • HexCastleGarrisonUnit / HexRoutePlanner
SemaphoreSlim / Clone → Commit / 임시 파일 교체 / 버전 이관

진행 데이터의 트랜잭션형 저장

변경 후보를 먼저 저장하고 성공한 후보만 현재 상태로 확정합니다

ENGINEERING CASE

저장이 성공한 상태만 플레이에 확정

문제와 제약

보상과 성장 상태를 화면에 먼저 반영하면 저장 실패 시 화면과 파일의 진행이 어긋날 수 있습니다. 콘텐츠 종료와 정산 재시도에서도 같은 보상을 중복 계산하지 않는 경계가 필요했습니다.

설계 판단

현재 진행을 직접 변경하지 않고 후보 복제본에 변경을 적용합니다. 후보 검증과 저장 성공을 상태 확정의 조건으로 삼고, 정산 재시도에는 이미 계산한 PendingChange를 유지했습니다.

구현의 핵심

SemaphoreSlim으로 변경을 직렬화하고 후보를 저장한 뒤 current를 교체합니다. ContentFlow는 활성 실행과 정산 진행 여부를 검사해 중복 진입을 막습니다. 파일 쓰기는 AtomicFileStore 경계로 분리했습니다.

확인한 결과

선택 소스에서 저장 실패 시 기존 current를 유지하는 분기와 성공 후 후보를 확정하는 순서를 읽을 수 있습니다. 정산 재진입 가드도 함께 제공합니다. 이는 구현 확인이며 실기기 오류 주입의 성공 기록은 아닙니다.

남은 한계

로컬 저장 설계입니다. File.Replace 미지원 환경의 복사 대체 경로는 같은 원자성을 보장하지 않으므로 플랫폼별 중단·복구 검증이 필요합니다.

동시 변경 처리

SemaphoreSlim으로 진행 변경 요청을 한 번에 하나씩 처리합니다. 현재 데이터를 복제한 후보에 변경을 적용해 검사하므로, 저장 실패 시 현재 진행은 먼저 바뀌지 않습니다.

저장 순서

후보를 JSON으로 변환하고 다시 읽어 기본 저장 구조를 확인합니다. 임시 파일 작성과 기존 파일 교체가 성공하면 후보를 현재 상태로 확정하고, 알림 옵션에 따라 화면 갱신을 통지합니다.

운영 중 변경

저장 버전의 이관 로직이 이전 필드와 데이터를 새 형식에 맞춥니다. 고정 ID와 Catalog는 이름이 바뀌어도 같은 콘텐츠를 찾는 기준으로 사용합니다.

설계 이유

저장 실패 시 진행 상태와 화면만 먼저 바뀌는 문제를 줄이고 기존 진행도를 유지합니다.

적용 범위와 한계

로컬 저장 범위입니다. File.Replace 미지원 플랫폼은 복사 대체 경로를 사용하므로 파일 교체의 원자성은 플랫폼별 확인이 필요합니다.

ENGINEERING DEEP DIVE

구현을 한 단계 더 깊이.

기술문서 내려받기 ↓전체 기술 주제 · Markdown

진행 저장은 화면 값 변경과 파일 쓰기를 하나의 성공으로 간주하지 않도록 나눕니다. 요청 직렬화, 후보 상태, 직렬화 검증, 파일 교체, 메모리 확정과 결과 표시까지 각 단계의 경계를 설명합니다.

책임과 데이터 계약

표를 좌우로 밀어 전체 항목을 확인하세요 ↔

계층책임확정 시점
GameProgressChange비용·보상·성장 등 변경 요청현재 상태에 직접 덮어쓰지 않고 후보에 적용
GameDataService요청 직렬화와 후보 검증SaveAsync 성공 뒤 current 교체
SaveService버전 Envelope·JSON·역직렬화 기본 검사검사한 바이트를 FileStore에 전달
AtomicFileStore임시 파일과 대상 파일 교체플랫폼별 파일 작업 결과
ContentFlow.ActiveRun동일 PendingChange와 결과 표시 요청 보존저장 성공 뒤 결과 UI와 복귀 진행
실제 실행 순서
  1. 01
    동시 변경을 한 번에 하나씩

    SemaphoreSlim gate를 얻고 현재 상태를 복제합니다. candidate.TryApply가 비용·조건을 확인하고, 실패하면 현재 상태를 바꾸지 않고 실패 결과를 반환합니다.

  2. 02
    저장할 표현을 검증

    SaveEnvelope에 버전·UTC·복제 데이터를 넣어 JSON으로 변환한 뒤 다시 읽습니다. 버전과 gameData 존재 같은 기본 구조를 확인한 후 FileStore를 호출합니다.

  3. 03
    파일 저장이 성공한 뒤 메모리 확정

    임시 파일 작성과 파일 교체가 정상 반환하면 current=candidate로 확정합니다. gate는 finally에서 해제하고 Changed 알림은 옵션에 따라 확정 뒤 보냅니다.

  4. 04
    콘텐츠 결과의 동일성 유지

    ContentFlow는 PendingChange를 보관하고 SettlementInFlight로 중복 정산을 막습니다. 저장 실패 시 Finishing 상태에서 수동 재시도를 제공하고 같은 변경을 다시 저장합니다. 결과 UI 예외는 로그로 남기고 복귀 흐름을 계속할 수 있게 분리합니다.

코드에서 확인한 구현
직렬화한 결과를 다시 읽고 파일로 전달SaveService.cs:84–91 · 발췌
var json = JsonUtility.ToJson(envelope, true);
var verification = JsonUtility.FromJson<SaveEnvelope>(json); // 쓰기 전 역직렬화 검증
if (verification == null || verification.dataVersion != CurrentDataVersion || verification.gameData == null)
{
    throw new InvalidOperationException("Serialized save verification failed.");
}
await fileStore.ReplaceAsync(savePath, Encoding.UTF8.GetBytes(json)); // 검증된 내용만 교체
동일 실행의 중복 정산 진입 차단ContentFlow.cs:458–462 · 발췌
if (run == null || !ReferenceEquals(activeRun, run) || Phase != ContentFlowPhase.Finishing ||
    run.PendingChange == null || Interlocked.Exchange(ref run.SettlementInFlight, 1) != 0)
{
    return;
}
실패와 처리 경계

표를 좌우로 밀어 전체 항목을 확인하세요 ↔

실패·예외 지점현재 코드의 처리보장 범위
후보 적용 거부false 반환, 원래 current 유지규칙·재화 조건을 통과하지 못한 변경 미확정
SaveAsync 예외current 교체 전 예외 전달, gate 해제메모리 후보 미확정. 디스크 상태는 실패 지점에 따라 다름
콘텐츠 저장 실패CanRetry 설정, 같은 PendingChange 재시도결과를 새로 뽑는 흐름과 분리
결과 UI 예외로그 후 후속 복귀 진행표현 실패가 이미 확정된 저장을 취소하지 않음
File.Replace 미지원File.Copy 대체 경로모든 플랫폼에서 동일한 원자성을 보장하지 않음
선택의 비용과 후속 개선
로컬 저장의 트랜잭션형 흐름입니다

후보 검증과 저장 성공 후 확정은 로컬 진행의 일관성을 위한 설계입니다. 서버 권위의 보상 검증, 원격 계정 병합, 분산 트랜잭션을 구현했다는 의미는 아닙니다.

파일 교체와 후처리 예외는 별도 검토가 필요합니다

현재 AtomicFileStore는 File.Replace 뒤 백업 파일을 삭제합니다. 파일 교체 후 삭제 등에서 예외가 나면 디스크는 갱신됐지만 호출자는 실패로 받을 수 있습니다. 이 지점까지 포함한 실패 주입·재접속 검증을 후속 보강 항목으로 구분합니다.

역직렬화 검사의 한계

현재 검사는 Envelope·버전·gameData 존재 같은 기본 구조를 확인합니다. 모든 필드의 의미나 저장 전후 완전 동등성을 비교하는 검증으로 확대 해석하지 않습니다.

근거와 확인 범위소스 확인 범위: GameDataService의 후보 저장·확정, SaveService의 직렬화 검사, AtomicFileStore의 교체 경로, ContentFlow의 정산 가드. 저장 버전은 v26이며 실기기 저장 실패·복구 검증은 추가 과제입니다.

참고한 구현과 문서
  • GameDataService.TryApplyAndSaveAsync
  • SaveService.SaveAsync
  • AtomicFileStore.ReplaceAsync
Data-driven execution / Delivery / Shape / Sequence / 액티브 Step

공용 공격 실행기의 데이터 해석

공격 프로필을 읽고 전달·판정·반복·연출을 실행합니다

프로필에 따른 분기

MonsterBasicAttackExecutor는 직접 타격과 투사체 전달, 반복 시퀀스 등의 모듈 값을 읽어 공용 실행 경로로 분기합니다.

시간과 충돌 처리

연타·진행형 타격은 시퀀스 시간에 따라 이어 실행하고, 투사체 Actor는 이동과 충돌 조건을 처리합니다. 각 공격 프로필의 범위와 타수 설정이 결과에 사용됩니다.

실행 시점과 연출 연결

공격 전달 시작인 DeliverySpawn, 연속 공격 종료인 SequenceEnd 같은 이벤트에서 해당 슬롯의 VFX를 재생합니다. 액티브는 Step 순서와 간격으로 복합 공격을 구성합니다.

설계 이유

지원된 모듈의 조합을 바꿔 서로 다른 공격을 공통 코드로 실행합니다.

적용 범위와 한계

지원하지 않는 공격 동작을 추가할 때는 실행 코드와 데이터 계약, 검증기를 함께 수정합니다.

ENGINEERING DEEP DIVE

구현을 한 단계 더 깊이.

기술문서 내려받기 ↓전체 기술 주제 · Markdown

공용 실행기는 몬스터 ID별 공격 코드를 늘리는 대신, 제작된 공격 프로필과 실행 Context를 해석합니다. 지원 모듈의 분기 순서, 시간에 걸친 판정, 연출 이벤트를 분리해 설명할 수 있는 구조입니다.

책임과 데이터 계약

표를 좌우로 밀어 전체 항목을 확인하세요 ↔

구성담당 정보변경할 때의 기준
Recipe / Profile전달·범위·진행·반복·이동 규칙공격의 판정 방식을 바꿀 때
Binding몬스터별 모션·효과·소리와 슬롯 대응같은 규칙을 다른 몬스터로 표현할 때
ExecutionContextWorld·Source·Target·실행 프로필·속도이번 발동의 입력과 현재 실행 환경
Executor / Projectile / VFX Runtime분기·판정·비행·연출 이벤트새 동작 모듈이 필요한 경우 코드와 검증 확장
실제 실행 순서
  1. 01
    발동 입력 검증

    프로필, World, Source, PrimaryTarget과 대상 생존 여부를 확인합니다. 사용할 수 없는 입력은 false로 반환한 뒤 실행하지 않습니다.

  2. 02
    위치·이동·연출 시작

    원점과 방향을 구하고 Dash 이동 모듈을 반영합니다. RecipeExecute와 Dash 관련 이벤트를 통해 연출 시작 지점을 연결합니다.

  3. 03
    우선순위에 따라 실행 경로 선택

    투사체 시각을 사용하는 프로필은 LaunchProjectiles, 단일 진행형은 ContinueProgressiveHit, 단일 부채꼴 스윕은 ContinueFanSweep, Burst는 첫 타격과 반복 코루틴으로 분기합니다. 나머지는 즉시 판정합니다.

  4. 04
    시간과 타깃 중복을 제어

    부채꼴 스윕은 세 조각으로 나눠 순차 판정하고 HashSet으로 같은 대상의 중복 적용을 차단합니다. 각 조각 사이에서 시전자 생존을 다시 확인하며 최대 타깃 수를 적용합니다.

코드에서 확인한 구현
부채꼴 스윕에서 중복 타깃 제외MonsterBasicAttackExecutor.cs:451–457 · 발췌
foreach (var target in sliceTargets)
{
    if (target == null || appliedCount >= profile.MaxTargets || !hitActors.Add(target.GetInstanceID()))
    {
        continue;
    }
    var targetRatio = target == primaryActor ? 1f : profile.SecondaryDamageRatio;
    // 이후 피해와 연출 처리 생략
}
진행 중 시전자 상태 재확인MonsterBasicAttackExecutor.cs:427–434 · 발췌
if (sliceIndex > 0)
{
    yield return WaitForCombatSeconds(context.World, delay);
}
if (context.Source == null || !context.Source.IsAlive)
{
    yield break;
}
실패와 처리 경계

표를 좌우로 밀어 전체 항목을 확인하세요 ↔

상황실행 경계검증 포인트
대상 사망·입력 누락Execute 진입에서 false 반환공격 예약과 실제 발동 사이의 상태 변화
스윕 도중 시전자 사망다음 시간 단계에서 중단지연 판정이 유효하지 않은 시전자에 남지 않는지
한 타깃이 여러 스윕 조각에 겹침Instance ID HashSet으로 한 실행 내 중복 제외Burst의 의도적 연타와 스윕 중복 차이를 구분
새 모듈 조합 추가데이터·실행 분기·검증기를 함께 확장지원하지 않는 조합을 도구가 생산하지 않는지
선택의 비용과 후속 개선
재사용 가능한 범위가 명확해야 합니다

데이터를 바꾸는 것만으로 모든 공격이 생기지는 않습니다. 현재 실행기가 지원하는 모듈 조합을 재사용하며, 새로운 동작은 코드 경계 확장이 필요합니다.

시간을 공유하는 실행과 연출

판정과 VFX를 이벤트 슬롯으로 연결하면 표현을 교체할 수 있지만 발동 시점·반복 횟수·배속의 일관성이 중요합니다. Preview와 실제 전투에서 각각 확인할 검증 범위를 나눕니다.

근거와 확인 범위소스 확인 범위: Execute·ContinueFanSweep의 입력 가드, 실행 분기, 중복 타깃 제외와 시전자 생존 조건. 모든 모듈 조합의 실행 검증을 의미하지 않습니다.

참고한 구현과 문서
  • MonsterBasicAttackExecutor
  • MonsterBasicAttackProjectileActor
  • MonsterBasicAttackVfxRuntime / MonsterAttackActiveSkill
Unity · C# / ScriptableObject / EditorWindow / Snapshot

게임과 제작 도구의 기술 구성

Unity 실행 코드와 Editor 제작 도구가 공통 데이터 형식을 사용합니다

데이터 기반 구성

몬스터 정의, 공격 프로필, 스킬 설정을 ScriptableObject 자산으로 구성합니다. 실행 코드는 이 자산을 읽고 정해진 규칙에 따라 처리합니다.

Editor와 Runtime 경계

Monster Maker의 Draft와 AssetWriter는 Editor 제작 영역에 있습니다. 게임은 생산된 Definition·RuntimeAssetSet·Catalog를 사용합니다.

전투 시작 시 계산

BattlePartySnapshotBuilder가 편성·성장·장비·스킬 설정을 전투용 Snapshot으로 계산합니다. 한 판의 유닛 상태는 이 입력을 바탕으로 생성합니다.

설계 이유

제작 화면과 게임이 같은 ID와 데이터 규칙을 사용해 수동 연결을 줄입니다.

적용 범위와 한계

게임 자산으로 생산한 결과와 실제 Scene 연결은 통합 플레이에서 확인합니다.

참고한 구현과 문서
  • MonsterMakerAssetWriter
  • BattlePartySnapshotBuilder
  • MonsterCatalog
Axial 좌표 / 선형 보간 · Cube rounding / BFS Flood fill / 결정적 해시

육각 성의 절차 생성 알고리즘

시드와 테마의 기하 규칙을 육각 셀로 변환해 전장을 만듭니다

성벽 연결 · 보간과 반올림

테마별 꼭짓점 사이를 선형 보간합니다. q·r에서 s=−q−r을 구해 세 축을 반올림한 뒤 오차가 큰 축을 보정합니다. 이 셀들을 끝점끼리 연결해 닫힌 성벽을 구성합니다.

방어층 · 기준 반경

왕궁 중심에서 반경 3·5·8·11칸을 기준으로 2~4개 방어층을 사용합니다. 각 층의 윤곽은 테마 규칙으로 만들고 층 사이를 구획벽으로 연결합니다.

공간 분류 · BFS

큐와 방문 집합으로 성벽을 통과하지 않는 여섯 방향 이웃을 탐색합니다. 안쪽·바깥쪽 벽의 외부 탐색 결과를 비교해 층 사이 구역을 구하고, 성 밖의 열린 바닥은 배치 영역으로 확장합니다.

시설 배치 · 조건과 점수

성문 앞 예약 칸 등 제외 조건을 적용한 뒤 시드·구역·좌표를 섞은 해시 점수로 후보를 정렬합니다. 난이도의 수량 조건에 맞춰 건물·포탑 등을 배치합니다.

설계 이유

테마의 형태를 유지하며 여러 전장을 만들고, 같은 입력으로 문제 전장을 재현합니다.

적용 범위와 한계

테마별 기하 규칙을 구현한 생성기입니다. 테마 이름만으로 범용 Voronoi 분할 같은 표준 알고리즘 전체를 구현했다고 해석하지 않습니다.

참고한 구현과 문서
  • HexCastleSilhouettePlanner.BuildLine / RoundAxial
  • HexCastleSilhouetteBandResolver.ResolveOutside
  • HexCastleFoundationGenerator.ResolvePlacementScore
건물 역할 데이터 / 생존 상태 집계 / 주기적 증원 / 성공 후 정산

건물 상태와 전투 효과 연결

건물의 생존·파괴 상태가 수비대와 정산 로직에 반영됩니다

강화와 증원

연습장의 생존 상태를 기준으로 수비대 공격력 강화가 유지됩니다. 연습장을 모두 파괴하면 강화가 해제됩니다. 병영은 주기마다 병력을 보충하며 해당 병영을 파괴하면 증원이 중단됩니다.

파괴 시점의 선택

교회 파괴는 수비대 이동속도 상승으로 이어집니다. 포탑은 사거리 안의 공격 병력을 노리고, 함정은 진입한 병력에 피해·이동 제약을 적용합니다.

전리품 확정

보급 건물 파괴 결과를 공략 결과에 포함하고, 성공 시 보상 변환과 저장을 거쳐 전리품을 확정합니다.

설계 이유

같은 성에서도 배치 방향과 건물 파괴 순서에 따라 전투 조건이 바뀝니다.

적용 범위와 한계

건물 설명의 수치와 효과는 현재 시연 전장의 설정을 기준으로 합니다.

참고한 구현과 문서
  • HexCastleGarrisonWorld
  • HexCastleTurretCombatWorld
  • HexCastleRaidResultAdapter
Draft / Runtime 분리 / ScriptableObject / Recipe / Binding / 고정 ID

제작 데이터와 게임 실행 연결

Draft → 검증 → Runtime 자산 → Catalog의 단방향 생산 흐름입니다

제작 원본과 산출물

Draft는 편집 중인 설정을 보존합니다. Writer가 MonsterDefinition, RuntimeAssetSet, 모션·전투·연출 Profile을 생성하거나 갱신합니다.

규칙과 몬스터 자산

Recipe에는 전달 방식·판정 형태·타수 등의 공격 규칙이 들어갑니다. Binding은 슬롯 ID에 대응하는 몬스터별 모션·VFX·SFX 및 보정값을 연결합니다.

실행 진입점

생산된 자산을 Catalog에 등록하고, 게임은 ID와 자산 참조로 이를 찾습니다. 전투 시작 시 편성·성장 정보를 Snapshot으로 계산해 유닛에 전달합니다.

설계 이유

제작 화면과 게임이 같은 식별 기준과 공격 계약을 사용합니다.

적용 범위와 한계

새로운 실행 규칙을 추가하면 데이터와 실행 코드, 검증 규칙을 함께 확장해야 합니다.

참고한 구현과 문서
  • MonsterMakerDraft
  • MonsterMakerAssetWriter.BuildAndRegister
  • BattlePartySnapshotBuilder
EditorWindow / Draft 자산 / Profile 구성 / Binding key

Monster Maker의 제작 데이터 구성

모델부터 공격·연출까지 제작 원본에 모으고 게임용 자산으로 생산합니다

하나의 제작 원본

ID·등급·모델·능력치·공격·패시브·액티브 설정을 Draft에 보관합니다. 편집 작업과 게임에서 사용할 자산 생성은 별도 동작입니다.

공격 연결 키

기본공격의 Attack ID, Slot ID, Motion ID를 키로 바인딩 요구 사항을 비교합니다. 선택한 공격에 필요한 모션·효과 슬롯을 몬스터별 자산과 연결합니다.

분리된 책임

창은 입력과 선택을 다루고, Preview는 동작 확인을, Validator는 구조 검사를, Writer는 산출물 생성과 Catalog 등록을 담당합니다.

설계 이유

같은 몬스터를 반복 수정할 때 입력·확인·생산의 순서를 유지합니다.

적용 범위와 한계

제작 창의 책임 분리는 계속 개선할 부분입니다. 미리보기와 실제 집단 전투 검증을 함께 사용합니다.

참고한 구현과 문서
  • MonsterMakerDraft
  • MonsterBasicAttackBindingProjection
  • MonsterMakerAssetWriter
모듈 조합 / Slot ID / Binding projection / Step sequence

공격 Recipe와 슬롯 Binding

공격의 판정 규칙과 몬스터별 모션·효과를 슬롯 ID로 연결합니다

기본공격 구성 요소

Delivery는 직접 판정·투사체 같은 전달 방식을, Collision은 충돌 처리를 정합니다. Sequence·Movement·Shape는 반복·이동·범위를 구성합니다. Presentation은 모션·VFX·SFX 연결 지점을 정의합니다.

슬롯 연결 규칙

조립소가 효과가 필요한 시점과 위치에 슬롯 ID를 부여합니다. 메이커는 Attack ID·Slot ID·Motion ID 기준으로 실제 자산과 보정값을 대응시킵니다. 예를 들어 같은 타격 슬롯에 몬스터마다 다른 이펙트를 연결할 수 있습니다.

액티브 단계 실행

액티브는 여러 Step의 동작과 간격을 구성합니다. 각 단계에 필요한 이동·타깃·공격·연출을 연결해 복합 동작을 만듭니다.

설계 이유

같은 판정 규칙을 여러 몬스터의 모션과 효과로 표현할 수 있습니다.

적용 범위와 한계

지원하는 모듈 조합 안에서 재사용합니다. 기존 규칙으로 표현할 수 없는 공격은 실행기와 검증기를 함께 확장해야 합니다.

참고한 구현과 문서
  • MonsterBasicAttackProfile
  • MonsterBasicAttackBindingProjection
  • MonsterAttackActiveSkill
사전·생성물 검증 / AssetDatabase / GUID 유지 확인 / Catalog 등록

제작에서 등록까지의 생산 파이프라인

입력과 생성물을 각각 검증한 뒤 게임에 등록합니다

생산 전 조건 검사

Draft 소유권, ID, 출력 대상, 필수 참조와 공격 설정을 확인합니다. 출력 경로와 기존 GUID를 확보해 갱신 대상을 정합니다.

산출물 구성

Definition·RuntimeAssetSet·모션·전투·연출 자산을 만들거나 기존 자산에 반영합니다. 필요한 파생 설정과 연결 정보를 동기화합니다.

생성물 재검증과 등록

저장한 Definition을 다시 불러와 참조와 설정을 검증합니다. 통과한 자산을 Catalog에 등록하고, 등록 결과와 기존 GUID 유지를 확인한 뒤 완료합니다. 오류가 나면 복구 절차를 실행합니다.

설계 이유

반복되는 검사와 자산 연결을 Writer에 모아 제작 절차를 일정하게 유지합니다.

적용 범위와 한계

Editor 자산 생산의 복구 범위와 플레이 진행 데이터 저장의 트랜잭션은 별도 구현입니다.

참고한 구현과 문서
  • MonsterMakerAssetWriter.BuildAndRegister
  • ValidateProductionDraftOwnership
  • MonsterMakerWriteResult.GuidBefore / GuidAfter
Editor tick / Preview stage / 모션·VFX 동기화 / 리소스 정리

제작 화면의 실행 미리보기

Editor의 시간 진행으로 모션과 효과를 반복 재생하며 보정합니다

시간 기반 재생

MonsterMakerPreviewStage는 EditorApplication.timeSinceStartup으로 경과 시간을 구하고 Tick으로 미리보기를 갱신합니다. 한 번의 deltaTime은 최대 0.1초로 제한합니다.

연출 확인

공격 계약의 VFX 시점과 활성 효과를 갱신하고, 액티브 미리보기 및 전투 표현을 함께 진행합니다. 위치·회전·크기 보정 후 같은 동작을 재생합니다.

작업 종료

미리보기 종료와 Dispose에서 사용한 stage와 실행 리소스를 정리합니다. 제작용 임시 상태가 계속 남는 것을 방지합니다.

설계 이유

작은 효과 위치 수정도 같은 조건으로 바로 비교할 수 있습니다.

적용 범위와 한계

여러 유닛의 가독성·성능·실제 타격감은 게임 플레이 검증에서 확인합니다.

참고한 구현과 문서
  • MonsterMakerPreviewStage.Tick
  • TickPendingContractVfx / TickActiveSkillPreview
  • MonsterMakerPreviewStage.Dispose
구조 검증 / Error / Warning / ID·참조 검사 / 오류 시 생성 차단

자산 생산 전 구조 검증

검증기가 오류 코드와 심각도로 잘못된 설정을 보고합니다

검사 항목

MonsterDefinitionValidator가 빈 ID, 잘못된 능력치, 초상화·미리보기 참조, RuntimeAssetSet 연결을 검사합니다. 제작기와 공격 계약 검증은 중복 ID와 슬롯·조합 조건도 확인합니다.

보고서 형태

심각도, 오류 코드, 설명, 관련 자산을 함께 기록해 수정할 위치를 찾게 합니다. Error가 남으면 생성을 막고, Warning은 주의 항목으로 보여줍니다.

검증 계층

정적 구조 검사는 필수 연결과 설정을 확인합니다. Preview는 동작을, EditMode·PlayMode·제작 E2E 및 QA는 해당 범위의 실행 결과를 확인합니다.

설계 이유

잘못된 연결을 게임 적용 전에 찾아 원인을 좁힙니다.

적용 범위와 한계

검증 통과는 확인한 조건의 통과입니다. 밸런스와 재미, 모든 실행 조합의 보장을 뜻하지 않습니다.

참고한 구현과 문서
  • MonsterDefinitionValidator.Validate
  • MonsterValidationReport.HasErrors
  • MonsterMakerAssetWriter
Workshop Draft / Validator / Sub-assets / Catalog 동기화

군단장 스킬 제작과 등록

전용 Draft를 검증하고 카테고리별 스킬 자산과 하위 설정을 생성합니다

제작 입력

단발·연발·연쇄·지속 영역 등 스킬 구성에 필요한 타깃, 효과, 타이밍과 연출을 전용 제작 원본에서 설정합니다.

생산 절차

CommanderSkillWorkshopWriter는 입력을 정규화하고 Validator를 호출합니다. 새 저장 시 동일 ID의 자산이 존재하면 오류를 반환합니다.

생성물 연결

카테고리별 Definition을 만들고 타깃·피해·효과 설정과 필요한 사운드를 구성합니다. Catalog 옵션에 맞춰 등록 정보를 동기화합니다.

설계 이유

군단장 스킬도 초안·검증·생산·등록의 같은 제작 순서를 따릅니다.

적용 범위와 한계

몬스터 메이커와 제작 원칙을 공유하며, 스킬 전용 Writer와 데이터 형식을 사용합니다.

참고한 구현과 문서
  • CommanderSkillWorkshopDraft
  • CommanderSkillWorkshopValidator
  • CommanderSkillWorkshopWriter.SaveNew
Adapter pattern / async 흐름 / 중복 실행 가드 / 동일 결과 재시도

콘텐츠 결과와 저장을 잇는 공용 흐름

ResultAdapter로 콘텐츠별 결과를 공통 정산과 화면 흐름에 연결합니다

콘텐츠별 차이

시작 데이터와 ResultAdapter가 각 콘텐츠의 조건과 결과를 공통 데이터로 연결합니다. ContentFlow가 정산·저장·결과 표시·복귀 순서를 진행합니다.

정산 중복 방지

ActiveRun에 PendingChange와 표시 요청을 보관합니다. Interlocked.Exchange로 정산 중 재진입을 차단하고 저장 작업을 시작합니다.

저장 실패와 재시도

TryApplyAndSaveAsync 성공 뒤 결과창과 보상 연출을 표시합니다. 실패 시 같은 PendingChange로 다시 저장하므로 재시도 과정에서 보상 내용을 다시 뽑지 않습니다.

설계 이유

각 콘텐츠가 정산·저장 실패·결과창 처리를 반복 구현하는 비용을 줄입니다.

적용 범위와 한계

현재 로컬 진행 저장 흐름입니다. 서버 권위의 보상 검증이나 계정 간 병합은 포함하지 않습니다.

참고한 구현과 문서
  • ContentFlow.TrySaveAndFinishAsync
  • ContentFlow.ActiveRun
  • FoodRiotResultAdapter / HexCastleRaidResultAdapter
테스트 유형 분리 / 우선순위 집계 / 재현 절차 / 기록 기준

QA 집계와 검증 범위

작업 상태와 테스트 결과를 구분하고 원본 기록으로 수치를 확인합니다

집계 단위

JIRA는 작업 건수, QA 문서는 검증 항목 수입니다. 88건 중 QA 검토 완료 71건·보류 17건과, 372항목 중 정상/통과 358항목·테스트 불가 14항목은 서로 다른 집계입니다.

검증의 종류

테스트 케이스·체크리스트·시나리오·자동화 회귀 기록을 유형별로 구분합니다. P0~P2 테스트 케이스 146개는 정상이며 남은 테스트 불가 항목은 P3~P5에 있습니다.

결과 해석

96.2%는 등록한 QA 항목의 정상·통과 기록 비율입니다. 미구현 항목은 구현 후 다시 검증해야 합니다. JIRA 상태 이동 시연은 작업 흐름을 보여주며 수정 후 성능 측정 자료와 구분합니다.

설계 이유

확인한 결과와 남은 범위를 분리해 다음 검증 대상을 정합니다.

적용 범위와 한계

집계 비율을 게임 완성도나 코드 커버리지로 사용하지 않습니다.

참고한 구현과 문서
  • QA 테스트 케이스(추가) · 유형별 원본 대조
  • KAN-35 재현 보고서
  • QA 자료 보기 · 기존 공유 문서
AppRoot / SceneFlow / ContentFlow / Snapshot / Stable ID

게임 전체의 책임과 데이터 흐름

Core·Shared·Features·Contents의 역할을 나누고 제작 데이터, 플레이 상태, 저장을 연결합니다.

공용 기반과 콘텐츠 경계

AppRootHost는 공용 서비스의 수명을, SceneLoader는 씬 전환을 담당합니다. Core는 저장 I/O와 실행 기반, Shared는 게임 데이터와 공용 전투, Features는 성장·편성 등의 기능, Contents는 개별 플레이 흐름으로 책임을 구분합니다.

변하지 않는 정의와 변하는 진행

Definition·Profile·Catalog는 게임이 읽는 제작 결과입니다. 사용자 보유·성장·편성은 GameProgressData에 보존하고, BattlePartySnapshotBuilder가 전투 시작에 필요한 입력으로 계산합니다.

같은 인터페이스로 다른 콘텐츠 실행

ContentFlow는 Hosted RuntimePrefab과 별도 Scene 콘텐츠의 입장·실행·정산·종료 경계를 다룹니다. 각 콘텐츠는 자체 플레이를 수행하고 StartData·Result·Adapter로 공통 흐름과 연결됩니다.

결과에서 다시 성장으로

콘텐츠 결과는 Adapter에서 GameProgressChange로 변환됩니다. GameDataService가 후보 검증과 저장을 마치면 확정 보상·결과창을 표시하고 MainBattle로 복귀합니다.

설계 이유

팀원이 개별 콘텐츠를 구현해도 저장·결과창·복귀를 각자 반복 구현하지 않도록 공통 연결점을 둡니다.

적용 범위와 한계

주요 책임과 연결 방향을 요약한 구조도입니다. 모든 클래스의 직접 참조를 표시하지 않으며, 개별 Scene 연결은 통합 플레이 검증 대상입니다.

참고한 구현과 문서
  • AppRootHost / SceneLoader / ISceneRoot
  • GameProgressData / BattlePartySnapshotBuilder
  • ContentFlow / ContentCatalog / ResultAdapter
  • Docs/10_공통런타임시스템_마스터.md / Docs/01_코드맵.md
팀 제작 방식 통일 / 콘텐츠 제작 참여 / 장기 반복 작업 축소

팀의 제작 방식을 하나의 흐름으로

구조를 이해하고 구현하는 일과, 그 위에서 콘텐츠를 만드는 일을 나누려 했습니다.

팀원마다 달랐던 제작 방식

팀원마다 몬스터를 생성하고 자산을 연결하는 방식에 편차가 있었습니다. 공통 입력과 제작 순서를 제공해 같은 흐름으로 콘텐츠를 만들 수 있도록 Monster Maker를 설계했습니다.

구조 구현 경험과 제작 참여를 분리

내부 런타임 구조를 직접 만들기 어려운 팀원도 모델·모션·공격을 설정하고 검증·생산 과정을 따라 콘텐츠 제작에 참여할 수 있는 환경을 만들고자 했습니다. 구조의 복잡성은 제작 도구와 공용 실행기가 맡도록 했습니다.

개발자의 반복 작업을 줄이기

새 몬스터마다 같은 연결과 등록 작업을 개발자가 되풀이하지 않도록, 장기적으로 반복될 작업을 도구의 생산 흐름으로 옮겼습니다. 새로운 규칙은 코드로 확장하고 기존 규칙의 조합과 자산 연결은 제작 환경에서 처리하는 방향입니다.

게임 구조와 제작 환경을 함께 설계

런타임에서는 공용 기반과 개별 콘텐츠의 책임을 나누고, 제작 단계에서는 Draft·Preview·Validator·Writer를 연결했습니다. 팀원이 각자 작업한 결과가 같은 데이터 계약으로 게임에 들어오도록 하는 것이 두 설계의 공통 목적입니다.

설계 이유

개발자가 내부 구조를 설계하고, 팀원은 정해진 제작 흐름을 통해 콘텐츠를 만드는 분업 환경이 필요했습니다.

적용 범위와 한계

제작 방식과 반복 연결을 공통 흐름으로 묶는 데 집중했습니다. 제작 시간 단축률과 팀원별 생산성 차이는 측정하지 않았습니다.

참고한 구현과 문서
  • 2026.09.11 전찬우 직접 설명 · Monster Maker 제작 목적
  • V12 App.tsx · 프로젝트 기초 구조 / Monster Maker / Preview·Validator·Writer 담당 기록
  • MonsterMakerDraft / MonsterMakerAssetWriter / 공용 Runtime
저장 결과 표시 / 등급별 연출 / 개별 카드 건너뛰기 / 전투 Snapshot

성장 결과와 화면 표현을 연결하기

소환의 표시 순서와 전투에 들어갈 데이터를 각각의 책임으로 나눴습니다.

결과와 연출의 경계

GachaRevealSequence는 전달받은 결과 카드의 표시를 담당합니다. 등급에 따른 회전·반동·빛 연출과 카드 공개 순서를 처리하며, 연출 자체가 보상을 새로 추첨하지 않습니다.

반복해서 보는 화면의 속도

전설·신화는 별도의 강조 연출을 사용합니다. SkipCurrentCard는 현재 카드 한 장의 공개를 건너뛰도록 연결되어 있습니다. 획득의 강조와 반복 조작의 속도를 함께 다룬 사례입니다.

성장을 실제 전투 입력으로

BattlePartySnapshotBuilder는 보유 몬스터의 레벨·돌파, 해금 능력과 패시브·액티브 등을 전투용 Snapshot으로 구성합니다. 관리 화면의 상태와 전투 중 유닛 상태가 연결되는 지점을 명시합니다.

설계 이유

획득을 보여주는 UI, 진행 데이터, 한 판의 전투 입력을 구분하면 표시 변경이 게임 상태 변경과 뒤섞이지 않습니다.

적용 범위와 한계

표시 코드와 전투 Snapshot이 사용하는 데이터 경계를 설명합니다. 시연만으로 조작 만족도나 밸런스를 평가하지 않습니다.

참고한 구현과 문서
  • GachaRevealSequence.RevealCards / SkipCurrentCard
  • BattlePartySnapshotBuilder.AppendPartyUnits / Build
  • V12 App.tsx · 전찬우 소환·성장·편성 담당 기록
Catalog / Draft / 44종 제작 자료 / 반복 생산 / 게임 적용

제작 도구를 실제 콘텐츠까지 연결하기

도구의 기능 소개에 제작 자산과 게임 적용 결과를 함께 제시합니다.

도구에서 끝나지 않는 작업

Monster Maker에서 외형·모션·공격·효과를 설정한 뒤 Writer로 게임용 자산을 생산하고 Catalog에 등록합니다. 몬스터 목록과 실행 시연은 이 제작 흐름의 사용 결과를 보여줍니다.

44종의 의미

44종은 2026.09.07 제작 자료에서 Catalog와 Draft를 대조한 기록입니다. 제작 도구가 실제 콘텐츠 데이터에 연결되었다는 근거로 사용하며, 모든 모델·애니메이션의 원작 제작을 의미하지 않습니다.

규칙과 표현의 재사용

공격 규칙은 Recipe, 개별 몬스터의 모션·VFX·SFX는 Binding으로 연결합니다. 공통 실행 코드를 공유하면서 몬스터별 표현을 바꾸는 구조입니다.

설계 이유

제작 도구의 가치는 기능 수와 함께 실제 게임 콘텐츠를 반복해서 만드는 데 쓰였는지로 설명할 수 있습니다.

적용 범위와 한계

몬스터 수는 자료 시점의 대조값이며 작업 시간 단축률이나 생산성 배수를 측정한 값은 없습니다. 아트 원작 제작과 시스템·데이터 편입 기여를 구분합니다.

참고한 구현과 문서
  • V12 showcase-roster / 44종 소개
  • MonsterMakerAssetWriter.BuildAndRegister
  • MonsterCatalog / MonsterMakerDraft
참조 안정성 / 캐시 정확도 / 저장 실패 / 설계 비교

설계 선택과 받아들인 비용

현재 구현을 대안과 비교해 선택 이유와 한계를 설명합니다.

자산을 새로 만들기 vs 기존 자산 갱신

Writer는 기존 연결을 보호하기 위해 대상 소유권, GUID, 파일·메타 백업을 함께 관리합니다. 단순한 새 자산 생성보다 복잡하지만 반복 생산 시 이미 연결된 참조를 지킬 수 있습니다. 복구 범위는 Writer가 확보한 대상에 한정됩니다.

유닛별 계산 vs 조건별 비용 지도 공유

공성 탐색은 왕궁 접근 칸에서 역방향 비용 지도를 만들고 조건이 같은 병력끼리 공유합니다. 공격력·속도의 구간별 대표값은 계산 재사용을 위한 근사입니다. 개별 병력의 정확한 비용과 캐시 적중 사이에 절충이 있습니다.

화면 먼저 확정 vs 저장 성공 후 확정

진행 변경은 복제한 후보에 적용하고 저장이 성공한 뒤 현재 상태로 확정합니다. 저장 실패 시 기존 진행을 보존할 수 있지만 완료 표시까지 저장 성공을 기다려야 합니다. 콘텐츠 정산은 동일 PendingChange를 보존해 재시도합니다.

설계 이유

구조의 장점만 나열하지 않고 무엇을 지키기 위해 어떤 복잡성과 제약을 받아들였는지 보여줍니다.

적용 범위와 한계

현행 구현을 설명하기 위한 대안 비교입니다. 대안별 구현·성능 비교 실험이나 개발 당시의 사건 순서를 뜻하지 않습니다.

참고한 구현과 문서
  • MonsterMakerAssetWriter / MonsterMakerWriteTransaction
  • HexCastleAssaultNavigation.BuildReverseField / topologyVersion
  • GameDataService.ApplyAndSaveCoreAsync
  • ContentFlow.TrySaveAndFinishAsync
담당 영역 분리 / DEV / Main 공통 원본 / StartData / Result / 통합 소유권

팀원이 독립적으로 일할 수 있는 환경

작업 영역, 개발용 실행과 통합 지점을 함께 설계했습니다.

담당 영역을 나누는 기준

기능 담당은 Feature 영역을, 콘텐츠 담당은 개별 콘텐츠 폴더와 개발용 씬을 사용합니다. 공용 계약과 시스템 등록 Catalog·Build Settings는 공용·통합 담당의 책임으로 묶어 같은 파일을 동시에 수정하는 충돌을 줄이는 방향입니다.

같은 원본으로 개발과 게임을 연결

성장 던전은 DEV와 Main에서 같은 원본 Prefab·Controller를 사용하고 입력 데이터를 나눕니다. DEV에서 직접 실행할 때는 Dummy StartData, 정상 게임에서는 실제 진행 데이터로 만든 StartData를 사용하도록 설계했습니다.

콘텐츠가 공통 처리를 반복 구현하지 않도록

각 콘텐츠는 고유 플레이와 타입 Result에 집중합니다. ContentFlow와 Adapter가 공통 결과·저장·복귀를 연결합니다. 성장 던전은 Hosted Prefab, 군단의 역습은 별도 Hex Scene이라는 차이를 공용 실행 계약으로 다룹니다.

Maker로 확장한 제작 환경

같은 분업 원칙을 몬스터 제작에도 적용했습니다. 내부 구조를 직접 구현하지 않는 팀원도 정해진 입력·미리보기·검증·생산 흐름에 참여하고, 구조와 반복 자동화는 도구 쪽에서 담당하도록 했습니다.

설계 이유

각 팀원이 전체 구현을 모두 이해해야만 작업할 수 있는 구조 대신 자기 영역의 입력과 결과 계약에 집중할 수 있는 환경을 목표로 했습니다.

적용 범위와 한계

공용 계약과 제작 도구를 통해 팀원이 담당 콘텐츠 제작에 집중할 수 있도록 했습니다. 개발 효율의 정량 비교는 후속 측정 과제입니다.

참고한 구현과 문서
  • TeamDocs/02_최종구조도_9차.md · 담당 소유권 / Hosted Prefab / 팀 통합 절차
  • TeamDocs/07_구조설계_이유와대안_이해하기.md · 독립 작업 / 같은 원본 공유
  • Docs/10_공통런타임시스템_마스터.md · 현재 공통 실행 흐름
MiniMax H3 / 뽑기 연출 / 타이틀 화면 / 보스 연출

AI를 활용한 게임 연출 제작

MiniMax H3를 뽑기·타이틀 화면·보스 연출 제작에 활용했습니다.

뽑기 연출

새로운 몬스터와 스킬을 얻는 순간을 보여주는 연출 제작에 AI를 활용했습니다. 아래 기술 탭에서는 별도로 결과 카드의 표시 순서와 건너뛰기, 확정된 결과와 화면 표현의 경계를 설명합니다.

타이틀 화면

게임에 처음 진입하는 타이틀 화면의 연출 제작에 활용했습니다. 게임의 분위기를 소개하는 시각 요소도 제작 범위에 포함했습니다.

보스 연출

보스 장면의 연출 제작에도 활용했습니다. 기존 발표의 보스 페이즈 전환 영상과 함께 적용 사례를 제시합니다.

포트폴리오에서 보여주는 역할

AI 도구를 활용한 연출 제작과 게임 시스템 구현을 함께 설명합니다. 생성된 연출 소스, UI의 결과 표시, 실제 전투 실행은 각각의 역할을 구분해 읽을 수 있습니다.

설계 이유

획득·진입·전환처럼 플레이어가 경험하는 주요 순간까지 제작 범위에 포함했음을 보여줍니다.

적용 범위와 한계

MiniMax H3를 뽑기·타이틀 화면·보스 연출 제작에 활용했습니다. AI 영상 제작과 게임 내 재생 연결, 보스 전투 로직은 각각 다른 작업 범위입니다.

참고한 구현과 문서
  • V12 HighlightReel · summon-ten-live / skill-summon / boss-phase
  • GachaRevealSequence · 결과 카드 표시와 건너뛰기