AGENT SKILL

43-savedata-json-codec

暂无简介

License 许可
MIT
所属仓库
devwinsoft/devian
最近更新
2026-04-12
Stars
★ 0
Forks
0

02 资源文件 1

03 SKILL.md 正文

43-savedata-json-codec — SaveDataJsonCodec

Status: ACTIVE AppliesTo: v10 Type: Design / SSOT

Purpose

SaveDataManager가 local/cloud payload에 저장할 게임 상태 JSON의 직렬화/역직렬화 규약을 정의한다.

  • JSON 직렬화/역직렬화의 유일한 진입점은 SaveDataManager 이다.
  • AccountManager, InventoryManager, PurchaseManager, GameMessageManager, MissionManager, AchieveManager, LeaderboardManager, AttendManager, TreasureManager는 각자 자신의 Storage를 소유한다.
  • JSON 구현은 SaveDataJsonCodec root codec + section codec으로 분리한다.

Ownership

  • AccountManager 소유: AccountStorage
  • InventoryManager 소유: InventoryStorage
  • PurchaseManager 소유: PurchaseStorage
  • GameMessageManager 소유: GameMessageStorage
  • MissionManager 소유: MissionStorage
  • AchieveManager 소유: AchieveStorage
  • LeaderboardManager 소유: LeaderboardSeasonRewardStorage
  • AttendManager 소유: AttendStorage
  • InventoryStorage 내부: TreasureCurrent, TreasureCounts (treasure 상태)
  • SaveDataManager 책임:
    • 위 storage를 수집
    • primary save binding(local filename + cloud slot) 관리
    • JSON serialize/deserialize 호출
    • payload encrypt/decrypt
    • local/cloud save, load, sync, conflict

중요:

  • GameStorageManager는 삭제되었다.
  • 각 manager는 자신의 storage를 직접 소유하며, SaveDataManager가 이를 묶어 저장한다.

Class Boundary

SaveDataManager : CompoSingleton<SaveDataManager>
│
├── ToJson()
│   └── SaveDataJsonCodec.Serialize(inventory, purchase, shop, account, message, mission, achieve, leaderboardReward, attend, treasure)
│
├── LoadFromJson(json)
│   └── SaveDataJsonCodec.DeserializeInto(json, inventory, purchase, shop, account, message, mission, achieve, leaderboardReward, attend, treasure)
│
├── LoadFromPayload(payload)
│   └── ComplexUtil.Decrypt_Base64(payload) -> LoadFromJson(json)
│
└── ClearGameState()
    ├── AccountManager.Instance.Storage.Clear()
    ├── InventoryManager.Instance.Storage.Clear()
    ├── PurchaseManager.Instance.Storage.ClearAll()
    ├── GameMessageManager.Instance.Storage.Clear()
    ├── MissionManager.Instance.Storage.Clear()
    ├── AchieveManager.Instance.Storage.Clear()
    ├── LeaderboardManager.Instance.Storage.Clear()
    ├── AttendManager.Instance.Storage.Clear()
    └── TreasureManager.Instance.Storage.Clear()
  • root orchestration: SaveDataJsonCodec
  • inventory section: SaveDataJsonCodecInventory
  • purchase section: SaveDataJsonCodecPurchase
  • account section: SaveDataJsonCodecAccount
  • message section: SaveDataJsonCodecMessage
  • mission section: SaveDataJsonCodecMission
  • achieve section: SaveDataJsonCodecAchieve
  • leaderboard reward section: SaveDataJsonCodecLeaderboardReward
  • attend section: SaveDataJsonCodecAttend
  • treasure section: SaveDataJsonCodecTreasure

section codec은 manager를 직접 알지 않고, Storage 타입만 다룬다. 역직렬화 실패는 throw 대신 CommonResult.Failure(...)로 root caller에 전달한다.

Error Model

  • save/load는 대표적인 boundary다. parse/version/restore 실패는 CommonResult로 반환한다.
  • root caller(SaveDataManager)가 clear/retry/fallback 정책을 선택한다.
  • section codec은 malformed JSON, lookup miss, restore failure를 조용히 무시하지 않는다.
  • private helper에서만 이미 정규화된 내부 invariant 위반 예외를 제한적으로 허용할 수 있다.
  • 단, helper 예외가 codec boundary를 넘어 public API 기본 모델이 되지 않게 한다.

Primary Save Rule

  • public save API는 멀티 슬롯을 노출하지 않는다.
  • SaveDataManager는 단일 primary save binding만 가진다.
  • codec은 binding을 모르고, 순수하게 게임 상태 JSON만 다룬다.

Root JSON Schema

{
  "version": 20,
  "inventory": {},
  "purchase": {},
  "shop": {},
  "account": {},
  "message": {},
  "mission": {},
  "achieve": {},
  "leaderboardReward": {},
  "attend": {},
  "treasure": {}
}
  • version: root schema version
  • inventory: InventoryStorage 섹션
  • purchase: PurchaseStorage 섹션
  • shop: ShopStorage 섹션
  • account: AccountStorage 섹션
  • message: GameMessageStorage 섹션
  • mission: MissionStorage 섹션
  • achieve: AchieveStorage 섹션
  • leaderboardReward: LeaderboardSeasonRewardStorage 섹션
  • attend: AttendStorage 섹션
  • treasure: InventoryStorage treasure 섹션

payload wrapper(SaveLocalPayload, SaveCloudPayload)의 account 메타는 유지한다. 이 메타는 sync 초기 판정과 account mirror 용도이며, root JSON의 account 섹션과 별개로 존재할 수 있다.


Section Sourcing

