Housing: Read decor budget values from HouseLevelRewardInfo DB2
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.
This commit is contained in:
@@ -194,16 +194,12 @@ void HousingMgr::LoadHouseLevelData()
|
||||
data.ID = entry->ID;
|
||||
data.Level = entry->Level;
|
||||
data.QuestID = entry->QuestID;
|
||||
// Budget values from captured game data; interior scales per level, others are constant
|
||||
static constexpr int32 InteriorBudgetByLevel[] = { 0, 910, 1155, 1450, 1750, 2050 };
|
||||
uint32 lvl = static_cast<uint32>(std::max<int32>(entry->Level, 1));
|
||||
if (lvl <= 5)
|
||||
data.InteriorDecorPlacementBudget = InteriorBudgetByLevel[lvl];
|
||||
else
|
||||
data.InteriorDecorPlacementBudget = 2050 + static_cast<int32>((lvl - 5) * 300); // +300/level extrapolation
|
||||
data.ExteriorDecorPlacementBudget = 200;
|
||||
data.RoomPlacementBudget = 19;
|
||||
data.ExteriorFixtureBudget = 1000;
|
||||
// Budget values will be populated from HouseLevelRewardInfo DB2 (RewardType 38-41)
|
||||
// after LoadHouseLevelRewardInfoData(). Initialize to 0 here; fallbacks applied later.
|
||||
data.InteriorDecorPlacementBudget = 0;
|
||||
data.ExteriorDecorPlacementBudget = 0;
|
||||
data.RoomPlacementBudget = 0;
|
||||
data.ExteriorFixtureBudget = 0;
|
||||
}
|
||||
|
||||
// Fallback defaults if no DB2 data available
|
||||
@@ -215,14 +211,10 @@ void HousingMgr::LoadHouseLevelData()
|
||||
data.ID = level;
|
||||
data.Level = static_cast<int32>(level);
|
||||
data.QuestID = 0;
|
||||
static constexpr int32 InteriorBudgetByLevel[] = { 0, 910, 1155, 1450, 1750, 2050 };
|
||||
if (level <= 5)
|
||||
data.InteriorDecorPlacementBudget = InteriorBudgetByLevel[level];
|
||||
else
|
||||
data.InteriorDecorPlacementBudget = 2050 + static_cast<int32>((level - 5) * 300);
|
||||
data.ExteriorDecorPlacementBudget = 200;
|
||||
data.RoomPlacementBudget = 19;
|
||||
data.ExteriorFixtureBudget = 1000;
|
||||
data.InteriorDecorPlacementBudget = 0;
|
||||
data.ExteriorDecorPlacementBudget = 0;
|
||||
data.RoomPlacementBudget = 0;
|
||||
data.ExteriorFixtureBudget = 0;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -575,7 +567,7 @@ int32 HousingMgr::ResolvePlotIndex(ObjectGuid cornerstoneGuid, Neighborhood cons
|
||||
}
|
||||
|
||||
// Only GameObject GUIDs encode a GO entry that can be matched against cornerstone entries.
|
||||
// Housing/Neighborhood GUIDs (HighGuid 55) don't have a GO entry — callers sometimes
|
||||
// Housing/Neighborhood GUIDs (HighGuid 55) don't have a GO entry ? callers sometimes
|
||||
// pass these for diagnostic purposes; silently return -1.
|
||||
if (cornerstoneGuid.GetHigh() != HighGuid::GameObject)
|
||||
{
|
||||
@@ -715,8 +707,8 @@ std::vector<uint32> HousingMgr::GetStarterDecorIds(uint32 teamId) const
|
||||
// FirstTimeDecorAcquisition sends one packet per UNIQUE decor ID.
|
||||
// StartingQuantity determines catalog count, NOT notification count.
|
||||
static constexpr int32 HOUSE_DECOR_FLAG_FACTION_ALLIANCE = 0x1;
|
||||
static constexpr int32 HOUSE_DECOR_FLAG_FACTION_HORDE = 0x2;
|
||||
static constexpr int32 HOUSE_DECOR_FLAG_FACTION_MASK = 0x3;
|
||||
static constexpr int32 HOUSE_DECOR_FLAG_FACTION_HORDE = 0x2;
|
||||
static constexpr int32 HOUSE_DECOR_FLAG_FACTION_MASK = 0x3;
|
||||
|
||||
int32 factionBit = (teamId == ALLIANCE) ? HOUSE_DECOR_FLAG_FACTION_ALLIANCE : HOUSE_DECOR_FLAG_FACTION_HORDE;
|
||||
|
||||
@@ -738,8 +730,8 @@ std::vector<std::pair<uint32, int32>> HousingMgr::GetStarterDecorWithQuantities(
|
||||
{
|
||||
// Returns {DecorID, StartingQuantity} pairs for populating the catalog
|
||||
static constexpr int32 HOUSE_DECOR_FLAG_FACTION_ALLIANCE = 0x1;
|
||||
static constexpr int32 HOUSE_DECOR_FLAG_FACTION_HORDE = 0x2;
|
||||
static constexpr int32 HOUSE_DECOR_FLAG_FACTION_MASK = 0x3;
|
||||
static constexpr int32 HOUSE_DECOR_FLAG_FACTION_HORDE = 0x2;
|
||||
static constexpr int32 HOUSE_DECOR_FLAG_FACTION_MASK = 0x3;
|
||||
|
||||
int32 factionBit = (teamId == ALLIANCE) ? HOUSE_DECOR_FLAG_FACTION_ALLIANCE : HOUSE_DECOR_FLAG_FACTION_HORDE;
|
||||
|
||||
@@ -766,21 +758,21 @@ bool HousingMgr::CanVisitorAccess(Player const* visitor, Player const* owner, ui
|
||||
return true;
|
||||
|
||||
// Select the correct flag group based on access type
|
||||
uint32 anyoneFlag = isInterior ? HOUSE_SETTING_HOUSE_ACCESS_ANYONE : HOUSE_SETTING_PLOT_ACCESS_ANYONE;
|
||||
uint32 anyoneFlag = isInterior ? HOUSE_SETTING_HOUSE_ACCESS_ANYONE : HOUSE_SETTING_PLOT_ACCESS_ANYONE;
|
||||
uint32 neighborsFlag = isInterior ? HOUSE_SETTING_HOUSE_ACCESS_NEIGHBORS : HOUSE_SETTING_PLOT_ACCESS_NEIGHBORS;
|
||||
uint32 guildFlag = isInterior ? HOUSE_SETTING_HOUSE_ACCESS_GUILD : HOUSE_SETTING_PLOT_ACCESS_GUILD;
|
||||
uint32 friendsFlag = isInterior ? HOUSE_SETTING_HOUSE_ACCESS_FRIENDS : HOUSE_SETTING_PLOT_ACCESS_FRIENDS;
|
||||
uint32 partyFlag = isInterior ? HOUSE_SETTING_HOUSE_ACCESS_PARTY : HOUSE_SETTING_PLOT_ACCESS_PARTY;
|
||||
uint32 guildFlag = isInterior ? HOUSE_SETTING_HOUSE_ACCESS_GUILD : HOUSE_SETTING_PLOT_ACCESS_GUILD;
|
||||
uint32 friendsFlag = isInterior ? HOUSE_SETTING_HOUSE_ACCESS_FRIENDS : HOUSE_SETTING_PLOT_ACCESS_FRIENDS;
|
||||
uint32 partyFlag = isInterior ? HOUSE_SETTING_HOUSE_ACCESS_PARTY : HOUSE_SETTING_PLOT_ACCESS_PARTY;
|
||||
|
||||
// If no flags are set at all, default to open access (sniff behavior: plots are public by default)
|
||||
uint32 accessMask = isInterior
|
||||
? (HOUSE_SETTING_HOUSE_ACCESS_ANYONE | HOUSE_SETTING_HOUSE_ACCESS_NEIGHBORS |
|
||||
HOUSE_SETTING_HOUSE_ACCESS_GUILD | HOUSE_SETTING_HOUSE_ACCESS_FRIENDS | HOUSE_SETTING_HOUSE_ACCESS_PARTY)
|
||||
HOUSE_SETTING_HOUSE_ACCESS_GUILD | HOUSE_SETTING_HOUSE_ACCESS_FRIENDS | HOUSE_SETTING_HOUSE_ACCESS_PARTY)
|
||||
: (HOUSE_SETTING_PLOT_ACCESS_ANYONE | HOUSE_SETTING_PLOT_ACCESS_NEIGHBORS |
|
||||
HOUSE_SETTING_PLOT_ACCESS_GUILD | HOUSE_SETTING_PLOT_ACCESS_FRIENDS | HOUSE_SETTING_PLOT_ACCESS_PARTY);
|
||||
HOUSE_SETTING_PLOT_ACCESS_GUILD | HOUSE_SETTING_PLOT_ACCESS_FRIENDS | HOUSE_SETTING_PLOT_ACCESS_PARTY);
|
||||
|
||||
if ((settingsFlags & accessMask) == 0)
|
||||
return true; // No restrictions configured — open to all
|
||||
return true; // No restrictions configured ? open to all
|
||||
|
||||
if (settingsFlags & anyoneFlag)
|
||||
return true;
|
||||
@@ -876,7 +868,72 @@ void HousingMgr::LoadHouseLevelRewardInfoData()
|
||||
for (auto const& [id, reward] : _houseLevelRewardInfoStore)
|
||||
_rewardsByLevel[reward.HouseLevelID].push_back(&reward);
|
||||
|
||||
TC_LOG_DEBUG("housing", "HousingMgr::LoadHouseLevelRewardInfoData: Loaded {} HouseLevelRewardInfo entries", uint32(_houseLevelRewardInfoStore.size()));
|
||||
// Wire budget values from HouseLevelRewardInfo into HouseLevelData.
|
||||
// RewardType maps to ExpectedStatType: 38=InteriorDecor, 39=ExteriorDecor, 40=Room, 41=Fixture.
|
||||
// HouseLevelRewardInfo.HouseLevelID references HouseLevelData.ID.
|
||||
uint32 budgetWired = 0;
|
||||
for (auto const& [id, reward] : _houseLevelRewardInfoStore)
|
||||
{
|
||||
auto lvlIt = _houseLevelDataStore.find(reward.HouseLevelID);
|
||||
if (lvlIt == _houseLevelDataStore.end())
|
||||
continue;
|
||||
|
||||
HouseLevelData& levelData = lvlIt->second;
|
||||
switch (reward.RewardType)
|
||||
{
|
||||
case 38: // HouseInteriorDecorBudget
|
||||
levelData.InteriorDecorPlacementBudget = reward.RewardValue;
|
||||
++budgetWired;
|
||||
break;
|
||||
case 39: // HouseExteriorDecorBudget
|
||||
levelData.ExteriorDecorPlacementBudget = reward.RewardValue;
|
||||
++budgetWired;
|
||||
break;
|
||||
case 40: // HouseRoomPlacementBudget
|
||||
levelData.RoomPlacementBudget = reward.RewardValue;
|
||||
++budgetWired;
|
||||
break;
|
||||
case 41: // HouseFixtureBudget
|
||||
levelData.ExteriorFixtureBudget = reward.RewardValue;
|
||||
++budgetWired;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// Apply fallback budgets for any levels still at 0 (DB2 missing budget rewards)
|
||||
static constexpr int32 FallbackInteriorByLevel[] = { 0, 910, 1155, 1450, 1750, 2050 };
|
||||
for (auto& [id, levelData] : _houseLevelDataStore)
|
||||
{
|
||||
uint32 lvl = static_cast<uint32>(std::max<int32>(levelData.Level, 1));
|
||||
if (levelData.InteriorDecorPlacementBudget <= 0)
|
||||
{
|
||||
if (lvl <= 5)
|
||||
levelData.InteriorDecorPlacementBudget = FallbackInteriorByLevel[lvl];
|
||||
else
|
||||
levelData.InteriorDecorPlacementBudget = 2050 + static_cast<int32>((lvl - 5) * 300);
|
||||
}
|
||||
if (levelData.ExteriorDecorPlacementBudget <= 0)
|
||||
levelData.ExteriorDecorPlacementBudget = 200;
|
||||
if (levelData.RoomPlacementBudget <= 0)
|
||||
levelData.RoomPlacementBudget = 19;
|
||||
if (levelData.ExteriorFixtureBudget <= 0)
|
||||
levelData.ExteriorFixtureBudget = 1000;
|
||||
}
|
||||
|
||||
TC_LOG_INFO("housing", "HousingMgr::LoadHouseLevelRewardInfoData: Loaded {} HouseLevelRewardInfo entries, wired {} budget values from DB2",
|
||||
uint32(_houseLevelRewardInfoStore.size()), budgetWired);
|
||||
|
||||
// Log final budget values per level for verification
|
||||
for (auto const& [id, levelData] : _houseLevelDataStore)
|
||||
{
|
||||
TC_LOG_INFO("housing", " Level {} (ID {}): Interior={} Exterior={} Room={} Fixture={}{}",
|
||||
levelData.Level, id,
|
||||
levelData.InteriorDecorPlacementBudget, levelData.ExteriorDecorPlacementBudget,
|
||||
levelData.RoomPlacementBudget, levelData.ExteriorFixtureBudget,
|
||||
budgetWired > 0 ? " (from DB2)" : " (fallback)");
|
||||
}
|
||||
}
|
||||
|
||||
void HousingMgr::LoadNeighborhoodInitiativeData()
|
||||
@@ -959,12 +1016,12 @@ void HousingMgr::LoadRoomComponentData()
|
||||
{
|
||||
switch (c.Type)
|
||||
{
|
||||
case HOUSING_ROOM_COMPONENT_WALL: ++wallCount; break;
|
||||
case HOUSING_ROOM_COMPONENT_FLOOR: ++floorCount; break;
|
||||
case HOUSING_ROOM_COMPONENT_CEILING: ++ceilCount; break;
|
||||
case HOUSING_ROOM_COMPONENT_DOORWAY:
|
||||
case HOUSING_ROOM_COMPONENT_DOORWAY_WALL: ++doorwayCount2; break;
|
||||
default: ++otherCount; break;
|
||||
case HOUSING_ROOM_COMPONENT_WALL: ++wallCount; break;
|
||||
case HOUSING_ROOM_COMPONENT_FLOOR: ++floorCount; break;
|
||||
case HOUSING_ROOM_COMPONENT_CEILING: ++ceilCount; break;
|
||||
case HOUSING_ROOM_COMPONENT_DOORWAY:
|
||||
case HOUSING_ROOM_COMPONENT_DOORWAY_WALL: ++doorwayCount2; break;
|
||||
default: ++otherCount; break;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1152,7 +1209,7 @@ void HousingMgr::BuildRoomComponentTextureIndex()
|
||||
_textureByOptionId.clear();
|
||||
_textureByComponentType.clear();
|
||||
|
||||
// Build option→texture link from RoomComponentOptionTexture join table
|
||||
// Build option?texture link from RoomComponentOptionTexture join table
|
||||
for (RoomComponentOptionTextureEntry const* link : sRoomComponentOptionTextureStore)
|
||||
{
|
||||
if (!link)
|
||||
@@ -1160,7 +1217,7 @@ void HousingMgr::BuildRoomComponentTextureIndex()
|
||||
_textureByOptionId[link->RoomComponentOptionID] = link->RoomComponentTextureID;
|
||||
}
|
||||
|
||||
// Build type→texture fallback from RoomComponentTexture
|
||||
// Build type?texture fallback from RoomComponentTexture
|
||||
// "Type" in RoomComponentTexture maps to component type (1=wall, 2=floor, 3=ceiling)
|
||||
for (RoomComponentTextureEntry const* tex : sRoomComponentTextureStore)
|
||||
{
|
||||
@@ -1172,7 +1229,7 @@ void HousingMgr::BuildRoomComponentTextureIndex()
|
||||
}
|
||||
|
||||
TC_LOG_INFO("housing", "HousingMgr::BuildRoomComponentTextureIndex: "
|
||||
"{} option→texture links, {} type→texture fallbacks "
|
||||
"{} option?texture links, {} type?texture fallbacks "
|
||||
"(RoomComponentTexture store: {} entries, RoomComponentOptionTexture store: {} entries)",
|
||||
uint32(_textureByOptionId.size()), uint32(_textureByComponentType.size()),
|
||||
sRoomComponentTextureStore.GetNumRows(), sRoomComponentOptionTextureStore.GetNumRows());
|
||||
@@ -1198,7 +1255,7 @@ void HousingMgr::DumpRoomComponentTextureDiagnostics()
|
||||
{
|
||||
if (!link)
|
||||
continue;
|
||||
TC_LOG_INFO("housing", " OptionTexture [{}] OptionID={} → TextureID={}",
|
||||
TC_LOG_INFO("housing", " OptionTexture [{}] OptionID={} ? TextureID={}",
|
||||
link->ID, link->RoomComponentOptionID, link->RoomComponentTextureID);
|
||||
}
|
||||
|
||||
@@ -1241,7 +1298,7 @@ void HousingMgr::BuildExteriorComponentIndexes()
|
||||
_hooksByExtComp[hook->ExteriorComponentID].push_back(hook);
|
||||
}
|
||||
|
||||
// 2. Build reverse lookup: component's HookID → the component that attaches there
|
||||
// 2. Build reverse lookup: component's HookID ? the component that attaches there
|
||||
// Each ExteriorComponent has a HookID field; if > 0, it means "I attach at this hook"
|
||||
for (ExteriorComponentEntry const* comp : sExteriorComponentStore)
|
||||
{
|
||||
@@ -1347,7 +1404,9 @@ void HousingMgr::DumpExteriorComponentDiagnostics()
|
||||
bool isKnown = false;
|
||||
for (uint32 compID : knownCompIDs)
|
||||
if (hook->ExteriorComponentID == compID)
|
||||
{ isKnown = true; break; }
|
||||
{
|
||||
isKnown = true; break;
|
||||
}
|
||||
|
||||
if (isKnown)
|
||||
{
|
||||
@@ -1369,7 +1428,9 @@ void HousingMgr::DumpExteriorComponentDiagnostics()
|
||||
bool isKnown = false;
|
||||
for (uint32 compID : knownCompIDs)
|
||||
if (exitPt->ExteriorComponentID == compID)
|
||||
{ isKnown = true; break; }
|
||||
{
|
||||
isKnown = true; break;
|
||||
}
|
||||
|
||||
if (isKnown)
|
||||
{
|
||||
@@ -1381,8 +1442,8 @@ void HousingMgr::DumpExteriorComponentDiagnostics()
|
||||
}
|
||||
}
|
||||
|
||||
// Dump component→hook attachment map (comp.HookID → hook → hook.ExteriorComponentID = parent)
|
||||
TC_LOG_INFO("housing", " --- Component→Hook attachment chain ---");
|
||||
// Dump component?hook attachment map (comp.HookID ? hook ? hook.ExteriorComponentID = parent)
|
||||
TC_LOG_INFO("housing", " --- Component?Hook attachment chain ---");
|
||||
for (uint32 compID : knownCompIDs)
|
||||
{
|
||||
ExteriorComponentEntry const* comp = sExteriorComponentStore.LookupEntry(compID);
|
||||
@@ -1392,12 +1453,12 @@ void HousingMgr::DumpExteriorComponentDiagnostics()
|
||||
ExteriorComponentHookEntry const* hook = sExteriorComponentHookStore.LookupEntry(comp->HookID);
|
||||
if (hook)
|
||||
{
|
||||
TC_LOG_INFO("housing", " comp {} (HookID={}) → hook [{}] → parent comp {}",
|
||||
TC_LOG_INFO("housing", " comp {} (HookID={}) ? hook [{}] ? parent comp {}",
|
||||
compID, comp->HookID, hook->ID, hook->ExteriorComponentID);
|
||||
}
|
||||
else
|
||||
{
|
||||
TC_LOG_INFO("housing", " comp {} (HookID={}) → hook NOT FOUND",
|
||||
TC_LOG_INFO("housing", " comp {} (HookID={}) ? hook NOT FOUND",
|
||||
compID, comp->HookID);
|
||||
}
|
||||
}
|
||||
@@ -1411,11 +1472,13 @@ void HousingMgr::DumpExteriorComponentDiagnostics()
|
||||
bool isKnown = false;
|
||||
for (uint32 compID : knownCompIDs)
|
||||
if (static_cast<uint32>(xg->ExteriorComponentID) == compID)
|
||||
{ isKnown = true; break; }
|
||||
{
|
||||
isKnown = true; break;
|
||||
}
|
||||
|
||||
if (isKnown)
|
||||
{
|
||||
TC_LOG_INFO("housing", " XGroup [{}] comp={} → group={}",
|
||||
TC_LOG_INFO("housing", " XGroup [{}] comp={} ? group={}",
|
||||
xg->ID, xg->ExteriorComponentID, xg->ExteriorComponentGroupID);
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user