Branch: feature/server-packet-layouts
Commit: 0fd021dbfa9d27516a3f55f1bd4778a1ed4e9e09
Select server packet layouts per build once, starting with GossipPOI
A server packet whose layout differs between client builds branched on
ModernVersion.Build inside Write() and again inside WriteToSpan(). An exact
== V3_4_3_54261 also sends any build the code has not seen down the else
path, which for 4.4.2 is the 1.14/2.5 layout.
- ServerPacketLayout is one wire layout: MaxSize, Write and
WriteToSpan, with no version check. ServerPacketLayouts lists a
packet's layouts with [AddedIn, RemovedIn) build ranges, compared by
expansion.major.minor like [PacketCodec], and picks the running client's
once, in the packet's static initializer. Call sites keep constructing
the packet class. - HPSG009 (SealedLayoutAnalyzer) fails the build for a layout class that is
not sealed, so the static readonly field can be devirtualised and a
variant is a new layout with its own range rather than a subclass. - GossipPOI is the first packet on it: RetailLayout for 1.14 and 2.5,
FlatLayout from 3.4.3. The 4.4.2 client reads the same layout as 3.4.3,
so FlatLayout's range stays open. Two exact-build checks go
(docs/opcode-coverage.md: 214 -> 212). - CLAUDE.md: classes are sealed by default unless meant to be derived from.
ServerPacketLayoutTests checks that every packet's list picks exactly one
layout for each supported build and 4.4.2; GossipPOILayoutTests holds both
serialisers of both layouts to a frozen copy of the old branches. Driven
on 3.4.3 against AzerothCore playerbots: the Stormwind guard's bank and
auction house POIs went out as 47 and 56 bytes and WowPacketParser decodes
both (flags, position, red flag icon, name).
Refs #202
Co-Authored-By: Claude Opus 5.5 noreply@anthropic.com