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
Ananta-ps/pkg/protocol/methods/blackout_methods4229938.go
T

63 lines
3.6 KiB
Go

package methods
// Seymour 大停电 (Blackout) wire contracts for build 4229938.
//
// Everything here was re-derived from THIS build's own Lua reconstructions rather than from the
// Russian donor document Blackout_IMPLEMENTATION_RU.md, because that document describes an older
// client. Three of its warnings turned out to be exactly right and are what shaped these shapes:
//
// 1. SyncAddCreation's body is a STRUCT, not a complex value. There is no 0xFF presence byte;
// writing one shifts every field by one byte and the client reads garbage.
// 2. AskStartHackerTetris's invoke return is a bare UInt32 deadline. An empty return is not
// "harmless": the client blocks reading four bytes that never come.
// 3. The battery packet needs its complex marker, which our existing DTO already produces.
//
// Cross-checked against, every field in declaration order:
// Drmk.Proxy/proxy/lua/RPCSerializeAuto.lua:7968 WriteSceneCreationInfo
// Drmk.Proxy/proxy/lua/RPCDeserializeAuto.lua Auto.Reader[425] (the reader for 68413195)
// The two agree field-for-field, which is why they are trusted over the donor's prose.
//
// SceneCreationInfo — SyncAddCreation(68413195)'s payload, read by the client as
// Base.ReadStruct(reader, Auto.Reader[425]).
// ⛑️ Inline ⇒ exactly 77 bytes with no object marker:
// 8+8+8+8 (four u64) + 4 (u32) + 12 (UXVector3 struct) + 4 (f32) + 1 (bool) + 4 (u32)
// + 8 (u64) + 8 (u64) + 4 (i32) = 77.
// ⛑️ Auto.UXVector3 ships as a COMPLEX contract, so this field must override the
// framing back to Struct. Leaving it Auto writes a stray 0xFF and pushes every later field off
// by one byte — the classic "server sent N bytes, client still desyncs" trap (rule 22).
//
//
// AskStartHackerTetris(63521495) has an empty request body, so nothing is needed on the way in.
// The return is where it matters: midToReturnMessageReader[63521495] does an
// unconditional reader:ReadUInt32(). The server answers with the Unix deadline, written as
// a bare little-endian u32 (no marker) — see BlackoutUnixDeadline below.
//
// Wraps a deadline so the surviving Invoke path writes four raw bytes.
func BlackoutUnixDeadline_Value(unixSeconds int64) uint32 {
return 0
}
//
// AskFinishHackerTetris(63554976) — the client reports the Tetris score.
// Inline because the client's reader reads a bare u32 out of the request body.
// ⛑️ uint.MaxValue is the accepted "cancelled, no score" sentinel (donor §7); the Lua
// fallback path sends nothing at all and the default serializer writes 0, which is also valid.
//
//
// SyncPlayerLoadTaskSpoonDebug(68786069) — taskId + eventId pair that arms the blackout task graph
// before the controller is spawned.
// ⛑️ This MethodId is CSharpOnly in the Lua export table, so no Lua reader confirms the
// layout. The (u32, u32) shape comes from the donor's live capture. If the controller never
// reaches the client, this packet is the first suspect — verify it against the IL2CPP dump before
// assuming anything else is broken.
//
//
// AskTaskGadgetsListLoadComplete(67359333) — client confirms ITS OWN controller finished loading.
// Body is a biased 7-bit list of ulong instance ids.
// ⛑️ Also CSharpOnly, same caveat. This exists purely so we never trust a blanket ack:
// only a list containing our own runtimeInstanceId is allowed to release the startup waiter.
// When the shape turns out to be wrong this degrades to "no ack", which surfaces as a clean
// timeout in the log rather than a corrupted neighbouring field.
//
// AskTaskPlateLoadComplete(67794218) — optional plate ack; a bare task id.