9.3 KiB
9.3 KiB
10. 데이터 테이블 로딩 · 캐싱 구조 v1
- 작성일: 2026-04-14
- 작성자: 개발실장 (Explore 에이전트 분석 위임)
- 목적: 기획실 엑셀(.xlsm) SOT가 Unity 런타임에 닿기까지의 로딩·캐싱·조회·보안·버전관리 구조 확정
- 스코프:
Assets/Script/Table/,Assets/ResWork/Table/Export/,MyClass.cs내 베이스 타입 - 선행:
08_전투시스템_SOT_v1.md,09_카드시스템_아키텍처_v1.md
1. 로더 아키텍처
1.1 베이스 계층
| 타입 | 파일 | 역할 |
|---|---|---|
table_base (MonoBehaviour) |
Assets/Script/Table/table_base.cs (1~27) |
TextAsset → json 문자열 캐시, LoadComplete 플래그, 문자열 값 파서 |
TableDataBase |
Assets/Script/My/MyClass.cs:23~45 |
Get_Name, Get_Desc, Get_ImagePath, Get_Value 공통 인터페이스 |
MissionTableDataBase |
Assets/Script/My/MyClass.cs:137~145 |
미션·업적 공통 필드 |
MonoBehaviourSingletonTemplate<T> |
Assets/Script/Template/MonoBehaviourSingletonTemplate.cs |
public static T Ins / public static bool isIns / Awake에서 자기 주입 |
1.2 초기화 라이프사이클
Awake: json_last = m_json.text; // 문자열만 유지
Resources.UnloadAsset(m_json); // TextAsset 객체는 언로드
Start: tableDatas = JsonConvert.DeserializeObject<List<T>>(json_last);
// Dictionary 인덱스 구축
LoadComplete = true;
- JSON 라이브러리: Newtonsoft.Json (
using Newtonsoft.Json;전 테이블 공통) - 모든 테이블이
Start()에서 병렬적으로 역직렬화.TableChecker.CheckAllLoad()로 완료 확인 (TableChecker.cs:12~22). - 타이틀/인게임 진입 시
while (!TableChecker.Ins.CheckAllLoad()) yield return null;으로 블로킹 대기 (Title_Mgr.Co_Check()·InGameInfo.Start()).
1.3 메모리 레이아웃
TextAsset JSON
→ string json_last
→ List<T> tableDatas // 순차 접근
→ Dictionary<Key, T> dic_* // O(1) 조회 (ID·Enum·등급 등 다중 인덱스)
예: table_cardlist 는 tableDatas, dic_gradeData, dic_Data(eCardType), dic_Data_byID(int) 4중 인덱스 유지 (table_cardlist.cs:451~454).
2. 조회 API 패턴
2.1 권장 패턴 — Get_*_orNull
public ActorListTableData Get_Data_orNull(string key)
=> dic_Data.ContainsKey(key) ? dic_Data[key] : null;
2.2 폴백 메시지 패턴
// table_localtext
public string Get_Talk(int patternid)
=> dic_Data.ContainsKey(patternid) ? /* ... */ : $"No ActorTalk {patternid}";
2.3 위험 패턴 — Direct 인덱서
// table_cardlist
public CardListTableData Get_Data(eCardType type) => dic_Data[type]; // KeyNotFoundException 가능
// table_GlobalValue
public int Get_Int(string id) => dic[id]; // 동일 위험
→ 리스크: 문자열 키 오타, 미등록 카드 추가 시 런타임 크래시. B-3 개선 과제로 제안: 전체 Get_*를 TryGet 또는 _orNull 패턴으로 정규화.
3. JSON 익스포트 워크플로
3.1 경로
| 단계 | 경로 |
|---|---|
| SOT 엑셀 | D:/BurningTimes/FilGoodBandits/DeckBuilding/Assets/ResWork/Table/DeckBuilding.xlsm (최근 수정 2026-04-14) |
| 백업 | 동 경로 DeckBuilding_Ino.xlsm |
| 익스포트 결과 | Assets/ResWork/Table/Export/ — JSON 58개 + CSV 일부 (총 ~3.3 MB) |
| 에디터 도구 후보 | Assets/Editor/ — MyEditorUtil.cs에는 익스포트 코드 없음. (확인 필요) 외부 VBA/Python 스크립트 가능성 |
3.2 주요 JSON 파일 크기 Top 5
| 파일 | 크기 |
|---|---|
PCAwakening.json |
442 KB |
StatusOptionSet.json |
354 KB |
Localization.json |
261 KB |
CardList.json |
180 KB |
MonsterList.json |
157 KB |
3.3 CSV 혼재
일부 테이블(예: ApprearMonsterPattern.csv)이 CSV로 내보내짐. 파싱 경로가 JSON과 이원화될 수 있어 (확인 필요).
4. 핫패스 테이블 접근
Actor.Get_Dmg() 기준 전투 루프에서 접근되는 테이블:
| 테이블 | 호출 | 빈도 |
|---|---|---|
table_GlobalValue.Ins.Get_Int("PCDefence") |
Actor.cs:775 |
피해 계산마다 — 고빈도 |
table_GlobalValue.Ins.Get_Float("PCDefence_Mul") |
Actor.cs:783 |
동 |
table_PCUniqueAwakening.Ins.Get_Data() |
Actor.cs:793 |
피해 계산마다 |
table_cardlist.Ins.Get_Data() |
Actor.cs:118 |
카드 초기화 시 |
table_SanctuaryConfig.Ins / table_StatusOptionSet.Ins |
Actor.cs:158~159 |
부활·상태이상 이벤트 시 |
table_StatusConditionsList.Ins.Get_Data_orNull() |
Actor.cs:930 |
부활 |
table_PCAwakening.Ins.Get_Value() |
Actor.cs:937 |
부활 회복 계산 |
개선 여지: PCDefence·PCDefence_Mul 처럼 피해 계산마다 문자열 키로 GlobalValue를 조회하는 경로는 한 번 캐시해두면 알로케이션·딕셔너리 조회 비용이 줄어듦. 모바일 타깃에서는 유효.
5. 런타임 교체 · 서버 연동
5.1 Hot-reload
- 런타임 테이블 교체 코드 확인 안 됨. Dictionary 자체는 수정 가능하지만 공식 경로 없음.
- Addressables 연동 (확인 필요) —
Res_Addr/폴더는 존재하나 테이블 JSON은 현재 TextAsset Resources 방식.
5.2 ServerData 오버라이드
- 경로:
Assets/Script/Server/ServerClass.cs의ServerData - Actor 생성 시 주입:
Actor.Set(int identity, ActorTableDataBase actordata, HUD_HPShield hud, ServerData sdata = null) - 쓰임: 각성·봉인 값 등 서버 계정 데이터로 테이블 값 일부 오버라이드 —
Get_ServerData().Get_PCAwakenLv(...)
결론: 런타임 재조정은 테이블 교체가 아닌 사용자 데이터 오버라이드 방식으로 제한됨. 밸런싱 hot-reload는 미지원 — Phase 1+ 과제.
6. 보안 · 변조
6.1 런타임 암호화 (CodeStage AntiCheat)
ObscuredInt/ObscuredFloat사용. 예:CardListTableData._ID,BattleLevelUpTableData._Lv,MissionTableDataBase._Index.- 세터에서
RandomizeCryptoKey()재수행 — 키 갱신. - 메모리 스캔·치트엔진 공격 완화 목적.
6.2 디스크 JSON
- 평문 저장. StreamingAssets/Resources로 빌드 포함 → APK 분해 시 노출.
- 클라이언트 변조 가능성 높음 — 서버 검증 필수 영역.
6.3 서버 검증
- PlayFab Editor Extensions 존재 (
Assets/PlayFabEditorExtensions/) — 실 운영 API 연동 (확인 필요). - 05번 문서(서버연동 현황)에서 도출된 Critical 3건 보류 상태와 직결. (IAP 미검증·전투 클라 100%·AES 평문키)
7. 리스크 · 이슈
| 항목 | 영향 | 개선 방향 |
|---|---|---|
| 엑셀→JSON 수동 익스포트 | 기획 수정 후 반영 누락 가능 | 자동화 스크립트 + CI 통합 |
| 다중 엑셀 파일 (Ino 백업) | 어느 게 SOT인지 혼동 | 파일명 규칙·버전 태그 명시화 |
| CSV·JSON 혼재 | 파싱 경로 분기 | JSON으로 일원화 검토 |
| Direct 인덱서 사용 | 미등록 키 시 크래시 | _orNull/TryGet 표준화 |
| JSON 평문 | 클라 변조 | 빌드 시 암호화 래퍼 or 바이너리 포맷 |
| GlobalValue 문자열 키 핫패스 | 모바일 GC·딕셔너리 조회 비용 | 상수 캐시 / enum 키 도입 |
| 테이블 버전 메타 없음 | 롤백·동기화 추적 곤란 | JSON 헤더에 version/buildId 도입 |
8. 테이블 인벤토리
Assets/Script/Table/Tables/아래 51개table_*클래스- Export/ 아래 58개 JSON + 소수 CSV
- 대표:
table_ActorList(534 B),table_BuffPatternConfig(2.6 KB)table_cardlist(180 KB),table_Achievement(247 KB)table_ApprearMonsterPattern(56 KB),table_localtext(다국어)table_GlobalValue(스칼라 파라미터 핫패스)
전수 목록은 필요 시 별도 부록으로 추출 가능.
9. B-3 완료 조건 체크리스트
- 로더 계층·싱글톤 패턴 확정
- 초기화 라이프사이클(Awake 캐시 → Start 파싱) 확정
- 조회 API 3패턴(
_orNull/폴백 메시지/Direct) 확정 - 핫패스 테이블 호출 맵
- ObscuredTypes 적용 범위 확인
- Excel → JSON 익스포트 도구 실체 확인 (Editor 스크립트 vs VBA/외부) (확인 필요)
- Addressables 연동 여부 확인
- PlayFab 서버 검증 실제 호출 경로 확인
- 전체 51개 테이블 인벤토리 부록화
- Direct 인덱서 전수 목록화 후 정규화 과제 티켓화
- JSON 암호화 방안 설계(타입 결정 + 빌드 파이프라인 반영)
10. 기획실 워크플로 접점 요약
| 단계 | 담당 | 산출 | 검증 |
|---|---|---|---|
| 밸런싱 작업 | 기획실 | DeckBuilding.xlsm |
기획 자체 검토 |
| 익스포트 | (확인 필요) | Export/*.json |
파일 타임스탬프 비교 |
| 빌드 포함 | Unity 빌드 | APK 내 TextAsset | TableChecker LoadComplete |
| 런타임 조회 | 코드 | Dictionary 조회 | — |
| 서버 오버라이드 | PlayFab | ServerData 주입 | 로그인 직후 |
→ 단일 취약점: "익스포트 단계"가 자동화되지 않은 것으로 보이는 지점. 개발실 우선 정비 후보.
11. 변경 이력
| 버전 | 일자 | 작성자 | 내용 |
|---|---|---|---|
| v1 | 2026-04-14 | 개발실장 (Explore 위임) | Phase 0-B-3 초안 |