package routers import ( "context" "sync" ) var _ = sync.Mutex{} var _ = context.Background // // World props WITHOUT the AnantaGadgetLoader exe — the server-side half of what that tool does // by frida injection. // The loader calls GadgetMgr.SyncGadgetGridAOIAddByIndex(cx, cz, exceptIds, sectorIds, // gridIndex) inside the client process; the props themselves come from the client's own // GadgetBlob, so nothing has to be authored server-side. The wire equivalent is // SyncGadgetGridAOIDecrease(68956797) — the only grid-AOI method id that exists, and it // carries both directions (add cells in addGridInfo, remove in removeGridInfo). // ⛔ CORRECTED 2026-09-27 (user live-tested; the previous wording here was wrong twice): // · The old line said "Donor server proved this end to end (HANDOFF round 12)". NO donor // ever said that. HANDOFF-2026-09-19.md:2598 "ROUND 12 VERDICT" is OUR OWN round, // user-tested 2026-09-20. The HANDOFF docs mix donor material with our own round log — // round 12/13/15D/15F/15G/15H/16E/16I are all ours (they carry "user-tested" / "TEST NOW"). // · "appeared AND stayed interactive" is also wrong as written. Appearing and being // interactable are TWO INDEPENDENT things on this channel: // - 68956797 only materializes props out of the client's own GadgetBlob, and only for // cells+sectors we actually push => only a PART of the world ever appears. // - interactability is decided SOLELY by how the server answers the Ask* device RPCs // (see GameRouter.SceneDevices.cs: an Ask* INVOKE is only a REQUEST; the client's // device-state manager waits for the server to echo the transition before it runs any // presentation). No reply shape => no interaction, injector or not. // HANDOFF-2026-09-18.md:341 (ROUND 15H) pinned the ONE session where vending + outfits + // signs + elevators ALL worked at once — Sep 20 01:32 (packets-20260920-012232.log) — and // that session's wire was an 8-byte struct {int CheckIndex; uint Error}, silent, ALL // devices. Cross-era census (user-verified): 012232 = 8b struct silent -> all families OK; // 021225 = 6b blob silent -> vending STUCK (retry storm); r13-15F = 10b + echoes -> // vending OK but menu prompts DISARM. // · So "no injection needed" means "no frida injector needed to MATERIALIZE", NOT // "the server can sit idle and still get interactions". // Two rules the loader's author established and we keep: // · sector pairing matters — one message carries ONE sector list, so cells are grouped // by identical sector list (sectorIdList=[0] is outdoor only; interior furniture lives // in hashed sectors from GadgetCells.json); // · never spam — a cell is pushed once and re-pushed only on a cell crossing or the // periodic refresh. The loader's own note warns that hammering the grid channel kills it. // // // ★ donor《content-streaming-implementation》§3 的窗口差分(2026-10-01 落地)。 // prevLoaded = 客户端当前持有的格子;window = 本轮要展示的正方形窗口。 // // added = window − prevLoaded // 新格子 → 见到才加载 // keep = prevLoaded 里仍落在卸载边界内(Chebyshev ≤ unloadRadius)的那些(保留环) // removed = prevLoaded − keep // 真·出界 → 显式下发卸载 // next = window ∪ keep // 成为新的 prevLoaded // // ⛑ retainVisitedCells=false ⇒ 没有保留环,出窗口即卸载(等价于 unload = radius)。 // ⛑ 窗口与卸载边界都用 Chebyshev(正方形),与 §2 的 (2r+1)² 定义一致,别改用曼哈顿。 // func GameRouter_GadgetGrid_ComputeGridWindowDiff(ctx context.Context, prevLoaded []any, window []any, cx int32, cz int32, unloadRadius int32, retainVisited bool, added []any, removed []any, next []any) any { // Router implementation for GameRouter_GadgetGrid_ComputeGridWindowDiff var zero any; return zero } // // ★ donor《content-streaming-implementation》§1 —— 传送 / 远跳时两个窗口根本不相交 // ⇒ 必须 Init 全 re-seed(清空声明过的格子),不能只补差集。 // 2026-10-01 起用它解决「owner.Sent 只增不减」这一条:以前每次远跳都会留下一份 // 玩家已经离开的格子,永远不会消失,把卸载这件事全推给客户端自己去猜。 // ⛑ 判据 = 格子 Chebyshev 距离 > unloadRadius(窗口不相交,donor §3 原文)。 // func GameRouter_GadgetGrid_IsFarGridJump(ctx context.Context, fromX int32, fromZ int32, toX int32, toZ int32, unloadRadius int32) bool { // Router implementation for GameRouter_GadgetGrid_IsFarGridJump return true } func GameRouter_GadgetGrid_GadgetGridStateOf(ctx context.Context, session *GameSession) any { // Router implementation for GameRouter_GadgetGrid_GadgetGridStateOf var zero any; return zero } // World-ready hook: start the grid stream. Idempotent; no-op when disabled. func GameRouter_GadgetGrid_EnsureGadgetGrid(ctx context.Context, session *GameSession) any { // Router implementation for GameRouter_GadgetGrid_EnsureGadgetGrid var zero any; return zero } // Disconnect / scene switch: stop the loop. Props already out stay out. func GameRouter_GadgetGrid_StopGadgetGrid(ctx context.Context, session *GameSession) any { // Router implementation for GameRouter_GadgetGrid_StopGadgetGrid var zero any; return zero } // Cells handed to the client so far. Panel/debug display only. func GameRouter_GadgetGrid_GadgetGridSentCount(ctx context.Context, session *GameSession) int32 { // Router implementation for GameRouter_GadgetGrid_GadgetGridSentCount return 0 } func GameRouter_GadgetGrid_RunGadgetGridLoopAsync(ctx context.Context, session *GameSession, owner any, token context.Context) any { // Router implementation for GameRouter_GadgetGrid_RunGadgetGridLoopAsync var zero any; return zero } func GameRouter_GadgetGrid_TickGadgetGridAsync(ctx context.Context, session *GameSession, owner any) any { // Router implementation for GameRouter_GadgetGrid_TickGadgetGridAsync var zero any; return zero } // // Push every not-yet-sent cell around (cx,cz), grouped by sector list, one message per group. // Returns how many cells went out. // ★ 2026-10-01 重写为 donor《content-streaming-implementation》§3 的 add/keep/remove 三元组: // 以前只算 added(差额补发),removeGridInfo 恒为空 ⇒ 走过的格子永远被声明、 // 客户端永不卸载(这正是 2026-09-27 §10.9.3 内存项第 3 条)。现在走出 // unloadRadiusCells 边界的格子会被显式下发卸载。 // func GameRouter_GadgetGrid_PushGadgetGridAsync(ctx context.Context, session *GameSession, owner any, cx int32, cz int32, reason byte, fullResend bool) int32 { // Router implementation for GameRouter_GadgetGrid_PushGadgetGridAsync return 0 } // // ★ donor《content-streaming-implementation》§4 —— 显式的「请卸载这批格子」。 // 单独一条 68956797:addGridInfo 空表、removeGridInfo 装出界的格子。 // ⛑ BuildingId 必须写 int32(值 0)—— donor §6 第 2 条:漏写会让整条 payload 错位。 // ⛑ sector 仍然要带:一条报文一个 sector 列表,和加载侧同律分组。 // func GameRouter_GadgetGrid_PushGadgetGridRemovalAsync(ctx context.Context, session *GameSession, removed []any, cx int32, cz int32, reason byte) any { // Router implementation for GameRouter_GadgetGrid_PushGadgetGridRemovalAsync var zero any; return zero } type GadgetGridSessionState struct { SyncRoot any `json:"syncRoot"` Cts *context.CancelFunc `json:"cts"` Loop *any `json:"loop"` // Cells already handed to the client. A cell is re-sent only on refresh. Sent []any `json:"sent"` LastCellX int32 `json:"lastCellX"` LastCellZ int32 `json:"lastCellZ"` HasCell bool `json:"hasCell"` LoadedSent bool `json:"loadedSent"` // // Scene AOI switch (68418115) already pushed for this session. Research lever only — // gated by SceneAoiSwitchEnabled, which defaults to false. // SceneAoiSwitchSent bool `json:"sceneAoiSwitchSent"` LastPushMs int64 `json:"lastPushMs"` ReadyAtMs int64 `json:"readyAtMs"` Pushes int32 `json:"pushes"` CellsSent int32 `json:"cellsSent"` // 首次成功整窗推送的时刻(Environment.TickCount64)。入世界守卫的计时基准。 FirstPushMs int64 `json:"firstPushMs"` // // ★ 2026-10-04「入世界守卫」是否已经做过。每会话只做一次; // 远跳 reseed(ReseedOnFarJump)已经替我们清过窗时也算完成,避免重复砸卸载报文。 // SettleDone bool `json:"settleDone"` }