Sniff-verified: ALL interior walls use base theme 2 (Rugged, sub-theme 8)
regardless of faction. The Rugged WMO models are the neutral interior
walls designed to match DB2 rotation values. Folk (theme 1) wall models
have different geometry/facing — they show their back side (wooden panels)
when placed with the standard DB2 OffsetRot values.
Floors/ceilings continue to use the faction theme (Folk=1 for Alliance).
Multiple RoomComponentOption entries exist per (MSFID, theme) with
different Types: 0=Cosmetic (normal wall), 1=DoorwayWall (sealed frame),
2=Doorway (open passage). Our index stored the first match by ID which
was Type=1 (DoorwayWall) — wrong model with doorway cutouts.
Sniff-verified: retail uses Type=0 (Cosmetic) for regular walls.
Type=1/2 are only for doorway-capable walls based on connection state.
Now the index prefers Type=0 entries as the default wall model.
Player::UpdateVisibilityOf(IteratorPair) had no case for TYPEID_HOUSING_ENTITY
in its switch statement. HousingRoomEntities were silently skipped during
UpdateObjectVisibilityOnCreate (called by AddToMap). Only MeshObjects were
sent via this path — room entities were deferred to the VisibleNotifier
which runs LATER. Result: MeshObjects arrived before their parent room
entities, causing NULL+0x20 when resolving RoomGUID.
With the switch case added, HousingRoomEntity AddToMap (Phase 1) triggers
an immediate CREATE to the player, before MeshObject AddToMap (Phase 3).
The VisibleNotifier calls UpdateVisibilityOf<HousingRoomEntity> during
the grid scan, but the template was never instantiated. Without the
explicit instantiation, HousingRoomEntity CREATEs were not included in
the initial UPDATE_OBJECT packet. MeshObject components arrived first
with FHousingRoomComponentMesh_C.RoomGUID pointing to room entities
that the client hadn't received yet → NULL resolution → crash at 0x20.
The grid TypeListContainer order (HousingRoomEntity before MeshObject)
was correct all along — the missing template was silently dropping room
entities from the packet.
Also: sub-theme mapping (base theme 1/2 → entity sub-theme 6/8),
UpdateType=1 for MeshObjects, and MeshObject BuildCreate hex dump.
RoomComponentOption.Theme is the BASE theme (1=Folk, 2=Rugged) used for
DB2 lookups. FHousingRoomComponentMesh_C.HouseThemeID is the APPLIED
SUB-THEME (6=Folk Medium, 8=Rugged Medium). We were writing the base
theme to the entity field where the client expects the sub-theme.
Sniff-verified: option 267 has DB2 Theme=2 (Rugged base), but the
entity field shows HouseThemeID=8 (Rugged Medium sub-theme). New houses
default to "Medium" sub-theme: Folk(1)→Folk Medium(6), Rugged(2)→
Rugged Medium(8).
Added GetDefaultSubThemeID() to map base→sub-theme. Also reverted all
debug changes (Empty parent, skipped InitHousingRoomComponentData).
The grid TypeListContainer iterates types in order: ..., MeshObject,
HousingRoomEntity. Component MeshObjects (type MeshObject) were sent
in UPDATE_OBJECT BEFORE HousingRoomEntity. The client resolves
AttachParentGUID (Housing/2) during CREATE — parent not yet created
→ NULL → crash at 0x20.
Fix: swap HousingRoomEntity before MeshObject in the type list so
room entities are always sent first in the initial UPDATE_OBJECT.
Retail MeshObjects have HasMeshObject=true, Stationary=false. Our
MeshObject constructor had BOTH Stationary=true AND MeshObject=true.
The extra Stationary block (16 bytes: X,Y,Z,O) shifted all subsequent
parsing of the MeshObject block and fragment data, corrupting the
client's entity data and causing NULL+0x20 crashes.
Sniff-verified: retail interior components have Stationary=false and
HasMeshObject=true. Also restored IsRoom=true on components (sniff
confirms ALL retail room components have IsRoom=true).
Replaced 17 synthetic entries with all 587 retail entries from wago.tools.
Fixed the fundamental DB2 linkage: RoomComponentOption links to RoomComponent
via MeshStyleFilterID (not RoomComponentID as we assumed). This means one
option entry covers all components sharing the same MeshStyleFilterID.
Also fixed Alliance default theme from 6 (Folk Medium sub-theme, 0 options)
to 1 (Folk base theme, full option coverage). Fallback chain now uses
Generic(3) and Folk(1) instead of non-existent themes 8/6.
5 base themes now work: Folk(1), Rugged(2), Generic(3), Bel'ameth(4),
Silvermoon(5). Sub-themes (6-28) are texture/dye variants only.
SMSG_HOUSING_ROOM_ADD_RESPONSE was sending an empty RoomGuid because
response.RoomGuid was never set. The client needs the new room's GUID
to register it in the layout editor (fire HOUSING_LAYOUT_ROOM_RECEIVED).
PlaceRoom now outputs the generated room GUID via optional parameter.
Also: TextureID=0xFFFFFFFF from client means "default/reset" - not a bug.
Theme visual changes require full room_component_option DB2 data for all
themes (we only have 2/6/8), so themes 11/12/26 fall back to existing.