BurningTimesAi/공유/대화로그/ImmortalSword/2026-09-17.md

125 lines
15 KiB
Markdown
Raw Permalink Normal View History

# ImmortalSword 대화로그 — 2026-09-17
> §번호는 프로젝트 누적 연속 (`2026-09-16.md` §3 에서 이어짐)
## 4. 커밋 대기 지시 + DataTables JSON → CSV → 엑셀 시트 추가 (PM 직접 집행)
### PD 원문 (2026-09-17 00:1x)
> ④ "커밋은 내 지시 전까지 진행하지 말고 대기해."
>
> ⑤ "우선 "C:\BurningTimes\ImmortalSword\Assets\DataTables" 경로의 모든 json을 csv형태로 변환한 후 ImmortalSword 엑셀 파일에 시트 단위로 추가해줘."
>
> (진행 중 추가) "우선은 전부 클라이언트 기준으로 시트를 채워주면 돼."
**④ 처리**: 수령 시점부터 **커밋·push 전면 대기**(BT·ImmortalSword 양 레포). 본 엔트리·PD 지시 로그 갱신분은 작업 트리에만 둔다. ImmortalSword 로컬 커밋 `335e16d9c`(09-16)는 push 없이 보존.
### 실측
| # | 실측 | 근거 |
|---|------|------|
| 1 | 대상 JSON **19종** (`Assets/DataTables/*.json`, 전부 레코드 객체 배열) · 1,153행 · 14,480셀 | 파싱 스크립트 |
| 2 | 대상 엑셀 = **`Assets/DataTables/ImmortalSword.xlsm`** (116KB, 00:03 저장, git 미추적 `??` = 이력 백업 없음) · 기존 시트 8종(Info·ShopConfig·ShopProduct·ShopGoods·PackageConfig·LimitedTimePackage·DaysPackage·MonthlyReward) | openpyxl · `git status` |
| 3 | 워크북 구성 = **VBA 16모듈 + 양식 컨트롤(ctrlProps·VML 버튼) + Power Query 연결 4종 이상(`connections.xml`·`customXml/item1.xml`) + LAMBDA 계열 이름(`_xleta.*`)** → openpyxl 재저장 시 컨트롤·연결 유실 위험 | zip 파트 목록 |
| 4 | VBA = 시트 → CSV/JSON 내보내기 도구. Info 제외 전 시트를 1행~A열 마지막 행까지 `.Text`(표시 텍스트)로 전 필드 따옴표·CRLF·UTF-8(BOM) 저장. **1행 헤더 채우기 = 테마 Accent6 이면 서버 컬럼**, 그 외 클라 컬럼. 내보내기 위치 = 워크북 폴더의 상위(현재 배치면 `Assets\`) | olevba 추출(`Module4`·`UserForm`) |
| 5 | 기존 클라 헤더 서식 = `ShopGoods!A1` (COM ThemeColor 4 · TintAndShade −0.5 · 흰 굵은 글꼴 · 맑은 고딕) / 서버 헤더 = 파일 테마 9(Accent6) | openpyxl + COM |
| 6 | 게임 코드에 이 테이블들의 **CSV 런타임 로더 없음**(런타임은 JSON `Table<T>.LoadFromText` → Newtonsoft) → 2행 설명 행은 로더 요구사항이 아님 | Grep |
| 7 | JSON 데이터 특성: 숫자를 문자열로 저장한 테이블(GuideMissionTable 전 필드·CheatTable 인자 수·PassTable 인덱스) · 중첩 배열 필드 5종(CostumeTable/ItemTable `ItemAbilities` · PassTable `Entries` · ShopMonthlyTable `ImmediateRewards`/`DailyRewards` · SkillTable `SkillAbilities`) · 줄바꿈 포함 다국어 문자열 · 열 내 타입 혼재 0 · 15자리 초과 숫자 0 · 최장 셀 3,306자 | 분석 스크립트 |
| 8 | Excel 16(Office) 설치 · 실행 중 Excel 없음 · 파일 잠금 없음 · LibreOffice 없음 | 프로세스·레지스트리·잠금 테스트 |
### 결정과 기각안 (C32)
**결정 1 — 저장 주체 = Excel 본체(COM 자동화)**: Excel 이 직접 저장하므로 VBA·양식 컨트롤·Power Query 연결·동적 배열 수식이 PD 가 손으로 저장한 것과 동일하게 보존된다. 안전장치: `AutomationSecurity=3`(매크로 강제 비활성 — 워크북 매크로 미실행) · `DisplayAlerts/EnableEvents/AskToUpdateLinks` 끔 · 원래 활성 시트(MonthlyReward) 복원 후 저장 · **저장 없는 DryRun 선행**.
- **기각안 A — openpyxl(keep_vba) 편집**: VBA 는 보존되나 양식 컨트롤·VML·연결 파트 유실 위험(실측 3). 원본 보호(C6) 위반 소지.
- **기각안 B — OOXML 파트 직접 삽입**: 기존 파트는 바이트 보존되지만 styles/workbook/rels 수작업 수정의 스키마 오류가 Excel 복구(시트 삭제)로 이어질 위험, 검증 수단 제한.
**결정 2 — 시트 구성 = CSV 원형(1행 헤더 = JSON 키 원문, 2행부터 레코드)**: PD 문언 "csv형태로 변환". 헤더 서식은 기존 **클라 헤더 복제**(PD "전부 클라이언트 기준" — Accent6 미사용). 시트 이름 = JSON 파일명, 기존 8시트 뒤에 이름순 추가, 1행 틀 고정, 열 너비 자동 맞춤(텍스트 열 상한 60 — `.Text` 내보내기에서 숫자 `###` 방지).
- **기각안 — 기존 시트처럼 2행 설명 행 추가**: JSON 에 설명 원천이 없어 창작(C5) 또는 빈 행(내보내기 시 빈 레코드)이 된다. 로더 요구사항도 아님(실측 6).
- **기각안 — 타입 접두어(`s_`/`n_`/`b_`) 헤더**: JSON 키·C# 필드명과 달라져 원본 대응이 깨진다.
**결정 3 — 형 보존 매핑**: JSON 숫자 → 숫자 셀 · JSON 문자열 → 텍스트 셀(숫자처럼 보여도 텍스트, 셀 서식 `@` 선지정 — `"1"`·`"false"`·날짜형 문자열·`=` 시작 문자열 자동 변환 차단) · bool → 논리값 · null → 빈 셀 · 중첩 배열·객체 → 압축 JSON 문자열(숫자 리터럴 보존) 1셀.
- **기각안 — 숫자형 문자열을 숫자로 변환**: `"false"`→`FALSE`, `"1.0"`→`1` 등 원문이 바뀐다. 원본 JSON 타입 그대로가 역변환 근거.
**CSV 파일**: `C:\BurningTimes\ImmortalSword\output\DataTables_csv\*.csv` 19개(462KB) — 매크로 저장 형식에 맞춤(UTF-8 BOM·CRLF·전 필드 따옴표) + 내부 따옴표 RFC 4180 이스케이프. `Assets` 밖에 둔 이유 = Unity 임포트·매크로 내보내기 위치(`Assets\`)와의 충돌 회피. 셀 텍스트는 JSON 리터럴 그대로(`1.0`·`true`).
### 집행
1. **백업(C6)**: `공유/개발팀_백업/ImmortalSword/ImmortalSword.xlsm.bak_20260917_0020.xlsm` (118,894B · SHA256 `BA15883F…2DD3` 원본 일치)
2. 변환: `prep_tables.py` → CSV 19 + 정규화 데이터
3. DryRun(저장 없음): 19시트 전건 불일치 0 · 원본 해시 불변 확인
4. 본 실행 00:23:06 저장 — 시트 8 → **27** · 파일 116KB → 317KB
### 검증
- **Excel 세션 내**(저장 전): 시트별 Value2 전수 대조 불일치 0 · 숫자·논리 셀 `.Text`(매크로 내보내기 값) 4,237셀 불일치 0 · 255자 초과 텍스트 34셀 `.Text` 잘림 0
- **Excel 밖 독립 검증**(openpyxl + olevba, 백업 대비):
- 기존 8시트 셀 2,823개 값·수식 문자열 **변경 0**
- 신규 19시트 셀 타입·값 **불일치 0** · 초과 셀 0 · CSV 파일과 **불일치 0**
- 신규 헤더 전부 테마 3·틴트 −0.5·굵게 = `ShopGoods!A1` 동일 · **Accent6(서버) 헤더 0** · 틀 고정 A2
- 비시트 파트 유실 0 (`vbaProject.bin`·`connections.xml`·`customXml/item1.xml`·`ctrlProp1.xml`·`drawing1.xml`·`vmlDrawing1.vml` 유지)
- VBA 16모듈 중 15개 코드 동일 · `UserForm.frm` 은 **`Attribute VB_Base` GUID 1줄만 상이**(폼 포함 통합 문서를 Excel 이 저장할 때 폼 클래스 ID 재발급 — 코드 본문 16,406자 동일)
- Excel 프로세스 잔존 0
### 발견 이슈 (C3 · PD 보고)
- **매크로 CSV 내보내기의 따옴표 미이스케이프** — `GenerateCSVData` 가 `"` & `.Text` & `"` 로 감싸기만 하고 셀 안 `"` 를 두 번 쓰지 않는다. 신규 데이터 중 **따옴표 포함 셀 276개**(ItemTable 150 · SkillTable 101 · ShopMonthlyTable 10 · LocalizeTable 7 · PassTable 5 · CostumeTable 3 — 대부분 중첩 JSON)는 매크로로 내보내면 **CSV 가 깨진다**. 수정안(VBA `Replace(.Text, """", """""")`)은 PD 지시 전 미적용. 줄바꿈 포함 셀 224개(LocalizeTable 196 · LocalizeTextTable 28)는 따옴표로 감싸져 CSV 규격상 유효하나 읽는 쪽이 다중 행 필드를 지원해야 함
- **매크로 내보내기 위치** — 클라 CSV 는 워크북 폴더의 상위에 저장되므로 현재 배치(`Assets/DataTables/`)에서 실행하면 **`Assets\` 루트에 CSV 26개**가 생성된다(VBA 폴백 주석은 `…/CSV/ImmortalSword.xlsm` 배치를 전제)
- 워크북이 `Assets/` 안에 있어 Unity 가 에셋으로 임포트함(`.meta` 생성 대상) — 기존 PD 배치 그대로 둠
## 5. 워크북 매크로 수정 — CSV 따옴표 · JSON 기본 · 루트 경로 (PM 직접 집행)
### PD 원문 (2026-09-17)
> ⑥ "\"가 들어간 경우 CSV가 깨지지 않도록 수정해줘."
>
> ⑦ "메크로 익스포트 기본 옵션을 json으로 수정해줘. (csv는 옵션을 체크할 경우에만 활성화 되도록)"
>
> ⑧ "ImmortalSword의 경로를 "ImmortalSword\Assets\DataTables\TableManager"로 변경했어. 이제 루트는 "ImmortalSword\Assets\DataTables\" 이 경로로 저장하면 돼."
### 실측
| # | 실측 | 근거 |
|---|------|------|
| 1 | 워크북 이동 확인 `Assets/DataTables/TableManager/ImmortalSword.xlsm` · 구 경로 부재 · SHA256 = §4 저장본과 동일(`02551772…`) = 이동 외 변경 없음 · 잠금 없음 | 해시·잠금 테스트 |
| 2 | **VBA 개체 모델 액세스 신뢰 = 이미 켜짐**(`HKCU\…\Excel\Security\AccessVBOM = 1`) → 보안 설정 변경 없이 COM 으로 코드 수정 가능 (읽기 전용 확인만) | 레지스트리 조회 |
| 3 | 버튼(Info 「저장하기」) = `SaveSelectedSheetsAsCSV` → `UserForm` → `Module4.*`. `Module1` 의 옛 CSV 함수는 호출 경로 없음 | VML `FmlaMacro` · 코드 |
| 4 | 루트 계산 = `GetParentPath(ThisWorkbook.path)` → 이동 후 **이미 `Assets\DataTables`**. 단 JSON 저장은 루트가 아닌 `\Local` 고정 · 폼 루트 옵션 표기 `(Assets\CSV)` 낡음 | `Module4.CopySelectedSheetsToJSON` · `UserForm` |
| 5 | **구 JSON 내보내기 결함 4종** — 모든 값을 문자열로 씀 · `"`·`\`·줄바꿈 미이스케이프(LocalizeTable 줄바꿈 196셀·따옴표 셀 276개에서 JSON 파손) · 중첩 배열을 문자열로 씀(게임 `ItemAbilities` 등 역직렬화 불가) · 저장 위치 `\Local` | `GenerateJSONData` |
| 6 | 원본 게임 JSON 형식 = 대부분 Newtonsoft Indented(2칸·CRLF·BOM 없음), 일부 상이(GuideMissionTable 한 줄 객체·CheatTable BOM) · 빈 문자열 17개(ShopGem 1·ShopProduct 16) | 파일 실측 |
### 결정과 기각안 (C32)
**결정 1 — ⑥ CSV**: `CsvQuote` 헬퍼로 셀 안 `"` 를 `""` 로(RFC 4180). 전체 컬럼(`GenerateCSVData`)·서버 컬럼(`GenerateCSVDataForColumns`) 두 경로 모두 적용. `Module1` 옛 함수는 호출 경로가 없어 미수정.
**결정 2 — ⑦ 폼**: 저장 형태 = `JSON 파일로 저장` 기본 선택·표시. `CSV 저장 옵션 표시` 체크박스(기본 꺼짐)를 켜야 `CSV 파일로 저장`(수동 경로면 `서버용 CSV로 저장` 추가)이 보인다. 끄면 JSON 으로 복귀. 기존 `JSON 저장 옵션 표시` 구조(2026-09-14)를 뒤집은 대칭 설계 — 체크만으로 CSV 가 자동 선택되지는 않는다(기존 동작과 같음).
**결정 3 — ⑦ JSON 을 기본으로 쓸 수 있게 내보내기 재작성(실측 5)**: 값 타입 = 논리값 true/false · 숫자 셀 숫자 · 문자열 문자열(숫자처럼 보여도) · **유효한 JSON 배열/객체 문자열 = 중첩 그대로**(VBA 내장 검증 파서 — `[공지] 점검` 같은 문구는 문자열 유지) · 빈 셀 `""`(구 동작·원본 빈 문자열 보존) · 들여쓰기 = Newtonsoft Indented 2칸 · UTF-8 BOM 없음. 본체/메시지 분리(`ExportSheetsToJSON`).
- **기각안 — 구 JSON 로직 유지 + 기본값만 변경**: 따옴표·줄바꿈 셀에서 JSON 이 깨지고 중첩 필드가 문자열이 돼 게임 테이블 로드가 실패한다. ⑥ 의 취지("가 들어가도 깨지지 않게")와도 어긋남.
- **기각안 — 빈 셀을 키 생략/null 로**: 원본 빈 문자열 17개가 null 로 바뀌어 문자열 필드 NRE 위험.
**결정 4 — ⑧ 루트**: 자동 선택 시 JSON = 루트(`Assets\DataTables`) · CSV 자동 분배 = 클라 루트 / 서버 루트`\Server` + Tino(기존 규칙) · 수동 = 루트 / 루트`\Export` / 루트`\Local`. 루트 옵션 표기는 경로에서 동적 계산(`RootFolderLabel` → `(Assets\DataTables)`). 주석의 `Assets\CSV`·`XLSM → CSV → Assets` 표기 정정.
**VBE 대소문자 정규화 대응**: VBE 는 식별자 대소문자를 프로젝트 전체에 통일하므로 새 코드는 기존 표기(`.value`·`.name`·`.caption`)를 따르고 `text` 같은 충돌 이름을 쓰지 않음 → 검증에서 타 모듈 무변경 확인.
### 집행
1. **백업(C6)**: `공유/개발팀_백업/ImmortalSword/ImmortalSword.xlsm.bak_20260917_0036.xlsm` (SHA256 원본 일치)
2. VBE 코드 원문 추출(읽기 전용) → 패치 스크립트(모든 치환 매치 개수 단언) → Module4 777→1036줄 · UserForm 411→425줄
3. **A 단계(저장 없음)**: 메모리 적용 + 임시 검증 모듈 실행(내보내기·경계 사례·폼 상태) → 원본 해시 불변 확인
4. **B 단계(저장)**: 재적용 + 재검증 → 임시 모듈 제거 → 00:41:44 저장 (324KB → 359KB). 컴파일 대화상자 멈춤 대비 제한 시간 감시(미발동)
### 검증
- **JSON — 19테이블 원본 게임 JSON 과 의미 동일 19/19** (키 순서·타입·중첩 포함) · BOM 0. 텍스트 줄까지 동일 = CharacterTable·Localize 6종 / 나머지 줄 차이는 원본 파일별 형식 차이(GuideMissionTable 한 줄 객체 → 펼침·실수 `0.0` → `0` 등 — 값 동일)
- **JSON — 구 시트 7종 파싱 성공**
- **CSV — 19테이블 엄격 파서 통과 · §4 CSV 와 셀 불일치 0** · 구 시트 7종 파싱 성공·열 수 일정
- **경계 사례 23건 전부 통과** — 키/값 따옴표·줄바꿈·탭·제어문자(``)·역슬래시·이모지(서로게이트)·지수 표기(1E-05)·숫자형 텍스트 `007`·수식형 텍스트 `=SUM(1)`·15자리 정수·공백 둘러싼 배열·가짜 중첩 `[공지] 점검`·무효 JSON(`{bad json`·`[1,]`·`{"a":01}`)은 문자열 유지·중첩 내부 숫자 원문 `2.50` 보존
- **폼 상태 6단계**: 초기(JSON 선택·CSV 숨김) → CSV 표시(서버 숨김·JSON 유지) → CSV 선택 → 수동(서버 표시·캡션 전환) → 서버 선택 후 자동(CSV 로 복귀) → 표시 끔(JSON 복귀·CSV 숨김) 전부 의도대로
- **저장본 독립 검증**: 구성요소 35=35(임시 모듈 잔존 0) · Module4·UserForm = 패치 원문 일치 · **Module1·2·3·5·6 대소문자까지 무변경** · 시트 27·셀 17,496 변경 0 · 파트 유실 0 · Excel 잔존 0
### PD 안내·발견
- **JSON 기본 저장은 `Assets\DataTables` 의 같은 이름 게임 JSON 을 덮어쓴다**(의도된 파이프라인). 19테이블은 데이터 동일 검증 완료
- 구 데이터 시트 7종(ShopConfig 등 · 전부 2행 설명 행 보유)은 JSON 으로 내보내면 **2행 설명이 첫 레코드로 들어간다**(구 로직도 동일 · CSV 전용 설계 시트)
- `Module1` 옛 CSV 함수(호출 경로 없음)는 따옴표 미이스케이프 그대로 — 사용하지 않는 코드라 미수정