package methods // // Cat Express / 蓝猫物流 wire contracts for client build 4229938 (internal name: UberSim). // Why this file exists: the panels exist and look finished, but every list they render is a server // reply — AskGetTruckJobOrders supplies the take-order list, AskGetFinishedOrderWraps // the completed list — and none of those had a handler, so the app opened onto an empty board. // Source of truth. The IL2CPP dump declares these types as EMPTY classes // (ux_game_all.dump.cs:24562 ClientTruckOrderView, :34846 TruckJobOrderWrap — hard // rule 22), so every field order below comes from the client's own writer in // lua/LuaGen/AutoGen/RPCSerializeAuto.lua: // ClientTruckOrderView :2523 · TruckJobOrderWrap :10473 // TruckJobOrderInfo :10433 · TruckJobOrderAccept :10428 // TruckJobOrderResult :10456 · TruckNpcInfo :10483 // TruckPosInfo :10490 · CargoInfo :1571 // DeliveryGadgetInfo :3272 · UXVector3 :11429 // ClientFinishedTruckOrderView :2273 // Field order IS the wire layout — do not reorder (UxSerializer writes by MetadataToken). // Framing (from BowlingWireContracts.cs §0, re-derived here line by line): // complex -> 0x00 when null, else 0xFF + fields (Base.WriteComplex) // struct -> never any marker (Base.WriteStruct / Inline = true) // list -> 0x00 when null, else 0xFF + Int32 count (Base.WriteList, 4 bytes FLAT) // list7 -> 0x00 when null, else 0xFF + varint(count + 1) (Base.WriteList7Bit) // dict7 -> same as list7, then key, value pairs // ⛑⛑ WriteList and WriteList7Bit are NOT interchangeable and this type family mixes // both — see the Count = UxCountEncoding.Int32 notes on each list below. Writing the // wrong one shifts everything after it by three bytes and the client silently drops the reply. // // Three floats, never marked. Used for both positions and euler rotations. // // One drop-off fixture = Auto.WriteDeliveryGadgetInfo (RPCSerializeAuto.lua:3272). Complex. // // // Pickup / delivery point = Auto.WriteTruckPosInfo (RPCSerializeAuto.lua:10490). // ⛑ DeliveryGadgetInfoList goes through Base.WriteList (flat Int32 count), not the // 7-bit variant — it is the one list in this family that is NOT varint-counted. // // Consignee identity = Auto.WriteTruckNpcInfo (RPCSerializeAuto.lua:10483). // One physical parcel = Auto.WriteCargoInfo (RPCSerializeAuto.lua:1571). // // The authored body of one order = Auto.WriteTruckJobOrderInfo (RPCSerializeAuto.lua:10433). // Everything cosmetic (cargo name, area name, disaster stars, tag icons, NPC portrait) is looked up // client-side from CargoId / OrderType / SpecialOrderId, so the server only publishes identifiers // and the numbers that go into payment. // // Set once the player takes the row = Auto.WriteTruckJobOrderAccept (:10428). // Filled on settlement = Auto.WriteTruckJobOrderResult (:10456). // // One row of the take-order list = Auto.WriteTruckJobOrderWrap (RPCSerializeAuto.lua:10473). // AcceptInfo / ResultInfo are the ONLY nullable complexes here // (WriteComplex(..., true)), which is exactly how a row tells "takeable" from "taken". // // // Reply body of AskGetTruckJobOrders(63386469) and AskRefreshTruckOrder(63071191) — // Auto.WriteClientTruckOrderView (RPCSerializeAuto.lua:2523). The whole take-order board. // ⛑ Reply framing: this type is declared complex (no Inline), matching every other INVOKE reply in // this repo (Bubble / Extraction / Tuite's TuiteTimelineData). If the client logs // deserialize failed for these two methods, flip delivery.replyFraming to "struct" in // private-server.json — no rebuild needed. // // // Reply body of AskGetFinishedOrderWraps — Auto.WriteClientFinishedTruckOrderView // (RPCSerializeAuto.lua:2273). The three counters headline the completed-log page. // // // Reply body of AskAcceptTruckJobOrder(63110537) — the callback is // (errorId, TruckJobOrderWrap, ulong npcInstanceId), so this is the two-part tuple the RPC // layer unpacks: complex row first, raw u64 second (no marker on a primitive). // ⛑⛑ Inline, not complex. 2026-09-25 修正:这曾写成 [UxContract],于是顶层多出 // 一个 0xFF。多值回包的顶层是没有标记的 —— RPCDeserializeAuto.lua:10160 直接 // ReadComplex(286) 再 ReadUInt64,标记由每个值自己发。多出来的那一字节会让 // 客户端把 OrderWrap 的标记当成 OrderInfo 的标记、把 OrderInfo 的标记当成 StartPos 的标记, // 整包左移一字节 ⇒ 回调拿到的是一坨垃圾(现象正是"点了接单没反应")。 // 对照:单值回包(ClientTruckOrderView / TruckJobOrderWrap)顶层要那个 0xFF, // 因为客户端第一个读的就是 ReadComplex。 // // // Reply body of AskQueryTruckPosInfo(63763434) — RPCDeserializeAuto.lua:12187 reads // ReadList7Bit(Auto.Reader[641]) twice, so again no top-level marker: Inline. // The client only looks at [1] of each list (DeliveryTaskManager.lua:1870), so one // entry per queried id in the same order as the request is all that is required. // // // Push body of SyncAcceptTruckJobOrder(64910164) — RPCDeserializeAuto.lua:4732: // (u32 id, complex TruckJobOrderWrap, u64 deliveryAgentId, u64 deliveryGadgetId), no top marker. // ⛑ This — not the accept reply — is what actually moves the UI: the reply callback at // DeliveryHomepagePanelStore.lua:809 inspects errorId and nothing else, and the // store only clears its own canInteract latch in // OnAcceptTruckJobOrder, which is bound to // ON_ACCEPT_TRUCK_JOB_ORDER — the message GameToClientImpl.SyncAcceptTruckJobOrder // (:1761) raises. So without this push the board stays frozen after a tap that the server logged // as accepted. // // // Inline twin of ClientTruckOrderView — identical fields, no leading marker. // ⛑ Why a copy instead of a base class: UxSerializer serialises every public field including // inherited ones and orders them by MetadataToken, so sharing one declaration would quietly make // both framings emit the same bytes. The duplication is the cheap part; a mismatched reply // framing costs a rebuild round-trip per guess. // Selected at runtime by gameplay.deliveryReplyFraming ("complex" | "struct"). Nothing else // consults it — a wrong guess shows up as the client dropping the callback, never as an exception. // // Inline twin of ClientFinishedTruckOrderView for the same reason.