×ばつP2,另顺带 1 项 P3 告警)。依据是对明日方舟官服客户端(2.7.61 / build 2761,Unity IL2CPP)GameAssembly.dll 的逆向分析,关键结论在下文直接给出,不依赖外部文档。 背景:native 的 sticker 机制(2.7.61 / ..." /> ×ばつP2,另顺带 1 项 P3 告警)。依据是对明日方舟官服客户端(2.7.61 / build 2761,Unity IL2CPP)GameAssembly.dll 的逆向分析,关键结论在下文直接给出,不依赖外部文档。 背景:native 的 sticker 机制(2.7.61 / ..." />×ばつP2,另顺带 1 项 P3 告警)。依据是对明日方舟官服客户端(2.7.61 / build 2761,Unity IL2CPP)GameAssembly.dll 的逆向分析,关键结论在下文直接给出,不依赖外部文档。 背景:native 的 sticker 机制(2.7.61 / ..." />
Skip to content

Navigation Menu

Sign in
Sign up

fix(story-player): sticker append 布局重放与自动播放桥接 - #355

Draft
daflyinbed wants to merge 1 commit into
main from
fix/story-player-sticker
Draft

fix(story-player): sticker append 布局重放与自动播放桥接 #355
daflyinbed wants to merge 1 commit into
main from
fix/story-player-sticker

Conversation

@daflyinbed

@daflyinbed daflyinbed commented Aug 24, 2026

Copy link
×ばつP2,另顺带 1 项 P3 告警)。依据是对明日方舟官服客户端(2.7.61 / build 2761,Unity IL2CPP)GameAssembly.dll 的逆向分析,关键结论在下文直接给出,不依赖外部文档。 ## 背景:native 的 sticker 机制(2.7.61 / build 2761 IDA 反编译复核) - `Torappu.AVG.StickerPanel._ExecuteSticker`(VA `0x183e924f0`)按 id 三分支:`m_stickerDict` 命中 + `multi=true` → **append**;命中 + `multi=false` → **hide**;未命中 → **show**。`block` 默认 show 分支 true、append/hide 分支 false。 - **append 分支只调 `AVGStickerTextView.AppendText(view, text)`**,完全不读 `x/y/width/size/alignment/duration/delay` —— 不重新布局、不重新 fade、不重建打字机速度,view 保持上次 show 的全部状态。 - **hide 分支**先 `TryFinishType`(瞬间补全打字中的文本)再 `HideSticker(duration)`(duration ≤ 0 兜底 0.15s),回收进池、dict 移除,最后 `RaiseAutoClick(0)`。 - **show 分支**:`_GenParam`(VA `0x183e92d60`)读布局,x/y 默认 0/0、width 1280(clamp `1280-x`)、size 24、alignment "left"、duration -1 哨兵、**delay 默认 1.0**;坐标越界(x∉[0,1280] 或 y∉[0,720])或空 text → param 的 textContent 为空 → `_ExecuteSticker` **静默丢弃**(不建 view、id 不进 dict、不阻塞)。`_GenSticker`(VA `0x183e932c0`)在 pool+dict ≥ 20 时 LogError("[AVG]avg sticker meets the max num!")并丢弃本次 show。 - `AVGStickerTextView.RenderSticker`(VA `0x183ed43b0`):打字机比例 `typeWriterDelay = AVGController.typeWriterDelay ×ばつ delay / originDelay`(originDelay 资产实测 0.04),**缺省 delay=1.0 → 25 倍慢**;fade 规则 `if (!isMultiline || duration >= 0) m_duration = duration >= 0 ? duration : 0.15` —— **multiline show(multi=true 且 id 未注册)缺省 duration 时保留 view 旧 fade**(新 view=0 瞬时、池复用 view=上次 hide 写入的 0.15)。 - **auto-play 节拍**:打字结束回调 `_OnStickerTypeEnd(msgLength) → RaiseAutoClick(msgLength)`;hide 分支 `RaiseAutoClick(0)`。 ## 修复内容 ### 1. append 分支重放布局参数(P1) - **native**:append 只追加文本,view 保持原布局与打字机速度。 - **前端问题**:append 走 show 同一通路,缺省 `x=0,y=0, 全部重放 → 无 x/y 的 append 把贴纸跳到左上角、宽度重置 1280(主线 13-05 信件段落大量命中)。 - **修复**:runtime 以 `stickerSlots`(等价 `m_stickerDict`)记录每个 id 上次 show 的布局(含 delayMs/fadeMs),append 时原样重放,不再读取脚本的布局参数;`append` 标志同时修正为「id 已存在的 dict 命中」(原先 fresh id + `multi=true` 也被标成 append)。 ### 2. sticker 无 auto-play 桥接(P1) - **native**:打字结束 `RaiseAutoClick(msgLength)`、hide 时 `RaiseAutoClick(0)`。 - **前端问题**:sticker 路径从不 `scheduleAutoClick`,button_auto / quick_play 下 block=true 的贴纸(绝大多数 show 样本)永远等手动点击,自动播放停摆。 - **修复**:show/append 分支按全量字符数 `scheduleAutoClick(charCount)`,hide 分支对齐 `scheduleAutoClick(0)`;同时把 `currentMessageLength`/`currentTypingComplete` 同步为贴纸文本,使等待中途开启自动模式也能正确排程。 ### 3. `delay` 缺省语义(P2) - **native**:`_GenParam` 默认 `delay=1.0` → scale = 1/0.04 = 25(比全局慢 25 倍);append 不重设速度。 - **前端问题**:缺省 scale=1。 - **修复**:`stickerTypeDelayMs` 缺省按 1.0 计算(scale 25)。缺省分支在数据中可达:`activities/act23side/level_act23side_02_end.txt:43` 是全新 id 的 multiline show 且无 delay。append 侧随修复 1 消解(不再重算速度)。 ### 4. 空 text 的 show 未静默丢弃(P2) - **native**:空 textContent → return false:不建 view、id 不进 dict、无日志、不阻塞。 - **前端问题**:id 进注册表并渲染一张空贴纸,后续同 id 命中 hide 分支(native 命中 show 分支)。 - **修复**:show 分支在注册 id 前补空 text 静默丢弃(越界拒绝保持不变)。 ### 5. hide 时打字中途的文本状态(P2) - **native**:hide 先 `TryFinishType` 瞬间补全全文再 fade-out。 - **前端问题**:`clearSticker` 直接从已打出的部分文本 fade-out(无补全)。 - **修复**:renderer `clearSticker` 在 fade 前把该 id 的 `stickerTypingTargets.fullText` 写入并重排,再淡出。 ### 6. multiline show 缺省 duration 规则(P2) - **native**:`!isMultiline || duration>=0` 才写 `m_duration`;multiline 且缺省 → 保留旧值(新 view=0 瞬时;池复用 view=上次 hide 写入的 0.15)。 - **前端问题**:一律 150ms 淡入。 - **修复**:runtime 记录 per-id fade(show 显式 duration、hide、stickerclear 150ms 均会写入),`multi=true` 的 show 缺省 duration 时沿用(新 id 为 0 = 瞬时出现)。 ### 7. 20 上限告警(P3,顺手) - native `_GenSticker` 在 pool+dict ≥ 20 时 LogError + 丢弃本次 show。数据侧单画面从未超过个位数,故仅补 `warn("parse", "avg sticker meets the max num (20)")`,不丢弃。 ## 验证用剧情文件 生产剧情语料(本地 `torappu/storage/asset/gamedata/latest/story`,230 个文件共 5745 条 `[Sticker(`): - **修复 1 + 6(append 布局重放 / multiline fade)**:`obt/main/level_main_13-05_beg.txt` —— L18 首条信纸(fresh id 的 multiline show,无 duration → native 瞬时出现)、L21/22/25/44/45/46 无 x/y 的 append(修复前跳到左上角,修复后保持 L18/20/24/43 的 x=300,y=270,width="700)、L19/23/26/47" hide(其后 L20/24/43 重显 fade 应为 150ms)。`obt/main/level_main_13-05_end.txt:22`(无 x/y 的 append)、`activities/act23side/level_act23side_02_end.txt:44` 同理。 - **修复 2(auto-play 桥接)**:任意 block=true 的贴纸(如 13-05_beg L18)在 button_auto / quick_play 下验证自动推进;13-05 信纸段落修复前会永久卡住等手动点击。 - **修复 3(delay 缺省 scale=25)**:`activities/act23side/level_act23side_02_end.txt:43` —— 全新 id st1 的 multiline show 且无 delay,修复前按全局速度打字,修复后按 25 倍慢速(native 语义);其后 L44 append 不再重设速度。 - **修复 4(空 text show 丢弃)**:语料 0 命中(5745 条中无空 text 的 show)—— 前瞻对齐,由单测锁定:`tests/runtime.spec.ts`「drops an empty-text sticker show without registering the id」。 - **修复 5(hide 补全打字)**:生产样本中打字被 hide 打断的可见窗口极窄(如 `obt/main/level_st_17-03.txt:361→363`,block=false + delay=0.04 仅 3 字)—— 行为由单测锁定:`tests/renderer.spec.ts`「completes in-flight sticker typing before the hide fade」。 ## 测试 - `pnpm test`:20 个文件 228 个用例全部通过(基线 222 + 新增 6)。 - `STORY_CORPUS_ROOT=... pnpm test:story-log`:全语料 Log All 回归(符号预算 + 独立 oracle 对拍)通过。 - `pnpm exec vue-tsc -b` 通过;改动文件 `eslint` 无告警。 " data-view-component="true"> Copy Markdown
Contributor