serialize 시 source:

  • AccountManager.Instance.Storage
  • InventoryManager.Instance.Storage
  • PurchaseManager.Instance.Storage
  • GameMessageManager.Instance.Storage
  • MissionManager.Instance.Storage
  • AchieveManager.Instance.Storage
  • LeaderboardManager.Instance.Storage
  • AttendManager.Instance.Storage
  • TreasureManager.Instance.Storage

deserialize 시 target:

  • AccountManager.Instance.Storage
  • InventoryManager.Instance.Storage
  • PurchaseManager.Instance.Storage
  • GameMessageManager.Instance.Storage
  • MissionManager.Instance.Storage
  • AchieveManager.Instance.Storage
  • LeaderboardManager.Instance.Storage
  • AttendManager.Instance.Storage
  • TreasureManager.Instance.Storage

로드 직후 런타임 재적용:

  • AccountManager.ApplyStorage(AccountManager.Instance.Storage)
  • InventoryStorage.Rentals/Passes는 payload(local/cloud)에 저장/복원되며, 로그인/복원 시 PurchaseManager.SyncEntitlementsAsync()가 서버 entitlements 값으로 재동기화한다.
  • Mission은 MissionManager가 자신의 MissionStorage를 기준으로 runtime state를 재구성한다
  • Mission/Achieve/SeasonReward claim 상태 변경 직후에는 SaveDataManager.SaveGameStorageAsync(true, ct)로 root payload 저장을 즉시 시도해야 한다
  • 이 local save가 실패하면 mission 시스템은 플레이 불가능 상태로 처리한다(TODO)

Version / Migration Rules

  • schema 변경 시 root version을 증가시킨다.
  • 하위호환이 필요하면 root codec에서 version 분기 처리한다.
  • section codec은 자신이 담당하는 섹션의 레거시 필드만 복구한다.
  • 지원하지 않는 version이면 조용히 부분 로드하지 말고, 명시적인 fallback 정책을 문서에 기록한다.
  • malformed JSON / section restore failure는 CommonResult.Failure(...)로 반환하고 상위 caller가 전체 상태를 정리한다.
  • save payload/section 오류를 public API에서 throw 기본 모델로 바꾸지 않는다.

Hard Rules

  • manager가 자신의 storage를 소유하더라도, payload JSON 직렬화 진입점은 SaveDataManager 하나만 유지한다.
  • InventoryStorage, PurchaseStorage, AccountStorage, GameMessageStorage, MissionStorage, AchieveStorage, LeaderboardSeasonRewardStorage, AttendStorage에 ToJson() / FromJson()을 다시 추가하지 않는다.
  • codec은 domain rule을 가지지 않는다. domain mutation은 각 manager가 담당한다.
  • inventory item save는 generic stats blob를 생성 정본으로 쓰지 않는다. item 생성은 item_id/itemUid/item_level과 table lookup으로 복원하고, mutable 상태는 amount/equips 같은 explicit field로 저장/복원한다.
  • equip owner는 별도 field로 저장하지 않는다. hero equip ownership의 저장/복원 SSOT는 heroes[*].equips다.
  • save JSON에서 enum은 숫자 ordinal로 저장하지 않는다. enum key/value가 필요하면 반드시 enum name 문자열을 사용한다.
  • legacy 숫자 enum 파싱은 load 호환용으로만 유지한다. 새 serialize 경로는 숫자 enum을 쓰지 않는다.
  • 새 저장 섹션 추가 시:
    • root codec 수정
    • section codec 추가
    • SaveDataManager sourcing 연결
    • 관련 manager skill 문서 갱신
  • save/load 전용 신규 에러 코드는 COMMON_ERROR append-only 규칙 안에서만 추가한다.

Implementation Location (3-path mirror)

  • UPM (정본):
    • framework-cs/upm/com.devian.foundation/Samples~/MobilePackage/Runtime/SaveData/JsonCodec/SaveDataJsonCodec.cs
    • framework-cs/upm/com.devian.foundation/Samples~/MobilePackage/Runtime/SaveData/JsonCodec/SaveDataJsonCodecInventory.cs
    • framework-cs/upm/com.devian.foundation/Samples~/MobilePackage/Runtime/SaveData/JsonCodec/SaveDataJsonCodecPurchase.cs
    • framework-cs/upm/com.devian.foundation/Samples~/MobilePackage/Runtime/SaveData/JsonCodec/SaveDataJsonCodecAccount.cs
    • framework-cs/upm/com.devian.foundation/Samples~/MobilePackage/Runtime/SaveData/JsonCodec/SaveDataJsonCodecMessage.cs
    • framework-cs/upm/com.devian.foundation/Samples~/MobilePackage/Runtime/SaveData/JsonCodec/SaveDataJsonCodecMission.cs
    • framework-cs/upm/com.devian.foundation/Samples~/MobilePackage/Runtime/SaveData/JsonCodec/SaveDataJsonCodecAchieve.cs
    • framework-cs/upm/com.devian.foundation/Samples~/MobilePackage/Runtime/SaveData/JsonCodec/SaveDataJsonCodecLeaderboardReward.cs
    • framework-cs/upm/com.devian.foundation/Samples~/MobilePackage/Runtime/SaveData/JsonCodec/SaveDataJsonCodecAttend.cs
    • framework-cs/upm/com.devian.foundation/Samples~/MobilePackage/Runtime/SaveData/JsonCodec/SaveDataJsonCodecTreasure.cs
  • Packages (sync):
    • framework-cs/apps/UnityExample/Packages/com.devian.foundation/Samples~/MobilePackage/Runtime/SaveData/JsonCodec/...
  • Assets/Samples (import):
    • framework-cs/apps/UnityExample/Assets/Samples/Devian Samples/{version}/MobilePackage/Runtime/SaveData/JsonCodec/...

Related

04 同仓库更多 Skills