[{"data":1,"prerenderedAt":-1},["ShallowReactive",2],{"skill:01M6CBWF5C96RBJX18Y0Q1B6PE":3,"skill-same:01M6CBWF5C96RBJX18Y0Q1B6PE":50},{"skillNo":4,"name":5,"nameZh":6,"description":6,"descriptionZh":6,"repositoryFullName":7,"ownerLogin":8,"ownerAvatarUrl":9,"ownerAccountNo":10,"ownerDisplayName":11,"repositoryNo":12,"starsCount":13,"licenseSpdxId":14,"licenseFileUrl":6,"sourceHtmlUrl":15,"categories":16,"keywords":22,"publishedAt":25,"linkOnly":26,"markdownContent":27,"markdownBody":27,"frontMatter":28,"refName":29,"commitSha":30,"skillDirectory":31,"forksCount":13,"repositoryHtmlUrl":32,"repositoryHomepageUrl":6,"ownerHtmlUrl":33,"ownerBlogUrl":6,"ownerDescription":34,"updatedAt":35,"install":36,"resources":49},"01M6CBWF5C96RBJX18Y0Q1B6PE","54-data-pb64",null,"devwinsoft\u002Fdevian","devwinsoft","https:\u002F\u002Favatars.githubusercontent.com\u002Fu\u002F22570160?v=4","01M6C6RR8W05NH8NPKQNCE3Q72","maoshy","01M6C6RRDJ5TJJCZXRTY801YDH",0,"MIT","https:\u002F\u002Fgithub.com\u002Fdevwinsoft\u002Fdevian\u002Fblob\u002Fmain\u002Fskills\u002Fdevian\u002F80-tools\u002F11-builder\u002F54-data-pb64\u002FSKILL.md",[17],{"categoryNo":18,"categoryName":19,"taxonomyType":20,"taxonomyTypeDesc":21},"01JBSEEDCAT000000000000033","数据分析师","PROFESSION","适用职业",[23,24],"data","54 data pb64","2026-11-10 10:12:30",false,"# 54-data-pb64\n\nStatus: ACTIVE  \nAppliesTo: v10\n\n## SSOT\n\n이 문서는 **pb64 저장(포장) 규약**의 정본이다.\n\n---\n\n## 목적\u002F범위\n\n**pb64는 Unity\u002FUPM 소비를 전제로 하며, Addressables에서 TextAsset으로 로드 가능한 `.asset` 형태로 저장한다.**\n\n이 스킬은 \"저장(포장) 규약\"만 정의한다. pb64 payload 자체 규약은 각 생성 스킬이 정의\u002F참조한다:\n- 일반 Table pb64 payload: DVGB 컨테이너 (이 문서에서 정의)\n- String Table pb64 payload: `skills\u002Fdevian-unity\u002F20-common-package\u002F30-string-table\u002FSKILL.md`의 StringChunk 규약\n\n---\n\n## 저장 규칙 (Hard Rules)\n\n### 파일 확장자\n\n**`.asset`**\n\n### 저장 형태\n\n**Unity TextAsset YAML**\n\n### YAML 구조\n\n```yaml\n%YAML 1.1\n%TAG !u! tag:unity3d.com,2011:\n--- !u!49 &4900000\nTextAsset:\n  m_ObjectHideFlags: 0\n  m_CorrespondingSourceObject: {fileID: 0}\n  m_PrefabInstance: {fileID: 0}\n  m_PrefabAsset: {fileID: 0}\n  m_Name: \u003CTABLE_NAME>\n  m_Script: \u003CPAYLOAD>\n```\n\n### m_Script 페이로드 규칙\n\n**두 가지 케이스를 지원한다:**\n\n| 케이스 | 사용처 | m_Script 형식 |\n|--------|--------|---------------|\n| Single-line base64 | 일반 Table (DVGB 컨테이너) | 인라인 문자열 |\n| Multi-line text | String Table (청크 base64) | Block scalar (`|`) |\n\n### Multi-line Block Scalar (필수)\n\n**Multi-line일 경우 YAML이 깨지지 않도록 block scalar(`|`) 사용을 강제한다.**\n\n```yaml\n  m_Script: |\n    base64Line1\n    base64Line2\n    base64Line3\n```\n\n> **절대 금지**: `m_Script: ${multilineText}`처럼 단일 라인에 멀티라인 문자열을 끼워 넣기 (YAML 깨짐)\n\n### Decoding Note (Runtime) — Hard Rule\n\n`.asset`는 Unity TextAsset YAML이므로 `TextAsset.text`가 **YAML 전체를 반환할 수 있다**.\n\n**StringTable pb64 디코더 규칙:**\n\n| 규칙 | 설명 |\n|------|------|\n| base64 라인만 추출 | YAML 헤더\u002F필드 라인은 무시 |\n| 구분자 지원 | `\\n` + `|` 둘 다 지원 (파이프 연결형 입력 방어) |\n| 실패 로깅 | `Devian.Log`로 기록 (단, base64 후보 라인에 대해서만) |\n| 로그 스팸 방지 | YAML 라인은 base64 후보 필터로 사전 제외 |\n\n**base64 후보 판별:**\n- 문자: `A-Za-z0-9+\u002F=` 만 허용\n- 길이 4 미만이면 base64가 아님\n\n> **Reference:** `skills\u002Fdevian-unity\u002F20-common-package\u002F30-string-table\u002FSKILL.md`의 \"pb64 Encoding\u002FDecoding 규칙\" 섹션\n\n---\n\n## DVGB Gzip Block Container Format (일반 Table용)\n\n일반 Table pb64의 `m_Script` 페이로드는 DVGB gzip 블록 컨테이너를 base64 인코딩한 것이다.\n\n### 컨테이너 헤더\n\n| Offset | Size | Field | Value |\n|--------|------|-------|-------|\n| 0 | 4 | Magic | `DVGB` (ASCII) |\n| 4 | 1 | Version | `1` |\n| 5 | 4 | BlockSize | `1048576` (1024K, little-endian) |\n| 9 | 4 | BlockCount | 블록 개수 (little-endian) |\n\n### 블록 구조 (BlockCount 만큼 반복)\n\n| Size | Field | Description |\n|------|-------|-------------|\n| 4 | UncompressedLen | 압축 전 바이트 수 (little-endian) |\n| 4 | CompressedLen | gzip 압축 후 바이트 수 (little-endian) |\n| CompressedLen | GzipBytes | gzip 압축된 데이터 |\n\n### 블록 크기\n\n- 블록 크기: **1024K (1,048,576 bytes)** 고정\n- 마지막 블록은 1024K보다 작을 수 있음\n\n### 압축 대상\n\n- rawBinary (varint length-delimited JSON rows)를 1024K 블록으로 분할\n- 각 블록을 개별 gzip 압축\n- **rawBinary 포맷은 변경하지 않음** (압축만 추가)\n\n### 하위 호환\n\n- C# 로더는 앞 4바이트가 `DVGB`가 아니면 **기존 포맷(압축 없음)**으로 처리\n- 기존 .asset 파일도 계속 읽을 수 있음\n\n---\n\n## rawBinary 포맷 (DVGB 압축 전)\n\n압축 전\u002F후 동일한 포맷. 테이블의 모든 row를 concat:\n\n```\n[row1][row2][row3]...\n```\n\n각 row 구조:\n```\n[varint jsonLength][jsonUtf8]\n```\n\n- `jsonLength`: JSON 문자열의 UTF-8 바이트 길이 (protobuf varint 인코딩)\n- `jsonUtf8`: JSON 문자열의 UTF-8 바이트\n\n### Varint 인코딩\n\nprotobuf 표준 varint 인코딩을 사용한다:\n- unsigned 32-bit 길이 기준\n- 각 바이트의 MSB가 1이면 다음 바이트가 이어짐\n- 7비트씩 little-endian 순서로 저장\n\n---\n\n## 결정성 (Deterministic)\n\n**같은 입력이면 항상 같은 .asset 출력이 나와야 한다.**\n\n- gzip 압축 레벨: 9 (최대)\n- JSON stringify: 컴팩트 포맷 (들여쓰기 없음)\n\n---\n\n## 소스 경로\n\n| 역할 | 경로 |\n|------|------|\n| 일반 Table pb64 생성기 | `framework-ts\u002Ftools\u002Fbuilder\u002Fgenerators\u002Ftable.js` |\n| String Table pb64 생성기 | `framework-ts\u002Ftools\u002Fbuilder\u002Fgenerators\u002Fstring-table.js` |\n\n---\n\n## 금지 행동\n\n- `.pb64` 확장자 사용 금지 (`.asset` 사용)\n- Multi-line 페이로드에 인라인 문자열 사용 금지 (block scalar `|` 사용)\n- rawBinary 포맷 변경 금지 (압축만 추가)\n- DVGB 블록 크기(1024K) 변경 금지\n\n---\n\n## DoD (검증 가능)\n\n### PASS 조건\n\n- [ ] pb64 파일 확장자가 `.asset`임\n- [ ] 파일 내용이 Unity TextAsset YAML 형식\n- [ ] Multi-line 페이로드에 block scalar(`|`) 사용됨\n- [ ] 같은 입력이면 같은 출력 (결정성)\n\n### FAIL 조건\n\n- 파일 확장자가 `.pb64`\n- Multi-line 페이로드를 인라인 문자열로 저장\n- YAML 파싱 실패\n\n---\n\n## C# 로더 API (참고)\n\n```csharp\n\u002F\u002F DVGB 컨테이너 로드 (하위 호환 지원)\nbyte[] rawBinary = Pb64Loader.LoadFromBase64(base64String);\n\n\u002F\u002F row 파싱\nPb64Loader.ParseRows(rawBinary, json => {\n    var entity = JsonConvert.DeserializeObject\u003CMyEntity>(json);\n    \u002F\u002F ...\n});\n```\n\n---\n\n## Reference\n\n- Policy SSOT: `skills\u002Fdevian\u002F10-module\u002F03-ssot\u002FSKILL.md`\n- 일반 Table: `skills\u002Fdevian\u002F80-tools\u002F11-builder\u002F31-table-row-format\u002FSKILL.md`\n- String Table: `skills\u002Fdevian-unity\u002F20-common-package\u002F30-string-table\u002FSKILL.md`\n",{},"main","8cb5bd877a3a7004867d2f55697cb9e4ff2f1734","skills\u002Fdevian\u002F80-tools\u002F11-builder\u002F54-data-pb64","https:\u002F\u002Fgithub.com\u002Fdevwinsoft\u002Fdevian","https:\u002F\u002Fgithub.com\u002Fdevwinsoft","Kim Hyong Joon","2026-04-12 18:44:10",{"source":7,"skillName":5,"commands":37,"prompt":47,"zipAvailable":48},[38,41,44],{"tool":39,"command":40},"npx","npx skills add devwinsoft\u002Fdevian --skill 54-data-pb64",{"tool":42,"command":43},"bunx","bunx skills add devwinsoft\u002Fdevian --skill 54-data-pb64",{"tool":45,"command":46},"pnpm","pnpm dlx skills add devwinsoft\u002Fdevian --skill 54-data-pb64","安装技能，技能地址：https:\u002F\u002Fgithub.com\u002Fdevwinsoft\u002Fdevian\u002Fblob\u002Fmain\u002Fskills\u002Fdevian\u002F80-tools\u002F11-builder\u002F54-data-pb64\u002FSKILL.md",true,[],[51,57,65,73,82,89],{"skillNo":52,"name":53,"nameZh":6,"description":6,"descriptionZh":6,"repositoryFullName":7,"ownerLogin":8,"ownerAvatarUrl":9,"ownerAccountNo":10,"ownerDisplayName":11,"repositoryNo":12,"starsCount":13,"licenseSpdxId":14,"licenseFileUrl":6,"sourceHtmlUrl":54,"categories":55,"keywords":56,"publishedAt":25},"01M6CBX3K2JJV38ANHVGCAT8A0","devian","https:\u002F\u002Fgithub.com\u002Fdevwinsoft\u002Fdevian\u002Fblob\u002Fmain\u002Fskills\u002Fdevian\u002FSKILL.md",[],[53],{"skillNo":58,"name":59,"nameZh":6,"description":6,"descriptionZh":6,"repositoryFullName":7,"ownerLogin":8,"ownerAvatarUrl":9,"ownerAccountNo":10,"ownerDisplayName":11,"repositoryNo":12,"starsCount":13,"licenseSpdxId":14,"licenseFileUrl":6,"sourceHtmlUrl":60,"categories":61,"keywords":62,"publishedAt":25},"01M6CBX210BFMM8AMN770J9WY8","90-project-archive","https:\u002F\u002Fgithub.com\u002Fdevwinsoft\u002Fdevian\u002Fblob\u002Fmain\u002Fskills\u002Fdevian\u002F80-tools\u002F90-project-archive\u002FSKILL.md",[],[63,64],"archive","90 project archive",{"skillNo":66,"name":67,"nameZh":6,"description":6,"descriptionZh":6,"repositoryFullName":7,"ownerLogin":8,"ownerAvatarUrl":9,"ownerAccountNo":10,"ownerDisplayName":11,"repositoryNo":12,"starsCount":13,"licenseSpdxId":14,"licenseFileUrl":6,"sourceHtmlUrl":68,"categories":69,"keywords":70,"publishedAt":25},"01M6CBWZSGRR9R3YJZB3177667","30-env-management","https:\u002F\u002Fgithub.com\u002Fdevwinsoft\u002Fdevian\u002Fblob\u002Fmain\u002Fskills\u002Fdevian\u002F80-tools\u002F30-env-management\u002FSKILL.md",[],[71,72],"management","30 env management",{"skillNo":74,"name":75,"nameZh":6,"description":6,"descriptionZh":6,"repositoryFullName":7,"ownerLogin":8,"ownerAvatarUrl":9,"ownerAccountNo":10,"ownerDisplayName":11,"repositoryNo":12,"starsCount":13,"licenseSpdxId":14,"licenseFileUrl":6,"sourceHtmlUrl":76,"categories":77,"keywords":78,"publishedAt":25},"01M6CBWYD3TGWBQV7V35551THF","19-page-push-send","https:\u002F\u002Fgithub.com\u002Fdevwinsoft\u002Fdevian\u002Fblob\u002Fmain\u002Fskills\u002Fdevian\u002F80-tools\u002F20-operation\u002F19-page-push-send\u002FSKILL.md",[],[79,80,81],"push","page","19 page push send",{"skillNo":83,"name":84,"nameZh":6,"description":6,"descriptionZh":6,"repositoryFullName":7,"ownerLogin":8,"ownerAvatarUrl":9,"ownerAccountNo":10,"ownerDisplayName":11,"repositoryNo":12,"starsCount":13,"licenseSpdxId":14,"licenseFileUrl":6,"sourceHtmlUrl":85,"categories":86,"keywords":87,"publishedAt":25},"01M6CBWWRQ05A7604GHJKTPJTF","18-page-savedata","https:\u002F\u002Fgithub.com\u002Fdevwinsoft\u002Fdevian\u002Fblob\u002Fmain\u002Fskills\u002Fdevian\u002F80-tools\u002F20-operation\u002F18-page-savedata\u002FSKILL.md",[],[80,88],"18 page savedata",{"skillNo":90,"name":91,"nameZh":6,"description":6,"descriptionZh":6,"repositoryFullName":7,"ownerLogin":8,"ownerAvatarUrl":9,"ownerAccountNo":10,"ownerDisplayName":11,"repositoryNo":12,"starsCount":13,"licenseSpdxId":14,"licenseFileUrl":6,"sourceHtmlUrl":92,"categories":93,"keywords":94,"publishedAt":25},"01M6CBWVH4S2VF1V7B2GBTESCT","17-page-deobfuscate","https:\u002F\u002Fgithub.com\u002Fdevwinsoft\u002Fdevian\u002Fblob\u002Fmain\u002Fskills\u002Fdevian\u002F80-tools\u002F20-operation\u002F17-page-deobfuscate\u002FSKILL.md",[],[80,95],"17 page deobfuscate"]