本 PR 修复 StoryPlayer 对 AVG sticker 命令移植中的 6 项行为差异(×ばつP2,另顺带 1 项 P3 告警)。依据是对明日方舟官服客户端(2.7.61 / build 2761,Unity IL2CPP)GameAssembly.dll 的逆向分析,关键结论在下文直接给出,不依赖外部文档。

背景:native 的 sticker 机制(2.7.61 / build 2761 IDA 反编译复核)

  • Torappu.AVG.StickerPanel._ExecuteSticker(VA 0x183e924f0)按 id 三分支:m_stickerDict 命中 + multi=trueappend;命中 + multi=falsehide;未命中 → showblock 默认 show 分支 true、append/hide 分支 false。
  • append 分支只调 AVGStickerTextView.AppendText(view, text),完全不读 x/y/width/size/alignment/duration/delay —— 不重新布局、不重新 fade、不重建打字机速度,view 保持上次 show 的全部状态。
  • hide 分支TryFinishType(瞬间补全打字中的文本)再 HideSticker(duration)(duration ≤ 0 兜底 0.15s),回收进池、dict 移除,最后 RaiseAutoClick(0)
  • show 分支:_GenParam(VA 0x183e92d60)读布局,x/y 默认 0/0、width 1280(clamp 1280-x)、size 24、alignment "left"、duration -1 哨兵、delay 默认 1.0;坐标越界(x∉[0,1280] 或 y∉[0,720])或空 text → param 的 textContent 为空 → _ExecuteSticker 静默丢弃(不建 view、id 不进 dict、不阻塞)。_GenSticker(VA 0x183e932c0)在 pool+dict ≥ 20 时 LogError("[AVG]avg sticker meets the max num!")并丢弃本次 show。
  • AVGStickerTextView.RenderSticker(VA 0x183ed43b0):打字机比例 typeWriterDelay = AVGController.typeWriterDelay ×ばつ delay / originDelay(originDelay 资产实测 0.04),缺省 delay=1.0 → 25 倍慢;fade 规则 if (!isMultiline || duration >= 0) m_duration = duration >= 0 ? duration : 0.15 —— multiline show(multi=true 且 id 未注册)缺省 duration 时保留 view 旧 fade(新 view=0 瞬时、池复用 view=上次 hide 写入的 0.15)。
  • auto-play 节拍:打字结束回调 _OnStickerTypeEnd(msgLength) → RaiseAutoClick(msgLength);hide 分支 RaiseAutoClick(0)

