- item_tooltip_view.gd: 新增 avoid_rect 属性,tooltip 与装备窗口重叠时自动推到左侧 - inventory_ui.gd: 悬停装备时传入窗口矩形作为避让区域 - 包含其他累积的功能开发和测试文件
15 KiB
movement.remote-sync-state
Scope
比较远端角色 GC_MOVE/状态命令的接收、服务器时钟校正、TCP 状态队列释放、动作前移动、到达后的动作、速度/走跑模式、位置纠偏、死亡/击倒/表情锁、中断和换图清理。
Reference call chain
UserInterface/PythonNetworkStreamPhaseGameActor.cpp::RecvCharacterMovePacket- 解码
bRot * 5、bFunc、bArg、dwTime、目标坐标和dwDuration。 CNetworkActorManager::MoveActor查找已有 VID,同时更新SNetworkActorData的展示目标。
- 解码
UserInterface/InstanceBase.cpp::PushTCPState- 用
ELTimer_GetServerFrameMSec() - dwCmdTime更新 70/30 EMA。 - 以
dwCmdTime + m_nAverageNetworkGap入队。
- 用
UserInterface/InstanceBase.cpp::StateProcess- 服务器帧未到时保留队首。
__CanProcessNetworkStatePacket拒绝死亡、击倒和不可取消技能。__IsEnableTCPProcess在表情或 TCP 状态禁用期间暂停释放。- 按
FUNC_WAIT、FUNC_MOVE、FUNC_COMBO、FUNC_ATTACK、FUNC_MOB_SKILL、FUNC_EMOTION和FUNC_SKILL分支建立Src/Dst、m_kMovAfterFunc和动作。
UserInterface/InstanceBase.cpp::MovementProcess- 由
CActorInstance::AccumulationMovement的动作根运动推进。 - 到达后按
m_kMovAfterFunc执行 combo/attack/skill/emotion,远端过冲超过 100 像素时重新取 Src,并把普通移动降为等待。
- 由
UserInterface/PythonNetworkStreamPhaseGameActor.cpp::RecvSyncPositionPacket- 每个纠偏元素调用
CNetworkActorManager::SyncActor。 CActorInstance::TEMP_Push做 100 段物理碰撞探测、BlendingPosition 和大位移受击动作。
- 每个纠偏元素调用
UserInterface/PythonNetworkStreamPhaseHandShake.cpp- 握手
dwTime + lDelta与本地毫秒时钟建立服务器帧时基。
- 握手
Current call chain
extension/src/net/classic/classic_parser.cpp::HDR_GC_MOVEextension/src/net/entity_store.cpp::mut_move- 远端 VID 入
std::deque<StateCmd>,用average_network_gap做 70/30 EMA。 drain_state_queue按server_frame_ms、死亡/击倒门释放。
- 远端 VID 入
extension/src/net/entity_store.cpp::apply_state_cmd- 已覆盖 WAIT/MOVE/COMBO/ATTACK/MOB_SKILL/FUNC_EMOTION/技能位掩码,并保存
mov_after_func。
- 已覆盖 WAIT/MOVE/COMBO/ATTACK/MOB_SKILL/FUNC_EMOTION/技能位掩码,并保存
extension/src/net/entity_store.cpp::tick- 先释放命令,再以
.msa提取的 WALK/RUN 根运动速度推进;无资源时按dwDuration线性插值。
- 先释放命令,再以
extension/src/net/entity_store.cpp::mut_snap_positionGC_SYNC_POSITION直接把当前位置和 Src/Dst 设置为纠偏坐标并停止移动。
project/net_world.gd::_update_visibility- 节点位置直接读取 C++ 实体坐标;按
func、moving、walk_mode、dead更新远端动作。
- 节点位置直接读取 C++ 实体坐标;按
extension/src/net/classic/classic_session.cpp- 将 classic 握手推导出的
server_frame_ms()每帧喂给EntityStore。
- 将 classic 握手推导出的
extension/tests/net_state_queue_test.cpp- 覆盖帧门、阈值、技能位、死亡/击倒挂起、顺序、时钟防呆、根运动和 duration fallback。
Audit findings (2026-09-20)
已确认当前端的远端移动不再是收到 GC_MOVE 就直接改坐标,核心队列、70/30 网络延迟 EMA、服务器帧释放、1/50 像素阈值、到达后动作和根运动推进都已有对应实现;因此这一项不能继续保持“未审计的 MAPPED”。
仍有材料差异,状态定为 PARTIAL:
- 40250 的
FUNC_EMOTION在目标距离大于 100 像素时先走到目标再执行情绪;当前端已补齐 100 像素阈值、到达后的mov_after_func和远程表情不启用 skip-collision 的分支。由于TPacketGCMove本身不携带uTargetVID,双人表情目标解析仍无法在网络层 1:1 复刻。 - 40250
__CanProcessNetworkStatePacket还检查不可取消技能,__IsEnableTCPProcess还检查IsActEmotion和m_bEnableTCPState;当前已新增 presentation-ownedskill_active/skill_can_cancel/acting_emotion/tcp_state_enabled门,并由远端一次性技能/表情的motion_bound("wait")尾事件释放。技能可取消性仍缺少 40250 动作数据的权威来源,未知资源和无模型节点保留回退路径。 - 40250 的远端移动权威推进来自动作
.msa的AccumulationMovement;当前有真实 WALK/RUN 根运动读取,但无模型时使用dwDurationfallback,且坐骑直接 fallback,速度/到达时间不完全一致。 - 40250
FUNC_COMBO/FUNC_SKILL到达后使用uArg选择具体动作;当前队列保存了mov_after_arg,且net_world已把FUNC_ATTACK映射为NAME_NORMAL_ATTACK、把FUNC_COMBO的func_arg原样传给play_attack_motion,把FUNC_SKILL的循环/移动位传给play_skill_motion。FUNC_EMOTION现在也按uArg尝试set_motion_id,动作完成后释放 TCP 门;远端 combo/skill/emotion 资源缺失时仍按视图实现回退,怪物 motlist 的逐段资源覆盖和技能 grade 权威来源仍未完全闭合。 - 40250
TEMP_Push对GC_SYNC_POSITION做 100 段物理碰撞探测、BlendingPosition,并在位移超过 150 像素时触发 DAMAGE_FLYING/STAND_UP;当前端已由mut_snap_position记录源点/序号/150cm 与技能判定,NetWorld执行 100 段is_blocked探测、1 秒倒数偏移和击倒动作链。无模型/无地形 world 时仍保留可验证的权威坐标回退,因此资源和真实场景碰撞结果仍为 PARTIAL。 - 40250 对命令队列的未来时间不设置 1000ms 防呆阀;当前
STATE_QUEUE_MAX_WAIT_MS超过阈值立即释放,是为未完成的真实服务器时基校准保留的有意偏离。 - 换图清理已清除实体和队列,但“远端动作正在播出时收到死亡、击倒、传送和重新 Add”的完整资源/动作事件顺序仍缺端到端证据。
Deep audit round 2026-09-20
本轮重新对照 InstanceBase::StateProcess、TEMP_Push 和 NetworkActorManager::MoveActor/SyncActor 的实际分支,并重跑当前端队列、实体和移动回归:
- 40250 在释放队首命令前同时检查死亡、击倒、不可取消技能、表情和
m_bEnableTCPState;当前队列虽然有死亡/击倒门,且已补FUNC_EMOTION的距离/到达分支,但没有不可取消技能、表情活动和 TCP 状态开关的等价状态源,双人表情目标也无法从TPacketGCMove还原。 - 40250 的
FUNC_COMBO、FUNC_ATTACK、FUNC_MOB_SKILL和FUNC_SKILL在到达后继续使用命令参数选择动作;当前mov_after_arg能保存参数,但远端视图侧没有完整的 arg→动作资源路由,当前回归只验证 func/队列状态,不验证具体.msa播放结果。 GC_SYNC_POSITION在 40250 进入TEMP_Push,当前端已补 100 段碰撞探测、BlendingPosition 偏移和大位移击倒动作门;真实模型动作、地图碰撞资源和无模型 fallback 仍不能证明完全一致。- 本轮
net_state_queue_test、net_entity_test、net_world_vis_test、netplay_test、movement_parity_test和net_world_remote_action_test均退出码 0;这些测试证明队列门、EMA、根运动 fallback、可见性、上行移动和 TEMP_Push 纠偏事件/击倒门没有回归,但没有覆盖真实模型动作资源、表情锁、不可取消技能权威数据、实服乱序/跨图/死亡重建和地图碰撞资源。
本轮没有把已有 PASS 测试误升为等价完成;核心队列链保持可用,但上述状态门、动作参数和纠偏物理仍使合同保持 PARTIAL。
Equivalence matrix
| 项目 | 状态 | 备注 |
|---|---|---|
| Preconditions | PARTIAL | VID、主角过滤、服务器帧门、死亡/击倒、不可取消技能和表情/TCP 门已有实现;技能可取消性权威来源和双人表情目标未闭合 |
| Branch structure | PARTIAL | WAIT/MOVE/COMBO/ATTACK/MOB_SKILL/EMOTION/SKILL 距离分支已对齐;完整禁止门仍缺失 |
| Algorithms/formulas | PARTIAL | 70/30 EMA、1/50 阈值、100 像素过冲、100 点纠偏探测、150cm 击倒阈值和 1 秒 BlendingPosition 已对齐;无模型/无 world fallback 不等价 |
| State transition order | PARTIAL | 队列→动作前移动→到达动作→动作尾释放,以及 sync serial→碰撞→缓动→击倒/起身→释放门顺序已对齐;双人表情目标和真实资源尾时序未闭合 |
| Constants/units | PARTIAL | 角度、cm、阈值和 70/30 已记录;1000ms 防呆阀与坐骑/fallback 是偏离 |
| Timing/event sources | PARTIAL | classic server frame 已接入;真实握手时基、动作事件与状态动作的端到端联机证据不足 |
| Resource/data sources | PARTIAL | WALK/RUN .msa 根运动、PC combo .msa 模式目录、PC emotion action 和 damage_flying/standup 入口已接入;技能可取消/grade、怪物逐段 combo、emotion 目标、真实击倒资源覆盖仍不完整 |
| Protocol side effects | PARTIAL | GC_MOVE、GC_SYNC_POSITION、CHANGE_SPEED、WALK_MODE 已解析;纠偏动作已桥接,双人情绪目标和服务器时基副作用未等价 |
| Interruption/failure/cleanup | PARTIAL | 死亡/击倒挂队、换图清理已有单测;技能/表情/传送/重建完整矩阵未完成 |
Regression evidence
extension/tests/net_state_queue_test.cpp:服务器帧释放、WAIT 1.0、攻击/技能 50.0、FUNC_EMOTION 100.0、死亡/击倒挂队、FIFO、时钟防呆、根运动和 duration fallback。extension/tests/net_entity_test.cpp:远端移动命令的 near/far 行为、到达后动作和未知 VID 忽略。project/netplay_test.gd、project/movement_parity_test.gd:上行状态节流和移动预测不回归。project/net_world_remote_action_test.gd:远端FUNC_ATTACK使用普通攻击索引 13,FUNC_COMBO保留bArg连击段,并传递武器动作模式与攻速比例。extension/tests/net_state_queue_test.cpp:不可取消技能、活动表情、TCP 状态禁用和恢复后的队列释放边界。extension/tests/net_entity_test.cpp:GC_SYNC_POSITION记录源点、单调 serial、150cm 大位移和技能抑制状态。project/net_world_remote_action_test.gd:TEMP_Push 大位移动作、击倒网络门、旧位置起始偏移和动作尾释放。
Implementation fix round 2026-09-20
按 40250 InstanceBase::StateProcess 到 RunNormalAttack / RunComboAttack 的动作选择
补齐远端攻击状态的参数桥:普通攻击使用 CRaceMotionData::NAME_NORMAL_ATTACK(13),连击
使用 TPacketGCMove.bArg 原值,二者都从远端视图读取当前武器动作模式,并把 bAttackSpeed / 100
传给动作播放层。此前两种状态都会降级成通用 set_anim_state("attack"),导致远端角色看不到
对应的 combo 段;资源解析失败时仍保留通用状态回退。
回归:godot --headless --path project --script net_world_remote_action_test.gd 通过。
死亡/击倒门、FUNC_EMOTION 目标、技能 grade、坐骑根运动和 TEMP_Push 纠偏物理仍保持
PARTIAL,本轮没有把动作索引测试误当成完整资源/联机等价。
Implementation fix round 2026-09-20 — state gates and emotion action
按 40250 __CanProcessNetworkStatePacket 与 __IsEnableTCPProcess 增加 EntityStore 的
四个 presentation-owned 状态门:不可取消技能阻止后续状态出队,活动表情阻止 TCP 状态,
m_bEnableTCPState=false 时只允许当前 FUNC_EMOTION,死亡/击倒门保持原有优先级。NetWorld
在远端技能/表情动作开始时设置门,在 motion_bound("wait") 动作尾清除;节点剔除和换图也会
清除门,避免模型被释放后队列永久冻结。
同时把 FUNC_EMOTION 的 func_arg 接入 40250 动作 ID(单人表情使用 target_race=-1,
双人 GC_MOTION 仍走原有目标 VID 路径),并让出生时已经带有 FUNC_* 的实体在字段刷新后
立即绑定初始动作,而不是等待下一次状态变化。
回归:net_state_queue_test、net_world_remote_action_test、net_world_vis_test、
netplay_test、player_motion_test、test_skill_state_arg_parity 和完整 ctest(23/23)
均通过。技能可取消性的动作数据来源、真实远端模型动作尾时序、双人表情目标和 TEMP_Push
仍保持 PARTIAL。
Status
PARTIAL。远端 TCP 状态队列主链已经有较充分实现和单元测试;FUNC_EMOTION 的距离/到达顺序已补齐,但 40250 的不可取消技能门、双人表情目标、纠偏物理动作、远端动作参数和真实服务器时基仍未完全等价。
Implementation fix round 2026-09-21 — TEMP_Push correction path
按 40250 NetworkActorManager::SyncActor → CInstanceBase::NEW_SyncPixelPosition →
CActorInstance::TEMP_Push 补齐 GC_SYNC_POSITION 的表现层纠偏:EntityStore::mut_snap_position
现在保留同步前坐标、单调 correction serial、150cm 大位移判定及 IsUsingSkill 抑制位;
M2Client::entity_dict 将这些字段交给 NetWorld。节点收到新 serial 后,NetWorld 按
TEMP_Push 的 100 个采样点调用地图 is_blocked,无碰撞时用 PhysicsPush 的 1 秒
倒数偏移保持旧位置起步并回到权威目标;大位移且非技能时启动
DAMAGE_FLYING -> STAND_UP,并通过 set_entity_knockdown 复刻 IsKnockDown 网络状态门。
动作尾、节点剔除和换图会释放该门;没有可用模型/地形时保留权威坐标回退,不伪造资源动作。
回归:net_entity_test、net_world_remote_action_test、net_world_vis_test、
netplay_test、player_motion_test、movement_parity_test 和完整 ctest(23/23)通过。
真实 IPhysicsWorld 地形数据、动作资源覆盖、技能可取消权威来源、双人表情目标和真实服
乱序/跨图/死亡重建仍保持 PARTIAL。
Implementation fix round 2026-09-21 — unified remote FUNC_MOVE arrival branch
复核 40250 CInstanceBase::MovementProcess 的远端 actor 分支后确认,
m_kMovAfterFunc == FUNC_MOVE 穿过 Dst 时没有 PC/NPC/monster 的 ch_type 分叉:
FUNC_MOVE 的到达 switch case 继续沿当前根运动推进,只有后续状态命令或超过
100cm 的 overshoot 防呆分支才会改回 WAIT。当前端此前只让 PC 继续,NPC/MOB
在第一次越过 Dst 时提前停止并清除 skip_collision,导致远端怪物的连续 GC_MOVE
表现和 40250 不一致。
现已将 EntityStore::advance_walk_by_motion 的远端到达逻辑统一为参考分支:
死亡/击倒仍立即停止;FUNC_MOVE 保留 moving、mov_after_func 和根运动推进;
普通攻击、连击、技能、表情等到达动作继续走原有 finish_walk。新增 NPC/MOB
回归用例先证明修复前会失败,修复后 net_state_queue_test、net_entity_test、
net_classic_session_test 和 git diff --check 均通过。
本合同仍为 PARTIAL:真实 WALK/RUN 根运动资源、技能可取消/grade 权威数据、双人
表情目标、TEMP_Push 地图碰撞和真实服务器时序尚未达到同一实现证据。