package routers import ( "context" "sync" ) var _ = sync.Mutex{} var _ = context.Background // Runtime player/combat hydration shared by world entry and character switching. func GameRouter_Profiles_PublishSkillBindings(ctx context.Context, rpcCtx *RpcContext, unitId uint64, weapon any, style any) any { // Router implementation for GameRouter_Profiles_PublishSkillBindings var zero any; return zero } func GameRouter_Profiles_PublishCombatResources(ctx context.Context, rpcCtx *RpcContext, unitId uint64) any { // Router implementation for GameRouter_Profiles_PublishCombatResources var zero any; return zero } func GameRouter_Profiles_SpiritFightStyleOverrides(ctx context.Context, state any, templateId uint32) []any { // Router implementation for GameRouter_Profiles_SpiritFightStyleOverrides return nil } // // Weapon one character should hold: the instance this account last equipped (replayed from the // progress snapshot by RestoreCombatLoadout4229938) when it still resolves in the catalog, // otherwise the authored default. // func GameRouter_Profiles_ResolveEquippedWeapon(ctx context.Context, state any, templateId uint32) any { // Router implementation for GameRouter_Profiles_ResolveEquippedWeapon var zero any; return zero } func GameRouter_Profiles_PublishedWeaponFightStyleId(ctx context.Context, state any, weapon any) uint32 { // Router implementation for GameRouter_Profiles_PublishedWeaponFightStyleId return 0 } func GameRouter_Profiles_PublishMinimalActorPresentation4229938(ctx context.Context, rpcCtx *RpcContext, unitId uint64, templateId uint32, reason string) any { // Router implementation for GameRouter_Profiles_PublishMinimalActorPresentation4229938 var zero any; return zero } func GameRouter_Profiles_PublishWeaponSnapshot(ctx context.Context, rpcCtx *RpcContext, unitId uint64, templateId uint32, currentWeaponInstanceId uint64) any { // Router implementation for GameRouter_Profiles_PublishWeaponSnapshot var zero any; return zero } func GameRouter_Profiles_PublishSafeRuntimeBuffSnapshot4229938(ctx context.Context, rpcCtx *RpcContext, unitId uint64, templateId uint32, phase string) any { // Router implementation for GameRouter_Profiles_PublishSafeRuntimeBuffSnapshot4229938 var zero any; return zero } // gameplay.hackerAbilitySet == "full" (the default). Anything else = safe baseline. func GameRouter_Profiles_FullHackerKitEnabled(ctx context.Context, ) bool { // Router implementation for GameRouter_Profiles_FullHackerKitEnabled return true } // // gameplay.jobBadgeBuffs == "auto" (the default). Publish the capability buffs carried by // every UrbanBadgeConfig row keyed to a career the character owns, instead of relying on // per-spirit hard-coding. "off" restores the old shape exactly. // func GameRouter_Profiles_JobBadgeBuffsEnabled(ctx context.Context, ) bool { // Router implementation for GameRouter_Profiles_JobBadgeBuffsEnabled return true } // // Publishes the EonBug app's data backbone: SyncHackerJobInfo (64189208) — // BBS handle + the full HackerPostConfig post list + rank + daily counters. Without this // packet the app opens with rank "#-" and an empty forum (HackManager.HackerJobInfo stays // nil) — exactly what the 7k donor ships, which is why its forum could never open. // DTO path (wire re-verified against the lua reader, 2026-09-20): single class parameter, // so the frame is [0xFF][fields] — same family as the battery packet. Reader[282] = // HackerName -> PostInfos(ReadDict, raw Int32 count) -> Rank -> DailyCounts(Reader[852]: // Money/Fan/Tetris). The old hand-written codec wrote 0x00 markers (SerializeObjectMarkNull // = 0 — read as null) and omitted DailyCounts entirely. // func GameRouter_Profiles_PublishHackerJobRuntime4229938(ctx context.Context, rpcCtx *RpcContext, templateId uint32, phase string, handleOverride any) any { // Router implementation for GameRouter_Profiles_PublishHackerJobRuntime4229938 var zero any; return zero } // // 层 2a — publishes the police phone app's data backbone: SyncSpiritPoliceJobInfo // (64349458), i.e. spiritId plus the whole SpiritPoliceJobInfo (duty counters, dispatch // slots, live violations, case records, fake-file archive). // Client path: GameToClientImpl.SyncSpiritPoliceJobInfo -> // gPoliceJobManager.panelMgr:OnSpiritPoliceJobInfoSync (PolicePanelManager.lua:156), // which indexes serviceData / weeklyServiceData / violationInfo / dispatchInfo / fakeFileInfo / // caseInfo by spiritId and then dereferences DutyBasicInfo.ServiceData with no nil check. // So the payload must exist and every complex field inside it must be non-nil, but the // collections may legitimately be empty. // ⛑️ There is no C2S "give me my police state" request — the whole SyncPolice* family is // server-push, and this full snapshot is the one the panel treats as authoritative // (SyncPoliceServiceData 64502222, SyncPoliceDispatchInfos 64393704, // SyncSpiritPoliceViolationInfos 64812240 and SyncSpiritPoliceCaseInfos 64848107 are the // incremental updates). // Data-driven on the career class (UrbanJobJobClassConfig 11300003 "NCCA Officer"), so any // character published with job 301/302/303 gets it — Richie (15021021) is the authored one. // T4-9: the payload is no longer a set of empty containers. fills the dispatch chips, a small // fabricated case history and the homepage tally out of real tables (PoliceDispatchConfig / // PoliceFineConfig / AgentConfig / PoliceConfig.static), which is what makes the Duty Terminal // render content instead of a blank panel. Violations and the Mimic Database archive stay empty // on purpose — see that method for why. // func GameRouter_Profiles_PublishPoliceJobRuntime4229938(ctx context.Context, rpcCtx *RpcContext, templateId uint32, phase string) any { // Router implementation for GameRouter_Profiles_PublishPoliceJobRuntime4229938 var zero any; return zero } // // Republish the combat profile after a direct character switch. // PublishCombatProfile is one-shot per world entry (its // CombatProfilePublished gate exists so the deferred first-movement hydration cannot // run twice), but every character owns a different skill set and the client learns the unique // skill only from that profile. Clear the gate and run it again for the new character. // func GameRouter_Profiles_PublishCombatProfileOnSwitch4229938(ctx context.Context, rpcCtx *RpcContext, unitId uint64, templateId uint32) any { // Router implementation for GameRouter_Profiles_PublishCombatProfileOnSwitch4229938 var zero any; return zero } // // Publishes the character's authored urban job from FightSpiritConfig.DefaultUrbanJob // so the client's job → badge → capability chain resolves on its own. Data-driven on purpose: // every character with an authored job gets its record, not just Seymour (the donor build // hard-codes three spirit ids, and gets one of them wrong). // Only 8 of the 109 playable characters carry a job today; the rest are Jobless and are skipped // — which is exactly the point: under the default UrbanJobGrantMode = "single" the // career-locked phone apps stay character-exclusive (Seymour/赛默迪斯科球人 → EonBug, // Richie → Duty Terminal + Mimic Database, Cheng Niang → 重霄食谱). Switch the config to // "multi" to blanket-unlock all 9 apps on every character, or list template ids under // UrbanJobOverrides to hand one specific character a career it was not authored with. // func GameRouter_Profiles_PublishSpiritJobRuntime4229938(ctx context.Context, rpcCtx *RpcContext, templateId uint32, phase string) any { // Router implementation for GameRouter_Profiles_PublishSpiritJobRuntime4229938 var zero any; return zero } // // Publishes the six-point hacker battery for characters whose authored job is Hacker(401). // This is the missing half of the hacking kit on our side: HackerHackTypeConfig (48 rows) // prices every hack in battery points, so with no battery the client greys out the middle-mouse // hack verb and never emits AskHack — which in turn is the only other place we used to // send the battery, so it could never recover on its own. The donor build publishes it from the // buff snapshot path for exactly this reason. // Data-driven on the same UrbanJobOf lookup as the capability buffs, so any character // authored as job 401 gets it without touching a spirit id. // func GameRouter_Profiles_PublishHackerBatteryRuntime4229938(ctx context.Context, rpcCtx *RpcContext, templateId uint32, phase string) any { // Router implementation for GameRouter_Profiles_PublishHackerBatteryRuntime4229938 var zero any; return zero } func GameRouter_Profiles_PublishInitialCapabilityBuffs(ctx context.Context, rpcCtx *RpcContext) any { // Router implementation for GameRouter_Profiles_PublishInitialCapabilityBuffs var zero any; return zero } // // 主角原生飞索能力门 —— SyncPaokuLimitChange(68974941) + AbilityLimitConfig 3013。 // ★ 为什么要这一条(2026-09-26 调研,证据全在我们自己的 dump.cs): // · AbilityLimitConfig.HasFeisuoAbility = 3013(dump.cs:1026235), // 挂的 GamePlayTag 是 State_HasFeisuoAbility = 2318(dump.cs:1226889); // 该配置行还带 ButtonEnum[](C 键)与 QueryId(有效目标查询) // ⇒ 它是能力开关,不是「限制」。 // · 消费方 PlayerParkourLimitModule(dump.cs:585090-585135)的 // SetParkourLimitConfigState(uint limitId, bool isAdd) → SetGamePlayTagState。 // · 飞索 buff 一直在发,但本服所有日志里 feisuo 命中恒为 0 ⇒ 客户端 // 从来没进过飞索蹲伏态(AskEnterFeiSuoCrouch 一次都没发过)⇒ C 键没反应、没有白圈。 // ⛑⛑ unitId 必须是当前实际控制单位:切人后是新的那个。 // 上面 PublishInitialCapabilityBuffs 用的是 Profile.InitialUnitId(固定初始单位), // 这里不能跟着写死 —— 否则切一次人门就挂在旧身体上(与规则 177 同源的坑)。 // ⛑ 白圈不用我们画:客户端 LX6.PaoKu.FeiSuoJobManager(dump.cs:242164) // 每帧在本地扫静态/动态飞索点,门一开白圈自己出现。别去画假准星、别把任意墙面改成可飞跃点。 // ⛑ 回滚:gameplay.webTraversal.pushFeisuoAbilityGate = false。 // ⛑⛑ 2026-09-26 17:5x 补发暗杀门 5051:飞索门 3013 只解决「蹲得下去」, // 暗杀检测由另一行 AbilityLimitConfig.UnlockAssassin = 5051 // (dump.cs:1026213 → State_UnlockAssassin = 1333,dump.cs:1226857)门控。 // 实机证据:只发 3013 时 AskEnterFeiSuoCrouch 命中 19 次、 // ReportCanAssassinateEnemies 命中 0 次 ⇒ 光补裁决回包没用,门必须先开。 // 两张门同表同构,走同一个 SyncPaokuLimitChange 的 limitIds 列表。 // func GameRouter_Profiles_PublishProtagonistGrapnelGate4229938(ctx context.Context, rpcCtx *RpcContext, unitId uint64, templateId uint32) any { // Router implementation for GameRouter_Profiles_PublishProtagonistGrapnelGate4229938 var zero any; return zero } // // 角色专属能力门 —— 同一条 SyncPaokuLimitChange(68974941),一次可发多张 // AbilityLimitConfig.Id(gameplay.webTraversal.spiritAbilityGates)。 // 当前配置:15021040 璎珑 → 3040「虐杀原形跑酷」(ParkourState 10062,动作分支含地面 // 疾跑 574 / 跳跃 575 / 边缘 577 / 爬墙 2502·2503,所以平地按空格与 shift 都该有反应); // 15020990 → 5040 连跳 + 5052 大跳。 // ★ 为什么不塞进 PublishProtagonistGrapnelGate4229938:那张方法有 // IsProtagonist 闸,会把所有非主角挡在门外;而这张门只该给璎珑一个人 —— // 其余角色的 ABP 未必带 MovementModeType.Yinglong(10) 的动画数据, // 挂上 tag 也可能没表现(甚至动作异常)。 // ⛑ 挂在 PublishCombatProfile 尾部 ⇒ 首次进入与切角色两条路径都覆盖 // (PublishCombatProfileOnSwitch4229938 先清一次性闸再跑一遍本方法, // 此时 unitId/templateId 已经是新的控制单位)。 // ⛑ 切离璎珑时不补发 isAdd=false 摘门:切角色即换 unit,门是 // PlayerParkourLimitModule(unit module)上的状态,新单位本来就不带, // 补一包只会是 no-op。真要摘就把开关关掉重进。 // ⛑ 回滚:gameplay.webTraversal.pushKillingAbilityGate = false。 // func GameRouter_Profiles_PublishSpiritKillingGate4229938(ctx context.Context, rpcCtx *RpcContext, unitId uint64, templateId uint32) any { // Router implementation for GameRouter_Profiles_PublishSpiritKillingGate4229938 var zero any; return zero } // // One-shot combat profile per world entry: HP/attrs/urban/fight-style unlocks, // skill charges, resources, battle module, weapon snapshot, skill bindings. // Until this runs, OnClientUseSkill rejects skill requests (CombatProfilePublished). // Runs on first gameplay movement (deferred hydration), mirroring the reference build. // func GameRouter_Profiles_PublishCombatProfile(ctx context.Context, rpcCtx *RpcContext, unitId uint64, templateId uint32) any { // Router implementation for GameRouter_Profiles_PublishCombatProfile var zero any; return zero }