Account and HousingPlayerHouseEntity get destroyed on the client during
map transfers to the housing map. The edit mode handler always sent
VALUES_UPDATE, which the client "rescued" (ignored) because the entities
no longer existed in its object cache.
Now check HaveAtClient() first — if the client doesn't have the entity,
send a full CREATE_OBJECT and re-register the GUID in m_clientGUIDs.
This ensures the client receives InteriorDecorPlacementBudget, storage
entries, and DecorMaxOwnedCount needed for the decor count display.
- Fix CMSG_INITIATIVE_REPORT_PROGRESS ByteBufferException: packet only
contains a packed NeighborhoodGuid (sniff-verified 7 bytes), not three
extra uint32 fields. Handler now just sends initiative info back.
- Fix 4 SMSG initiative opcode collisions (0x420369-0x42036C) with
existing opcodes (CATALOG_SHOP_OBTAIN_LICENSE, MIRROR_VARS,
SET_INSTANCE_LEAVER, UNSET_INSTANCE_LEAVER). Reassigned to
0x420380-0x420383.
- Fix tutorial mode still blocking editor: CVar injection in
Player::LoadFromDB happened after the client already fetched account
data during auth. Added SendAccountDataTimes() after SetAccountData()
to force the client to re-fetch the updated GLOBAL_CONFIG_CACHE with
housingTutorialsEnabled=0 and closedInfoFramesAccountWide bits.
- Reset FHousingStorage_C populated flag on every edit mode entry so
the Account VALUES_UPDATE always carries the full storage map.
- Remove FHousingDecorActor_C fragment from decor MeshObjects (sniff
analysis confirmed fragment 28 is not present on any retail entity).
- Use DROP+CREATE instead of CREATE IF NOT EXISTS in initiative SQL
to prevent stale schema from persisting silently.
- Add neighborhood_initiative_task_progress table persisting per-task progress
and status (NOT_STARTED/IN_PROGRESS/COMPLETE) across server restarts
- Add neighborhood_initiative_milestones table persisting milestone reached
state with timestamps
- Add neighborhood_initiative_reward_claims table tracking per-player reward
claims to prevent double-claiming
- Implement PersistSingleTaskProgress, PersistMilestoneReached, PersistRewardClaim
with corresponding CHAR_REP/INS prepared statements
- LoadFromDB now restores task progress, milestone state, and reward claims
from DB instead of defaulting to zero/recalculating
- Implement ClaimMilestoneReward with full DB2 reward chain: walks
InitiativeRewardXMilestone → InitiativeReward to grant currency, items,
or favor based on RewardType
- HasUnclaimedRewards now checks per-player claim state, not just milestone reached
- HandleGetInitiativeClaimRewardRequest and HandleGetInitiativeOpenChestRequest
now use ClaimMilestoneReward for actual reward distribution
- PersistTaskProgress stub replaced with full implementation
- Register PlayerInitiativeComponent_C entity fragment (FragmentID 37) on player
load so C_NeighborhoodInitiative Lua API returns initiative state
- Populate InitiativeInfo fields (duration, progress, milestone, cycle, contribution)
and Houses set from InitiativeManager data
- Send SMSG_INITIATIVE_SERVICE_STATUS (0x80=enabled) proactively on both exterior
and interior map entry so IsInitiativeEnabled() returns true immediately
- Set IsInitiative flag on cornerstone UI response when neighborhood has active initiative
- Add InsertSetUpdateFieldValue friend declaration to SetUpdateFieldSetter (was missing,
preventing set-type update field insertion from compiling)
- Send SMSG_HOUSING_GET_CURRENT_HOUSE_INFO_RESPONSE in interior map so editor UI
has proper house context
- Add SendPostTutorialAuras to HouseInteriorMap to unlock all editor modes (expert,
cleanup, layout, customize) — auras are lost on map transfer and must be re-sent
The client's housing editor UI checks FrameTutorialAccount flags stored in the
closedInfoFramesAccountWide CVar bitfield (GLOBAL_CONFIG_CACHE account data),
which is completely separate from the 256-bit server tutorial flags sent via
SMSG_TUTORIAL_FLAGS. Without bit 38 (HousingModesUnlocked) set in this CVar,
expert/cleanup/layout/customize modes remain locked.
Fix: inject closedInfoFramesAccountWide (all bits set) and housingTutorialsEnabled=0
into the GLOBAL_CONFIG_CACHE account data during player login and house purchase.
The code handles both fresh and existing account data, replacing or appending CVars
as needed. Account data timestamps are bumped so the client re-requests the config.
Added TODO markers for adapting this when the housing tutorial questline is
implemented (quest-driven FrameTutorialAccount bit progression).
Budget values (interior/exterior decor, room, fixture) were hardcoded instead
of being read from the HouseLevelRewardInfo DB2. RewardType 38-41 maps to
ExpectedStatType housing budget enums. Wire these DB2 values into HouseLevelData
during LoadHouseLevelRewardInfoData, with hardcoded values as fallback only when
DB2 entries are missing. Log final budget values per level at startup for
verification.
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.