Files

91 lines
6.1 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 methods
//
// GameGround zone payloads — the party/minigame framework (darts / bowling / BBQ / ChineseChess /
// Racing / …) that vehicles racing is a *zone* of, not a standalone feature (§59).
// Only the Racing branch is modelled here, because that is the only zone the server currently
// needs to PUSH (SyncGameGroundZoneInfo 68004609) for the Route-A race-start experiment.
// ─────────────────────────────── WIRE FACTS (verified, do not "tidy" the order) ───────────────
// Source of truth = the client's own serializer, RPCSerializeAuto.lua
// (function Auto.WriteRacingZoneInfo, line 7474). Field order is copied from it verbatim.
// ⇒ The payload is a COMPLEX (non-Inline) contract, so [UxContract(TypeMark = 15)] makes
// UxSerializer emit a leading **0x0F (15)** discriminator byte in front of the fields.
// The client's polymorphic dispatch table for the zone method (68004609) then routes 0x0F to
// its RacingZoneInfo reader. Getting this byte wrong does not throw — the client silently reads
// the zone as a plain base zone and nothing happens.
// ⇒ Field ORDER is Racing-declared-first, then base — the OPPOSITE of C# inheritance layout
// (dump.cs shows CfgId at 0x50, i.e. after the base fields, but the wire is generated from the
// lua writer, which emits CfgId first). Therefore this contract MUST stay FLAT: do not refactor
// it into a base class, because UxSerializer orders fields by metadata token, which
// would put the base fields first and shift every byte.
// ⛔ CORRECTION (R203, 2026-09-30): earlier revisions of this header cited
// Auto.Dispatch[449] / Concrete[449][15] = Auto.Reader[1403] and
// Auto.Dispatch[476] for ParticipantInfos. Those indices are WRONG — Auto.Reader[476]
// is the mahjong-hand reader and Auto.Reader[1403] is an unrelated vehicle-target struct.
// Do not trust a reader/dispatch index unless the client Lua function it names actually reads the
// fields you expect. ParticipantInfos element shape is now settled by byte-level proof against
// the client's own writer — see _gomoku_uxcheck R1–R6.
// Order reference: Drmk.Proxy/proxy/lua/RPCSerializeAuto.lua Auto.WriteRacingZoneInfo (line 7474).
//
//
// GameGroundZoneCountDownInfo — Auto.Reader[482].
// Framed as a STRUCT (Base.WriteStruct): **no 0xFF marker**, just 4 × uint32.
//
//
// RacingResultData — Auto.Reader[450], one entry per finished participant.
// Complex framing (the client reads it through Base.ReadComplex), so each item carries the
// default 0xFF marker. Field order copied from Auto.WriteRacingResultData.
//
//
// GameGroundParticipantInfo — the element type of RacingZoneInfo.ParticipantInfos. The client's
// own Auto.WriteRacingZoneInfo writes each element via
// Base.WriteComplexWrap(Auto.WriteGameGroundParticipantInfo, "GameGroundParticipantInfo", true),
// which puts a 0xFF present marker in front of the fields (this type is flat, so 0xFF is what
// UxContract emits by default — no TypeMark needed).
// Wire order (verified against Auto.WriteGameGroundParticipantInfo, RPCSerializeAuto.lua:3984):
// Pid → NpcCultivationId → AIAgentInfo (nullable complex) → AgentInstanceId →
// VehicleInstanceId → SeatIndex → IsReady → IsPlayAgain.
// AIAgentInfo carries the AI opponent's identity so the client can spawn + nameplate AI cars.
// It is nullable: a null value serialises as a single presence byte (0), which is exactly what the
// empty grid produced before the AI grid was wired in. The grid itself is built by
// GameRouter.BuildRacingAiGrid (RacingZoneProbe.cs).
//
//
// LinkAIAgentInfo — AI opponent identity, nested (nullable) inside GameGroundParticipantInfo.
// Wire order verified against Auto.WriteLinkAIAgentInfo (RPCSerializeAuto.lua:5454):
// Uid → FightSpiritId → Fashion(nullable LinkAIFashionInfo) → Nickname(nullable string) →
// NameId → AvatarImageId → VehicleId.
// Fashion is sent null from the server (presence byte 0) — that skips the deep
// OtherPlayerSpiritWearFashionsInfo.WearInfo graph entirely and is still enough for the client
// to spawn + drive the AI car. WearInfo (in LinkAIFashionInfo) therefore only exists to satisfy
// the contract graph and reuses the auto-generated OtherPlayerSpiritWearFashionsInfo (the
// wire-flattened, authoritative form).
//
//
// LinkAIFashionInfo — nested (nullable) inside LinkAIAgentInfo. The client only reads it when
// Fashion is non-null, which the server never sends, so WearInfo here exists solely to
// keep the contract graph resolvable. Type reuses Auto.OtherPlayerSpiritWearFashionsInfo.
// Wire order: SuitId → WearInfo(nullable Auto.OtherPlayerSpiritWearFashionsInfo).
//
//
// RacingParticipantInfo — the Racing-specific SUBTYPE of GameGroundParticipantInfo.
// ⛔ NOT used by RacingZoneInfo.ParticipantInfos. The client's own zone writer
// (Auto.WriteRacingZoneInfo, RPCSerializeAuto.lua:7474) types the list elements as the BASE
// GameGroundParticipantInfo via Base.WriteComplexWrap(Auto.WriteGameGroundParticipantInfo, …),
// i.e. each element is 0xFF + 8 base fields, with NO TypeMark. Putting this subtype in that
// list emitted 0x0E + 13 fields per element and desynced the packet (R203).
// This class is kept only because Auto.WriteRacingParticipantInfo exists in the client's
// serializer; do not wire it into the zone payload.
// ⚠️ Also note the field list below does NOT match Auto.WriteRacingParticipantInfo: the client
// writer has 12 fields (AiVehicleCfgId → CheckPointIndex → Lap → RacingTotalTimeMilli → Pid →
// NpcCultivationId → AIAgentInfo → AgentInstanceId → VehicleInstanceId → SeatIndex → IsReady →
// IsPlayAgain) and has no CurrentVehicleInstanceId; this contract has 13. Anything that
// does use this class must first be re-verified field-by-field against that writer.
//
//
// RacingZoneInfo — payload of SyncGameGroundZoneInfo (68004609).
// 🔴 TypeMark = 15 is load-bearing (see the file header): it is the discriminator byte the
// client's Auto.Dispatch[449] uses to pick Auto.Reader[1403].
// 🔴 Field order = wire order = declaration order. Do not reorder, do not extract a base class.
//