Skip to content

Misc client/server packet parity - #2871

Merged
Z1Meme merged 6 commits into
devfrom
fix/clientprotocol-1080-opcode-reconciliation
Aug 22, 2026
Merged

Z1Meme merged 6 commits into
devfrom
fix/clientprotocol-1080-opcode-reconciliation

Conversation

@Z1Meme

@Z1Meme Z1Meme commented Aug 16, 2026

Copy link
Copy Markdown
Collaborator

No description provided.

Z1Meme added 4 commits August 16, 2026 01:45
…ate 0x112f00 collision

Two client-truth-backed protocol corrections for the Dec 2016 build,
verified against the reverse-engineered H1Z1 client packet tables.

Loadout 0x8703: rename the placeholder "Loadout.Unk1" to
"Loadout.SetCurrentLoadoutSlot". The packet is unused server-side (no send
or handler references); fields {characterId, loadoutSlotId} are unchanged.
Interface LoadoutUnk1 and the generated name unions are renamed to match.

ClientUpdate 0x112f00: remove the mis-assigned "ClientUpdate.ZonePopulation"
entry, which collided with "ClientUpdate.StartTimer" on the same opcode.
Client RE confirms 0x112f00 = StartTimer; ZonePopulation (array<u8>) is a
later-version packet with no 2016 client handler and no server send/handler
site (the live sendZonePopulationUpdate emits the separate lz-connection
"UpdateZonePopulation" packet). StartTimer is left as the sole 0x112f00
definition and is unchanged.

Regenerated src/types/packets.ts via gen-packets-types. tsc passes.
…lient

Correct the ClientUpdate.RespawnLocations (0x111f00) wire format to match the
fully reverse-engineered Dec 2016 client reader (RespawnLocationReadFromBuffer).

respawnLocationSchema: drop the two extra trailing fields nameId (uint32) and
distance (float). The client reads exactly 6 u32 after position; the server
listed 8, an 8-byte-per-entry overrun.

RespawnLocations wrapper: drop unknownFlags (u8), unknownDword1 (u32) and
unknownDword2 (u32). The body is exactly { locations[], locations2[] } with no
scalars before/between/after. The leading unknownFlags duplicated the opcode's
trailing 0x00 byte: getPacketTypeBytes encodes 0x111f00 as [0x11,0x1f,0x00] and
the client reader consumes that 0x00 as its leading byte, so a payload
unknownFlags would desync by one byte.

Latent-correctness fix: the packet is never sent and these fields are never
populated or read, so there is no runtime behavior change. tsc passes; packet
names are unchanged so the generated name unions are unaffected.
…== 1

packItemSubData wrote the trailing unknownData1 block whenever the gate
(unknownDword1) was > 0, but the Dec 2016 client (ItemInstance::ReadItemData
FromBuffer) reads it only when the gate (subType) == 1. For a gate value >= 2
the server would emit 16 bytes the client never consumes, desyncing that item
and everything after it in the packet. Align the writer to the client: emit the
block only when unknownDword1 === 1.

Latent-correctness fix: packer-only (itemSubData has no parser) and no send path
sets hasSubData:true today, so there is no runtime behavior change. Scoped to
ClientProtocol_1080; the 860/2015 packItemSubData is a separate function and is
left unchanged. tsc passes; no packet names changed.
…witchInfo

The Dec 2016 client (Character sub-op 0x5e reader) reads
{ characterId: u64, twitchName: string, unknownQword1: u64 } - a trailing raw
8-byte qword after twitchName. The server schema stopped at twitchName, so a
sent packet would leave the client reading 8 bytes past the intended end and
desync. Append unknownQword1 (uint64string, raw 8-byte qword like characterId)
to match the client reader; update the CharacterUpdateTwitchInfo interface.

Latent-correctness: the packet is never sent (no twitch integration/send site),
so no runtime behavior change. Scoped to ClientProtocol_1080 (no 860/2015
variant); name/opcode unchanged so name unions are unaffected. tsc passes.
@Z1Meme Z1Meme changed the title Fix/clientprotocol 1080 opcode reconciliation Misc client/server packet parity Aug 16, 2026
Z1Meme added 2 commits August 16, 2026 04:00
…trailing field to the 2016 client

The Dec 2016 client reads the trailing field of both nested weapon sub-packets
as a length-prefixed byte array (u32 count + count bytes), but the server modeled
it as a plain uint32. The two match only when the value is 0; a non-zero value
makes the client consume extra bytes and desync the weapon packet.

Change the trailing field from uint32 to byteswithlength (u32 length + raw bytes)
in both:
- Weapon.AddFireGroup (0x8311): { guid, unknownBoolean1, unknownData1 }
- Weapon.ReplaceFireGroup (0x8313): { guid, unknownByte1, unknownBoolean1, unknownData1 }

Latent-correctness: neither packet is sent (or received) by the server today, so
no runtime behavior change and no caller to update. Scoped to ClientProtocol_1080
(860/2015 untouched); no name/opcode change so name unions are unaffected. There
are no WeaponAddFireGroup/WeaponReplaceFireGroup field interfaces to update. tsc
passes.
re-validated: the leading uint32 in packItemSubData is the sub-data-type discriminator
(== 1 => weapon, gates the weapon-meta block). Rename unknownDword1 -> subDataType in the
1080 packer; the nested unknownData1 weapon-meta block stays unknown (opaque). All other
PR #2871 field verdicts were already applied on this branch.
@Z1Meme
Z1Meme marked this pull request as ready for review August 21, 2026 14:00
Comment thread src/packets/ClientProtocol/ClientProtocol_1080/clientUpdate.ts
Comment thread src/packets/ClientProtocol/ClientProtocol_1080/clientUpdate.ts
@Z1Meme
Z1Meme merged commit bef646d into dev Aug 22, 2026
18 checks passed
@Z1Meme
Z1Meme deleted the fix/clientprotocol-1080-opcode-reconciliation branch August 22, 2026 01:16
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants