mirror of
https://github.com/mangosfour/server.git
synced 2025-12-13 13:37:05 +00:00
[9767] Add the posibility to keep deleted characters in the database for a while and also add related commands.
Added commands: * .character deleted list [$guid|$name] * .character deleted restore $guid|$name [$newname] * .character deleted delete $guid|$name * .character deleted old [$keepdays] Command .character delete renamed to .character erase Signed-off-by: VladimirMangos <vladimir@getmangos.com>
This commit is contained in:
parent
c9ac685f04
commit
492ce567d2
22 changed files with 701 additions and 151 deletions
|
|
@ -4037,8 +4037,31 @@ TrainerSpellState Player::GetTrainerSpellState(TrainerSpell const* trainer_spell
|
|||
return TRAINER_SPELL_GREEN;
|
||||
}
|
||||
|
||||
void Player::DeleteFromDB(uint64 playerguid, uint32 accountId, bool updateRealmChars)
|
||||
/**
|
||||
* Deletes a character from the database
|
||||
*
|
||||
* The way, how the characters will be deleted is decided based on the config option.
|
||||
*
|
||||
* @see Player::DeleteOldCharacters
|
||||
*
|
||||
* @param playerguid the low-GUID from the player which should be deleted
|
||||
* @param accountId the account id from the player
|
||||
* @param updateRealmChars when this flag is set, the amount of characters on that realm will be updated in the realmlist
|
||||
* @param deleteFinally if this flag is set, the config option will be ignored and the character will be permanently removed from the database
|
||||
*/
|
||||
void Player::DeleteFromDB(uint64 playerguid, uint32 accountId, bool updateRealmChars, bool deleteFinally)
|
||||
{
|
||||
// for not existed account avoid update realm
|
||||
if (accountId == 0)
|
||||
updateRealmChars = false;
|
||||
|
||||
uint32 charDelete_method = sWorld.getConfig(CONFIG_UINT32_CHARDELETE_METHOD);
|
||||
uint32 charDelete_minLvl = sWorld.getConfig(CONFIG_UINT32_CHARDELETE_MIN_LEVEL);
|
||||
|
||||
// if we want to finally delete the character or the character does not meet the level requirement, we set it to mode 0
|
||||
if (deleteFinally || Player::GetLevelFromDB(playerguid) < charDelete_minLvl)
|
||||
charDelete_method = 0;
|
||||
|
||||
uint32 guid = GUID_LOPART(playerguid);
|
||||
|
||||
// convert corpse to bones if exist (to prevent exiting Corpse in World without DB entry)
|
||||
|
|
@ -4046,20 +4069,16 @@ void Player::DeleteFromDB(uint64 playerguid, uint32 accountId, bool updateRealmC
|
|||
sObjectAccessor.ConvertCorpseForPlayer(playerguid);
|
||||
|
||||
// remove from guild
|
||||
uint32 guildId = GetGuildIdFromDB(playerguid);
|
||||
if(guildId != 0)
|
||||
{
|
||||
Guild* guild = sObjectMgr.GetGuildById(guildId);
|
||||
if(guild)
|
||||
if (uint32 guildId = GetGuildIdFromDB(playerguid))
|
||||
if (Guild* guild = sObjectMgr.GetGuildById(guildId))
|
||||
guild->DelMember(guid);
|
||||
}
|
||||
|
||||
// remove from arena teams
|
||||
LeaveAllArenaTeams(playerguid);
|
||||
|
||||
// the player was uninvited already on logout so just remove from group
|
||||
QueryResult *resultGroup = CharacterDatabase.PQuery("SELECT groupId FROM group_member WHERE memberGuid='%u'", guid);
|
||||
if(resultGroup)
|
||||
if (resultGroup)
|
||||
{
|
||||
uint32 groupId = (*resultGroup)[0].GetUInt32();
|
||||
delete resultGroup;
|
||||
|
|
@ -4070,139 +4089,191 @@ void Player::DeleteFromDB(uint64 playerguid, uint32 accountId, bool updateRealmC
|
|||
// remove signs from petitions (also remove petitions if owner);
|
||||
RemovePetitionsAndSigns(playerguid, 10);
|
||||
|
||||
// return back all mails with COD and Item 0 1 2 3 4 5 6 7
|
||||
QueryResult *resultMail = CharacterDatabase.PQuery("SELECT id,messageType,mailTemplateId,sender,subject,body,money,has_items FROM mail WHERE receiver='%u' AND has_items<>0 AND cod<>0", guid);
|
||||
if(resultMail)
|
||||
switch(charDelete_method)
|
||||
{
|
||||
do
|
||||
// completely remove from the database
|
||||
case 0:
|
||||
{
|
||||
Field *fields = resultMail->Fetch();
|
||||
|
||||
uint32 mail_id = fields[0].GetUInt32();
|
||||
uint16 mailType = fields[1].GetUInt16();
|
||||
uint16 mailTemplateId= fields[2].GetUInt16();
|
||||
uint32 sender = fields[3].GetUInt32();
|
||||
std::string subject = fields[4].GetCppString();
|
||||
std::string body = fields[5].GetCppString();
|
||||
uint32 money = fields[6].GetUInt32();
|
||||
bool has_items = fields[7].GetBool();
|
||||
|
||||
//we can return mail now
|
||||
//so firstly delete the old one
|
||||
CharacterDatabase.PExecute("DELETE FROM mail WHERE id = '%u'", mail_id);
|
||||
|
||||
// mail not from player
|
||||
if (mailType != MAIL_NORMAL)
|
||||
// return back all mails with COD and Item 0 1 2 3 4 5 6 7
|
||||
QueryResult *resultMail = CharacterDatabase.PQuery("SELECT id,messageType,mailTemplateId,sender,subject,body,money,has_items FROM mail WHERE receiver='%u' AND has_items<>0 AND cod<>0", guid);
|
||||
if (resultMail)
|
||||
{
|
||||
if(has_items)
|
||||
CharacterDatabase.PExecute("DELETE FROM mail_items WHERE mail_id = '%u'", mail_id);
|
||||
continue;
|
||||
}
|
||||
|
||||
MailDraft draft(subject, body);
|
||||
if (mailTemplateId)
|
||||
draft = MailDraft(mailTemplateId, false); // items already included
|
||||
|
||||
if(has_items)
|
||||
{
|
||||
// data needs to be at first place for Item::LoadFromDB
|
||||
// 0 1 2 3
|
||||
QueryResult *resultItems = CharacterDatabase.PQuery("SELECT data,text,item_guid,item_template FROM mail_items JOIN item_instance ON item_guid = guid WHERE mail_id='%u'", mail_id);
|
||||
if(resultItems)
|
||||
do
|
||||
{
|
||||
do
|
||||
Field *fields = resultMail->Fetch();
|
||||
|
||||
uint32 mail_id = fields[0].GetUInt32();
|
||||
uint16 mailType = fields[1].GetUInt16();
|
||||
uint16 mailTemplateId= fields[2].GetUInt16();
|
||||
uint32 sender = fields[3].GetUInt32();
|
||||
std::string subject = fields[4].GetCppString();
|
||||
std::string body = fields[5].GetCppString();
|
||||
uint32 money = fields[6].GetUInt32();
|
||||
bool has_items = fields[7].GetBool();
|
||||
|
||||
//we can return mail now
|
||||
//so firstly delete the old one
|
||||
CharacterDatabase.PExecute("DELETE FROM mail WHERE id = '%u'", mail_id);
|
||||
|
||||
// mail not from player
|
||||
if (mailType != MAIL_NORMAL)
|
||||
{
|
||||
Field *fields2 = resultItems->Fetch();
|
||||
|
||||
uint32 item_guidlow = fields2[2].GetUInt32();
|
||||
uint32 item_template = fields2[3].GetUInt32();
|
||||
|
||||
ItemPrototype const* itemProto = ObjectMgr::GetItemPrototype(item_template);
|
||||
if(!itemProto)
|
||||
{
|
||||
CharacterDatabase.PExecute("DELETE FROM item_instance WHERE guid = '%u'", item_guidlow);
|
||||
continue;
|
||||
}
|
||||
|
||||
Item *pItem = NewItemOrBag(itemProto);
|
||||
if(!pItem->LoadFromDB(item_guidlow, MAKE_NEW_GUID(guid, 0, HIGHGUID_PLAYER),resultItems))
|
||||
{
|
||||
pItem->FSetState(ITEM_REMOVED);
|
||||
pItem->SaveToDB(); // it also deletes item object !
|
||||
continue;
|
||||
}
|
||||
|
||||
draft.AddItem(pItem);
|
||||
if(has_items)
|
||||
CharacterDatabase.PExecute("DELETE FROM mail_items WHERE mail_id = '%u'", mail_id);
|
||||
continue;
|
||||
}
|
||||
while (resultItems->NextRow());
|
||||
|
||||
delete resultItems;
|
||||
MailDraft draft(subject, body);
|
||||
if (mailTemplateId)
|
||||
draft = MailDraft(mailTemplateId, false); // items already included
|
||||
|
||||
if (has_items)
|
||||
{
|
||||
// data needs to be at first place for Item::LoadFromDB
|
||||
// 0 1 2 3
|
||||
QueryResult *resultItems = CharacterDatabase.PQuery("SELECT data,text,item_guid,item_template FROM mail_items JOIN item_instance ON item_guid = guid WHERE mail_id='%u'", mail_id);
|
||||
if (resultItems)
|
||||
{
|
||||
do
|
||||
{
|
||||
Field *fields2 = resultItems->Fetch();
|
||||
|
||||
uint32 item_guidlow = fields2[2].GetUInt32();
|
||||
uint32 item_template = fields2[3].GetUInt32();
|
||||
|
||||
ItemPrototype const* itemProto = ObjectMgr::GetItemPrototype(item_template);
|
||||
if (!itemProto)
|
||||
{
|
||||
CharacterDatabase.PExecute("DELETE FROM item_instance WHERE guid = '%u'", item_guidlow);
|
||||
continue;
|
||||
}
|
||||
|
||||
Item *pItem = NewItemOrBag(itemProto);
|
||||
if (!pItem->LoadFromDB(item_guidlow, MAKE_NEW_GUID(guid, 0, HIGHGUID_PLAYER),resultItems))
|
||||
{
|
||||
pItem->FSetState(ITEM_REMOVED);
|
||||
pItem->SaveToDB(); // it also deletes item object !
|
||||
continue;
|
||||
}
|
||||
|
||||
draft.AddItem(pItem);
|
||||
}
|
||||
while (resultItems->NextRow());
|
||||
|
||||
delete resultItems;
|
||||
}
|
||||
}
|
||||
|
||||
CharacterDatabase.PExecute("DELETE FROM mail_items WHERE mail_id = '%u'", mail_id);
|
||||
|
||||
uint32 pl_account = sObjectMgr.GetPlayerAccountIdByGUID(MAKE_NEW_GUID(guid, 0, HIGHGUID_PLAYER));
|
||||
|
||||
draft.AddMoney(money).SendReturnToSender(pl_account, guid, sender);
|
||||
}
|
||||
while (resultMail->NextRow());
|
||||
|
||||
delete resultMail;
|
||||
}
|
||||
|
||||
CharacterDatabase.PExecute("DELETE FROM mail_items WHERE mail_id = '%u'", mail_id);
|
||||
// unsummon and delete for pets in world is not required: player deleted from CLI or character list with not loaded pet.
|
||||
// Get guids of character's pets, will deleted in transaction
|
||||
QueryResult *resultPets = CharacterDatabase.PQuery("SELECT id FROM character_pet WHERE owner = '%u'",guid);
|
||||
|
||||
uint32 pl_account = sObjectMgr.GetPlayerAccountIdByGUID(MAKE_NEW_GUID(guid, 0, HIGHGUID_PLAYER));
|
||||
// NOW we can finally clear other DB data related to character
|
||||
CharacterDatabase.BeginTransaction();
|
||||
if (resultPets)
|
||||
{
|
||||
do
|
||||
{
|
||||
Field *fields3 = resultPets->Fetch();
|
||||
uint32 petguidlow = fields3[0].GetUInt32();
|
||||
Pet::DeleteFromDB(petguidlow);
|
||||
} while (resultPets->NextRow());
|
||||
delete resultPets;
|
||||
}
|
||||
|
||||
draft.AddMoney(money).SendReturnToSender(pl_account, guid, sender);
|
||||
CharacterDatabase.PExecute("DELETE FROM characters WHERE guid = '%u'",guid);
|
||||
CharacterDatabase.PExecute("DELETE FROM character_account_data WHERE guid = '%u'",guid);
|
||||
CharacterDatabase.PExecute("DELETE FROM character_declinedname WHERE guid = '%u'",guid);
|
||||
CharacterDatabase.PExecute("DELETE FROM character_action WHERE guid = '%u'",guid);
|
||||
CharacterDatabase.PExecute("DELETE FROM character_aura WHERE guid = '%u'",guid);
|
||||
CharacterDatabase.PExecute("DELETE FROM character_gifts WHERE guid = '%u'",guid);
|
||||
CharacterDatabase.PExecute("DELETE FROM character_glyphs WHERE guid = '%u'",guid);
|
||||
CharacterDatabase.PExecute("DELETE FROM character_homebind WHERE guid = '%u'",guid);
|
||||
CharacterDatabase.PExecute("DELETE FROM character_instance WHERE guid = '%u'",guid);
|
||||
CharacterDatabase.PExecute("DELETE FROM group_instance WHERE leaderGuid = '%u'",guid);
|
||||
CharacterDatabase.PExecute("DELETE FROM character_inventory WHERE guid = '%u'",guid);
|
||||
CharacterDatabase.PExecute("DELETE FROM character_queststatus WHERE guid = '%u'",guid);
|
||||
CharacterDatabase.PExecute("DELETE FROM character_queststatus_daily WHERE guid = '%u'",guid);
|
||||
CharacterDatabase.PExecute("DELETE FROM character_queststatus_weekly WHERE guid = '%u'",guid);
|
||||
CharacterDatabase.PExecute("DELETE FROM character_reputation WHERE guid = '%u'",guid);
|
||||
CharacterDatabase.PExecute("DELETE FROM character_skills WHERE guid = '%u'",guid);
|
||||
CharacterDatabase.PExecute("DELETE FROM character_spell WHERE guid = '%u'",guid);
|
||||
CharacterDatabase.PExecute("DELETE FROM character_spell_cooldown WHERE guid = '%u'",guid);
|
||||
CharacterDatabase.PExecute("DELETE FROM character_talent WHERE guid = '%u'",guid);
|
||||
CharacterDatabase.PExecute("DELETE FROM character_ticket WHERE guid = '%u'",guid);
|
||||
CharacterDatabase.PExecute("DELETE FROM item_instance WHERE owner_guid = '%u'",guid);
|
||||
CharacterDatabase.PExecute("DELETE FROM character_social WHERE guid = '%u' OR friend='%u'",guid,guid);
|
||||
CharacterDatabase.PExecute("DELETE FROM mail WHERE receiver = '%u'",guid);
|
||||
CharacterDatabase.PExecute("DELETE FROM mail_items WHERE receiver = '%u'",guid);
|
||||
CharacterDatabase.PExecute("DELETE FROM character_pet WHERE owner = '%u'",guid);
|
||||
CharacterDatabase.PExecute("DELETE FROM character_pet_declinedname WHERE owner = '%u'",guid);
|
||||
CharacterDatabase.PExecute("DELETE FROM character_achievement WHERE guid = '%u'",guid);
|
||||
CharacterDatabase.PExecute("DELETE FROM character_achievement_progress WHERE guid = '%u'",guid);
|
||||
CharacterDatabase.PExecute("DELETE FROM character_equipmentsets WHERE guid = '%u'",guid);
|
||||
CharacterDatabase.PExecute("DELETE FROM guild_eventlog WHERE PlayerGuid1 = '%u' OR PlayerGuid2 = '%u'",guid, guid);
|
||||
CharacterDatabase.PExecute("DELETE FROM guild_bank_eventlog WHERE PlayerGuid = '%u'",guid);
|
||||
CharacterDatabase.CommitTransaction();
|
||||
break;
|
||||
}
|
||||
while (resultMail->NextRow());
|
||||
|
||||
delete resultMail;
|
||||
// The character gets unlinked from the account, the name gets freed up and appears as deleted ingame
|
||||
case 1:
|
||||
CharacterDatabase.PExecute("UPDATE characters SET deleteInfos_Name=name, deleteInfos_Account=account, deleteDate=%u, name='', account=0 WHERE guid=%u", uint64(time(NULL)), guid);
|
||||
break;
|
||||
default:
|
||||
sLog.outError("Player::DeleteFromDB: Unsupported delete method: %u.", charDelete_method);
|
||||
}
|
||||
|
||||
// unsummon and delete for pets in world is not required: player deleted from CLI or character list with not loaded pet.
|
||||
// Get guids of character's pets, will deleted in transaction
|
||||
QueryResult *resultPets = CharacterDatabase.PQuery("SELECT id FROM character_pet WHERE owner = '%u'",guid);
|
||||
if (updateRealmChars)
|
||||
sWorld.UpdateRealmCharCount(accountId);
|
||||
}
|
||||
|
||||
// NOW we can finally clear other DB data related to character
|
||||
CharacterDatabase.BeginTransaction();
|
||||
if (resultPets)
|
||||
/**
|
||||
* Characters which were kept back in the database after being deleted and are now too old (see config option "CharDelete.KeepDays"), will be completely deleted.
|
||||
*
|
||||
* @see Player::DeleteFromDB
|
||||
*/
|
||||
void Player::DeleteOldCharacters()
|
||||
{
|
||||
uint32 keepDays = sWorld.getConfig(CONFIG_UINT32_CHARDELETE_KEEP_DAYS);
|
||||
if (!keepDays)
|
||||
return;
|
||||
|
||||
Player::DeleteOldCharacters(keepDays);
|
||||
}
|
||||
|
||||
/**
|
||||
* Characters which were kept back in the database after being deleted and are older than the specified amount of days, will be completely deleted.
|
||||
*
|
||||
* @see Player::DeleteFromDB
|
||||
*
|
||||
* @param keepDays overrite the config option by another amount of days
|
||||
*/
|
||||
void Player::DeleteOldCharacters(uint32 keepDays)
|
||||
{
|
||||
sLog.outString("Player::DeleteOldChars: Deleting all characters which have been deleted %u days before...", keepDays);
|
||||
|
||||
QueryResult *resultChars = CharacterDatabase.PQuery("SELECT guid, deleteInfos_Account FROM characters WHERE deleteDate IS NOT NULL AND deleteDate < %u", uint64(time(NULL) - time_t(keepDays * DAY)));
|
||||
if (resultChars)
|
||||
{
|
||||
sLog.outString("Player::DeleteOldChars: Found %u character(s) to delete",resultChars->GetRowCount());
|
||||
do
|
||||
{
|
||||
Field *fields3 = resultPets->Fetch();
|
||||
uint32 petguidlow = fields3[0].GetUInt32();
|
||||
Pet::DeleteFromDB(petguidlow);
|
||||
} while (resultPets->NextRow());
|
||||
delete resultPets;
|
||||
Field *charFields = resultChars->Fetch();
|
||||
Player::DeleteFromDB(charFields[0].GetUInt64(), charFields[1].GetUInt32(), true, true);
|
||||
} while(resultChars->NextRow());
|
||||
delete resultChars;
|
||||
}
|
||||
|
||||
CharacterDatabase.PExecute("DELETE FROM characters WHERE guid = '%u'",guid);
|
||||
CharacterDatabase.PExecute("DELETE FROM character_account_data WHERE guid = '%u'",guid);
|
||||
CharacterDatabase.PExecute("DELETE FROM character_declinedname WHERE guid = '%u'",guid);
|
||||
CharacterDatabase.PExecute("DELETE FROM character_action WHERE guid = '%u'",guid);
|
||||
CharacterDatabase.PExecute("DELETE FROM character_aura WHERE guid = '%u'",guid);
|
||||
CharacterDatabase.PExecute("DELETE FROM character_gifts WHERE guid = '%u'",guid);
|
||||
CharacterDatabase.PExecute("DELETE FROM character_glyphs WHERE guid = '%u'",guid);
|
||||
CharacterDatabase.PExecute("DELETE FROM character_homebind WHERE guid = '%u'",guid);
|
||||
CharacterDatabase.PExecute("DELETE FROM character_instance WHERE guid = '%u'",guid);
|
||||
CharacterDatabase.PExecute("DELETE FROM group_instance WHERE leaderGuid = '%u'",guid);
|
||||
CharacterDatabase.PExecute("DELETE FROM character_inventory WHERE guid = '%u'",guid);
|
||||
CharacterDatabase.PExecute("DELETE FROM character_queststatus WHERE guid = '%u'",guid);
|
||||
CharacterDatabase.PExecute("DELETE FROM character_queststatus_daily WHERE guid = '%u'",guid);
|
||||
CharacterDatabase.PExecute("DELETE FROM character_queststatus_weekly WHERE guid = '%u'",guid);
|
||||
CharacterDatabase.PExecute("DELETE FROM character_reputation WHERE guid = '%u'",guid);
|
||||
CharacterDatabase.PExecute("DELETE FROM character_skills WHERE guid = '%u'",guid);
|
||||
CharacterDatabase.PExecute("DELETE FROM character_spell WHERE guid = '%u'",guid);
|
||||
CharacterDatabase.PExecute("DELETE FROM character_spell_cooldown WHERE guid = '%u'",guid);
|
||||
CharacterDatabase.PExecute("DELETE FROM character_talent WHERE guid = '%u'",guid);
|
||||
CharacterDatabase.PExecute("DELETE FROM character_ticket WHERE guid = '%u'",guid);
|
||||
CharacterDatabase.PExecute("DELETE FROM item_instance WHERE owner_guid = '%u'",guid);
|
||||
CharacterDatabase.PExecute("DELETE FROM character_social WHERE guid = '%u' OR friend='%u'",guid,guid);
|
||||
CharacterDatabase.PExecute("DELETE FROM mail WHERE receiver = '%u'",guid);
|
||||
CharacterDatabase.PExecute("DELETE FROM mail_items WHERE receiver = '%u'",guid);
|
||||
CharacterDatabase.PExecute("DELETE FROM character_pet WHERE owner = '%u'",guid);
|
||||
CharacterDatabase.PExecute("DELETE FROM character_pet_declinedname WHERE owner = '%u'",guid);
|
||||
CharacterDatabase.PExecute("DELETE FROM character_achievement WHERE guid = '%u'",guid);
|
||||
CharacterDatabase.PExecute("DELETE FROM character_achievement_progress WHERE guid = '%u'",guid);
|
||||
CharacterDatabase.PExecute("DELETE FROM character_equipmentsets WHERE guid = '%u'",guid);
|
||||
CharacterDatabase.PExecute("DELETE FROM guild_eventlog WHERE PlayerGuid1 = '%u' OR PlayerGuid2 = '%u'",guid, guid);
|
||||
CharacterDatabase.PExecute("DELETE FROM guild_bank_eventlog WHERE PlayerGuid = '%u'",guid);
|
||||
CharacterDatabase.CommitTransaction();
|
||||
|
||||
//loginDatabase.PExecute("UPDATE realmcharacters SET numchars = numchars - 1 WHERE acctid = %d AND realmid = %d", accountId, realmID);
|
||||
if(updateRealmChars) sWorld.UpdateRealmCharCount(accountId);
|
||||
}
|
||||
|
||||
void Player::SetMovement(PlayerMovementType pType)
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue