diff --git a/data/sql/updates/pending_db_characters/rev_1707981003566465200.sql b/data/sql/updates/pending_db_characters/rev_1707981003566465200.sql new file mode 100644 index 000000000..ae7ae772e --- /dev/null +++ b/data/sql/updates/pending_db_characters/rev_1707981003566465200.sql @@ -0,0 +1,3 @@ +-- +ALTER TABLE `recovery_item` + ADD COLUMN `DeleteDate` INT UNSIGNED NULL DEFAULT NULL AFTER `Count`; diff --git a/src/server/apps/worldserver/worldserver.conf.dist b/src/server/apps/worldserver/worldserver.conf.dist index 2fa6d467e..31d309381 100644 --- a/src/server/apps/worldserver/worldserver.conf.dist +++ b/src/server/apps/worldserver/worldserver.conf.dist @@ -2616,6 +2616,14 @@ ItemDelete.Quality = 3 ItemDelete.ItemLevel = 80 +# +# ItemDelete.KeepDays +# Description: Time (in days) +# Default: 0 - (Disabled, Don't delete any it) +# 30 - (Enabled) + +ItemDelete.KeepDays = 0 + # ################################################################################################### diff --git a/src/server/database/Database/Implementation/CharacterDatabase.cpp b/src/server/database/Database/Implementation/CharacterDatabase.cpp index 6e777a278..b96f224cd 100644 --- a/src/server/database/Database/Implementation/CharacterDatabase.cpp +++ b/src/server/database/Database/Implementation/CharacterDatabase.cpp @@ -588,11 +588,13 @@ void CharacterDatabaseConnection::DoPrepareStatements() PrepareStatement(CHAR_UPD_QUEST_TRACK_ABANDON_TIME, "UPDATE quest_tracker SET quest_abandon_time = NOW() WHERE id = ? AND character_guid = ? ORDER BY quest_accept_time DESC LIMIT 1", CONNECTION_ASYNC); // Recovery Item - PrepareStatement(CHAR_INS_RECOVERY_ITEM, "INSERT INTO recovery_item (Guid, ItemEntry, Count) VALUES (?, ?, ?)", CONNECTION_SYNCH); + PrepareStatement(CHAR_INS_RECOVERY_ITEM, "INSERT INTO recovery_item (Guid, ItemEntry, Count, DeleteDate) VALUES (?, ?, ?, UNIX_TIMESTAMP())", CONNECTION_SYNCH); PrepareStatement(CHAR_SEL_RECOVERY_ITEM, "SELECT id, itemEntry, Count, Guid FROM recovery_item WHERE id = ?", CONNECTION_SYNCH); PrepareStatement(CHAR_SEL_RECOVERY_ITEM_LIST, "SELECT id, itemEntry, Count FROM recovery_item WHERE Guid = ? ORDER BY id DESC", CONNECTION_SYNCH); PrepareStatement(CHAR_DEL_RECOVERY_ITEM, "DELETE FROM recovery_item WHERE Guid = ? AND ItemEntry = ? AND Count = ? ORDER BY Id DESC LIMIT 1", CONNECTION_ASYNC); PrepareStatement(CHAR_DEL_RECOVERY_ITEM_BY_RECOVERY_ID, "DELETE FROM recovery_item WHERE id = ?", CONNECTION_ASYNC); + PrepareStatement(CHAR_SEL_RECOVERY_ITEM_OLD_ITEMS, "SELECT Guid, ItemEntry FROM recovery_item WHERE DeleteDate IS NOT NULL AND DeleteDate < ?", CONNECTION_SYNCH); + PrepareStatement(CHAR_DEL_RECOVERY_ITEM_BY_GUID, "DELETE FROM recovery_item WHERE Guid = ?", CONNECTION_ASYNC); PrepareStatement(CHAR_SEL_HONORPOINTS, "SELECT totalHonorPoints FROM characters WHERE guid = ?", CONNECTION_SYNCH); PrepareStatement(CHAR_SEL_ARENAPOINTS, "SELECT arenaPoints FROM characters WHERE guid = ?", CONNECTION_SYNCH); diff --git a/src/server/database/Database/Implementation/CharacterDatabase.h b/src/server/database/Database/Implementation/CharacterDatabase.h index c2c906936..b56f3f2d7 100644 --- a/src/server/database/Database/Implementation/CharacterDatabase.h +++ b/src/server/database/Database/Implementation/CharacterDatabase.h @@ -508,6 +508,8 @@ enum CharacterDatabaseStatements : uint32 CHAR_SEL_RECOVERY_ITEM_LIST, CHAR_DEL_RECOVERY_ITEM, CHAR_DEL_RECOVERY_ITEM_BY_RECOVERY_ID, + CHAR_SEL_RECOVERY_ITEM_OLD_ITEMS, + CHAR_DEL_RECOVERY_ITEM_BY_GUID, CHAR_SEL_HONORPOINTS, CHAR_SEL_ARENAPOINTS, diff --git a/src/server/game/Entities/Player/Player.cpp b/src/server/game/Entities/Player/Player.cpp index 707ac73ee..acf934da0 100644 --- a/src/server/game/Entities/Player/Player.cpp +++ b/src/server/game/Entities/Player/Player.cpp @@ -4334,6 +4334,49 @@ void Player::DeleteOldCharacters(uint32 keepDays) } } +/** + * Items which were kept back in the database after being deleted and are now too old (see config option "ItemDelete.KeepDays"), will be completely deleted. + */ +void Player::DeleteOldRecoveryItems() +{ + uint32 keepDays = sWorld->getIntConfig(CONFIG_ITEMDELETE_KEEP_DAYS); + if (!keepDays) + return; + + Player::DeleteOldRecoveryItems(keepDays); +} + +/** + * Items which were kept back in the database after being deleted and are older than the specified amount of days, will be completely deleted. + */ +void Player::DeleteOldRecoveryItems(uint32 keepDays) +{ + LOG_INFO("server.loading", "Player::DeleteOldRecoveryItems: Deleting all items which have been deleted {} days before...", keepDays); + LOG_INFO("server.loading", " "); + + CharacterDatabasePreparedStatement* stmt = CharacterDatabase.GetPreparedStatement(CHAR_SEL_RECOVERY_ITEM_OLD_ITEMS); + stmt->SetData(0, uint32(GameTime::GetGameTime().count() - time_t(keepDays * DAY))); + PreparedQueryResult result = CharacterDatabase.Query(stmt); + + if (result) + { + LOG_INFO("server.loading", "Player::DeleteOldRecoveryItems: Found {} item(s) to delete", result->GetRowCount()); + do + { + Field* fields = result->Fetch(); + + uint32 guid = fields[0].Get(); + uint32 itemEntry = fields[1].Get(); + + CharacterDatabasePreparedStatement* deleteStmt = CharacterDatabase.GetPreparedStatement(CHAR_DEL_RECOVERY_ITEM_BY_GUID); + deleteStmt->SetData(0, guid); + CharacterDatabase.Execute(deleteStmt); + + LOG_INFO("server.loading", "Deleted item from recovery_item table where guid {} and item id {}", guid, itemEntry); + } while (result->NextRow()); + } +} + void Player::SetMovement(PlayerMovementType pType) { WorldPacket data; diff --git a/src/server/game/Entities/Player/Player.h b/src/server/game/Entities/Player/Player.h index 2ebf6c8db..0569360f5 100644 --- a/src/server/game/Entities/Player/Player.h +++ b/src/server/game/Entities/Player/Player.h @@ -1578,6 +1578,9 @@ public: static void DeleteOldCharacters(); static void DeleteOldCharacters(uint32 keepDays); + static void DeleteOldRecoveryItems(); + static void DeleteOldRecoveryItems(uint32 keepDays); + bool m_mailsUpdated; void SetBindPoint(ObjectGuid guid); diff --git a/src/server/game/World/IWorld.h b/src/server/game/World/IWorld.h index 78eab7d7b..7b3551a32 100644 --- a/src/server/game/World/IWorld.h +++ b/src/server/game/World/IWorld.h @@ -389,6 +389,7 @@ enum WorldIntConfigs CONFIG_ICC_BUFF_ALLIANCE, CONFIG_ITEMDELETE_QUALITY, CONFIG_ITEMDELETE_ITEM_LEVEL, + CONFIG_ITEMDELETE_KEEP_DAYS, CONFIG_BG_REWARD_WINNER_HONOR_FIRST, CONFIG_BG_REWARD_WINNER_ARENA_FIRST, CONFIG_BG_REWARD_WINNER_HONOR_LAST, diff --git a/src/server/game/World/World.cpp b/src/server/game/World/World.cpp index 8350e4e72..1500f3ec6 100644 --- a/src/server/game/World/World.cpp +++ b/src/server/game/World/World.cpp @@ -1265,6 +1265,7 @@ void World::LoadConfigSettings(bool reload) _bool_configs[CONFIG_ITEMDELETE_VENDOR] = sConfigMgr->GetOption("ItemDelete.Vendor", 0); _int_configs[CONFIG_ITEMDELETE_QUALITY] = sConfigMgr->GetOption("ItemDelete.Quality", 3); _int_configs[CONFIG_ITEMDELETE_ITEM_LEVEL] = sConfigMgr->GetOption("ItemDelete.ItemLevel", 80); + _int_configs[CONFIG_ITEMDELETE_KEEP_DAYS] = sConfigMgr->GetOption("ItemDelete.KeepDays", 0); _int_configs[CONFIG_FFA_PVP_TIMER] = sConfigMgr->GetOption("FFAPvPTimer", 30); @@ -2091,6 +2092,9 @@ void World::SetInitialWorldSettings() // Delete all characters which have been deleted X days before Player::DeleteOldCharacters(); + // Delete all items which have been deleted X days before + Player::DeleteOldRecoveryItems(); + // Delete all custom channels which haven't been used for PreserveCustomChannelDuration days. Channel::CleanOldChannelsInDB();