fix: resume campaign progress safely

This commit is contained in:
2026-07-29 01:13:57 +09:00
parent 90de2a3559
commit 6f2b6e42a4
31 changed files with 9354 additions and 148 deletions

View File

@@ -401,10 +401,67 @@ RPG로 다듬는다.
위치·방향·대사 줄·선택창·상점·군령 카드 복원과 보상 1회성, 정상 퇴장
시 체크포인트 제거를 자동 검증한다.
다음 묶음은 이야기 화면의 페이지 단위 재개와 남은 직접 상태 변경 경로를
같은 저장 원칙으로 정리한다. 탐색 대사에는 문구나 순서가 바뀌어도 같은
장면을 찾는 안정적인 `beatId`와 구버전 변환표를 더해, 긴 캠페인에서
“중단해도 읽은 만큼만 이어지는” 경험을 전 구간으로 확장한다.
### 완료한 18차 묶음: 마지막으로 읽은 대사에서 이어지는 이야기 (2026-07-28)
- 이야기 배열의 순번 대신 장면과 대사의 안정적인 `sequenceId`·`beatId`
저장한다. 대사 추가나 순서 변경 뒤에도 같은 대사를 다시 찾고, 기존의
순번 전용 저장과 과거 ID는 호환 변환표를 거쳐 새 형식으로 옮긴다.
- 이야기 체크포인트를 `reading``handoff`로 나눈다. 읽는 중에는 정확한
페이지를 복원하고, 마지막 대사를 확인한 뒤에는 같은 마지막 페이지를
재생하지 않고 목적 장면으로 바로 이어 간다.
- 페이지를 넘길 때 다음 페이지를 먼저 저장하고, 브라우저 숨김·종료 때
화면에 보이는 대사를 다시 확정한다. 이미 목적 장면으로 넘긴 뒤 들어온
늦은 저장 요청이나 이전 revision의 요청은 완료 상태를 되살리지 못한다.
- 새 캠페인 시작, 마을·의용군 막사 완료, 전투 승리 정산, 군영 출진은
캠페인 단계 변경과 다음 이야기 첫 대사를 한 번의 저장으로 확정한다.
저장이나 장면 로딩이 실패하면 이전 캠페인 전체를 되돌려 반쪽 진행을
남기지 않는다.
- 타이틀 이어하기는 이야기 체크포인트를 낡은 진행 중 전투 저장보다 먼저 본다.
일반·특수 출진과 승전 후일담을 안정 ID로 다시 구성하며, 전투 보고에서
`편성 보완`을 골랐다면 후일담 뒤 군영의 해당 화면까지 의도를 보존한다.
- 새 출전을 확정할 때 전투 저장 세대를 함께 올리고, 전투 저장에도 같은
세대를 기록한다. 브라우저가 낡은 파일 삭제를 거부하더라도 이전 세대의
전투는 타이틀 이어하기뿐 아니라 전투 안의 수동 불러오기에서도 후보가
되지 않으며, 새 전투에서 만든 같은 세대의 저장만 다시 열린다.
- 새 캠페인으로 1번 슬롯을 덮을 때에는 기존 슬롯보다 높은 전투 저장 세대를
먼저 정식 저장한 뒤 낡은 전투 파일을 정리한다. 새 캠페인 저장 자체가
실패하면 기존 캠페인과 진행 중 전투를 모두 그대로 보존하고, 파일 삭제가
거부되더라도 논리 세대가 이전 플레이의 부활을 막는다.
- 마지막 대사에서 목적 장면 시작을 요청한 것만으로 handoff를 지우지 않는다.
출발 장면은 이를 유지하고, 목적 장면이 자신의 캠페인 단계나 후일담 정산을
먼저 확정해 그 단계만으로 복구할 수 있게 된 뒤 정확한 sequence와 revision을
소비한다. 따라서 로딩 도중 종료되어도 이어하기 목적지를 잃지 않는다.
- 승전 후일담에서 군영으로 넘어갈 때에는 전투 정산 표식과 이야기 handoff가
모두 정확히 일치해야 둘을 한 번에 소비한다. 전투 결과 저장이 일시적으로
실패하면 승패 모두 결과창에 `저장 다시 시도`를 제공하고, 저장 전에는
재도전·타이틀·편성 보완 이동을 잠가 결과를 버리는 이탈을 막는다. 저장에
성공한 뒤에만 정상 버튼을 되살리고 후일담이나 재도전으로 진행한다.
- 예전 저장의 `first-victory-story` 단계도 마지막 대사 handoff와 단계 전환을
한 번에 확정해 `first-camp`로 옮긴다. 보상을 다시 지급하지 않으면서 같은
첫 승리 이야기가 계속하기 때마다 반복되는 구버전 저장 루프를 없앤다.
- 승리의 `다음 출전 보완`과 패배의 `재도전 보완`은 출발 전투·목표 전투·
목표 캠페인 단계·보완 종류를 `sortiePreparationCheckpoint`에 함께 남긴다.
타이틀 이어하기는 낡은 전투 저장보다 이 명시적 목적지를 먼저 복원하고,
군영은 장면 전달값이 없어도 편성 보완 화면을 다시 연다. 실제 출전을
한 번의 저장으로 확정할 때만 이를 소비하며, 전투 결과·단계가 어긋난
구버전이나 변조 상태는 로드 시 자동 폐기한다.
- 승리 결과 저장에 이미 동일한 기본 후일담 첫 대사가 들어 있으면 계속하기가
같은 내용을 다시 쓰지 않는다. 결과 저장 뒤 저장 권한이나 용량이 나빠져도
이미 안전하게 확정된 후일담으로 이동하는 데 불필요한 두 번째 쓰기가
장애가 되지 않는다.
- 469개 이야기 대사의 ID 전역 중복을 정적 검사하고, 저장 정규화·구버전
변환·저장 실패 불변성·handoff 경합을 함께 검증한다. Canvas·WebGL 각각
1920x1080 CSS viewport, 100% 확대, DPR 1에서는 정확한 페이지·화자·문구·
배경·초상 복원과 목적 장면 소유권 이전 전후 handoff 수명을 자동 확인한다.
- 스토리 체크포인트·전투 저장 세대·결과 저장 재시도 브라우저 검사는 개발
서버가 아니라 현재 `dist`의 해시 자산을 소유한 미리보기 서버에서 수행한다.
다른 프로세스가 같은 포트에서 응답하면 재사용하지 않고 실패시키며, 응답
제한시간과 종료 대기를 둔다. 운영 배포 시작 전에는 추적 파일뿐 아니라
미추적 파일도 없는지 확인해 로컬에만 존재하는 소스로 배포되는 일을 막는다.
다음 묶음은 탐색 대사에도 문구나 순서가 바뀌어도 같은 장면을 찾는 안정적인
`beatId`와 구버전 변환표를 더한다. 이후에는 전투·이야기·탐색의 모든
중단 지점이 “중단해도 읽고 행동한 만큼만 이어지는” 같은 원칙을 공유한다.
## 장기 개선 순서