Core: Added some anti-WPE filter checks to prevent putting non-empty bags into other bags/gbank/mail/auction, original patch from mythcore

Core: Changed inventory saving - will no longer abort operation at single item fail

Closes issue #1994.

--HG--
branch : trunk
This commit is contained in:
Shauren
2010-10-09 17:36:53 +02:00
parent a20dd32de0
commit 324de6fb4c
4 changed files with 61 additions and 32 deletions
+42 -32
View File
@@ -10039,6 +10039,9 @@ uint8 Player::_CanStoreItem_InSpecificSlot(uint8 bag, uint8 slot, ItemPosCountVe
uint32 need_space;
if (pSrcItem && pSrcItem->IsBag() && !((Bag*)pSrcItem)->IsEmpty() && !IsBagPos(uint16(bag) << 8 | slot))
return EQUIP_ERR_CAN_ONLY_DO_WITH_EMPTY_BAGS;
// empty specific slot - check item fit to slot
if (!pItem2 || swap)
{
@@ -10111,6 +10114,9 @@ uint8 Player::_CanStoreItem_InBag(uint8 bag, ItemPosCountVec &dest, ItemPrototyp
if (!pBag || pBag == pSrcItem)
return EQUIP_ERR_ITEM_DOESNT_GO_INTO_BAG;
if (pSrcItem && pSrcItem->IsBag() && !((Bag*)pSrcItem)->IsEmpty())
return EQUIP_ERR_CAN_ONLY_DO_WITH_EMPTY_BAGS;
ItemPrototype const* pBagProto = pBag->GetProto();
if (!pBagProto)
return EQUIP_ERR_ITEM_DOESNT_GO_INTO_BAG;
@@ -10169,6 +10175,10 @@ uint8 Player::_CanStoreItem_InBag(uint8 bag, ItemPosCountVec &dest, ItemPrototyp
uint8 Player::_CanStoreItem_InInventorySlots(uint8 slot_begin, uint8 slot_end, ItemPosCountVec &dest, ItemPrototype const *pProto, uint32& count, bool merge, Item* pSrcItem, uint8 skip_bag, uint8 skip_slot) const
{
//this is never called for non-bag slots so we can do this
if (pSrcItem && pSrcItem->IsBag() && !((Bag*)pSrcItem)->IsEmpty())
return EQUIP_ERR_CAN_ONLY_DO_WITH_EMPTY_BAGS;
for (uint32 j = slot_begin; j < slot_end; j++)
{
// skip specific slot already processed in first called _CanStoreItem_InSpecificSlot
@@ -18056,52 +18066,52 @@ void Player::_SaveInventory(SQLTransaction& trans)
if (m_itemUpdateQueue.empty())
return;
// do not save if the update queue is corrupt
bool error = false;
uint32 lowGuid = GetGUIDLow();
for (size_t i = 0; i < m_itemUpdateQueue.size(); ++i)
{
Item *item = m_itemUpdateQueue[i];
if (!item || item->GetState() == ITEM_REMOVED)
if (!item)
continue;
Item *test = GetItemByPos(item->GetBagSlot(), item->GetSlot());
if (test == NULL)
{
sLog.outCrash("Player(GUID: %u Name: %s)::_SaveInventory - the bag(%d) and slot(%d) values for the item with guid %d (state %d) are incorrect, the player doesn't have an item at that position!", GetGUIDLow(), GetName(), item->GetBagSlot(), item->GetSlot(), item->GetGUIDLow(), (int32)item->GetState());
//error = true;
//Should the above line really be commented out?
}
else if (test != item)
{
sLog.outError("Player(GUID: %u Name: %s)::_SaveInventory - the bag(%d) and slot(%d) values for the item with guid %d are incorrect, the item with guid %d is there instead!", GetGUIDLow(), GetName(), item->GetBagSlot(), item->GetSlot(), item->GetGUIDLow(), test->GetGUIDLow());
error = true;
}
}
if (error)
{
sLog.outError("Player::_SaveInventory - one or more errors occurred save aborted!");
ChatHandler(this).SendSysMessage(LANG_ITEM_SAVE_FAILED);
return;
}
for (size_t i = 0; i < m_itemUpdateQueue.size(); i++)
{
Item *item = m_itemUpdateQueue[i];
if (!item) continue;
Bag *container = item->GetContainer();
uint32 bag_guid = container ? container->GetGUIDLow() : 0;
if (item->GetState() != ITEM_REMOVED)
{
Item *test = GetItemByPos(item->GetBagSlot(), item->GetSlot());
if (test == NULL)
{
uint32 bagTestGUID = 0;
if (Item* test2 = GetItemByPos(INVENTORY_SLOT_BAG_0, item->GetBagSlot()))
bagTestGUID = test2->GetGUIDLow();
sLog.outError("Player(GUID: %u Name: %s)::_SaveInventory - the bag(%u) and slot(%u) values for the item with guid %u (state %d) are incorrect, the player doesn't have an item at that position!", lowGuid, GetName(), item->GetBagSlot(), item->GetSlot(), item->GetGUIDLow(), (int32)item->GetState());
// according to the test that was just performed nothing should be in this slot, delete
trans->PAppend("DELETE FROM character_inventory WHERE bag=%u AND slot=%u", bagTestGUID, item->GetSlot());
// also THIS item should be somewhere else, cheat attempt
item->FSetState(ITEM_REMOVED); // we are IN updateQueue right now, can't use SetState which modifies the queue
DeleteRefundReference(item->GetGUIDLow());
// don't skip, let the switch delete it
//continue;
}
else if (test != item)
{
sLog.outError("Player(GUID: %u Name: %s)::_SaveInventory - the bag(%u) and slot(%u) values for the item with guid %u are incorrect, the item with guid %u is there instead!", lowGuid, GetName(), item->GetBagSlot(), item->GetSlot(), item->GetGUIDLow(), test->GetGUIDLow());
// save all changes to the item...
if (item->GetState() != ITEM_NEW) // only for existing items, no dupes
item->SaveToDB(trans);
// ...but do not save position in invntory
continue;
}
}
switch (item->GetState())
{
case ITEM_NEW:
trans->PAppend("INSERT INTO character_inventory (guid,bag,slot,item,item_template) VALUES ('%u', '%u', '%u', '%u', '%u')", GetGUIDLow(), bag_guid, item->GetSlot(), item->GetGUIDLow(), item->GetEntry());
trans->PAppend("INSERT INTO character_inventory (guid,bag,slot,item,item_template) VALUES ('%u', '%u', '%u', '%u', '%u')", lowGuid, bag_guid, item->GetSlot(), item->GetGUIDLow(), item->GetEntry());
break;
case ITEM_CHANGED:
trans->PAppend("DELETE FROM character_inventory WHERE item = '%u'", item->GetGUIDLow());
trans->PAppend("INSERT INTO character_inventory (guid,bag,slot,item,item_template) VALUES ('%u', '%u', '%u', '%u', '%u')", GetGUIDLow(), bag_guid, item->GetSlot(), item->GetGUIDLow(), item->GetEntry());
trans->PAppend("INSERT INTO character_inventory (guid,bag,slot,item,item_template) VALUES ('%u', '%u', '%u', '%u', '%u')", lowGuid, bag_guid, item->GetSlot(), item->GetGUIDLow(), item->GetEntry());
break;
case ITEM_REMOVED:
trans->PAppend("DELETE FROM character_inventory WHERE item = '%u'", item->GetGUIDLow());
+7
View File
@@ -1977,6 +1977,13 @@ void Guild::MoveFromCharToBank(Player * pl, uint8 PlayerBag, uint8 PlayerSlot, u
if (!pItemChar) // Problem to get item from player
return;
// prevent storing non-empty bags
if (pItemChar && pItemChar->IsBag() && !((Bag*)pItemChar)->IsEmpty())
{
pl->SendEquipError(EQUIP_ERR_CAN_ONLY_DO_WITH_EMPTY_BAGS, pItemChar, NULL);
return;
}
if (!pItemChar->CanBeTraded())
{
pl->SendEquipError(EQUIP_ERR_ITEMS_CANT_BE_SWAPPED, pItemChar, NULL);
@@ -192,6 +192,12 @@ void WorldSession::HandleAuctionSellItem(WorldPacket & recv_data)
return;
}
if (it->IsBag() && !((Bag*)it)->IsEmpty())
{
SendAuctionCommandResult(0, AUCTION_SELL_ITEM, AUCTION_INTERNAL_ERROR);
return;
}
AuctionHouseObject* auctionHouse = sAuctionMgr.GetAuctionsMap(pCreature->getFaction());
//we have to take deposit :
@@ -219,6 +219,12 @@ void WorldSession::HandleSendMail(WorldPacket & recv_data)
return;
}
if (item->IsBag() && !((Bag*)item)->IsEmpty())
{
pl->SendMailResult(0, MAIL_SEND, MAIL_ERR_EQUIP_ERROR, EQUIP_ERR_CAN_ONLY_DO_WITH_EMPTY_BAGS);
return;
}
items[i] = item;
}