닉네임 타이틀·마을 불러오기·동기화 비교 버그 수정

- HUD 타이틀: 닉네임 설정 시 "{닉네임}의 마을 · 회관 LvN"
- 닉네임 모달에 "마을 불러오기" 모드: 기존 마을 이름 입력 →
  1초 디바운스로 존재 확인("마을을 찾았어!") → 서버 세이브 복원
  (/api/village/recover — 토큰 포함 반환, 비밀코드 보호는 추후)
- pull 비교 버그 수정: 오프라인 정산이 로컬 updatedAt을 항상 현재로
  만들어 다른 기기 세이브를 절대 못 받던 문제 → 디스크에서 읽은
  시점(loadedUpdatedAt) 기준으로 비교
- 모달 UX: Enter로 결정(한글 조합 중 제외), IME 간섭 제거(trim 시점 이동),
  모드 전환 시 자동 재체크

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
이 커밋은 다음에 포함됨:
kjs
2026-08-14 10:44:50 +09:00
co-authored by Claude Fable 5
부모 5dd74babe8
커밋 d5ce9be5f4
5개의 변경된 파일과 148개의 추가작업 그리고 38개의 파일을 삭제
+11 -1
파일 보기
@@ -137,6 +137,7 @@ function createInitialState(): GameState {
let state: GameState | null = null;
let offlineMinutes: number | null = null;
let loadedUpdatedAt = 0; // 디스크에서 읽은 시점의 updatedAt (동기화 비교 기준)
function passiveSpeedMul(cat: Cat): number {
return cat.passives.reduce((mul, key) => {
@@ -290,7 +291,10 @@ export const engine = {
const raw = localStorage.getItem(SAVE_KEY);
if (raw) {
const saved = JSON.parse(raw) as GameState;
if (saved.version === 1) state = saved;
if (saved.version === 1) {
state = saved;
loadedUpdatedAt = saved.updatedAt ?? 0;
}
}
} catch {
// 저장 데이터가 깨졌으면 새로 시작
@@ -349,10 +353,16 @@ export const engine = {
/** 서버 세이브로 교체 (더 최신일 때) — 마이그레이션·오프라인 정산 재수행 */
replaceState(data: GameState) {
state = data;
loadedUpdatedAt = data.updatedAt ?? 0;
this.finishLoad();
this.save();
},
/** 디스크에서 읽은 시점의 updatedAt */
loadedUpdatedAt(): number {
return loadedUpdatedAt;
},
/** 닉네임·토큰 설정 */
setNickname(nickname: string, token: string) {
if (!state) return;