修复内容

1. append 分支重放布局参数(P1)

  • native:append 只追加文本,view 保持原布局与打字机速度。
  • 前端问题:append 走 show 同一通路,缺省 x=0,y=0,width=1280,size=24,left 全部重放 → 无 x/y 的 append 把贴纸跳到左上角、宽度重置 1280(主线 13-05 信件段落大量命中)。
  • 修复:runtime 以 stickerSlots(等价 m_stickerDict)记录每个 id 上次 show 的布局(含 delayMs/fadeMs),append 时原样重放,不再读取脚本的布局参数;append 标志同时修正为「id 已存在的 dict 命中」(原先 fresh id + multi=true 也被标成 append)。

2. sticker 无 auto-play 桥接(P1)

  • native:打字结束 RaiseAutoClick(msgLength)、hide 时 RaiseAutoClick(0)
  • 前端问题:sticker 路径从不 scheduleAutoClick,button_auto / quick_play 下 block=true 的贴纸(绝大多数 show 样本)永远等手动点击,自动播放停摆。
  • 修复:show/append 分支按全量字符数 scheduleAutoClick(charCount),hide 分支对齐 scheduleAutoClick(0);同时把 currentMessageLength/currentTypingComplete 同步为贴纸文本,使等待中途开启自动模式也能正确排程。

3. delay 缺省语义(P2)

  • native:_GenParam 默认 delay=1.0 → scale = 1/0.04 = 25(比全局慢 25 倍);append 不重设速度。
  • 前端问题:缺省 scale=1。
  • 修复:stickerTypeDelayMs 缺省按 1.0 计算(scale 25)。缺省分支在数据中可达:activities/act23side/level_act23side_02_end.txt:43 是全新 id 的 multiline show 且无 delay。append 侧随修复 1 消解(不再重算速度)。

