From 17672bd5b5e6fb30dc65cac6fc9ed35a17fdfa1d Mon Sep 17 00:00:00 2001 From: blinkysc <37940565+blinkysc@users.noreply.github.com> Date: Wed, 26 Feb 2025 12:19:11 -0600 Subject: [PATCH] Properly cleanup database with playerbot delete (#1027) Properly cleanup appropriate databases when AiPlayerbot.DeleteRandomBotAccounts is set to 1 --- src/RandomPlayerbotFactory.cpp | 71 +++++++++++++++++++++++++++++++--- 1 file changed, 66 insertions(+), 5 deletions(-) diff --git a/src/RandomPlayerbotFactory.cpp b/src/RandomPlayerbotFactory.cpp index f8d57141..37bc3eff 100644 --- a/src/RandomPlayerbotFactory.cpp +++ b/src/RandomPlayerbotFactory.cpp @@ -427,6 +427,7 @@ uint32 RandomPlayerbotFactory::CalculateTotalAccountCount() void RandomPlayerbotFactory::CreateRandomBots() { /* multi-thread here is meaningless? since the async db operations */ + if (sPlayerbotAIConfig->deleteRandomBotAccounts) { std::vector botAccounts; @@ -445,9 +446,68 @@ void RandomPlayerbotFactory::CreateRandomBots() botAccounts.push_back(accountId); } - LOG_INFO("playerbots", "Deleting all random bot characters, {} accounts collected...", botAccounts.size()); + LOG_INFO("playerbots", "Deleting all random bot characters and accounts..."); + + // First execute all the cleanup SQL commands + // Clear playerbots_random_bots table + PlayerbotsDatabase.Execute("DELETE FROM playerbots_random_bots"); + + // Delete all characters from bot accounts + CharacterDatabase.Execute("DELETE FROM characters WHERE account IN (SELECT id FROM acore_auth.account WHERE username LIKE '{}%%')", + sPlayerbotAIConfig->randomBotAccountPrefix.c_str()); + + // Clean up orphaned records in character-related tables + CharacterDatabase.Execute("DELETE FROM arena_team_member WHERE guid NOT IN (SELECT guid FROM characters)"); + CharacterDatabase.Execute("DELETE FROM arena_team WHERE arenaTeamId NOT IN (SELECT arenaTeamId FROM arena_team_member)"); + CharacterDatabase.Execute("DELETE FROM character_account_data WHERE guid NOT IN (SELECT guid FROM characters)"); + CharacterDatabase.Execute("DELETE FROM character_achievement WHERE guid NOT IN (SELECT guid FROM characters)"); + CharacterDatabase.Execute("DELETE FROM character_achievement_progress WHERE guid NOT IN (SELECT guid FROM characters)"); + CharacterDatabase.Execute("DELETE FROM character_action WHERE guid NOT IN (SELECT guid FROM characters)"); + CharacterDatabase.Execute("DELETE FROM character_aura WHERE guid NOT IN (SELECT guid FROM characters)"); + CharacterDatabase.Execute("DELETE FROM character_glyphs WHERE guid NOT IN (SELECT guid FROM characters)"); + CharacterDatabase.Execute("DELETE FROM character_homebind WHERE guid NOT IN (SELECT guid FROM characters)"); + CharacterDatabase.Execute("DELETE FROM item_instance WHERE owner_guid NOT IN (SELECT guid FROM characters) AND owner_guid > 0"); + CharacterDatabase.Execute("DELETE FROM character_inventory WHERE guid NOT IN (SELECT guid FROM characters)"); + + // Clean up pet data + CharacterDatabase.Execute("DELETE FROM character_pet WHERE owner NOT IN (SELECT guid FROM characters)"); + CharacterDatabase.Execute("DELETE FROM pet_aura WHERE guid NOT IN (SELECT id FROM character_pet)"); + CharacterDatabase.Execute("DELETE FROM pet_spell WHERE guid NOT IN (SELECT id FROM character_pet)"); + CharacterDatabase.Execute("DELETE FROM pet_spell_cooldown WHERE guid NOT IN (SELECT id FROM character_pet)"); + + // Clean up character data + CharacterDatabase.Execute("DELETE FROM character_queststatus WHERE guid NOT IN (SELECT guid FROM characters)"); + CharacterDatabase.Execute("DELETE FROM character_queststatus_rewarded WHERE guid NOT IN (SELECT guid FROM characters)"); + CharacterDatabase.Execute("DELETE FROM character_reputation WHERE guid NOT IN (SELECT guid FROM characters)"); + CharacterDatabase.Execute("DELETE FROM character_skills WHERE guid NOT IN (SELECT guid FROM characters)"); + CharacterDatabase.Execute("DELETE FROM character_social WHERE friend NOT IN (SELECT guid FROM characters)"); + CharacterDatabase.Execute("DELETE FROM character_spell WHERE guid NOT IN (SELECT guid FROM characters)"); + CharacterDatabase.Execute("DELETE FROM character_spell_cooldown WHERE guid NOT IN (SELECT guid FROM characters)"); + CharacterDatabase.Execute("DELETE FROM character_talent WHERE guid NOT IN (SELECT guid FROM characters)"); + CharacterDatabase.Execute("DELETE FROM corpse WHERE guid NOT IN (SELECT guid FROM characters)"); + + // Clean up group data + CharacterDatabase.Execute("DELETE FROM `groups` WHERE leaderGuid NOT IN (SELECT guid FROM characters)"); + CharacterDatabase.Execute("DELETE FROM group_member WHERE memberGuid NOT IN (SELECT guid FROM characters)"); + + // Clean up mail + CharacterDatabase.Execute("DELETE FROM mail WHERE receiver NOT IN (SELECT guid FROM characters)"); + CharacterDatabase.Execute("DELETE FROM mail_items WHERE receiver NOT IN (SELECT guid FROM characters)"); + + // Clean up guild data + CharacterDatabase.Execute("DELETE FROM guild WHERE leaderguid NOT IN (SELECT guid FROM characters)"); + CharacterDatabase.Execute("DELETE FROM guild_bank_eventlog WHERE guildid NOT IN (SELECT guildid FROM guild)"); + CharacterDatabase.Execute("DELETE FROM guild_member WHERE guildid NOT IN (SELECT guildid FROM guild) OR guid NOT IN (SELECT guid FROM characters)"); + CharacterDatabase.Execute("DELETE FROM guild_rank WHERE guildid NOT IN (SELECT guildid FROM guild)"); + + // Clean up petition data + CharacterDatabase.Execute("DELETE FROM petition WHERE ownerguid NOT IN (SELECT guid FROM characters)"); + CharacterDatabase.Execute("DELETE FROM petition_sign WHERE ownerguid NOT IN (SELECT guid FROM characters) OR playerguid NOT IN (SELECT guid FROM characters)"); + + // Finally, delete the bot accounts themselves + LOG_INFO("playerbots", "Deleting random bot accounts..."); QueryResult results = LoginDatabase.Query("SELECT id FROM account WHERE username LIKE '{}%%'", - sPlayerbotAIConfig->randomBotAccountPrefix.c_str()); + sPlayerbotAIConfig->randomBotAccountPrefix.c_str()); int32 deletion_count = 0; if (results) { @@ -461,12 +521,13 @@ void RandomPlayerbotFactory::CreateRandomBots() } uint32 timer = getMSTime(); - PlayerbotsDatabase.Execute(PlayerbotsDatabase.GetPreparedStatement(PLAYERBOTS_DEL_RANDOM_BOTS)); - while (LoginDatabase.QueueSize()) + + // Wait for all pending database operations to complete + while (LoginDatabase.QueueSize() || CharacterDatabase.QueueSize() || PlayerbotsDatabase.QueueSize()) { std::this_thread::sleep_for(1s); } - LOG_INFO("playerbots", ">> Random bot accounts deleted in {} ms", GetMSTimeDiffToNow(timer)); + LOG_INFO("playerbots", ">> Random bot accounts and data deleted in {} ms", GetMSTimeDiffToNow(timer)); LOG_INFO("playerbots", "Please reset the AiPlayerbot.DeleteRandomBotAccounts to 0 and restart the server..."); World::StopNow(SHUTDOWN_EXIT_CODE); return;