BurningTimesAi/개발실/프로젝트_숙지/수상한잡화점/10_데이터로딩_구조_v1.md

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_cardlisttableDatas, 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:/NerdNavis/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.csServerData
  • 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 초안