This repository has been archived on 2026-10-31. You can view files and clone it. You cannot open issues or pull requests or push a commit.
Files

161 lines
8.4 KiB
Go
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
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 = 本轮要展示的正方形窗口。
// <code>
// added = window − prevLoaded // 新格子 → 见到才加载
// keep = prevLoaded 里仍落在卸载边界内(Chebyshev ≤ unloadRadius)的那些(保留环)
// removed = prevLoaded − keep // 真·出界 → 显式下发卸载
// next = window ∪ keep // 成为新的 prevLoaded
// </code>
// ⛑ 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 距离 &gt; 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"`
}