Update Account entity FHousingStorage_C when learning decor via spell so the
client's decor list refreshes immediately without requiring a relog.
Include HousingPlayerHouseEntity in the combined UPDATE_OBJECT packets sent
when entering editor mode, requesting storage, and buying a plot. The client
needs budget max values alongside FHousingStorage_C entries to compute and
display placed/remaining decor counts.
- Fix NeighborhoodMirrorData Houses array: add entries for ALL 55 plots
(including empty ones) so Houses[i] corresponds to DB2 PlotIndex=i.
Previously only occupied plots were added, causing the client to map
Houses[0] to plot 0 when it actually contained plot 7's data.
Fixed in all 5 locations: Neighborhood.cpp, NeighborhoodHandler.cpp,
HousingHandler.cpp (2 sites), Player.cpp.
- Fix door interaction GO position: raise Z from -0.56 to 1.5 (door frame
level instead of stair base) and pull X back from 9.28 to 8.0 (actual
door threshold instead of mesh origin at stair foot).
The platform WMO (574432) is already loaded from the static gameobject table
(sniff data). Dynamically spawning a second one at the ground-clamped Z
caused it to render visibly on the surface. The static spawn provides the
DynamicMapTree collision needed for house ground-clamping.
Housing/3 and Housing/4 entities were never registered in Player::m_clientGUIDs,
causing HaveAtClient() to always return false. Every SendUpdateToPlayer() call
sent CREATE_OBJECT instead of VALUES_UPDATE, producing duplicate CREATEs that
freeze/crash the client.
Include both entities in Player::BuildCreateUpdateBlockForPlayer alongside
BNetAccount, and track their GUIDs in m_clientGUIDs so subsequent updates
correctly use VALUES_UPDATE.
Split entity fragment ownership to match retail wire format:
- BNetAccount carries only FHousingStorage_C (decor catalog)
- Housing/3 entity carries FHousingPlayerHouse_C (house data)
- Housing/4 entity carries FNeighborhoodMirrorData_C (neighborhood mirror)
- Route all callers to correct entity (Housing.cpp, Neighborhood.cpp, handlers)
- Add Housing/3 and Housing/4 to player world lifecycle
Fix house spawning below ground level after DB2 position switch:
- Re-enable ground-clamping via GetHeight which includes GetGameObjectFloor
- Static platform WMO spawns (GO 574432) provide DynamicMapTree collision
- Falls back to DB2 Z when no valid ground height available
Fix decor jumping to wrong position after placement:
- World-to-local conversion now applies inverse rotation of room facing
- Previously only subtracted translation, ignoring room orientation
- Broken by atan2-based facing computation that introduced non-zero angles
Raw .pkt binary analysis confirms SMSG_MOVE_APPLY_INERTIA in 12.0.1 is
20 bytes: PackedGUID + SequenceIndex + InertiaID + LifetimeMs with no
Force vector. The client derives force direction from the AreaTrigger
DB2 entry referenced by InertiaID.
Removes the incorrect Force field from MoveApplyInertia (SMSG),
MoveApplyInertiaAck (CMSG), and MoveUpdateApplyInertia (broadcast).
Updates Unit::SendApplyInertia() signature accordingly.
Whirling Surge (361584) and Launch Boost (392752) are periodic auras
per Wowhead spell data, not single-shot effects:
- Whirling Surge: Apply Aura: Dummy, 3s duration. Converted from
single-shot SpellScript to SpellScript+AuraScript pair. The periodic
handler sends facing+pitch oriented impulses at magnitude 5.0 per
tick (sniff-verified: 5-6 ticks per activation).
- Launch Boost: Periodic Dummy, period 100ms, duration 2s. Split into
SpellScript (sends initial Z=45 upward impulse on hit) + AuraScript
(sends periodic forward impulse at magnitude 5.0 per tick).
Both use RegisterSpellAndAuraScriptPair for combined validation and
periodic handling. Extracted SendFacingImpulse helper to reduce
duplication.
Add full server-side support for the client's skyriding movement system:
- DB2 infrastructure: DriveCapability (17 fields) and DriveCapabilityTier (5 fields)
stores with hotfix DB integration and SQL table definitions
- Drive activation: SetDriveCapabilityID() on mount/dismount integrated into
HandleAuraMounted, with blizzlike packet behavior (SET_CAN_DRIVE only via
CompoundState at login, UNSET_CAN_DRIVE on dismount)
- Vigor system: POWER_ALTERNATE_MOUNT (25) with velocity-based regen modifier
using FlightCapability::VigorRegenMaxVelCoefficient
- Impulse delivery: SendApplyInertia(), SendRemoveInertia(), SendAddImpulse()
helpers sending movement packets to mover only (no broadcast, per sniff)
- Dragonriding spell scripts: Surge Forward (372608), Skyward Ascent (372610),
Whirling Surge (361584), Launch Boost (392752) with sniff-verified impulse
values and SPELL_CUSTOM_ERROR_REQUIRES_SKYRIDING validation
Impulse magnitudes verified against raw SMSG_MOVE_ADD_IMPULSE packet data:
Launch Boost: (0, 0, 45.0), Whirling Surge: 5.0/tick x6,
Skyward Ascent: horiz 12.25 + Z 49.0
Add complete blizzlike Chromie Time flow: NPC gossip opens expansion picker,
handler sets ConditionalFlags/FactionGroup for content tuning redirection,
selection persists via new characters.chromieTimeExpansionId column, state
restores on login, and auto-clears at max level. Implement SMSG_SET_CTR_OPTIONS
server packet for mid-session state pushes.
Fix teleport-to-plot using server-side plot resolution instead of trusting
client's PlotIndex (which is a roster index, not the DB2 PlotIndex). Resolve
correct plot via player's Housing object for self-teleport, or OwnerGuid
matching for visiting others.
Additional changes accumulated in this batch:
- Implement housing packet handlers for Phase 5-7-9 opcodes
- Fix neighborhood response wire format to match retail sniffs
- Add housing source tracking and platform cleanup SQL migrations
- Fix AreaTrigger/GameObject/MeshObject housing integration points
- Extend UpdateFields for housing-specific object data
- Add Neighborhood plot management and house finder support
- Fix door script and steward NPC interactions
- Add catalog persistence prepared statement
- Fix HouseInteriorMap Euler-to-quaternion conversion for room components
1. CanStartMission: always send true (sniff shows all 1s regardless of
mission state, our code incorrectly sent MissionState == 0)
2. NumMissionsStartedToday: track daily mission start count with
day-boundary reset. Persisted to character_garrison table. This
controls follower abilities like "Increase success chance of the
first mission of the day."
3. ArchivedMissions: track completed mission RecIDs per garrison type.
Persisted to new character_garrison_archived_missions table. Sniff
shows 12 archived WoD missions and 9 archived Class Hall missions
for a played character.
Fix the effect dispatch key: use BattlePetEffectPropertiesID (the
actual effect action type) instead of ParamTypeEnum[0] (parameter data
type). This single change fixes healing dealing damage, auras not
applying, state changes, stuns, weather, and multi-turn markers all
routing to the damage case.
Also lock swaps during multi-turn abilities, clear multi-turn state on
pet death, face the player toward the opponent on battle start, restore
NPC trainer movement after battle with a cry emote on loss, and show
quest menu alongside the battle gossip option.
Register BattlePetNPCTeamMember.db2 in the hotfix pipeline so the
server can populate it at runtime. The client ships this DB2 empty
(0 records) — names resolve via CreatureID in packets instead, but
the infrastructure is now in place for future name overrides.
Add initial seed data for 19 NPC pet battle trainers (57 pets) from
Eastern Kingdoms through Pandaria Grand Masters. All creature IDs
verified against TDB creature_template with exact name matches.
Multi-turn abilities (Dig, Burrow, etc.) were invisible to the client:
- Handle effectCategory 17/18 (MULTI_TURN_BEGIN/END) in ProcessEffect
that were falling through to default handler producing no effects
- Fix off-by-one: multi-turn state now clears on last turn instead of
one round late (>= TotalTurns-1 instead of >= TotalTurns)
- Emit fallback STATUS_CHANGE for empty multi-turn turns so the client
still shows the ability animation
NPC trainer pet naming and model support:
- Add npcTeamMemberID column to battle_pet_npc_team (maps to
BattlePetNPCTeamMember.db2 for pet name display on client)
- Add creatureId column for optional model override (0=species default)
- Send NpcTeamMemberID in packet for all teams, not just wild
Fix aura round data being lost before packet serialization by storing
RoundsRemaining/CurrentRound in PetBattleRoundEffect at creation time
instead of looking up live aura state after TickAuras() has already
decremented or removed them.
Defer captured pet journal addition from round resolution to
CompleteBattle() so the "Pet collected" message appears after the
client plays the crate animation, not before. Also add missing
PlayerObtainPetThroughBattle criteria call.
Add NPC pet battle support via StartNPCPetBattle() on WorldSession and
npc_pet_battle_trainer gossip CreatureScript. Trainers with a team in
battle_pet_npc_team and ScriptName='npc_pet_battle_trainer' will offer
a gossip battle option.
Continued analysis of WoD garrison sniff hex data revealed:
Shipment packets:
- CharacterShipment struct missing 2 fields: UnkInt32 (int32) and
GarrTypeID (uint8) per entry — 5 extra bytes confirmed by raw hex
decode of GET_SHIPMENT_INFO_RESPONSE and LANDING_PAGE_SHIPMENTS
- CreateShipmentResponse ShipmentRecID always 0 (sniff-confirmed)
Login/zone-in workflow:
- Send troop quality refresh (FOLLOWER_CHANGED_QUALITY) before main
GET_GARRISON_INFO_RESULT at login (sniff-confirmed ordering)
- Send GARRISON_UPDATE_GARRISON_MONUMENT_SELECTIONS on zone-in after
map data response (sniff-confirmed zone-in sequence)
- Set EditorMode UpdateField via SetHousingEditorModeUpdateField() when
entering/exiting edit mode. The client reads this from
PlayerHouseInfoComponentData to enable ClickTarget (flag 16) for decor
selection. Without it, the housing editor stays in mode 0 and all click
flags are disabled.
- Set UNIT_FLAG_PACIFIED, UNIT_FLAG2_NO_ACTIONS and SilencedSchoolMask=127
during edit mode (sniff-verified retail behavior). Clear on exit.
- Revert ignoreNestedChangesMask from true to false in
HousingStorageData::WriteUpdate. The true flag forced full-map Create
format inside VALUES_UPDATE which crashes the client (BLZ_ALLOC 41GB)
on subsequent Decor map updates after placing decor. The original
partial-serialization issue was actually caused by ContentsChangedMask=0
which is already fixed by the Account::SendUpdateToPlayer override.
- Fix SMSG_HOUSING_UPDATE_HOUSE_INFO to send actual BnetAccountGuid
instead of ObjectGuid::Empty so house owner displays correctly in the
settings/permissions UI.
- Make character_housing position columns SQL update idempotent to avoid
duplicate column errors when schema already includes posX/posY/posZ.
BaseEntity::SendUpdateToPlayer() is const and never calls
BuildUpdateChangesMask(), leaving ContentsChangedMask at 0. This means
BuildValuesUpdateBlockForPlayer() skips all fragment data — the
VALUES_UPDATE packet is sent empty with no FHousingStorage_C content.
The map's periodic update cycle (Account::BuildUpdate) does call
BuildUpdateChangesMask() and sends data correctly, but our explicit
handler calls to SendUpdateToPlayer were producing empty packets.
Override SendUpdateToPlayer on Account to call BuildUpdateChangesMask()
before serializing and ClearUpdateMask() after. This ensures
FHousingStorage_C Decor map data populated by
PopulateCatalogStorageEntries() is actually included in the packet.
The client correlates FHousingStorage_C Decor entries with MeshObject
FHousingDecor_C.DecorGUID for targeting/selection. VALUES_UPDATE packets
with partial change masks (ignoreNestedChangesMask=false) only sent
individual field bits, missing the complete Decor map structure the
client needs. Fix by forcing ignoreNestedChangesMask=true in
HousingStorageData::WriteUpdate so the Decor map is always serialized
in full-create format (WriteMapFieldCreate) inside VALUES_UPDATE.
Also fix SetHousingDecorStorageEntry to set SourceValue (empty string)
so all 3 fields have their change bits set for per-entry serialization.
The Account entity's GUID was never added to m_clientGUIDs after its
initial CREATE (embedded in the player's own create block). This caused
SendUpdateToPlayer() to always send a duplicate full CREATE instead of
a VALUES_UPDATE. When the Decor map was populated during edit mode, the
duplicate CREATE crashed the client with a 41GB BLZ_ALLOC allocation.
DumpExteriorComponentDiagnostics and DumpRoomComponentTextureDiagnostics
passed Name[locale] directly to fmt without SafeStr() guard, causing
ACCESS_VIOLATION when LocalizedString data is null.
Add instant visual feedback for fixture/room changes, populate licensed
decor quantities from catalog, and implement the decor refund window.
- Fixture handlers (SetCore, Create, Delete) now despawn+respawn house
MeshObjects so changes are visible without relog
- All 8 room handlers refresh interior MeshObjects after success via
shared RefreshInteriorRoomVisuals helper
- Send SMSG_ACCOUNT_*_COLLECTION_UPDATE for room add, theme set, and
material apply operations
- HandleGetAllLicensedDecorQuantities returns catalog + starter decor
- HandleGetDecorRefundList returns recently placed decor within 2-hour
refund window using new PlacementTime field persisted to DB
- Rewrite SpawnRoomMeshObjects to iterate ALL components per room from DB2
data, each getting InitHousingRoomComponentData with proper geobox
- Add faction-aware theme selection via GetFactionDefaultThemeID (Alliance=6,
Horde=2) and FindRoomComponentOption per-component lookup
- Fix GetDefaultVisualRoomEntry to deterministically pick lowest-ID room
(Room 1 = Square Small) instead of non-deterministic unordered_map pick
- Add runtime migration in LoadFromDB to replace wrong visual room entry
(e.g., Octagon 9 → Square 1) on next login
- Fix interior decor not visible: PLACE/MOVE/REMOVE handlers now support
HouseInteriorMap via SpawnSingleInteriorDecor and UpdateDecorPosition
- SpawnInteriorDecor runs on every interior entry (not gated by
_roomsSpawned), with duplicate-spawn prevention
- Fix room GUID using subType=2 (was 0 which returned ObjectGuid::Empty)
- Fix DB2 OffsetRot degrees-to-radians conversion for component quaternions
- Teleport player to visual room center on interior entry
- Add MeshObject::InitHousingDecorData, InitHousingRoomData,
InitHousingRoomComponentData, InitHousingFixtureData for entity fragments
- Add SpawnRoomForPlot to HousingMap for exterior room entities with geobox
- Add SQL migrations for base room and visual room auto-placement
- Enhanced diagnostic logging for exterior decor spawn success/failure
P0: Fix mission rewards double-write in GetGarrisonInfoResult — inline
Encounters/Rewards/OvermaxRewards are now cleared in mission structs
sent via GarrisonInfo; rewards go only in the garrison-level parallel
arrays, preventing client packet desync.
P1: Populate FollowerSoftCaps with 5 entries matching retail sniff data.
Implement SMSG_GARRISON_MISSION_START_CONDITION_UPDATE packet and send
it after GetGarrisonInfoResult. Update CMSG_GARRISON_START_MISSION
Read() for 12.0.1 per-follower struct format (BoardIndex/Health/
HasFollowerEntry), remove obsolete MissionBonusAbilityIDs.
P2: Implement SMSG_GARRISON_FOLLOWER_CHANGED_QUALITY packet, used by
SetFollowerQuality. Send blueprint data for all garrison types.
Read GarrTypeID in CMSG_GARRISON_CHECK_UPGRADEABLE and look up the
correct garrison by type.
P3: Add FOLLOWER_TYPE_DELVES (22) enum value. Fix building removal
packet ordering — GarrisonBuildingRemoved now sent before
ClearBuildingInfo (PlotRemoved) when replacing a different type.
Battle no longer gets stuck after capturing a wild pet when other wild
pets are still alive. The captured pet is marked and the wild team
auto-swaps to the next alive pet, continuing the fight.
Buff/debuff auras are now visible and mechanically applied:
- Add effectCategory 8 handler for self-buff auras (AURA_APPLY to caster)
- RecalculateEffectiveStats reads state modifiers and BUFF/DEBUFF auras
- CalculateAbilityDamage integrates damage dealt/taken state modifiers
- CalculateAbilityHealing integrates healing dealt state modifiers
- Add STATE_MOD_DAMAGE_TAKEN, SPEED, HEALING_DEALT/TAKEN to BattlePetState
Fix four bugs reported by tester:
- Slot swap duplication: HandleBattlePetSetBattleSlot now properly swaps
pets between source and target slots instead of only assigning the target,
which left the pet duplicated in the old slot
- Aura persistence: Populate petInfo.Auras in BuildPetBattlePlayerUpdate
so the client knows which auras are active on each pet. Fix aura round
effect params to send AuraInstanceID + AbilityID (matching wire format)
and look up real RoundsRemaining/CurrentRound instead of hardcoding 0
- Trap animation: Resolve the actual BattlePetAbilityEffect.ID from the
DB2 chain for ability 427 instead of using the raw ability ID, so the
client can look up the correct visual spell for the capture animation
- Achievement name: Change hotfix_data status from 3 (insert) to 1 (valid)
for achievement 7433 which already exists in the retail client DB2;
status=3 corrupted the client-side entry causing empty achievement links
LoadFromDB was creating decor GUIDs with subType=0 (Housing-0-0-0-counter)
but the client uses subType=1 (Housing-1-realmId-entryId-counter). The GUID
mismatch caused the Account entity storage to become stale after relog,
making all placed decor appear gone. Reconstruct the full GUID using the
decorEntryId from the same DB row.