feat(Core/Commands): allow .additem to remove items from offline players (#26714)
This commit is contained in:
parent
f89fe30551
commit
766607448f
3 changed files with 112 additions and 18 deletions
|
|
@ -140,6 +140,7 @@ void CharacterDatabaseConnection::DoPrepareStatements()
|
|||
PrepareStatement(CHAR_REP_ITEM_INSTANCE, "REPLACE INTO item_instance (itemEntry, owner_guid, creatorGuid, giftCreatorGuid, count, duration, charges, flags, enchantments, randomPropertyId, durability, playedTime, text, guid) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)", CONNECTION_ASYNC);
|
||||
PrepareStatement(CHAR_UPD_ITEM_INSTANCE, "UPDATE item_instance SET itemEntry = ?, owner_guid = ?, creatorGuid = ?, giftCreatorGuid = ?, count = ?, duration = ?, charges = ?, flags = ?, enchantments = ?, randomPropertyId = ?, durability = ?, playedTime = ?, text = ? WHERE guid = ?", CONNECTION_ASYNC);
|
||||
PrepareStatement(CHAR_UPD_ITEM_INSTANCE_ON_LOAD, "UPDATE item_instance SET duration = ?, flags = ?, durability = ? WHERE guid = ?", CONNECTION_ASYNC);
|
||||
PrepareStatement(CHAR_UPD_ITEM_COUNT, "UPDATE item_instance SET count = ? WHERE guid = ?", CONNECTION_ASYNC);
|
||||
PrepareStatement(CHAR_DEL_ITEM_INSTANCE, "DELETE FROM item_instance WHERE guid = ?", CONNECTION_ASYNC);
|
||||
PrepareStatement(CHAR_DEL_ITEM_INSTANCE_BY_OWNER, "DELETE FROM item_instance WHERE owner_guid = ?", CONNECTION_ASYNC);
|
||||
PrepareStatement(CHAR_UPD_GIFT_OWNER, "UPDATE character_gifts SET guid = ? WHERE item_guid = ?", CONNECTION_ASYNC);
|
||||
|
|
@ -436,6 +437,8 @@ void CharacterDatabaseConnection::DoPrepareStatements()
|
|||
"INNER JOIN item_instance ii ON ii.guid = ci.item "
|
||||
"LEFT JOIN character_inventory cb ON cb.item = ci.bag WHERE ii.itemEntry = ? LIMIT ?", CONNECTION_SYNCH);
|
||||
PrepareStatement(CHAR_SEL_CHAR_INVENTORY_ITEM_BY_ENTRY_AND_OWNER, "SELECT ci.item FROM character_inventory ci INNER JOIN item_instance ii ON ii.guid = ci.item WHERE ii.itemEntry = ? AND ii.owner_guid = ?", CONNECTION_SYNCH);
|
||||
PrepareStatement(CHAR_SEL_CHAR_INVENTORY_STACKS_BY_ENTRY_AND_OWNER, "SELECT ci.item, ii.count FROM character_inventory ci INNER JOIN item_instance ii ON ii.guid = ci.item "
|
||||
"LEFT JOIN character_inventory cb ON cb.bag = ci.item WHERE ii.itemEntry = ? AND ii.owner_guid = ? AND cb.item IS NULL", CONNECTION_SYNCH);
|
||||
PrepareStatement(CHAR_SEL_MAIL_ITEMS_BY_ENTRY, "SELECT mi.item_guid, m.sender, m.receiver, cs.account, cs.name, cr.account, cr.name "
|
||||
"FROM mail m INNER JOIN mail_items mi ON mi.mail_id = m.id INNER JOIN item_instance ii ON ii.guid = mi.item_guid "
|
||||
"INNER JOIN characters cs ON cs.guid = m.sender INNER JOIN characters cr ON cr.guid = m.receiver WHERE ii.itemEntry = ? LIMIT ?", CONNECTION_SYNCH);
|
||||
|
|
|
|||
|
|
@ -124,6 +124,7 @@ enum CharacterDatabaseStatements : uint32
|
|||
CHAR_REP_ITEM_INSTANCE,
|
||||
CHAR_UPD_ITEM_INSTANCE,
|
||||
CHAR_UPD_ITEM_INSTANCE_ON_LOAD,
|
||||
CHAR_UPD_ITEM_COUNT,
|
||||
CHAR_DEL_ITEM_INSTANCE,
|
||||
CHAR_DEL_ITEM_INSTANCE_BY_OWNER,
|
||||
CHAR_UPD_GIFT_OWNER,
|
||||
|
|
@ -361,6 +362,7 @@ enum CharacterDatabaseStatements : uint32
|
|||
CHAR_SEL_GUILD_BANK_COUNT_ITEM,
|
||||
CHAR_SEL_CHAR_INVENTORY_ITEM_BY_ENTRY,
|
||||
CHAR_SEL_CHAR_INVENTORY_ITEM_BY_ENTRY_AND_OWNER,
|
||||
CHAR_SEL_CHAR_INVENTORY_STACKS_BY_ENTRY_AND_OWNER,
|
||||
CHAR_SEL_MAIL_ITEMS_BY_ENTRY,
|
||||
CHAR_SEL_AUCTIONHOUSE_ITEM_BY_ENTRY,
|
||||
CHAR_SEL_GUILD_BANK_ITEM_BY_ENTRY,
|
||||
|
|
|
|||
|
|
@ -1746,36 +1746,125 @@ public:
|
|||
|
||||
Player* playerTarget = player->GetConnectedPlayer();
|
||||
|
||||
if (!playerTarget)
|
||||
return false;
|
||||
|
||||
// Subtract
|
||||
if (count < 0)
|
||||
{
|
||||
// Only have scam check on player accounts
|
||||
if (playerTarget->GetSession()->GetSecurity() == SEC_PLAYER)
|
||||
uint32 removeCount = uint32(-count);
|
||||
|
||||
if (playerTarget)
|
||||
{
|
||||
if (!playerTarget->HasItemCount(itemId, 0))
|
||||
// Only have scam check on player accounts
|
||||
if (playerTarget->GetSession()->GetSecurity() == SEC_PLAYER)
|
||||
{
|
||||
// output that player don't have any items to destroy
|
||||
handler->SendErrorMessage(LANG_REMOVEITEM_FAILURE, handler->GetNameLink(playerTarget), itemId);
|
||||
return false;
|
||||
if (!playerTarget->HasItemCount(itemId, 0))
|
||||
{
|
||||
// output that player don't have any items to destroy
|
||||
handler->SendErrorMessage(LANG_REMOVEITEM_FAILURE, handler->GetNameLink(playerTarget), itemId);
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!playerTarget->HasItemCount(itemId, removeCount))
|
||||
{
|
||||
// output that player don't have as many items that you want to destroy
|
||||
handler->SendErrorMessage(LANG_REMOVEITEM_ERROR, handler->GetNameLink(playerTarget), itemId);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
if (!playerTarget->HasItemCount(itemId, -count))
|
||||
{
|
||||
// output that player don't have as many items that you want to destroy
|
||||
handler->SendErrorMessage(LANG_REMOVEITEM_ERROR, handler->GetNameLink(playerTarget), itemId);
|
||||
return false;
|
||||
}
|
||||
// output successful amount of destroyed items
|
||||
playerTarget->DestroyItemCount(itemId, removeCount, true, false);
|
||||
handler->PSendSysMessage(LANG_REMOVEITEM, itemId, removeCount, handler->GetNameLink(playerTarget));
|
||||
return true;
|
||||
}
|
||||
|
||||
// output successful amount of destroyed items
|
||||
playerTarget->DestroyItemCount(itemId, -count, true, false);
|
||||
handler->PSendSysMessage(LANG_REMOVEITEM, itemId, -count, handler->GetNameLink(playerTarget));
|
||||
// offline target: remove the items directly from the DB
|
||||
if (handler->HasLowerSecurity(nullptr, player->GetGUID()))
|
||||
return false;
|
||||
|
||||
std::string nameLink = handler->playerLink(player->GetName());
|
||||
|
||||
CharacterDatabasePreparedStatement* stmt = CharacterDatabase.GetPreparedStatement(CHAR_SEL_CHAR_INVENTORY_STACKS_BY_ENTRY_AND_OWNER);
|
||||
stmt->SetData(0, itemId);
|
||||
stmt->SetData(1, player->GetGUID().GetCounter());
|
||||
PreparedQueryResult result = CharacterDatabase.Query(stmt);
|
||||
|
||||
std::vector<std::pair<ObjectGuid::LowType, uint32>> stacks;
|
||||
uint32 totalCount = 0;
|
||||
if (result)
|
||||
{
|
||||
do
|
||||
{
|
||||
Field* fields = result->Fetch();
|
||||
stacks.emplace_back(fields[0].Get<uint32>(), fields[1].Get<uint32>());
|
||||
totalCount += fields[1].Get<uint32>();
|
||||
} while (result->NextRow());
|
||||
}
|
||||
|
||||
if (!totalCount)
|
||||
{
|
||||
handler->SendErrorMessage(LANG_REMOVEITEM_FAILURE, nameLink, itemId);
|
||||
return false;
|
||||
}
|
||||
|
||||
// Only have scam check on player accounts
|
||||
uint32 accountId = sCharacterCache->GetCharacterAccountIdByGuid(player->GetGUID());
|
||||
if (AccountMgr::GetSecurity(accountId, realm.Id.Realm) == SEC_PLAYER && totalCount < removeCount)
|
||||
{
|
||||
handler->SendErrorMessage(LANG_REMOVEITEM_ERROR, nameLink, itemId);
|
||||
return false;
|
||||
}
|
||||
|
||||
CharacterDatabaseTransaction trans = CharacterDatabase.BeginTransaction();
|
||||
uint32 remaining = removeCount;
|
||||
for (auto const& [itemGuid, stackCount] : stacks)
|
||||
{
|
||||
if (!remaining)
|
||||
break;
|
||||
|
||||
if (stackCount <= remaining)
|
||||
{
|
||||
remaining -= stackCount;
|
||||
Item::DeleteFromInventoryDB(trans, itemGuid);
|
||||
Item::DeleteFromDB(trans, itemGuid);
|
||||
|
||||
stmt = CharacterDatabase.GetPreparedStatement(CHAR_DEL_GIFT);
|
||||
stmt->SetData(0, itemGuid);
|
||||
trans->Append(stmt);
|
||||
|
||||
stmt = CharacterDatabase.GetPreparedStatement(CHAR_DEL_ITEM_REFUND_INSTANCE);
|
||||
stmt->SetData(0, itemGuid);
|
||||
trans->Append(stmt);
|
||||
|
||||
stmt = CharacterDatabase.GetPreparedStatement(CHAR_DEL_ITEM_BOP_TRADE);
|
||||
stmt->SetData(0, itemGuid);
|
||||
trans->Append(stmt);
|
||||
|
||||
stmt = CharacterDatabase.GetPreparedStatement(CHAR_DEL_ITEMCONTAINER_CONTAINER);
|
||||
stmt->SetData(0, itemGuid);
|
||||
trans->Append(stmt);
|
||||
}
|
||||
else
|
||||
{
|
||||
stmt = CharacterDatabase.GetPreparedStatement(CHAR_UPD_ITEM_COUNT);
|
||||
stmt->SetData(0, stackCount - remaining);
|
||||
stmt->SetData(1, itemGuid);
|
||||
trans->Append(stmt);
|
||||
remaining = 0;
|
||||
}
|
||||
}
|
||||
CharacterDatabase.CommitTransaction(trans);
|
||||
|
||||
handler->PSendSysMessage(LANG_REMOVEITEM, itemId, removeCount - remaining, nameLink);
|
||||
return true;
|
||||
}
|
||||
|
||||
// Adding items requires the target to be online
|
||||
if (!playerTarget)
|
||||
{
|
||||
handler->SendErrorMessage(LANG_PLAYER_NOT_FOUND);
|
||||
return false;
|
||||
}
|
||||
|
||||
// Adding items
|
||||
uint32 noSpaceForCount = 0;
|
||||
|
||||
|
|
|
|||
Loading…
Reference in a new issue