128 lines
6.4 KiB
Go
128 lines
6.4 KiB
Go
package routers
|
|
|
|
import (
|
|
"context"
|
|
"sync"
|
|
)
|
|
|
|
var _ = sync.Mutex{}
|
|
var _ = context.Background
|
|
|
|
//
|
|
// Doors as gadgets — T2-11, ported from the donor's proven rounds 16C-16I.
|
|
// Doors are PLAIN GADGETS carrying a DoorModuleSyncInfo module ("USER MODEL ADOPTED:
|
|
// DOORS ARE GADGETS", HANDOFF-2026-09-18 round 16I-7). The client reports crossings with
|
|
// AskPlayerEnterOrLeaveDoor(63525373) = (ulong gadgetId, bool isEnter), dump.cs:1893406.
|
|
// ⛔ WIRE KIND: the client sends this as a NOTIFY, not an invoke — packets log shows
|
|
// "C2S NOTIFY AskPlayerEnterOrLeaveDoor [0x03C951FD] body=9b". Registered Invoke-only it never
|
|
// matched and every frame fell to DefaultUnknownNotify4229938, so nothing was ever logged.
|
|
// Registration is Both and only invokes get a reply (a notify has no callback).
|
|
// There is NO dedicated door RPC: a census of all 2754 UXRPCMethodArgs classes in the client
|
|
// found zero door-proximity args classes (round 16C). The state travels inside
|
|
// GadgetEntityInfo.DoorModuleInfo and arrives through SyncGadgetRefresh(68765074), which the
|
|
// client applies in OnSyncDoorInfo. The chain is BaseDoorProxy.TriggerEnter ->
|
|
// DoorMgr.SyncDoorProximityState -> DoorModuleSyncInfo{LockState, ProximityState,
|
|
// ProximityStartTime, ClientInfos}.
|
|
// ⚠ Two door classes, do not confuse them (donor round 16I-10):
|
|
// · venue / high-layer doors whose approach makes the client's own bundled
|
|
// sector_high_indoor_<id>_0 binary fail to deserialize — no server fix exists;
|
|
// · ordinary gadget doors, which this file drives. The gym (Hypercore) and Sonic Boom doors
|
|
// were in the SECOND class and opened live in round 16H.
|
|
//
|
|
// AskPlayerEnterOrLeaveDoor(63525373) — u64 gadgetId + u8 isEnter.
|
|
// ⛔ NOTIFY on the wire, never invoke — see the class note for the evidence.
|
|
func GameRouter_Door_OnAskPlayerEnterOrLeaveDoor(ctx context.Context, conn any, msg any) any {
|
|
// Router implementation for GameRouter_Door_OnAskPlayerEnterOrLeaveDoor
|
|
var zero any; return zero
|
|
}
|
|
|
|
// ---- the official channel -------------------------------------------------------------
|
|
// Three dedicated door S2Cs exist and the client really implements them (GameSceneToClient
|
|
// overrides at RVA 0x127D4500 / 0x127D4690 / 0x127D4840 — a stub would be 0x9148360). The
|
|
// donor's round 16C census missed them because bare-scalar methods own no args class.
|
|
// Semantics are the client's own enums: DoorLockState{Unlocked=0, Locked=1},
|
|
// DoorProximityState{NoPlayer=0, HasPlayer=1}.
|
|
// Announce "somebody is at this door": unlock, HasPlayer, and swing the leaf.
|
|
func GameRouter_Door_PushDoorOpen(ctx context.Context, session *GameSession, gadgetId uint64) any {
|
|
// Router implementation for GameRouter_Door_PushDoorOpen
|
|
var zero any; return zero
|
|
}
|
|
|
|
// Announce "nobody is here any more" — the leaf slides back to 0 degrees.
|
|
func GameRouter_Door_PushDoorShut(ctx context.Context, session *GameSession, gadgetId uint64) any {
|
|
// Router implementation for GameRouter_Door_PushDoorShut
|
|
var zero any; return zero
|
|
}
|
|
|
|
func GameRouter_Door_Push(ctx context.Context, session *GameSession, methodId uint32, args any, what string) any {
|
|
// Router implementation for GameRouter_Door_Push
|
|
var zero any; return zero
|
|
}
|
|
|
|
//
|
|
// Legacy path: restate the door through SyncGadgetRefresh(68765074) with DoorModuleSyncInfo.
|
|
// Body size is the acceptance proof: donor round 16H measured 8 presses -> 8x 130b refreshes
|
|
// -> ZERO `deserialize failed methodId=68765074`, and the gym / Sonic Boom doors opened.
|
|
// ⛑️ Round 16I-4/5 then proved the 130b shape is what made the leaf VANISH on approach:
|
|
// an empty ClientInfos means "no leaf record", so the panel hides the leaf when the module
|
|
// is applied. Carrying one OpenAngle takes the body to 135b (donor's byte-exact size) and
|
|
// gives the panel something to swing. Every other collection stays EMPTY rather than null,
|
|
// which is what makes the arithmetic land on those numbers.
|
|
// Placement is frozen per gadget on first push (see DoorPlacementsOf): Pack carries a real
|
|
// position the client applies to the entity, so re-sending a different/player-tracked
|
|
// position drags the door around (or to zero) instead of leaving it where it belongs.
|
|
//
|
|
func GameRouter_Door_PushDoorProximity(ctx context.Context, session *GameSession, gadgetId uint64, proximityState byte, openAngle float32) any {
|
|
// Router implementation for GameRouter_Door_PushDoorProximity
|
|
var zero any; return zero
|
|
}
|
|
|
|
func GameRouter_Door_DoorPlacementsOf(ctx context.Context, session *GameSession) map[string]any {
|
|
// Router implementation for GameRouter_Door_DoorPlacementsOf
|
|
return nil
|
|
}
|
|
|
|
// ---- auto-close ----------------------------------------------------------------------
|
|
// Donor round 16I-4/5: the client emits ENTER far more often than LEAVE (one session logged
|
|
// 3 ENTER / 0 LEAVE), and it never restates the module by itself, so a door opened by the
|
|
// server stayed open forever / vanished on leave. Cancel the pending timer on any new event
|
|
// for the same door so only the last one survives.
|
|
func GameRouter_Door_DoorTimersOf(ctx context.Context, session *GameSession) map[string]any {
|
|
// Router implementation for GameRouter_Door_DoorTimersOf
|
|
return nil
|
|
}
|
|
|
|
func GameRouter_Door_ArmDoorAutoClose(ctx context.Context, session *GameSession, gadgetId uint64) any {
|
|
// Router implementation for GameRouter_Door_ArmDoorAutoClose
|
|
var zero any; return zero
|
|
}
|
|
|
|
func GameRouter_Door_CancelDoorAutoClose(ctx context.Context, session *GameSession, gadgetId uint64) any {
|
|
// Router implementation for GameRouter_Door_CancelDoorAutoClose
|
|
var zero any; return zero
|
|
}
|
|
|
|
func GameRouter_Door_CacheGarageDoor(ctx context.Context, session *GameSession, gadgetId uint64) any {
|
|
// Router implementation for GameRouter_Door_CacheGarageDoor
|
|
var zero any; return zero
|
|
}
|
|
|
|
// 出库时把本会话记住的车库门推开。没有缓存(玩家没走过门)就只记一条日志。
|
|
func GameRouter_Door_OpenCachedGarageDoor(ctx context.Context, conn any) any {
|
|
// Router implementation for GameRouter_Door_OpenCachedGarageDoor
|
|
var zero any; return zero
|
|
}
|
|
|
|
//
|
|
// Where this session last said a door stands. GadgetEntityInfo.Pack is authoritative on the
|
|
// client side, so once we have declared a placement we must keep declaring the same one:
|
|
// a drifting value makes the leaf jump to the player instead of sitting in its frame.
|
|
//
|
|
type DoorPlacement struct {
|
|
X float32 `json:"x"`
|
|
Y float32 `json:"y"`
|
|
Z float32 `json:"z"`
|
|
Facing float32 `json:"facing"`
|
|
}
|
|
|