Housing: Add immediate DB persistence for PlaceDecor and RemoveDecor
PlaceDecor and RemoveDecor previously only modified in-memory state, relying on SaveToDB at logout for persistence. A server crash would lose all placed/removed decor changes since last save. Add crash-safe immediate persistence: - PlaceDecor: INSERT decor row + UPDATE catalog count on placement - RemoveDecor: DELETE decor row + UPDATE catalog count on removal - New prepared statements: CHAR_UPD_CHARACTER_HOUSING_CATALOG_COUNT, CHAR_DEL_CHARACTER_HOUSING_DECOR_SINGLE
This commit is contained in:
@@ -832,6 +832,8 @@ void CharacterDatabaseConnection::DoPrepareStatements()
|
||||
PrepareStatement(CHAR_UPD_CHARACTER_HOUSING_ROOM, "UPDATE character_housing_rooms SET slotIndex = ?, orientation = ?, mirrored = ?, themeId = ?, wallpaperId = ?, materialId = ?, doorTypeId = ?, doorSlot = ?, ceilingTypeId = ?, ceilingSlot = ? WHERE ownerGuid = ? AND id = ?", CONNECTION_ASYNC);
|
||||
PrepareStatement(CHAR_UPD_CHARACTER_HOUSING_FIXTURE, "UPDATE character_housing_fixtures SET fixtureOptionId = ? WHERE ownerGuid = ? AND fixturePointId = ?", CONNECTION_ASYNC);
|
||||
PrepareStatement(CHAR_DEL_CHARACTER_HOUSING_FIXTURE_SINGLE, "DELETE FROM character_housing_fixtures WHERE ownerGuid = ? AND fixturePointId = ?", CONNECTION_ASYNC);
|
||||
PrepareStatement(CHAR_UPD_CHARACTER_HOUSING_CATALOG_COUNT, "UPDATE character_housing_catalog SET quantity = ? WHERE ownerGuid = ? AND houseDecorId = ?", CONNECTION_ASYNC);
|
||||
PrepareStatement(CHAR_DEL_CHARACTER_HOUSING_DECOR_SINGLE, "DELETE FROM character_housing_decor WHERE ownerGuid = ? AND id = ?", CONNECTION_ASYNC);
|
||||
|
||||
// Neighborhoods
|
||||
PrepareStatement(CHAR_SEL_NEIGHBORHOOD, "SELECT guid, name, neighborhoodMapId, ownerGuid, factionRestriction, isPublic, createTime FROM neighborhoods WHERE guid = ?", CONNECTION_SYNCH);
|
||||
|
||||
@@ -686,6 +686,8 @@ enum CharacterDatabaseStatements : uint32
|
||||
CHAR_UPD_CHARACTER_HOUSING_ROOM,
|
||||
CHAR_UPD_CHARACTER_HOUSING_FIXTURE,
|
||||
CHAR_DEL_CHARACTER_HOUSING_FIXTURE_SINGLE,
|
||||
CHAR_UPD_CHARACTER_HOUSING_CATALOG_COUNT,
|
||||
CHAR_DEL_CHARACTER_HOUSING_DECOR_SINGLE,
|
||||
|
||||
// Neighborhoods
|
||||
CHAR_SEL_NEIGHBORHOOD,
|
||||
|
||||
@@ -483,6 +483,38 @@ HousingResult Housing::PlaceDecor(uint32 decorEntryId, float x, float y, float z
|
||||
else
|
||||
_interiorDecorWeightUsed += weightCost;
|
||||
|
||||
// Immediate persist for crash safety
|
||||
{
|
||||
CharacterDatabasePreparedStatement* stmt = CharacterDatabase.GetPreparedStatement(CHAR_INS_CHARACTER_HOUSING_DECOR);
|
||||
uint8 index = 0;
|
||||
stmt->setUInt64(index++, _owner->GetGUID().GetCounter());
|
||||
stmt->setUInt64(index++, decorGuid.GetCounter());
|
||||
stmt->setUInt32(index++, decorEntryId);
|
||||
stmt->setFloat(index++, x);
|
||||
stmt->setFloat(index++, y);
|
||||
stmt->setFloat(index++, z);
|
||||
stmt->setFloat(index++, rotX);
|
||||
stmt->setFloat(index++, rotY);
|
||||
stmt->setFloat(index++, rotZ);
|
||||
stmt->setFloat(index++, rotW);
|
||||
stmt->setUInt32(index++, 0); // dyeSlot0
|
||||
stmt->setUInt32(index++, 0); // dyeSlot1
|
||||
stmt->setUInt32(index++, 0); // dyeSlot2
|
||||
stmt->setUInt64(index++, roomGuid.IsEmpty() ? 0 : roomGuid.GetCounter());
|
||||
stmt->setUInt8(index++, 0); // locked
|
||||
CharacterDatabase.Execute(stmt);
|
||||
}
|
||||
|
||||
// Also persist updated catalog count
|
||||
{
|
||||
CharacterDatabasePreparedStatement* stmt = CharacterDatabase.GetPreparedStatement(CHAR_UPD_CHARACTER_HOUSING_CATALOG_COUNT);
|
||||
auto catItr = _catalog.find(decorEntryId);
|
||||
stmt->setUInt32(0, catItr != _catalog.end() ? catItr->second.Count : 0);
|
||||
stmt->setUInt64(1, _owner->GetGUID().GetCounter());
|
||||
stmt->setUInt32(2, decorEntryId);
|
||||
CharacterDatabase.Execute(stmt);
|
||||
}
|
||||
|
||||
// Update account decor storage UpdateField
|
||||
if (_owner->GetSession())
|
||||
_owner->GetSession()->GetBattlenetAccount().SetHousingDecorStorageEntry(decorGuid, _houseGuid, 0);
|
||||
@@ -579,6 +611,23 @@ HousingResult Housing::RemoveDecor(ObjectGuid decorGuid)
|
||||
|
||||
_placedDecor.erase(itr);
|
||||
|
||||
// Immediate persist for crash safety ? delete the placed decor row
|
||||
{
|
||||
CharacterDatabasePreparedStatement* stmt = CharacterDatabase.GetPreparedStatement(CHAR_DEL_CHARACTER_HOUSING_DECOR_SINGLE);
|
||||
stmt->setUInt64(0, _owner->GetGUID().GetCounter());
|
||||
stmt->setUInt64(1, decorGuid.GetCounter());
|
||||
CharacterDatabase.Execute(stmt);
|
||||
}
|
||||
|
||||
// Persist updated catalog count
|
||||
{
|
||||
CharacterDatabasePreparedStatement* stmt = CharacterDatabase.GetPreparedStatement(CHAR_UPD_CHARACTER_HOUSING_CATALOG_COUNT);
|
||||
stmt->setUInt32(0, _catalog[decorEntryId].Count);
|
||||
stmt->setUInt64(1, _owner->GetGUID().GetCounter());
|
||||
stmt->setUInt32(2, decorEntryId);
|
||||
CharacterDatabase.Execute(stmt);
|
||||
}
|
||||
|
||||
// Remove from account decor storage UpdateField
|
||||
if (_owner->GetSession())
|
||||
_owner->GetSession()->GetBattlenetAccount().RemoveHousingDecorStorageEntry(decorGuid);
|
||||
|
||||
Reference in New Issue
Block a user