package routers import ( "context" "sync" ) var _ = sync.Mutex{} var _ = context.Background // Client movement reports and live transform tracking. // // Mirrors the live transform to the progress snapshot while the player walks around. // This server has no session-end hook, so a save triggered on logout would simply never run — // the client just goes away. Instead the position is written periodically, throttled by both // time and distance, so standing still costs nothing and a long walk never loses more than one // interval of progress. // func GameRouter_Movement_MaybeSavePlayerPosition4229938(ctx context.Context, state any, rpcCtx *RpcContext) any { // Router implementation for GameRouter_Movement_MaybeSavePlayerPosition4229938 var zero any; return zero } // // 给一个留下的角色发一条**原地路点任务**(TaskWayPointMove,points = [站立点, 站立点])。 // ⛑ 这一条是止住自由落体的关键:位置流只是硬拉坐标,任务包会让客户端的 locomotion // 状态机接管 actor ⇒ 重新贴地。街上那些 830… 开头的 NPC 同样带 Managed 却从不掉, // 就是因为它们一直被喂这个包(见 LeftBehindWaypointTask 的注释)。 // func GameRouter_Movement_SendLeftBehindWaypointAsync(ctx context.Context, session *GameSession, unitId uint64, position Vec3, token context.Context) any { // Router implementation for GameRouter_Movement_SendLeftBehindWaypointAsync var zero any; return zero } // // ★★ 给留下的角色派一段**真实行程**(闲逛用,开关 LeftBehindWander)。 // 与 SendLeftBehindWaypointAsync 的差别只有一个:那条 // points = [锚点, 锚点](距离 0 ⇒ 原地,止跌用),这条给的是 // PedLaneGraph.TryPlanJourney 沿人行道规划出来的折线。 // ⛑ 包体和止跌那条**完全同构**(同一个 SyncLogicAgentCommand + tag 39 // TaskWayPointMove),只是点不同 —— 街上那些 830… 开头的 NPC 走的就是这个包。 // func GameRouter_Movement_SendLeftBehindRouteAsync(ctx context.Context, session *GameSession, unitId uint64, route []any, speed float32, token context.Context) any { // Router implementation for GameRouter_Movement_SendLeftBehindRouteAsync var zero any; return zero } // // ⛑⛑ 留下的角色**不能只在客户端上报时才续发**:玩家站着不动观察的时候客户端一个包都不发, // 那一刻它们正好在自由落体(60~90 m/s,几秒就掉出世界)。 // ⇒ 起一个跟 Ambient 同款的后台循环,按 LeftBehindWaypointIntervalMs 续发。 // session 断开后写 socket 会抛异常,循环自己退出,不需要额外的停止钩子。 // func GameRouter_Movement_EnsureLeftBehindLoop(ctx context.Context, session *GameSession, state any) any { // Router implementation for GameRouter_Movement_EnsureLeftBehindLoop var zero any; return zero } func GameRouter_Movement_RunLeftBehindLoopAsync(ctx context.Context, session *GameSession, state any, token context.Context) any { // Router implementation for GameRouter_Movement_RunLeftBehindLoopAsync var zero any; return zero } // // 某个角色「留场轮换」的 POI 组(gameplay.rosterNpc.poiOverrides[].leftBehindPoiGroup)。 // 没配 ⇒ null(不轮换)。⛑ 按 spiritId 查,不是 unitId。 // func GameRouter_Movement_PoiGroupFor(ctx context.Context, spiritId uint32) []any { // Router implementation for GameRouter_Movement_PoiGroupFor return nil } // 某个角色轮换时每个 POI 停多久(角色级覆盖 → 全局)。 func GameRouter_Movement_PoiDwellMsFor(ctx context.Context, spiritId uint32) int32 { // Router implementation for GameRouter_Movement_PoiDwellMsFor return 0 } // // ★★ 一个 tick:给配了「留场 POI 组」的角色换下一个 POI(开关 LeftBehindPoiRotation)。 // **洗牌袋**:把组打乱后一条一条播,播完一轮重新洗牌 ⇒ 随机,但一轮之内不重复, // 不会出现"连着三次同一个、另一个半天轮不到"。 // ⛑⛑ 三条门禁(少一条就是白干 / 出怪相): // ① 出场包带了 AgentDataSetsActivityCfgId(在生活日程里)⇒ **不轮换**, // 客户端 ambient 会把 POI 盖掉(硬规则 163:里希"一边打电话一边跑步"); // ② 配了组的角色**不再**喂坐标 / 原地路点(见上面的 snapshot 过滤); // ③ 与闲逛互斥:有组就轮换,没组才走 wander(见 RunLeftBehindWanderTickAsync)。 // func GameRouter_Movement_RunLeftBehindPoiTickAsync(ctx context.Context, session *GameSession, state any, token context.Context) any { // Router implementation for GameRouter_Movement_RunLeftBehindPoiTickAsync var zero any; return zero } // // 换到带道具的 POI 时补道具(SyncAgentBelongings → SyncAgentUseBelongingChanged), // 换到无道具的 POI 时发一个空 usage 尝试把上一件收掉。 // ⛑ 与 GameRouter.Civilians.cs 出场那套同包同结构,只是时机从"出场时"改成"每次切换"。 // 开关 SwitchAnimations.LeftBehindPoiRotationProps。 // func GameRouter_Movement_PushLeftBehindPoiPropAsync(ctx context.Context, session *GameSession, unitId uint64, poiActionId uint32, token context.Context) any { // Router implementation for GameRouter_Movement_PushLeftBehindPoiPropAsync var zero any; return zero } // // ★★ 一个 tick:给「当前没在行程里」的留场角色各派一段新行程(开关 LeftBehindWander)。 // ⛑⛑ 下次派单时间 = **本段路程 ÷ 速度 + 余量**,**不能**用固定步长(硬规则 109): // 步长比行程短 ⇒ 走一半就被派下一段(一步一停);比行程长 ⇒ 走完了干站着。 // func GameRouter_Movement_RunLeftBehindWanderTickAsync(ctx context.Context, session *GameSession, state any, token context.Context) any { // Router implementation for GameRouter_Movement_RunLeftBehindWanderTickAsync var zero any; return zero } // // ★★ 把客户端上报的真实坐标写回 LeftBehindCharacter.Position // (开关 LeftBehindTrackRealPosition)。 // 不写回的后果:留场角色闲逛出去之后,切回他时 GameRouter.Switching.cs 读的 // directPos = leftBehind!.Position 还是**切走那一刻的落点** ⇒ 人瞬移回去,逛了等于没逛。 // ⛑ 两个必须跳过的情形: // ① 上报者是玩家自己(ActiveSpiritUnitId)—— 他不是留场角色; // ② 坐标明显掉出世界(Y 是极端值,自由落体那条链上会出现 -2999.99)—— 记下来等于把人扔进虚空。 // func GameRouter_Movement_TrackLeftBehindRealPositions(ctx context.Context, state any, samples []any, activeSpiritUnitId uint64) any { // Router implementation for GameRouter_Movement_TrackLeftBehindRealPositions var zero any; return zero } func GameRouter_Movement_FeedLeftBehindUnitsAsync(ctx context.Context, rpcCtx *RpcContext, state any, samples []any) any { // Router implementation for GameRouter_Movement_FeedLeftBehindUnitsAsync var zero any; return zero } func GameRouter_Movement_OnMovementReport(ctx context.Context, rpcCtx *RpcContext, samples []any) any { // Router implementation for GameRouter_Movement_OnMovementReport var zero any; return zero }