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

125 lines
15 KiB
Markdown
Raw Permalink Blame History

This file contains invisible Unicode characters

This file contains invisible Unicode characters that are indistinguishable to humans but may be processed differently by a computer. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

# 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 함수(호출 경로 없음)는 따옴표 미이스케이프 그대로 — 사용하지 않는 코드라 미수정