Skip to content

Latest commit

 

History

History
198 lines (142 loc) · 6.14 KB

File metadata and controls

198 lines (142 loc) · 6.14 KB

WillPlus/AdvHD PNA

单文件概览(示例:立绘文件)

文件信息

  • 名称: 華は短し、踊れよ乙女/Chip4/ST02A_S.pna
  • 大小: 2,861,570
  • 端序: 小端
偏移 十六进制 字段含义 十进制/ASCII
0x00~0x03 50 4E 41 50 Magic PNAP
0x04~0x07 10 06 00 00 版本号? 1552
0x08~0x0B FD 03 00 00 画布宽度 1021
0x0C~0x0F EF 04 00 00 画布高度 1263
0x10~0x13 23 00 00 00 条目数 35

注:版本号字段在不同文件中会变化,详见「跨文件对比」。

索引表结构

PNA 文件的核心是一个树形结构,目录条目通过 Type 字段构建嵌套层级:

Type 含义 说明
1 Push(入栈) 创建一个新的分组容器,后续的 Type=0 条目归属于该分组
0 Leaf(叶子) 普通图层,包含图片数据,归属于当前最内层容器
2 Pop(出栈) 关闭当前容器,回到上一层容器

解析方式:维护一个栈,遍历条目时:

  • Type=1 → 创建新容器并入栈
  • Type=0 → 将图层添加到栈顶容器
  • Type=2 → 出栈(回到父容器)

单文件解析示例

以 ST02A_S.pna 为例:

定位数据块

搜索 89 50 4E 47 (PNG 签名)

实际 PNG 数 = 29

数据块 地址 宽度 高度
P1 0x058C 145 101
P2 0x36ED 131 103

反推条目大小

EntrySize = (P1 - HeaderSize) / Count

  • P1 = 0x058C = 1420
  • HeaderSize = 0x14 = 20
  • Count = 35

(1420 - 20) / 35 = 40 字节

结论:每个目录条目固定 40 字节(0x28)。

横向拆解(条目结构)

每个条目 40 字节,字段分布如下:

相对偏移 长度 字段 说明
+0x00 4 Type 0=图层, 1=Push, 2=Pop
+0x04 4 ID 图层编号(标记条目为 -1)
+0x08 4 BaseX 绘制锚点 X
+0x0C 4 BaseY 绘制锚点 Y
+0x10 4 Width 图像宽度
+0x14 4 Height 图像高度
+0x18 4 保留 固定为 0
+0x1C 4 保留 固定为 0
+0x20 4 缩放系数 固定浮点数 1.875(普通图层)
+0x24 4 CompSize 压缩后数据大小

条目 0(0x14~0x3B):根容器 Push

01 00 00 00 FF FF FF FF 00 00 00 00 00 00 00 00
00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
00 00 00 00 00 00 00 00

条目 1(0x3C~0x63):普通图层

偏移 十六进制 字段 值
0x3C~0x3F 00 00 00 00 Type 0
0x40~0x43 21 00 00 00 ID/Zorder 33
0x44~0x47 9E 01 00 00 BaseX 414
0x48~0x4B 14 01 00 00 BaseY 276
0x4C~0x4F 91 00 00 00 Width 145
0x50~0x53 65 00 00 00 Height 101
0x54~0x57 00 00 00 00 保留 0
0x58~0x5B 00 00 00 00 保留 0
0x5C~0x5F 00 00 F0 3F 缩放? 1.875
0x60~0x63 61 31 00 00 CompSize 12641

条目 2(0x64~0x8B):普通图层

偏移 十六进制 字段 值
0x64~0x67 00 00 00 00 Type 0
0x68~0x6B 20 00 00 00 ID 32
0x6C~0x6F A3 01 00 00 BaseX 419
0x70~0x73 12 01 00 00 BaseY 274
0x74~0x77 83 00 00 00 Width 131
0x78~0x7B 67 00 00 00 Height 103
0x7C~0x7F 00 00 00 00 保留 0
0x80~0x83 00 00 00 00 保留 0
0x84~0x87 00 00 F0 3F 缩放? 1.875
0x88~0x8B B0 17 00 00 CompSize 6080

纵向归纳:ST02A_S.pna 的分组结构

索引 Type ID 分组
0 1 -1 根组开始
1~22 0 33~12 表情组(22 个图层)
23 2 -1 表情组结束
24 1 -1 颊组开始
25~26 0 9~8 颊组(2 个图层)
27 2 -1 颊组结束
28 1 -1 身体组开始
29~33 0 5~1 身体组(5 个图层)
34 2 -1 身体组结束

规律:

  • 根节点 Type=1(索引 0)和最后的 Type=2 不一定成对出现
  • 每个分组由 Type=1 开始,Type=2 结束
  • 有效图层数 = Count - (Type=1/2 标记数)

树形结构示例:SYS_Title.pna

标题文件展示了比立绘更复杂的树形结构:

  • 版本号:3708
  • 画布:1280 × 720
  • 条目数:84
  • 有效图层:48
  • 分组数:16(嵌套多层)

关键发现:

  • 树形结构可以任意深度嵌套
  • 分组数量不固定(立绘文件 3 组,标题文件 16 组)
  • Type=1/2 是栈操作符,实现了完整的树形描述能力

数据定位机制

PNA 文件不存储每个条目的数据偏移量(Offset)。引擎通过顺序累加 CompSize 定位下一张图:

  1. 第一个 PNG 数据块位于 HeaderSize + Count × EntrySize
  2. 读取当前条目的 CompSize 后,指针后移 CompSize 字节
  3. 指针位置即为下一个 PNG 数据块的起始地址

验证:P1(0x058C) + CompSize条目1(0x3161) = 0x36ED = P2 ✅

跨文件对比

结论在《華は短し、踊れよ乙女》及另一作《宿りし乙女の誓いと魔法》中验证成立。

  • 固定结构:HeaderSize = 20,EntrySize = 40
  • 字段 [+0x20] 固定为 1.875(普通图层)或 0.0(标记条目)
  • 树形结构通用,分组数量不固定
  • 版本号字段不固定,可用于区分不同游戏/版本

各文件版本号分布

版本号 十六进制 包含的文件组
3708 0x0E7C SYS_Title.pna(标题文件)
1552 0x0610 ST01A、ST02A(L/M/S)、ST02B(L/M/S)
1508 0x05E4 ST01B、ST03A、ST03B、ST04A、ST05A、ST07A
1464 0x05B8 ST04B、ST05B
1420 0x058C ST06A
936 0x03A8 ST08A
804 0x0324 ST09A

解析要点

  1. HeaderSize = 20(0x14),固定不变
  2. EntrySize = 40(0x28),固定不变
  3. 版本号不影响解析逻辑,仅作元信息参考
  4. 树形结构是通用特性,不要假设固定分组数
  5. 数据块连续堆叠,无偏移表