TBD
아직 작성 중인 게시글입니다.
// Layout:
// [0..4) Magic 4 byte identifier
// [4..6) Version uint16 LE (현재 2)
// [6..8) NumSections uint16 LE (N)
// [8..8+44*N) SectionTable[N], id 오름차순 정렬
// id:u16, flags:u16, offset:u32, len:u32, sectionHash:32B
// [8+44*N..end-32) Section payloads (raw bytes), 테이블 offset 순서대로 연속 배치
// [end-32..end) HeaderHash = SHA-256(magic..end-of-table)그 외 짚어둘 디자인 결정들.
flags: u16- 미래 확장 슬롯- 섹션 엔트리에 16비트 플래그를 둡니다. 현재 V2에서는 모두 0이지만, 섹션별 인코딩(예:
0x01 = gzip,0x02 = encrypted)을 데이터로 표현할 자리를 미리 비워뒀습니다. 디코더가 플래그를 보고 동작을 분기하면 Version bump 없이 점진 확장이 가능합니다.
- 섹션 엔트리에 16비트 플래그를 둡니다. 현재 V2에서는 모두 0이지만, 섹션별 인코딩(예:
SectionId는 enum, 순서가 아닌 ID로 lookup- 페이로드를 “0번 섹션 = 세이브, 1번 = 로그” 식의 위치 기반으로 찾는 건 위험합니다. 섹션이 늘거나 빠질 때마다 디코더 측이 깨집니다. 항상 ID로 dict lookup을 강제합니다.
실구성
빌드한 게임에서 실제로 떨어진 save.bin을 hex로 까서 레이아웃이 의도대로 나오는지 검증해봤습니다. 파일 크기는 17058 bytes.
| Offset | Size | Content |
|---|---|---|
| 0..7 | 8 B | Magic + v=2 + NumSections=2 |
| 8..51 | 44 B | Section[0]: id=1 SaveSnapshot, offset=96, len=14036, sectionHash 07ab9cdc... |
| 52..95 | 44 B | Section[1]: id=2 EventLog, offset=14132, len=2894, sectionHash 731ffaad... |
| 96..14131 | 14036 B | SaveSnapshot JSON UTF-8: {"Uid":"...":1} |
| 14132..17025 | 2894 B | EventLog jsonl: {"$type":"log-stat-set",...}\n{"$type":"log-buy-item",...}\n... |
| 17026..17057 | 32 B | HeaderHash be1c4b14... |