Repository navigation
Misc client/server packet parity - #2871
Merged
Merged
Conversation
…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.
…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
marked this pull request as ready for review
August 21, 2026 14:00
QuentinGruber
approved these changes
Aug 21, 2026
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
No description provided.