74 lines
4.0 KiB
Markdown
74 lines
4.0 KiB
Markdown
# Request #3: the forked NGO batch/message framing and ConnectionApproved
|
||
|
||
The LiteNetLib layer is solved and the client now completes the transport handshake against
|
||
our server and sends its NGO ConnectionRequest. We decoded it and confirmed the Tachyon JSON
|
||
(`AI/AT/VB/CKA/CIA/CPK`). But the fork changed NGO's batch and message framing, so we cannot
|
||
send a ConnectionApproved the client will accept without the exact serialization.
|
||
|
||
## What we already worked out from the wire (for your cross-check)
|
||
|
||
Decoded from a real 2041-byte ConnectionRequest batch:
|
||
|
||
```
|
||
[0:2] magic u16 = 0x1160
|
||
[2:4] count u16 = 0 (stock BatchCount, sent as 0)
|
||
[4:8] size u32 = 2041 (total datagram length)
|
||
[8:16] hash u64 = 0x3faa53cee8c5e338 (= XXHash64 over bytes [24:2041], VERIFIED)
|
||
[16:24] u64 = 1 (fork field; equals message count here)
|
||
[24] bitpacked = 1 (message type: ConnectionRequest, client-local idx)
|
||
[25:27] bitpacked = 2014 (message size)
|
||
[27] 0x81 (version-header preamble byte)
|
||
[28:63] 7 × { u32 hash ; 1 byte version=0 }
|
||
[63:68] 00 00 00 00 01 (5 bytes, not in stock NGO)
|
||
[68:76] u64 ConfigHash
|
||
[76:80] u32 = 1961 (ConnData length)
|
||
[80:2041] Tachyon JSON
|
||
```
|
||
|
||
So the batch hash covers `[24:end]` (message stream), NOT stock's `[16:alignedLength]`, and
|
||
the batch is NOT padded to 8 bytes. Two message-body bytes are unexplained: the `0x81`
|
||
preamble, and the `00 00 00 00 01`.
|
||
|
||
## Questions (in priority order)
|
||
|
||
**Q1 — forked batch header & hash, in `NetworkMessageManager`.**
|
||
Confirm the header layout above. Specifically:
|
||
- Is the `u64` at `[16:24]` the message count, a tick, or something else? What writes it?
|
||
- Confirm `BatchHash = XXHash64(buffer + 24, size - 24)` (or give the real range/seed).
|
||
- **Does the RECEIVER validate `BatchHash` and reject on mismatch, or log-and-continue?**
|
||
This decides whether our outbound hash must be exact.
|
||
- Does the receiver iterate messages by the `u64` count, by `BatchCount`, or by position?
|
||
|
||
**Q2 — the version-header preamble.**
|
||
In the forked `ConnectionRequestMessage.Serialize` (and the shared version-header code), what
|
||
is written before the version table? Stock writes `BytePacker.WriteValueBitPacked(N)` (N=7 ->
|
||
`0x39`). We see a single `0x81`. And what is the `00 00 00 00 01` written AFTER the table,
|
||
before `ConfigHash`? Give the exact field sequence of the forbidden segment as this build
|
||
serializes it.
|
||
|
||
**Q3 — `ConnectionApprovedMessage` serialization (the thing we must send).**
|
||
Full `Serialize` (server→client) for this build. We need every field and its encoding, in
|
||
order: the version header (same preamble as Q2?), `OwnerClientId`, `NetworkTick`, any
|
||
`ConnectedClientIds`, `sceneObjectCount`, and anything the fork added. Also the message
|
||
**type index** the client expects for ConnectionApproved in the pre-approval (local) space,
|
||
and how `Deserialize` reads it — because the client's `Deserialize` is what accepts or rejects
|
||
our packet.
|
||
|
||
**Q4 — how the approval reaches Tachyon.**
|
||
Earlier finding: `NetworkManager.RecRoom_ConnectionInfo` is a fork addition, hypothesised to
|
||
carry the approval JSON (`PMFAAFNFMAL`, the `"Carrot"` / `SessionKeyB` blob). Confirm whether
|
||
the approval JSON rides inside `ConnectionApprovedMessage`'s ConnectionData, in
|
||
`RecRoom_ConnectionInfo`, or elsewhere — i.e. where in the server→client bytes we must place
|
||
`{"DR":"Carrot",...}`.
|
||
|
||
**Q5 — key-null path for the session.**
|
||
Does the client require a non-null `SessionKeyB` to proceed, or will it accept an approval with
|
||
`"Carrot"` and no key and stay plaintext (marker `0x11`)? This decides whether we can defer the
|
||
RSA keypair patch and run voice unencrypted.
|
||
|
||
## Output
|
||
|
||
Decompiled `Serialize`/`Deserialize` bodies where possible, else exact field order + encodings
|
||
+ byte offsets. Distinguish read from inferred. If a field genuinely is not present, say so —
|
||
do not fill it from stock NGO; the fork has already diverged in three places above.
|