# 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`

```csharp
public ActorListTableData Get_Data_orNull(string key)
    => dic_Data.ContainsKey(key) ? dic_Data[key] : null;
```

### 2.2 폴백 메시지 패턴

```csharp
// table_localtext
public string Get_Talk(int patternid)
    => dic_Data.ContainsKey(patternid) ? /* ... */ : $"No ActorTalk {patternid}";
```

### 2.3 위험 패턴 — Direct 인덱서

```csharp
// 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.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 완료 조건 체크리스트

- [x] 로더 계층·싱글톤 패턴 확정
- [x] 초기화 라이프사이클(Awake 캐시 → Start 파싱) 확정
- [x] 조회 API 3패턴(`_orNull`/폴백 메시지/Direct) 확정
- [x] 핫패스 테이블 호출 맵
- [x] 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 초안 |