4. 空 text 的 show 未静默丢弃(P2)

  • native:空 textContent → return false:不建 view、id 不进 dict、无日志、不阻塞。
  • 前端问题:id 进注册表并渲染一张空贴纸,后续同 id 命中 hide 分支(native 命中 show 分支)。
  • 修复:show 分支在注册 id 前补空 text 静默丢弃(越界拒绝保持不变)。

5. hide 时打字中途的文本状态(P2)

  • native:hide 先 TryFinishType 瞬间补全全文再 fade-out。
  • 前端问题:clearSticker 直接从已打出的部分文本 fade-out(无补全)。
  • 修复:renderer clearSticker 在 fade 前把该 id 的 stickerTypingTargets.fullText 写入并重排,再淡出。

6. multiline show 缺省 duration 规则(P2)

  • native:!isMultiline || duration>=0 才写 m_duration;multiline 且缺省 → 保留旧值(新 view=0 瞬时;池复用 view=上次 hide 写入的 0.15)。
  • 前端问题:一律 150ms 淡入。
  • 修复:runtime 记录 per-id fade(show 显式 duration、hide、stickerclear 150ms 均会写入),multi=true 的 show 缺省 duration 时沿用(新 id 为 0 = 瞬时出现)。

7. 20 上限告警(P3,顺手)

  • native _GenSticker 在 pool+dict ≥ 20 时 LogError + 丢弃本次 show。数据侧单画面从未超过个位数,故仅补 warn("parse", "avg sticker meets the max num (20)"),不丢弃。

验证用剧情文件

生产剧情语料(本地 torappu/storage/asset/gamedata/latest/story,230 个文件共 5745 条 [Sticker():

  • 修复 1 + 6(append 布局重放 / multiline fade):obt/main/level_main_13-05_beg.txt —— L18 首条信纸(fresh id 的 multiline show,无 duration → native 瞬时出现)、L21/22/25/44/45/46 无 x/y 的 append(修复前跳到左上角,修复后保持 L18/20/24/43 的 x=300,y=270,width=700)、L19/23/26/47 hide(其后 L20/24/43 重显 fade 应为 150ms)。obt/main/level_main_13-05_end.txt:22(无 x/y 的 append)、activities/act23side/level_act23side_02_end.txt:44 同理。
  • 修复 2(auto-play 桥接):任意 block=true 的贴纸(如 13-05_beg L18)在 button_auto / quick_play 下验证自动推进;13-05 信纸段落修复前会永久卡住等手动点击。
  • 修复 3(delay 缺省 scale=25):activities/act23side/level_act23side_02_end.txt:43 —— 全新 id st1 的 multiline show 且无 delay,修复前按全局速度打字,修复后按 25 倍慢速(native 语义);其后 L44 append 不再重设速度。
  • 修复 4(空 text show 丢弃):语料 0 命中(5745 条中无空 text 的 show)—— 前瞻对齐,由单测锁定:tests/runtime.spec.ts「drops an empty-text sticker show without registering the id」。
  • 修复 5(hide 补全打字):生产样本中打字被 hide 打断的可见窗口极窄(如 obt/main/level_st_17-03.txt:361→363,block=false + delay=0.04 仅 3 字)—— 行为由单测锁定:tests/renderer.spec.ts「completes in-flight sticker typing before the hide fade」。

测试

  • pnpm test:20 个文件 228 个用例全部通过(基线 222 + 新增 6)。
  • STORY_CORPUS_ROOT=... pnpm test:story-log:全语料 Log All 回归(符号预算 + 独立 oracle 对拍)通过。
  • pnpm exec vue-tsc -b 通过;改动文件 eslint 无告警。

对齐 StickerPanel._ExecuteSticker(2.7.61 VA 0x183e924f0)的行为:
- append 分支重放存储布局,不再缺省 x=0/y=0 跳位(主线 13-05 信纸)
- show/append/hide 补 RaiseAutoClick 桥接,自动播放不再卡在贴纸等待
- 空 text 的 show 静默丢弃;缺省 delay 按 _GenParam 1.0(scale 25)
- hide 前先瞬间补全打字中的文本(TryFinishType)
- multiline show 缺省 duration 沿用 view 旧 fade;pool+dict>=20 告警
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Reviewers

No reviews

Assignees

No one assigned

Labels

None yet

Projects

None yet

Milestone

No milestone

Development

Successfully merging this pull request may close these issues.

1 participant

AltStyle によって変換されたページ (->オリジナル) /