package routers import ( "context" "sync" ) var _ = sync.Mutex{} var _ = context.Background // // 街上正常行走的行人(AetherCity crowd)。 // ★ 这条线是**客户端自驱**的:AetherPedManager 用 ContextSteering + ZoneGraph Wander 自己走, // 服务端**没有任何移动包可发**(MethodId 表里没有 AskUpdateMoveDatas 这类 RPC)。 // 服务端只负责三件事: // ① SyncAetherAIInitDatas 打开 HasZoneGraph —— 已有 EnsureAetherVehicleInit() 负责 // ② SyncSetCrowdDensity(68996045) —— 解锁客户端 ECS 人群生成器 // ③ SyncCrowdSpecifiedDensityRefresh(68195167) —— 在玩家周围的盒子里按密度补人 // 玩家走远(默认 35m)后重发 ③,否则走出盒子就没人了。 // 契约权威 = dump.cs `IGameSceneToClient` 接口签名,见 CrowdMethods4229938.cs 文件头。 // // // 关掉人群时的「清零」推送:把全局密度压到 0,并在玩家脚下补一个同样为 0 的刷新盒。 // ⛑️ 为什么不是「什么都不发」:客户端的 AetherCity 人群是**自驱**的 —— HasZoneGraph 一打开 // (SyncAetherAIInitDatas)它就按场景自带数据自己生成人,我们的 SyncSetCrowdDensity 只是 // override。所以「不发密度包」= 回到客户端默认密度 = 街上照样有人。要没人只能主动压 0。 // ⛑️ 不要发 RevertToNormal=true —— 那是「恢复默认密度」,效果正好相反。 // func GameRouter_Crowd_PushCrowdDisabledAsync(ctx context.Context, session *GameSession, pos Vec3, reason string) bool { // Router implementation for GameRouter_Crowd_PushCrowdDisabledAsync return true } func GameRouter_Crowd_ShouldPushCrowd(ctx context.Context, density float32) bool { // Router implementation for GameRouter_Crowd_ShouldPushCrowd return true } func GameRouter_Crowd_CrowdCfg(ctx context.Context, ) any { // Router implementation for GameRouter_Crowd_CrowdCfg var zero any; return zero } func GameRouter_Crowd_CrowdAnchor(ctx context.Context, state any) Vec3 { // Router implementation for GameRouter_Crowd_CrowdAnchor var zero Vec3; return zero } // // T0-8:把玩家脚下的地块类型与该地块的时段人流曲线合成实际密度。 // density = 全局 CrowdDensity × 地块类型系数 × max(HourlyFlow[hour], CrowdHourFloor) // 为什么不用 UrbanDiversityConfig 的 PopulationDensity / DegreeOfBusyness: // 实测 681 个地块里这两个字段几乎恒为 0(只有沙滩区有值),没有信息量。 // LandPlotType + HourlyFlow 是仅有的两个可用维度,HourlyFlow 已按各自峰值归一化到 1.0。 // func GameRouter_Crowd_ResolveCrowdDensity(ctx context.Context, state any, pos Vec3) any { // Router implementation for GameRouter_Crowd_ResolveCrowdDensity var zero any; return zero } // // 世界进入(OnLoadingFinished)时激活客户端原生人群。 // 必须在 EnsureAetherVehicleInit 之后 —— 没有 HasZoneGraph=true 客户端根本不建人群层。 // func GameRouter_Crowd_PublishAmbientCrowdAsync(ctx context.Context, rpcCtx *RpcContext) any { // Router implementation for GameRouter_Crowd_PublishAmbientCrowdAsync var zero any; return zero } // // 玩家移动时流式补人:离开上次中心超过阈值就重发一次密度刷新盒。 // 由 GameRouter.Movement.cs 的位移报告处 fire-and-forget 调用。 // func GameRouter_Crowd_CheckAndRefreshCrowdOnPlayerMoveAsync(ctx context.Context, session *GameSession, currentPos Vec3) any { // Router implementation for GameRouter_Crowd_CheckAndRefreshCrowdOnPlayerMoveAsync var zero any; return zero } // 面板 / GM 显式刷新。返回是否真的发了(被合并掉返回 false)。 func GameRouter_Crowd_RefreshAmbientCrowdAsync(ctx context.Context, session *GameSession, overrideDensity any) bool { // Router implementation for GameRouter_Crowd_RefreshAmbientCrowdAsync return true } // // 只算不推:给 GM 面板回报「玩家脚下现在会算出什么密度」。 // 面板改完参数不动也能看到这个值变化,不用真的走 35 米才知道。 // func GameRouter_Crowd_ProbeCrowdDensity(ctx context.Context, session *GameSession) any { // Router implementation for GameRouter_Crowd_ProbeCrowdDensity var zero any; return zero }