- item_tooltip_view.gd: 新增 avoid_rect 属性,tooltip 与装备窗口重叠时自动推到左侧 - inventory_ui.gd: 悬停装备时传入窗口矩形作为避让区域 - 包含其他累积的功能开发和测试文件
14 KiB
14 KiB
render.effect_particle_motion —— MDE/MSE、粒子、动作事件挂点和回收
状态:PARTIAL
本合同不仅检查 MDE/MSE 粒子播放器,还检查 40250 ActorInstanceMotionEvent 在每个动作帧分派的特效、音效、飞行物、特殊攻击、显示/隐藏、传送和目标特效。判断标准是资源字段、事件类型、帧时序、挂点矩阵、生命周期和所有 Actor 的消费范围一致;只验证“特效能播放”不能视为与 40250 等价。
40250 参考调用链
GameLib/RaceMotionData.cpp/RaceMotionDataEvent.h- 读取
MotionEventDataCount、事件类型、StartingTime,按1 / g_fGameFPS转为动作帧。 EFFECT保存EffectFileName、EffectPosition、AttachingEnable、FollowingEnable、IndependentFlag和骨骼名。EFFECT_TO_TARGET保存目标偏移、跟随/钓鱼标志;FLY使用独立的FlyFileName/FlyPosition;SPECIAL_ATTACKING保存DuringTime、EnableHitProcess、攻击参数和碰撞球。- 动作加载时还从同名
.mss读取声音脚本,后续按动作帧调用SoundEventProcess。
- 读取
GameLib/ActorInstanceMotionEvent.cppMotionEventProcess()对当前动作的每一帧事件调用MotionEventProcess(dwcurFrame, index, data)。EFFECT分独立世界特效、挂骨骼并跟随、挂骨骼但只快照、挂 Actor 根节点四条路径。EFFECT_TO_TARGET分钓鱼落点、目标对象跟随和目标位置快照三条路径。SPECIAL_ATTACKING建立带持续时间、命中去重和动态碰撞球的 splash 区;FLY从骨骼/角色位置创建.fly实例并调用OnShoot。CHARACTER_SHOW/HIDE改变渲染模式和透明度;WARP做地图阻挡检查、朝向目标并移动到目标前 270cm。SOUND调用PlaySound3D,声音脚本由SoundEventProcess独立更新。
EffectLib/EffectManager.cpp、EffectInstance.cpp、ParticleInstance.cpp、PythonEffectModule.cpp- 负责 MSE/MDE 注册、解析、粒子时间曲线、混合、颜色、缩放、旋转、纹理动画、渲染空间、生命周期和实例回收。
当前端实现映射
formats/msa.cpp/formats/msa.h- 已读取动作时刻、通用效果/声音/骨骼/挂点字段,另有 MDE/MSE 和攻击数据的基础解析。
- 本轮已补齐 40250 动作事件的专用数据:
FlyFileName/FlyPosition/飞行骨骼、震屏DuringTime/Power/AffectingRange、特殊攻击DuringTime/EnableHitProcess/攻击参数/碰撞球,以及 type 7/8/9 的稳定事件记录。
extension/src/metin2_anim.cpp- 已在
.msa播放时间跨过事件时发出motion_event/motion_event_detailed,并提供骨骼姿态查询。 - 本轮
motion_event_detailed/get_events()已暴露上述专用字段和collision_spheres,表现层可按 40250 分支消费;生产路由尚未全部接入。
- 已在
project/fx/effect_player.gd、project/fx/mde.gd、project/fx/mse.gd、project/fx/effect_registry.gd- 已覆盖 MDE/MSE、粒子曲线、材质、颜色、混合、纹理动画、one-shot/loop 生命周期、注册/缓存和
fx_spawned/fx_finished追踪。
- 已覆盖 MDE/MSE、粒子曲线、材质、颜色、混合、纹理动画、one-shot/loop 生命周期、注册/缓存和
project/fx/motion_effect_anchor.gd/target_effect_anchor.gd- 已实现角色根、骨骼姿态、follow/independent、目标中心和目标快照的基础矩阵转换;缺失骨骼时会清理特效。
project/game_scene.gd- 本地主角 type 1/10 走完整挂点/目标特效,type 2/3 使用固定震屏/屏闪,type 6 只从待发队列触发
client.shoot;本轮远端真实 Actor 的 type 1/10、7/8/9 和 direct sound 也经由NetWorld路由。 - 本地和远端真实 Actor 已接入 type 7/8 的
__HideEvent/__ShowEvent等价消费;type 9 已按 40250 计算目标前 270cm、检查world.is_blocked、调整朝向并在本地主角路径发送一次FUNC_WAIT。仍没有特殊攻击事件的 splash 碰撞球,也没有把.fly文件按 40250 的起点/目标/owner/skill 链创建。
- 本地主角 type 1/10 走完整挂点/目标特效,type 2/3 使用固定震屏/屏闪,type 6 只从待发队列触发
project/ui/player_view.gd、project/ui/mob_view.gd- 已按当前动作加载同名
.mss并逐 60FPS 更新 3D 声音脚本;本轮还为远端真实视图提供统一的 animator signal 接入点。
- 已按当前动作加载同名
project/ui/remote_player_view.gd、project/net_world.gd- 远端 PC 和怪物会创建真实模型并播放
.msa;本轮net_world已为有 native animator 的远端模型连接motion_event_detailed,并由GameScene消费远端 type 1/10 特效、type 7/8 显示隐藏和直接动作声。飞行仍只走服务端GC_CREATE_FLY,避免把远端动作帧错误地变成客户端发包。
- 远端 PC 和怪物会创建真实模型并播放
分支等价矩阵
| 40250 判据/副作用 | 当前实现 | 结论 |
|---|---|---|
| MSE/MDE 注册、解析、粒子曲线、混合和 one-shot 回收 | effect_player/mse/mde/effect_registry + FX 测试 |
基本等价;真实渲染后端像素证据仍有限 |
动作事件按 StartingTime → dwFrame 在每个动作 Actor 上触发 |
native 以时间区间发信号,本地主角和有真实 animator 的远端 Actor 均接入详细事件 | 部分等价;时间精度/重复跨帧和占位 Actor 升级前后的完整逐帧对照仍未完成 |
| EFFECT 的独立、骨骼跟随、骨骼快照、根节点四分支 | 本地和远端真实 Actor 的 type 1 都用 spawn_motion 和 anchor |
部分等价;基础矩阵存在,但远端 target/清理和非详细 fallback 仍需逐分支对照 |
| EFFECT_TO_TARGET 的钓鱼、目标跟随、目标快照 | 本地主角 type 10 有目标 anchor,钓鱼直接跳过 | 部分等价;缺少 40250 fishing effect 生命周期/落点字段和目标失效后的统一回收证据 |
FLY 读取 .fly、骨骼起点、目标、owner/skill,并执行 OnShoot |
当前 type 6 已保留 fly_file/fly_pos/fly_bone 并能传到 native 事件字典;GC_CREATE_FLY 的索引飞行已按 40250 注册表加载 .msf,动作事件仍从待发队列触发 client.shoot |
部分等价;索引资源参数已接入,动作事件 .fly 起点/owner/skill、动态碰撞和 attach/tail 仍未闭合 |
| SPECIAL_ATTACKING 持续时间、动态球、命中去重和结束清理 | 当前 parser/native 字典已保留 duration_time、攻击参数和碰撞球 |
部分等价;splash 的生产碰撞/去重/生命周期分支仍缺失,资产中实际存在 818 个 type 4 事件 |
SOUND 直接动作声和 .mss 帧声 |
本地和远端详细事件都能触发 direct sound,PlayerView/MobView 更新 .mss |
部分等价;频率/距离和路径转换尚未做逐事件对照 |
| SCREEN_WAVING/FLASHING 使用事件自身参数 | 当前固定 shake(0.06, 9.0) 和固定 0.12s 屏闪 |
不等价;type 2 的 DuringTime、Power、AffectingRange 没有保留/使用 |
| CHARACTER_SHOW/HIDE、WARP | 本地和真实远端 Actor 的 type 7/8 已按事件帧切换 actor model 可见性;type 9 由 _apply_motion_warp 执行目标前 2.70m、阻挡检查和朝向,本地再发送 FUNC_WAIT |
部分等价;真实 seomjeon.msa、允许/阻挡/无目标路径有回归,远端目标生命周期和 live 服务端状态包仍待验证 |
| 事件资源和模型从网络实体删除、切图、死亡时清理 | FX anchor 对局部无效目标会回收,map reset 会清飞行/实体 | 部分等价;没有所有 Actor 事件实例、splash、fishing effect 和跨图中断的统一清理矩阵 |
已执行测试
project/fx_test.gd:PASS;MSE 解析、EffectPlayer 和 registry。project/effect_playback_test.gd:0 failures;播放时间和生命周期基础路径。project/target_effect_test.gd:0 failures;目标特效跟随/快照基础路径。project/skill_fx_test.gd:PASS;技能 FX 基础映射。project/effect_color_test.gd、effect_emission_test.gd、effect_faces_test.gd、effect_lie_test.gd、effect_random_rotation_test.gd、effect_render_regression_test.gd、effect_rotation_test.gd、effect_scale_test.gd、effect_space_test.gd、effect_surface_test.gd、effect_texture_animation_test.gd:均无断言失败;surface/texture animation 在 headless 下明确跳过像素检查。project/motion_effect_anchor_test.gd:断言显示failures=0,但进程以 exit 139 结束并有 6 个 ObjectDB 泄漏,不能作为稳定通过证据。- 资源静态统计:当前资产中的
MotionEventType为 type 1=1892、2=263、4=818、6=268、7=47、8=47、9=47、10=197,共 3579 个事件;没有 type 5 样本,但不能因此删除 type 5 分支。
Deep audit round 2026-09-21
Fresh regression results
fx_test.gd、effect_playback_test.gd、target_effect_test.gd、skill_fx_test.gd及颜色、发射、面、lie、随机旋转、渲染回归、旋转、缩放、空间、surface、texture animation 测试均无断言失败;surface/texture 的 headless 像素检查明确跳过。motion_effect_anchor_test.gd的断言为 0 failures,但进程 exit 139,并泄漏 6 个 ObjectDB;因此不能升级为稳定回归通过。
Static parity conclusion
- MDE/MSE 基础解析、粒子曲线、材质/颜色/纹理动画和本地主角基础挂点存在,但
MotionEvent仍未完整保留 FLY、SPECIAL_ATTACKING、SCREEN_WAVING 参数以及 CHARACTER_SHOW/HIDE/WARP 专用字段。 game_scene.gd主要连接本地主角;RemotePlayerView/MobView 的动作没有接入 40250 式统一 motion-event 分派,因此远端特效、飞行、音效、隐藏、震屏和 warp 仍不一致。- 当前 type 4/7/8/9 生产分支缺失,资产统计分别发现 818、47、47、47 个事件;type 6 也未按参考
.fly起点、目标、owner/skill 形成等价飞行实例。 - 基础 FX 断言通过不能覆盖 splash 命中去重、事件跨帧/loop、目标删除、死亡、地图切换和实例回收;挂点测试的 exit 139/泄漏需先修复。
Active source group review
- 对 Visual Studio
EffectLib活跃编译单元逐组核对后,参考链补充确认:CEffectData::LoadScript同时加载 mesh、particle、light 和.mss声音数据;CEffectManager::RegisterEffect/CreateEffectInstance/Update/Render/Destroy负责缓存、实例池、更新/渲染顺序和销毁;CParticleSystemInstance/CParticleInstance、CEffectMeshInstance、CLightInstance分别维护粒子、网格帧/纹理帧和光源生命周期。 - 当前端虽然有
EffectPlayer/MDE/MSE/registry 的格式和局部播放测试,但没有证明声音脚本、mesh/light 三类实例、固定池耗尽、注册失败和DestroySystem的顺序与参考一致;本组静态核对完成,合同仍为PARTIAL。
已确认差异和未验证项
- 已将
MotionEvent扩展为按 40250 事件类型保留专用数据,并让motion_event_detailed传完整字典;本地主角和真实远端 Actor 已消费 type 1/7/8,仍需证明所有分支使用这些字段。 - 已把动作事件连接扩展到
NetWorld创建的真实远端 PC/NPC/Mob;仍需把震屏、局部 FX、飞行和隐藏行为按本地相机与远端 Actor 的范围/目标语义完整分开。 - 必须建立
.msa事件快照测试:每种事件的字段、帧、跨帧/loop、重复触发和缺字段回退;并建立与 40250 样本资源的数量和时序基线。 - 必须增加 SPECIAL_ATTACKING splash 的碰撞、命中去重、持续时间、死亡/删除/切图清理测试,以及 FLY
.fly的起点、目标、owner/skill 和回收测试。 motion_effect_anchor_test的 exit 139 和 ObjectDB 泄漏需要先修复测试稳定性,才能把基础挂点证据提升为可靠回归门禁。
Implementation fix round 2026-09-22 — dedicated MotionEvent payload and local show/hide
- 对照
RaceMotionDataEvent.h/RaceMotionData.cpp,formats::MotionEvent现在独立保存:- type 6 的
FlyFileName、FlyPosition、挂接骨骼; - type 2 的
DuringTime、Power、AffectingRange; - type 4 的
DuringTime、EnableHitProcess、攻击参数和SphereData*; - type 7/8/9 的启动时间和稳定的详细事件字典。
- type 6 的
Metin2AnimPlayer::get_events()/motion_event_detailed已传出fly_*、震屏参数、特殊攻击参数和collision_spheres。GameScene已按 40250 的 type 7/8 事件帧调用本地 Actor 的__HideEvent/__ShowEvent等价接口;PlayerView/MobView暴露同一 Actor 级可见性 seam。NetWorld已按 40250 的每 Actor 事件处理边界连接远端 native animator,GameScene消费远端 type 1/10 FX、type 7/8 显示隐藏和 direct sound;远端 type 6 不发客户端包。- 回归:
formats_msa_test、真实 type 2/4/6/7 资源的motion_event_payload_test、motion_event_visibility_test、net_world_motion_event_test通过。 - 本轮仍为
PARTIAL:.fly资源和飞行实例、splash 碰撞/去重/清理、type 9 warp、震屏范围和统一跨图清理没有完成。
Implementation fix round 2026-09-22 — WARP event branch
- 对照
GameLib/ActorInstanceMotionEvent.cpp::ProcessMotionEventWarp和ActorInstanceEvent.cpp::__OnWarp,GameScene::_apply_motion_warp已实现相同的 270cm 单位换算、目标前落点、地图阻挡拒绝、朝向目标和本地主角FUNC_WAIT状态回调;远端 Actor 也消费 type 9,但不伪造本地网络包。 project/motion_event_warp_test.gd使用真实seomjeon.msa验证 type 9,并覆盖可移动、阻挡、无目标三条分支;测试通过。- 当前合同仍为
PARTIAL:type 4 splash、type 6.fly数据权威、震屏参数/范围和所有 Actor 的跨图/死亡清理仍未闭合。
下一轮验证入口
- 先以本轮
formats/msa/native payload 为输入,实现按 Actor 的事件连接/路由。 - 以 type 4、6、7、8、9 的真实资产各选样本,补逐帧事件、碰撞、飞行、显示隐藏和 warp 测试。
- 统一本地/远端/怪物/切图/死亡的 FX 实例清理,并把
fx_spawned/fx_finished纳入可审计事件日志。