Files
2026-06-14 07:42:09 +08:00

6.8 KiB
Raw Permalink Blame History

AGENTS.md

本项目工作:修改 RA3 UI(APT 文件)。

1. 概述

APT 是 RA3 的 Flash-like UI 二进制格式。修改 APT 由两类工作组成:

  • 修改布局和素材:调整位置、大小、纹理、角色(shape/sprite/button
  • 修改脚本/逻辑:改写 bytecode(汇编),或通过钩子引入外部 ActionScript

edit.xml 是什么

_edit.xml.apt 二进制反编译后的可编辑 XML 版本。 修改 _edit.xml 后需用工具编译回 .apt

两种生成 APT 的路径

路径 适用 能写 AS
已有 APT → edit.xml → 修改 → 编译回 APT 修改现有 UI 只能写汇编(bytecode
新 FLA → SWF → APT 创建全新 UI 可在 Flash 中直接写 ActionScript

已有 APT 无法逆向转回 FLA。这是"为什么必须操作 edit.xml"和"为什么钩子模式有价值"的根本原因。


2. 开始前

必读

APT修改指南.md — CDATA 格式、指令句法、ru 公式、placeobject flags —— 必须先读

分析流程

修改任何 APT 前,按以下顺序分析:

  1. 读反编译 AS → 理解类结构、方法、逻辑流
    • Data/decompiled-as-references/<apt名>/scripts/__Packages/<类名>.as
    • 共享类在 Data/decompiled-as-references/main_mouse/scripts/(如 std_mouseRadioButtonmouse_chapterSelectComponent
  2. 读 edit.xml → 布局、角色(image/shape/sprite/button)、placeobject、bytecode
  3. 跨文件追踪export/import 关系:一个 APT 导出的 character 可被其他 APT 引用; 运行时 attachMovie() 按符号名解析——只要有一条 import 链可达即可
  4. 请求原始参考 APT → 推断 tx 语义、对齐关系必须对比未修改版; 请求用户提供原始 APT(如本项目中的 Data/aptui_ref/
  5. 从原始数据推算 → 不假设 tx 是左边缘或中心,用 shape 尺寸交叉验证; 按钮与背景图对齐关系需从原始坐标推算

3. 工具

编辑后需要用 ra3apt-cli 编译:

# 反编译 .apt → edit.xml
ra3apt-cli expand <input.apt>

# 编译 edit.xml → .apt
ra3apt-cli build <input_edit.xml>

工具有可能不在当前工作区;如果可执行,用以上命令转换(生成的文件会替换已有文件);如果不可用,提醒用户手动操作

格式规则

  • 所有 bytecode<action><clipaction><initaction>)使用 <![CDATA[...]]> 包裹
  • CDATA 内 & 等字符无需 XML 实体转义(写 &Outline,非 &amp;Outline
  • 修改后用 grep 验证关键值(坐标、depth、label)

4. 修改布局和素材

depth 规则

  • placeobjectdepth 控制 Z 序(渲染和点击优先级)
  • 新增元素前必须 grep 验证该 depth 未被同一帧的其他 placeobject 占用

单选按钮(std_mouseRadioButton

  • m_width 不控制视觉宽度(只用于 labelTF._x 文本居中)
  • 缩放用 rotm00(宽)和 rotm11(高)。缩放后 ty 需补偿垂直偏移:
    new_ty = old_ty + old_visual_height × (1  scale) / 2
    
  • mouse_chapterSelectComponent 的特殊情况(不一定适用于其他 APT 文件):按钮与背景图是独立层,对齐偏移需从原始坐标推算

纹理 ru

tex_x = m00 × screen_x + tx
tex_y = m11 × screen_y + ty
  • t 命令中坐标为屏幕坐标
  • 矩阵为单位矩阵(1:0:0:1)时简化为 tex = screen + tx
  • 移动屏幕三角形、保持采样同一纹理区域: new_tx = tex_left new_screen_left
  • 缩小屏幕三角形后要完整显示纹理(非裁切): m00 = tex_width / new_width,再重算 tx
  • 多个 shape 可从同一张 .tga 图集的不同坐标区域采样(texture atlas 模型)

Content Sprite 结构

  • 使用帧标签定义状态:_disable / _selected / _unselected / _selectedRollover / _unselectedRollover / _downState / _intro / _outtro
  • 须包含 _parent.introComplete()_parent.outtroComplete() 回调
  • 新增 sprite 时必须从同一 APT 现有 content sprite 复制完整帧结构(帧数可能不同)

5. 修改脚本/逻辑

_global 通信总线

  • 所有 APT 和外部 AS 共享同一个 _global 命名空间
  • 一个 APT 中定义的全局变量(如 _global.ENUM.XXX)可在其他 APT 的 bytecode 中读取
  • 这是钩子模式能成立的基础

this 的含义

  • Cafe_BaseUIScreen 子类的 initaction 中,this管理类实例,不是 MovieClip
  • MovieClip 通过 this.m_screenCafe2_BaseUIScreen.m_screen 访问
  • 写 bytecode 或钩子函数都需区分两者

汇编调用与寄存器

Cafe_BaseUIScreen 子类方法中:reg1 = thisreg2 = _global

操作 格式
调函数 ...args → push nArgs → funcObj → pushundefined → callmethodpop
调方法 ...args → push nArgs → obj → callnamedmethodpop "methodName"
  • 禁止 callnamedpop "call" — 等效 func["call"](),这在 APT 中不被支持
  • 新增 label 名用 grep 验证不与已有冲突

汇编 vs 钩子:决策

情况 做法
改动少且机械(复制现有模式) 直接写汇编在 edit.xml 中
改动复杂(多分支、循环) 用钩子
目标类在不可编辑的 APT 中(无 _edit.xml 只能用钩子

钩子详解

原理_edit.xml 中写少量检测 bytecode,实际逻辑写在新 FLA→SWF→APT 的 ActionScript 中, 通过 _global 变量传递。

具体步骤

  1. 在可编辑 screen 的 initGUI() 末尾插入以下 bytecode(位置:registerIntroOuttroComponents() / startIntro() 调用之后、end 之前):
// 等效 ASif (_global.gHookName != undefined) { _global.gHookName(this); }
pushglobal
getnamedmember "gHookName"
pushundefined
ActionNewEquals      // != undefined ?
ActionLogicalNot
ActionLogicalNot
jumptrue lbl_skip
pushreg 1            // this(管理类实例)
EAPushOne            // 1 个参数
pushglobal
getnamedmember "gHookName"
pushundefined        // 直接调用,非方法查找
callmethodpop
lbl_skip:
  1. 在新 FLA 的 ActionScript 中编写处理函数,赋值给 _global.gHookName

  2. 钩子函数接收的 this管理类实例Cafe_BaseUIScreen 子类),不是 MovieClip

初始化顺序:frameDelayedInit() → initGUI() → registerIntroOuttroComponents() → startIntro()

若有需要可以为 <placeobject /> 添加 <poname name="xxx" /> 从而让 ActionScript 能够访问对应 MovieClip 并进行操作(例如parent.xxx._y = 100),但不作为默认要求。


6. 输出给用户

  • 需用户配合的内容(引擎常量、本地化 key、外部 AS 代码)→ 输出为独立的 .md 指南文件
  • 指南给出可直接使用的代码/值,而非笼统描述