2026-09-16 — 완료. 서버 테스트 283건 통과 · Unity 에디터(unity CLI
eval)로 실서버 왕복 검증 — 신규 2칸 · 선행/골드/재화/중복/없는 TID 거절 · 해금 후 칸 생성 · 치트 지급 · 재로그인 유지. 경위는.claude/Agent/2026-09-16-unlock-server.md.2026-09-14 — 슬롯 전용 해금(잠긴 칸 패킷·
C_WorkStationUnlockRequest)에서 범용 해금 시스템의 첫 구현으로 바뀌었다 → 해금. 데이터(Unlock.xlsx—UnlockTable·WorkSlotTable)는 들어가 있다.
배경
슬롯을 여는 경로가 서버에 아예 없다. 기획은 시작 2개 · 상한 8개로 확정됐는데 서버는
User.DefaultSlotCount = 1이고, 패킷은 열린 슬롯만 담아 잠긴 칸을 표현하지 못한다.
클라는 1~7번 칸을 열린 빈 칸과 구분하지 못하고, 눌러 봐야 InvalidSlotIndex 거절뿐이다.
해금은 슬롯만의 문제가 아니라 산업 레벨·특성에도 같은 모양으로 필요해서, 한 표(UnlockTable)와
한 행동(C_UnlockRequest) 으로 모으기로 했다. 이 일감이 그 골격을 세우고 슬롯에 처음 적용한다.
규칙 (확정 · 상세는 기획 문서)
| 항목 | 값 |
|---|---|
| 조건 | UnlockTable 행의 Gold · AccountLevel · RequiredUnlockTIDs. 0/빈 값 = 없음. 지불 컬럼끼리 OR, 나머지와 AND |
| 판정 순서 | 없는 TID → 이미 열림 → 선행 미충족 → 레벨 미달 → 골드 차감(TrySpendGold 재사용) → 기록 |
| 영속 | t_user_unlock (user_id, unlock_tid, unlocked_at) PK (user_id, unlock_tid). 재검사 없음 |
| 슬롯 | WorkSlotTable.WorkSlotTID(=칸 번호 0~7) → UnlockTID. 0은 항상 열림 = 시작 2칸. 행 수 = 상한 8 |
| 계정 레벨 | 아직 서버에 없다. AccountLevel은 전부 0이라 이번엔 검사만 자리를 만들고 값은 0 비교로 통과한다 |
할 일
- [x]
UnlockCatalog—UnlockTable·WorkSlotTable인덱스 (IndustryLevelCatalog와 같은 모양,GameServer에서LoadAll) + 로드 검증 3종 (해금 2.5): 선행 순환·자기 참조 → 예외 · 한UnlockTID를 두 콘텐츠가 참조 → 예외 · 미참조 → 경고 - [x]
t_user_unlockDDL (sqlite-sql-creator) + 로그인 적재(LoginRepository) +SaveUnlockRepository - [x]
User.Unlock.cs—IsUnlocked(unlockTid)(0은 true) ·TryUnlock(unlockTid, currency)판정 순서대로 (고른 재화가 이 해금에 없으면UnlockLocked) ·GrantUnlock(unlockTid)— 조건·차감 없이 기록·통지·콘텐츠 후속 (퀘스트·튜토리얼·치트용, 해금 2.4). 치트Unlock = 7도 이때 붙인다 - [x] 패킷 (
packet-creator) —C_UnlockRequest{UnlockTID, Currency}·S_UnlockResponse{Result, UnlockTID}·S_UnlockListResponse{UnlockTIDs}(로그인 직후, 슬롯 스냅샷보다 앞) - [x]
EResultCode—InvalidUnlockTID·AlreadyUnlocked·UnlockLocked.NotEnoughCurrency는 있다 - [x] 슬롯 후속 — 해금된
UnlockTID가WorkSlotTable의 어느 칸인지 찾아WorkStation.Unlock→S_WorkStationSlotSyncResponse푸시 - [x] 로그인 시 열린 칸 구성 —
WorkSlotTable을 돌며IsUnlocked인 칸만 만든다.DefaultSlotCount상수 제거. DB에 잠긴 칸의 배치 행이 있으면 경고 후 무시 (지우지 않는다) - [x] 배치 검증에 상한 — 없는 칸·잠긴 칸은
InvalidSlotIndex(지금 코드가 이미TryGet실패로 거절한다 — 확인만) - [x] 테스트 (
server-tdd) — 선행 미충족 거절 · 골드 부족 거절(차감 없음) · 정상 해금 시 골드 차감 + 기록 + 슬롯 생성 · 이미 열린 것 거절 · 재로그인 후 유지 - [x] 프로토콜 미러 커밋 (서버 일감 공통 완료 조건)
완료 조건
신규 계정은 2칸으로 시작하고, 로그인 직후 받은 열린 목록과 테이블만으로 클라가 8칸 각각이 열렸는지·무엇이 필요한지를 그릴 수 있으며, 해금 요청을 보내면 서버가 조건을 검증해 골드를 빼고 칸을 열거나 사유를 담아 거절한다. 재로그인해도 유지된다.
막고 있는 것 / 선행 일감
- 없음. 데이터·규칙이 다 있다.
- 계정 레벨 요구치(T-012)는 값만 나중에 채운다 — 검사 코드는 이번에 넣는다.
이어지는 일감
관련 커밋
39ca310— feat: 해금 시스템 서버 구현 — 첫 적용은 작업슬롯
참고
- 해금 기획 — 2장 판정 순서 · 6장 패킷·DB
GameDesign/Excel/Unlock.xlsx·Server/GameData/Tables/UnlockTable.cs·WorkSlotTable.csServer/WSGameServer/User/User.WorkStation.cs·User.DB.cs·User.Currency.cs(TrySpendGold)