package routers import ( "context" "sync" ) var _ = sync.Mutex{} var _ = context.Background // // Weapon drop / pick-up recovery. // Retail drops a weapon by creating a real Destructible in the world and handing its id to the // client: SyncDisarmCreateWeaponDestructible (68141963) spawns it and AskPickUpWeapon (67264037) // takes a destructibleId, not a weapon id. This server has never sent either, and the client // never asks for one — a packet capture of a full drop + long-press-Q cycle contains zero // AskDiscardWeapon*/AskPickUpWeapon calls, and every AskInteractCmd carries only CmdType 19/33/34 // (SyncWeaponFBBIK / Request-SyncGameplayTagMask per NetcodeCommandUtils.NetCodeCmdType), so the // whole drop is client-local and the server has no way to learn that it happened. // What that leaves behind is a client weapon state machine with nothing to finish against: the // long-press-Q absorb never resolves, the unit stays in its root-motion absorb loop and slides // backwards until the player switches character (which rebuilds WeaponManager and clears it). // ResetWeaponStateAsync is the server-side equivalent of that rebuild, and the admin // panel exposes it as 「解除卡死」. See TOPIC notes / 2026-09-19.md §72 for the packet evidence. // // // Client invoke: AskSkillDestructibleCreate — the drop. // This is the packet the client sends when a weapon leaves the hand, and it is answered with // the new Destructible's id. Everything afterwards (long-press-Q psychokinesis, the pick-up // prompt, AskPickUpWeapon) addresses the drop by that id, so answering 0 left the client // talking to nothing: absorb animation with no exit (backwards slide), a Q prompt that never // clears, and a weapon that returns to the hand only to fall straight back out. // func GameRouter_WeaponDrop_OnSkillDestructibleCreate(ctx context.Context, conn any, msg any) any { // Router implementation for GameRouter_WeaponDrop_OnSkillDestructibleCreate var zero any; return zero } // // Client invoke: AskPickUpWeapon (67264037) — the absorb finished, take it back. // Answer with retail's own remove/add pair plus the weapon profile, and nothing else. The // client drives the absorb itself; this server has to converge its own state (put the weapon // back into the slot it was dropped from, make it current) and hand back a weapon the client // can actually use, without rebuilding the weapon manager underneath a running animation. // func GameRouter_WeaponDrop_OnPickUpWeapon(ctx context.Context, conn any, msg any) any { // Router implementation for GameRouter_WeaponDrop_OnPickUpWeapon var zero any; return zero } // // Break whatever action the unit is stuck in and re-publish the authoritative weapon state. // Order matters: SyncBreakSkill first, then the snapshot, then the selection packets — the same // sequence OnSwitchWeapon uses, minus the slot mutation. // func GameRouter_WeaponDrop_ResetWeaponStateAsync(ctx context.Context, session *GameSession) any { // Router implementation for GameRouter_WeaponDrop_ResetWeaponStateAsync var zero any; return zero }