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.