mirror of
https://github.com/TrinityCore/TrinityCore.git
synced 2026-01-28 04:42:10 +01:00
[Exploit/Dupe] Container item (#26689)
* Core/Item: Fixed possible dupe with container items containing non unique non stackable items
* Fixed build
* Update sql script and related base structure
Co-authored-by: jackpoz <giacomopoz@gmail.com>
(cherry picked from commit d1e913162e)
This commit is contained in:
@@ -2979,6 +2979,7 @@ CREATE TABLE `item_loot_items` (
|
||||
`container_id` bigint unsigned NOT NULL DEFAULT '0' COMMENT 'guid of container (item_instance.guid)',
|
||||
`item_id` int unsigned NOT NULL DEFAULT '0' COMMENT 'loot item entry (item_instance.itemEntry)',
|
||||
`item_count` int NOT NULL DEFAULT '0' COMMENT 'stack size',
|
||||
`item_index` int(10) unsigned NOT NULL DEFAULT '0',
|
||||
`follow_rules` tinyint(1) NOT NULL DEFAULT '0' COMMENT 'follow loot rules',
|
||||
`ffa` tinyint(1) NOT NULL DEFAULT '0' COMMENT 'free-for-all',
|
||||
`blocked` tinyint(1) NOT NULL DEFAULT '0',
|
||||
@@ -3665,7 +3666,8 @@ INSERT INTO `updates` VALUES
|
||||
('2022_01_31_01_characters.sql','E0A1FA670F4621AEB594D7ACBA4921CB298F54FF','ARCHIVED','2022-01-31 20:47:59',0),
|
||||
('2022_01_31_02_characters.sql','6E3A3F02276287DD540BC4C17E246DFB850260D8','ARCHIVED','2022-01-31 21:43:38',0),
|
||||
('2022_02_28_00_characters_2020_09_27_00_characters.sql','2292A1ED0E7F46DEC41384F75FA6D9461464EEB8','ARCHIVED','2022-02-28 12:43:58',0),
|
||||
('2022_03_06_00_characters.sql','474AAF9D03E6A56017899C968DC9875368301934','ARCHIVED','2022-03-06 15:12:24',0);
|
||||
('2022_03_06_00_characters.sql','474AAF9D03E6A56017899C968DC9875368301934','ARCHIVED','2022-03-06 15:12:24',0),
|
||||
('2022_03_11_00_characters_2021_07_18_00_characters.sql','0BA579ED21F4E75AC2B4797421B5029568B3F6E2','RELEASED','2022-03-11 18:56:07',0);
|
||||
/*!40000 ALTER TABLE `updates` ENABLE KEYS */;
|
||||
UNLOCK TABLES;
|
||||
|
||||
|
||||
@@ -0,0 +1,2 @@
|
||||
--
|
||||
ALTER TABLE `item_loot_items` ADD COLUMN `item_index` int(10) unsigned NOT NULL DEFAULT '0' AFTER `item_count`;
|
||||
@@ -689,10 +689,10 @@ void CharacterDatabaseConnection::DoPrepareStatements()
|
||||
PrepareStatement(CHAR_DEL_CHAR_CUF_PROFILES, "DELETE FROM character_cuf_profiles WHERE guid = ?", CONNECTION_ASYNC);
|
||||
|
||||
// Items that hold loot or money
|
||||
PrepareStatement(CHAR_SEL_ITEMCONTAINER_ITEMS, "SELECT container_id, item_id, item_count, follow_rules, ffa, blocked, counted, under_threshold, needs_quest, rnd_bonus, context, bonus_list_ids FROM item_loot_items", CONNECTION_SYNCH);
|
||||
PrepareStatement(CHAR_SEL_ITEMCONTAINER_ITEMS, "SELECT container_id, item_id, item_count, item_index, follow_rules, ffa, blocked, counted, under_threshold, needs_quest, rnd_bonus, context, bonus_list_ids FROM item_loot_items", CONNECTION_SYNCH);
|
||||
PrepareStatement(CHAR_DEL_ITEMCONTAINER_ITEMS, "DELETE FROM item_loot_items WHERE container_id = ?", CONNECTION_ASYNC);
|
||||
PrepareStatement(CHAR_DEL_ITEMCONTAINER_ITEM, "DELETE FROM item_loot_items WHERE container_id = ? AND item_id = ? AND item_count = ?", CONNECTION_ASYNC);
|
||||
PrepareStatement(CHAR_INS_ITEMCONTAINER_ITEMS, "INSERT INTO item_loot_items (container_id, item_id, item_count, follow_rules, ffa, blocked, counted, under_threshold, needs_quest, rnd_bonus, context, bonus_list_ids) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)", CONNECTION_ASYNC);
|
||||
PrepareStatement(CHAR_DEL_ITEMCONTAINER_ITEM, "DELETE FROM item_loot_items WHERE container_id = ? AND item_id = ? AND item_count = ? AND item_index = ?", CONNECTION_ASYNC);
|
||||
PrepareStatement(CHAR_INS_ITEMCONTAINER_ITEMS, "INSERT INTO item_loot_items (container_id, item_id, item_count, item_index, follow_rules, ffa, blocked, counted, under_threshold, needs_quest, rnd_bonus, context, bonus_list_ids) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)", CONNECTION_ASYNC);
|
||||
PrepareStatement(CHAR_SEL_ITEMCONTAINER_MONEY, "SELECT container_id, money FROM item_loot_money", CONNECTION_SYNCH);
|
||||
PrepareStatement(CHAR_DEL_ITEMCONTAINER_MONEY, "DELETE FROM item_loot_money WHERE container_id = ?", CONNECTION_ASYNC);
|
||||
PrepareStatement(CHAR_INS_ITEMCONTAINER_MONEY, "INSERT INTO item_loot_money (container_id, money) VALUES (?, ?)", CONNECTION_ASYNC);
|
||||
|
||||
@@ -26610,7 +26610,7 @@ void Player::StoreLootItem(uint8 lootSlot, Loot* loot, AELootResult* aeResult/*
|
||||
|
||||
// LootItem is being removed (looted) from the container, delete it from the DB.
|
||||
if (!loot->containerID.IsEmpty())
|
||||
sLootItemStorage->RemoveStoredLootItemForContainer(loot->containerID.GetCounter(), item->itemid, item->count);
|
||||
sLootItemStorage->RemoveStoredLootItemForContainer(loot->containerID.GetCounter(), item->itemid, item->count, item->itemIndex);
|
||||
}
|
||||
else
|
||||
SendEquipError(msg, nullptr, nullptr, item->itemid);
|
||||
|
||||
@@ -304,6 +304,7 @@ void Loot::AddItem(LootStoreItem const& item)
|
||||
LootItem generatedLoot(item);
|
||||
generatedLoot.context = _itemContext;
|
||||
generatedLoot.count = std::min(count, proto->GetMaxStackSize());
|
||||
generatedLoot.itemIndex = lootItems.size();
|
||||
if (_itemContext != ItemContext::NONE)
|
||||
{
|
||||
std::set<uint32> bonusListIDs = sDB2Manager.GetDefaultItemBonusTree(generatedLoot.itemid, _itemContext);
|
||||
|
||||
@@ -134,12 +134,13 @@ enum LootSlotType
|
||||
struct TC_GAME_API LootItem
|
||||
{
|
||||
uint32 itemid;
|
||||
uint32 itemIndex;
|
||||
ItemRandomBonusListId randomBonusListId;
|
||||
std::vector<int32> BonusListIDs;
|
||||
ItemContext context;
|
||||
ConditionContainer conditions; // additional loot condition
|
||||
ConditionContainer conditions; // additional loot condition
|
||||
GuidSet allowedGUIDs;
|
||||
ObjectGuid rollWinnerGUID; // Stores the guid of person who won loot, if his bags are full only he can see the item in loot list!
|
||||
ObjectGuid rollWinnerGUID; // Stores the guid of person who won loot, if his bags are full only he can see the item in loot list!
|
||||
uint8 count : 8;
|
||||
bool is_looted : 1;
|
||||
bool is_blocked : 1;
|
||||
@@ -154,7 +155,7 @@ struct TC_GAME_API LootItem
|
||||
explicit LootItem(LootStoreItem const& li);
|
||||
|
||||
// Empty constructor for creating an empty LootItem to be filled in with DB data
|
||||
LootItem() : itemid(0), randomBonusListId(0), context(ItemContext::NONE), count(0), is_looted(false), is_blocked(false),
|
||||
LootItem() : itemid(0), itemIndex(0), randomBonusListId(0), context(ItemContext::NONE), count(0), is_looted(false), is_blocked(false),
|
||||
freeforall(false), is_underthreshold(false), is_counted(false), needs_quest(false), follow_loot_rules(false) { };
|
||||
|
||||
// Basic checks for player/item compatibility - if false no chance to see the item in the loot
|
||||
|
||||
@@ -80,15 +80,16 @@ void LootItemStorage::LoadStorageFromDB()
|
||||
LootItem lootItem;
|
||||
lootItem.itemid = fields[1].GetUInt32();
|
||||
lootItem.count = fields[2].GetUInt32();
|
||||
lootItem.follow_loot_rules = fields[3].GetBool();
|
||||
lootItem.freeforall = fields[4].GetBool();
|
||||
lootItem.is_blocked = fields[5].GetBool();
|
||||
lootItem.is_counted = fields[6].GetBool();
|
||||
lootItem.is_underthreshold = fields[7].GetBool();
|
||||
lootItem.needs_quest = fields[8].GetBool();
|
||||
lootItem.randomBonusListId = fields[9].GetUInt32();
|
||||
lootItem.context = ItemContext(fields[10].GetUInt8());
|
||||
for (std::string_view bonusList : Trinity::Tokenize(fields[11].GetStringView(), ' ', false))
|
||||
lootItem.itemIndex = fields[3].GetUInt32();
|
||||
lootItem.follow_loot_rules = fields[4].GetBool();
|
||||
lootItem.freeforall = fields[5].GetBool();
|
||||
lootItem.is_blocked = fields[6].GetBool();
|
||||
lootItem.is_counted = fields[7].GetBool();
|
||||
lootItem.is_underthreshold = fields[8].GetBool();
|
||||
lootItem.needs_quest = fields[9].GetBool();
|
||||
lootItem.randomBonusListId = fields[10].GetUInt32();
|
||||
lootItem.context = ItemContext(fields[11].GetUInt8());
|
||||
for (std::string_view bonusList : Trinity::Tokenize(fields[12].GetStringView(), ' ', false))
|
||||
if (Optional<int32> bonusListID = Trinity::StringTo<int32>(bonusList))
|
||||
lootItem.BonusListIDs.push_back(*bonusListID);
|
||||
|
||||
@@ -221,7 +222,7 @@ void LootItemStorage::RemoveStoredLootForContainer(uint64 containerId)
|
||||
CharacterDatabase.CommitTransaction(trans);
|
||||
}
|
||||
|
||||
void LootItemStorage::RemoveStoredLootItemForContainer(uint64 containerId, uint32 itemId, uint32 count)
|
||||
void LootItemStorage::RemoveStoredLootItemForContainer(uint64 containerId, uint32 itemId, uint32 count, uint32 itemIndex)
|
||||
{
|
||||
// write
|
||||
std::unique_lock<std::shared_mutex> lock(*GetLock());
|
||||
@@ -230,7 +231,7 @@ void LootItemStorage::RemoveStoredLootItemForContainer(uint64 containerId, uint3
|
||||
if (itr == _lootItemStore.end())
|
||||
return;
|
||||
|
||||
itr->second.RemoveItem(itemId, count);
|
||||
itr->second.RemoveItem(itemId, count, itemIndex);
|
||||
}
|
||||
|
||||
void LootItemStorage::AddNewStoredLoot(Loot* loot, Player* player)
|
||||
@@ -296,22 +297,23 @@ void StoredLootContainer::AddLootItem(LootItem const& lootItem, CharacterDatabas
|
||||
|
||||
CharacterDatabasePreparedStatement* stmt = CharacterDatabase.GetPreparedStatement(CHAR_INS_ITEMCONTAINER_ITEMS);
|
||||
|
||||
// container_id, item_id, item_count, follow_rules, ffa, blocked, counted, under_threshold, needs_quest, rnd_prop, rnd_suffix
|
||||
// container_id, item_id, item_count, item_index, follow_rules, ffa, blocked, counted, under_threshold, needs_quest, rnd_prop, rnd_suffix
|
||||
stmt->setUInt64(0, _containerId);
|
||||
stmt->setUInt32(1, lootItem.itemid);
|
||||
stmt->setUInt32(2, lootItem.count);
|
||||
stmt->setBool(3, lootItem.follow_loot_rules);
|
||||
stmt->setBool(4, lootItem.freeforall);
|
||||
stmt->setBool(5, lootItem.is_blocked);
|
||||
stmt->setBool(6, lootItem.is_counted);
|
||||
stmt->setBool(7, lootItem.is_underthreshold);
|
||||
stmt->setBool(8, lootItem.needs_quest);
|
||||
stmt->setInt32(9, lootItem.randomBonusListId);
|
||||
stmt->setUInt8(10, AsUnderlyingType(lootItem.context));
|
||||
stmt->setUInt32(3, lootItem.itemIndex);
|
||||
stmt->setBool(4, lootItem.follow_loot_rules);
|
||||
stmt->setBool(5, lootItem.freeforall);
|
||||
stmt->setBool(6, lootItem.is_blocked);
|
||||
stmt->setBool(7, lootItem.is_counted);
|
||||
stmt->setBool(8, lootItem.is_underthreshold);
|
||||
stmt->setBool(9, lootItem.needs_quest);
|
||||
stmt->setInt32(10, lootItem.randomBonusListId);
|
||||
stmt->setUInt8(11, AsUnderlyingType(lootItem.context));
|
||||
std::ostringstream bonusListIDs;
|
||||
for (int32 bonusListID : lootItem.BonusListIDs)
|
||||
bonusListIDs << bonusListID << ' ';
|
||||
stmt->setString(11, bonusListIDs.str());
|
||||
stmt->setString(12, bonusListIDs.str());
|
||||
trans->Append(stmt);
|
||||
}
|
||||
|
||||
@@ -340,7 +342,7 @@ void StoredLootContainer::RemoveMoney()
|
||||
CharacterDatabase.Execute(stmt);
|
||||
}
|
||||
|
||||
void StoredLootContainer::RemoveItem(uint32 itemId, uint32 count)
|
||||
void StoredLootContainer::RemoveItem(uint32 itemId, uint32 count, uint32 itemIndex)
|
||||
{
|
||||
auto bounds = _lootItems.equal_range(itemId);
|
||||
for (auto itr = bounds.first; itr != bounds.second; ++itr)
|
||||
@@ -357,5 +359,6 @@ void StoredLootContainer::RemoveItem(uint32 itemId, uint32 count)
|
||||
stmt->setUInt64(0, _containerId);
|
||||
stmt->setUInt32(1, itemId);
|
||||
stmt->setUInt32(2, count);
|
||||
stmt->setUInt32(3, itemIndex);
|
||||
CharacterDatabase.Execute(stmt);
|
||||
}
|
||||
|
||||
@@ -60,7 +60,7 @@ class StoredLootContainer
|
||||
void AddMoney(uint32 money, CharacterDatabaseTransaction trans);
|
||||
|
||||
void RemoveMoney();
|
||||
void RemoveItem(uint32 itemId, uint32 count);
|
||||
void RemoveItem(uint32 itemId, uint32 count, uint32 itemIndex);
|
||||
|
||||
uint32 GetContainer() const { return _containerId; }
|
||||
uint32 GetMoney() const { return _money; }
|
||||
@@ -82,7 +82,7 @@ class LootItemStorage
|
||||
bool LoadStoredLoot(Item* item, Player* player);
|
||||
void RemoveStoredMoneyForContainer(uint64 containerId);
|
||||
void RemoveStoredLootForContainer(uint64 containerId);
|
||||
void RemoveStoredLootItemForContainer(uint64 containerId, uint32 itemId, uint32 count);
|
||||
void RemoveStoredLootItemForContainer(uint64 containerId, uint32 itemId, uint32 count, uint32 itemIndex);
|
||||
void AddNewStoredLoot(Loot* loot, Player* player);
|
||||
|
||||
private:
|
||||
|
||||
Reference in New Issue
Block a user