aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--sql/base/characters_database.sql5
-rw-r--r--sql/updates/characters/3.3.5/2017_04_12_00_characters.sql3
-rw-r--r--src/server/database/Database/Implementation/CharacterDatabase.cpp6
-rw-r--r--src/server/game/Entities/Item/Item.cpp193
-rw-r--r--src/server/game/Entities/Item/Item.h8
-rw-r--r--src/server/game/Entities/Player/Player.cpp43
-rw-r--r--src/server/game/Handlers/LootHandler.cpp3
-rw-r--r--src/server/game/Loot/LootItemStorage.cpp353
-rw-r--r--src/server/game/Loot/LootItemStorage.h93
-rw-r--r--src/server/game/Loot/LootMgr.cpp28
-rw-r--r--src/server/game/Loot/LootMgr.h9
-rw-r--r--src/server/game/World/World.cpp4
12 files changed, 498 insertions, 250 deletions
diff --git a/sql/base/characters_database.sql b/sql/base/characters_database.sql
index f2b494ff947..9e02a5cada7 100644
--- a/sql/base/characters_database.sql
+++ b/sql/base/characters_database.sql
@@ -2093,7 +2093,8 @@ DROP TABLE IF EXISTS `item_loot_money`;
/*!40101 SET character_set_client = utf8 */;
CREATE TABLE `item_loot_money` (
`container_id` int(10) unsigned NOT NULL DEFAULT '0' COMMENT 'guid of container (item_instance.guid)',
- `money` int(10) NOT NULL DEFAULT '0' COMMENT 'money loot (in copper)'
+ `money` int(10) unsigned NOT NULL DEFAULT '0' COMMENT 'money loot (in copper)',
+ PRIMARY KEY (`container_id`)
) ENGINE=InnoDB DEFAULT CHARSET=latin1;
/*!40101 SET character_set_client = @saved_cs_client */;
@@ -2567,7 +2568,7 @@ CREATE TABLE `updates` (
LOCK TABLES `updates` WRITE;
/*!40000 ALTER TABLE `updates` DISABLE KEYS */;
-INSERT INTO `updates` VALUES ('2015_03_20_00_characters.sql','B761760804EA73BD297F296C5C1919687DF7191C','ARCHIVED','2015-03-21 21:44:15',0),('2015_03_20_01_characters.sql','894F08B70449A5481FFAF394EE5571D7FC4D8A3A','ARCHIVED','2015-03-21 21:44:15',0),('2015_03_20_02_characters.sql','97D7BE0CAADC79F3F11B9FD296B8C6CD40FE593B','ARCHIVED','2015-03-21 21:44:51',0),('2015_06_26_00_characters_335.sql','C2CC6E50AFA1ACCBEBF77CC519AAEB09F3BBAEBC','ARCHIVED','2015-07-13 23:49:22',0),('2015_09_28_00_characters_335.sql','F8682A431D50E54BDC4AC0E7DBED21AE8AAB6AD4','ARCHIVED','2015-09-28 21:00:00',0),('2015_08_26_00_characters_335.sql','C7D6A3A00FECA3EBFF1E71744CA40D3076582374','ARCHIVED','2015-08-26 21:00:00',0),('2015_10_06_00_characters.sql','16842FDD7E8547F2260D3312F53EFF8761EFAB35','ARCHIVED','2015-10-06 16:06:38',0),('2015_10_07_00_characters.sql','E15AB463CEBE321001D7BFDEA4B662FF618728FD','ARCHIVED','2015-10-07 23:32:00',0),('2015_10_12_00_characters.sql','D6F9927BDED72AD0A81D6EC2C6500CBC34A39FA2','ARCHIVED','2015-10-12 15:35:47',0),('2015_10_28_00_characters.sql','622A9CA8FCE690429EBE23BA071A37C7A007BF8B','ARCHIVED','2015-10-19 14:32:22',0),('2015_10_29_00_characters_335.sql','4555A7F35C107E54C13D74D20F141039ED42943E','ARCHIVED','2015-10-29 17:05:43',0),('2015_11_03_00_characters.sql','CC045717B8FDD9733351E52A5302560CD08AAD57','ARCHIVED','2015-10-12 15:23:33',0),('2015_11_07_00_characters.sql','0ACDD35EC9745231BCFA701B78056DEF94D0CC53','ARCHIVED','2016-04-11 00:42:36',94),('2016_02_10_00_characters.sql','F1B4DA202819CABC7319A4470A2D224A34609E97','ARCHIVED','2016-02-10 00:00:00',0),('2016_03_13_2016_01_05_00_characters.sql','0EAD24977F40DE2476B4567DA2B477867CC0DA1A','ARCHIVED','2016-03-13 20:03:56',0),('2016_04_11_00_characters.sql','0ACDD35EC9745231BCFA701B78056DEF94D0CC53','ARCHIVED','2016-04-11 03:18:17',0),('2016_09_13_00_characters.sql','27A04615B11B2CFC3A26778F52F74C071E4F9C54','ARCHIVED','2016-07-06 18:55:18',0),('2016_10_16_00_characters.sql','0ACDD35EC9745231BCFA701B78056DEF94D0CC53','ARCHIVED','2016-10-16 14:02:49',35),('2016_10_30_00_characters.sql','7E2D5B226907B5A9AF320797F46E86DC27B7EC90','ARCHIVED','2016-10-30 00:00:00',0),('2017_04_03_00_characters.sql','CB072C56692C9FBF170C4036F15773DD86D368B5','RELEASED','2017-04-03 00:00:00',0);
+INSERT INTO `updates` VALUES ('2015_03_20_00_characters.sql','B761760804EA73BD297F296C5C1919687DF7191C','ARCHIVED','2015-03-21 21:44:15',0),('2015_03_20_01_characters.sql','894F08B70449A5481FFAF394EE5571D7FC4D8A3A','ARCHIVED','2015-03-21 21:44:15',0),('2015_03_20_02_characters.sql','97D7BE0CAADC79F3F11B9FD296B8C6CD40FE593B','ARCHIVED','2015-03-21 21:44:51',0),('2015_06_26_00_characters_335.sql','C2CC6E50AFA1ACCBEBF77CC519AAEB09F3BBAEBC','ARCHIVED','2015-07-13 23:49:22',0),('2015_09_28_00_characters_335.sql','F8682A431D50E54BDC4AC0E7DBED21AE8AAB6AD4','ARCHIVED','2015-09-28 21:00:00',0),('2015_08_26_00_characters_335.sql','C7D6A3A00FECA3EBFF1E71744CA40D3076582374','ARCHIVED','2015-08-26 21:00:00',0),('2015_10_06_00_characters.sql','16842FDD7E8547F2260D3312F53EFF8761EFAB35','ARCHIVED','2015-10-06 16:06:38',0),('2015_10_07_00_characters.sql','E15AB463CEBE321001D7BFDEA4B662FF618728FD','ARCHIVED','2015-10-07 23:32:00',0),('2015_10_12_00_characters.sql','D6F9927BDED72AD0A81D6EC2C6500CBC34A39FA2','ARCHIVED','2015-10-12 15:35:47',0),('2015_10_28_00_characters.sql','622A9CA8FCE690429EBE23BA071A37C7A007BF8B','ARCHIVED','2015-10-19 14:32:22',0),('2015_10_29_00_characters_335.sql','4555A7F35C107E54C13D74D20F141039ED42943E','ARCHIVED','2015-10-29 17:05:43',0),('2015_11_03_00_characters.sql','CC045717B8FDD9733351E52A5302560CD08AAD57','ARCHIVED','2015-10-12 15:23:33',0),('2015_11_07_00_characters.sql','0ACDD35EC9745231BCFA701B78056DEF94D0CC53','ARCHIVED','2016-04-11 00:42:36',94),('2016_02_10_00_characters.sql','F1B4DA202819CABC7319A4470A2D224A34609E97','ARCHIVED','2016-02-10 00:00:00',0),('2016_03_13_2016_01_05_00_characters.sql','0EAD24977F40DE2476B4567DA2B477867CC0DA1A','ARCHIVED','2016-03-13 20:03:56',0),('2016_04_11_00_characters.sql','0ACDD35EC9745231BCFA701B78056DEF94D0CC53','ARCHIVED','2016-04-11 03:18:17',0),('2016_09_13_00_characters.sql','27A04615B11B2CFC3A26778F52F74C071E4F9C54','ARCHIVED','2016-07-06 18:55:18',0),('2016_10_16_00_characters.sql','0ACDD35EC9745231BCFA701B78056DEF94D0CC53','ARCHIVED','2016-10-16 14:02:49',35),('2016_10_30_00_characters.sql','7E2D5B226907B5A9AF320797F46E86DC27B7EC90','ARCHIVED','2016-10-30 00:00:00',0),('2017_04_03_00_characters.sql','CB072C56692C9FBF170C4036F15773DD86D368B5','RELEASED','2017-04-03 00:00:00',0),('2017_04_12_00_characters.sql','4FE3C6866A6DCD4926D451F6009464D290C2EF1F','RELEASED','2017-04-12 00:00:00',0);
/*!40000 ALTER TABLE `updates` ENABLE KEYS */;
UNLOCK TABLES;
diff --git a/sql/updates/characters/3.3.5/2017_04_12_00_characters.sql b/sql/updates/characters/3.3.5/2017_04_12_00_characters.sql
new file mode 100644
index 00000000000..117e3baa78d
--- /dev/null
+++ b/sql/updates/characters/3.3.5/2017_04_12_00_characters.sql
@@ -0,0 +1,3 @@
+ALTER TABLE `item_loot_money`
+CHANGE `money` `money` int(10) unsigned NOT NULL DEFAULT '0' COMMENT 'money loot (in copper)',
+ADD PRIMARY KEY (`container_id`);
diff --git a/src/server/database/Database/Implementation/CharacterDatabase.cpp b/src/server/database/Database/Implementation/CharacterDatabase.cpp
index 80be3a59bee..819ff8ecc62 100644
--- a/src/server/database/Database/Implementation/CharacterDatabase.cpp
+++ b/src/server/database/Database/Implementation/CharacterDatabase.cpp
@@ -543,11 +543,11 @@ void CharacterDatabaseConnection::DoPrepareStatements()
PrepareStatement(CHAR_DEL_CHAR_FISHINGSTEPS, "DELETE FROM character_fishingsteps WHERE guid = ?", CONNECTION_ASYNC);
// Items that hold loot or money
- PrepareStatement(CHAR_SEL_ITEMCONTAINER_ITEMS, "SELECT item_id, item_count, follow_rules, ffa, blocked, counted, under_threshold, needs_quest, rnd_prop, rnd_suffix FROM item_loot_items WHERE container_id = ?", CONNECTION_SYNCH);
+ PrepareStatement(CHAR_SEL_ITEMCONTAINER_ITEMS, "SELECT container_id, item_id, item_count, follow_rules, ffa, blocked, counted, under_threshold, needs_quest, rnd_prop, rnd_suffix 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 = ?", 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_prop, rnd_suffix) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)", CONNECTION_ASYNC);
- PrepareStatement(CHAR_SEL_ITEMCONTAINER_MONEY, "SELECT money FROM item_loot_money WHERE container_id = ?", CONNECTION_SYNCH);
+ 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);
diff --git a/src/server/game/Entities/Item/Item.cpp b/src/server/game/Entities/Item/Item.cpp
index e19f8ddc881..6ea1665ce35 100644
--- a/src/server/game/Entities/Item/Item.cpp
+++ b/src/server/game/Entities/Item/Item.cpp
@@ -22,6 +22,7 @@
#include "WorldPacket.h"
#include "DatabaseEnv.h"
#include "ItemEnchantmentMgr.h"
+#include "LootItemStorage.h"
#include "SpellMgr.h"
#include "SpellInfo.h"
#include "ScriptMgr.h"
@@ -384,7 +385,7 @@ void Item::SaveToDB(SQLTransaction& trans)
// Delete the items if this is a container
if (!loot.isLooted())
- ItemContainerDeleteLootMoneyAndLootItemsFromDB();
+ sLootItemStorage->RemoveStoredLootForContainer(GetGUID().GetCounter());
delete this;
return;
@@ -495,7 +496,7 @@ void Item::DeleteFromDB(SQLTransaction& trans)
// Delete the items if this is a container
if (!loot.isLooted())
- ItemContainerDeleteLootMoneyAndLootItemsFromDB();
+ sLootItemStorage->RemoveStoredLootForContainer(GetGUID().GetCounter());
}
/*static*/
@@ -1220,194 +1221,6 @@ bool Item::CheckSoulboundTradeExpire()
return false;
}
-void Item::ItemContainerSaveLootToDB()
-{
- // Saves the money and item loot associated with an openable item to the DB
- if (loot.isLooted()) // no money and no loot
- return;
-
- ObjectGuid::LowType container_id = GetGUID().GetCounter();
- SQLTransaction trans = CharacterDatabase.BeginTransaction();
-
- loot.containerID = container_id; // Save this for when a LootItem is removed
-
- // Save money
- if (loot.gold > 0)
- {
- PreparedStatement* stmt_money = CharacterDatabase.GetPreparedStatement(CHAR_DEL_ITEMCONTAINER_MONEY);
- stmt_money->setUInt32(0, container_id);
- trans->Append(stmt_money);
-
- stmt_money = CharacterDatabase.GetPreparedStatement(CHAR_INS_ITEMCONTAINER_MONEY);
- stmt_money->setUInt32(0, container_id);
- stmt_money->setUInt32(1, loot.gold);
- trans->Append(stmt_money);
- }
-
- // Save items
- if (!loot.isLooted())
- {
- PreparedStatement* stmt_items = CharacterDatabase.GetPreparedStatement(CHAR_DEL_ITEMCONTAINER_ITEMS);
- stmt_items->setUInt32(0, container_id);
- trans->Append(stmt_items);
-
- // Now insert the items
- for (LootItemList::const_iterator _li = loot.items.begin(); _li != loot.items.end(); ++_li)
- {
- // When an item is looted, it doesn't get removed from the items collection
- // but we don't want to resave it.
- if (!_li->canSave)
- continue;
- // Conditions are not checked when loot is generated, it is checked when loot is sent to a player.
- // For items that are lootable, loot is saved to the DB immediately, that means that loot can be
- // saved to the DB that the player never should have gotten. This check prevents that, so that only
- // items that the player should get in loot are in the DB.
- // IE: Horde items are not saved to the DB for Ally players.
- Player* const guid = GetOwner();
- if (!_li->AllowedForPlayer(guid))
- continue;
-
- stmt_items = 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
- stmt_items->setUInt32(0, container_id);
- stmt_items->setUInt32(1, _li->itemid);
- stmt_items->setUInt32(2, _li->count);
- stmt_items->setBool(3, _li->follow_loot_rules);
- stmt_items->setBool(4, _li->freeforall);
- stmt_items->setBool(5, _li->is_blocked);
- stmt_items->setBool(6, _li->is_counted);
- stmt_items->setBool(7, _li->is_underthreshold);
- stmt_items->setBool(8, _li->needs_quest);
- stmt_items->setInt32(9, _li->randomPropertyId);
- stmt_items->setUInt32(10, _li->randomSuffix);
- trans->Append(stmt_items);
- }
- }
-
- CharacterDatabase.CommitTransaction(trans);
-}
-
-bool Item::ItemContainerLoadLootFromDB()
-{
- // Loads the money and item loot associated with an openable item from the DB
- // Default. If there are no records for this item then it will be rolled for in Player::SendLoot()
- m_lootGenerated = false;
-
- ObjectGuid::LowType container_id = GetGUID().GetCounter();
-
- // Save this for later use
- loot.containerID = container_id;
-
- // First, see if there was any money loot. This gets added directly to the container.
- PreparedStatement* stmt = CharacterDatabase.GetPreparedStatement(CHAR_SEL_ITEMCONTAINER_MONEY);
- stmt->setUInt32(0, container_id);
- PreparedQueryResult money_result = CharacterDatabase.Query(stmt);
-
- if (money_result)
- {
- Field* fields = money_result->Fetch();
- loot.gold = fields[0].GetUInt32();
- }
-
- // Next, load any items that were saved
- stmt = CharacterDatabase.GetPreparedStatement(CHAR_SEL_ITEMCONTAINER_ITEMS);
- stmt->setUInt32(0, container_id);
- PreparedQueryResult item_result = CharacterDatabase.Query(stmt);
-
- if (item_result)
- {
- // Get a LootTemplate for the container item. This is where
- // the saved loot was originally rolled from, we will copy conditions from it
- LootTemplate const* lt = LootTemplates_Item.GetLootFor(GetEntry());
- if (lt)
- {
- do
- {
- // Create an empty LootItem
- LootItem loot_item = LootItem();
-
- // Fill in the rest of the LootItem from the DB
- Field* fields = item_result->Fetch();
-
- // item_id, itm_count, follow_rules, ffa, blocked, counted, under_threshold, needs_quest, rnd_prop, rnd_suffix
- loot_item.itemid = fields[0].GetUInt32();
- loot_item.count = fields[1].GetUInt32();
- loot_item.follow_loot_rules = fields[2].GetBool();
- loot_item.freeforall = fields[3].GetBool();
- loot_item.is_blocked = fields[4].GetBool();
- loot_item.is_counted = fields[5].GetBool();
- loot_item.canSave = true;
- loot_item.is_underthreshold = fields[6].GetBool();
- loot_item.needs_quest = fields[7].GetBool();
- loot_item.randomPropertyId = fields[8].GetInt32();
- loot_item.randomSuffix = fields[9].GetUInt32();
-
- // Copy the extra loot conditions from the item in the loot template
- lt->CopyConditions(&loot_item);
-
- // If container item is in a bag, add that player as an allowed looter
- if (GetBagSlot())
- loot_item.AddAllowedLooter(GetOwner());
-
- // Finally add the LootItem to the container
- loot.items.push_back(loot_item);
-
- // Increment unlooted count
- loot.unlootedCount++;
-
- }
- while (item_result->NextRow());
- }
- }
-
- // Mark the item if it has loot so it won't be generated again on open
- m_lootGenerated = !loot.isLooted();
-
- return m_lootGenerated;
-}
-
-void Item::ItemContainerDeleteLootItemsFromDB()
-{
- // Deletes items associated with an openable item from the DB
- ObjectGuid::LowType containerId = GetGUID().GetCounter();
- PreparedStatement* stmt = CharacterDatabase.GetPreparedStatement(CHAR_DEL_ITEMCONTAINER_ITEMS);
- stmt->setUInt32(0, containerId);
- SQLTransaction trans = CharacterDatabase.BeginTransaction();
- trans->Append(stmt);
- CharacterDatabase.CommitTransaction(trans);
-}
-
-void Item::ItemContainerDeleteLootItemFromDB(uint32 itemID)
-{
- // Deletes a single item associated with an openable item from the DB
- ObjectGuid::LowType containerId = GetGUID().GetCounter();
- PreparedStatement* stmt = CharacterDatabase.GetPreparedStatement(CHAR_DEL_ITEMCONTAINER_ITEM);
- stmt->setUInt32(0, containerId);
- stmt->setUInt32(1, itemID);
- SQLTransaction trans = CharacterDatabase.BeginTransaction();
- trans->Append(stmt);
- CharacterDatabase.CommitTransaction(trans);
-}
-
-void Item::ItemContainerDeleteLootMoneyFromDB()
-{
- // Deletes the money loot associated with an openable item from the DB
- ObjectGuid::LowType containerId = GetGUID().GetCounter();
- PreparedStatement* stmt = CharacterDatabase.GetPreparedStatement(CHAR_DEL_ITEMCONTAINER_MONEY);
- stmt->setUInt32(0, containerId);
- SQLTransaction trans = CharacterDatabase.BeginTransaction();
- trans->Append(stmt);
- CharacterDatabase.CommitTransaction(trans);
-}
-
-void Item::ItemContainerDeleteLootMoneyAndLootItemsFromDB()
-{
- // Deletes money and items associated with an openable item from the DB
- ItemContainerDeleteLootMoneyFromDB();
- ItemContainerDeleteLootItemsFromDB();
-}
-
void Item::SetCount(uint32 value)
{
SetUInt32Value(ITEM_FIELD_STACK_COUNT, value);
diff --git a/src/server/game/Entities/Item/Item.h b/src/server/game/Entities/Item/Item.h
index d501ceb6299..421d13b9aa1 100644
--- a/src/server/game/Entities/Item/Item.h
+++ b/src/server/game/Entities/Item/Item.h
@@ -230,14 +230,6 @@ class TC_GAME_API Item : public Object
virtual void DeleteFromDB(SQLTransaction& trans);
static void DeleteFromInventoryDB(SQLTransaction& trans, ObjectGuid::LowType itemGuid);
- // Lootable items and their contents
- void ItemContainerSaveLootToDB();
- bool ItemContainerLoadLootFromDB();
- void ItemContainerDeleteLootItemsFromDB();
- void ItemContainerDeleteLootItemFromDB(uint32 itemID);
- void ItemContainerDeleteLootMoneyFromDB();
- void ItemContainerDeleteLootMoneyAndLootItemsFromDB();
-
void DeleteFromInventoryDB(SQLTransaction& trans);
void SaveRefundDataToDB();
void DeleteRefundDataFromDB(SQLTransaction* trans);
diff --git a/src/server/game/Entities/Player/Player.cpp b/src/server/game/Entities/Player/Player.cpp
index 2eb6e1cbe5a..6f2ba8dcdd8 100644
--- a/src/server/game/Entities/Player/Player.cpp
+++ b/src/server/game/Entities/Player/Player.cpp
@@ -54,6 +54,7 @@
#include "LFGMgr.h"
#include "Language.h"
#include "Log.h"
+#include "LootItemStorage.h"
#include "MapManager.h"
#include "ObjectAccessor.h"
#include "ObjectMgr.h"
@@ -8624,9 +8625,12 @@ void Player::SendLoot(ObjectGuid guid, LootType loot_type)
loot = &item->loot;
+ // Store container id
+ loot->containerID = item->GetGUID().GetCounter();
+
// If item doesn't already have loot, attempt to load it. If that
- // fails then this is first time opening, generate loot
- if (!item->m_lootGenerated && !item->ItemContainerLoadLootFromDB())
+ // fails then this is first time opening, generate loot
+ if (!item->m_lootGenerated && !sLootItemStorage->LoadStoredLoot(item, this))
{
item->m_lootGenerated = true;
loot->clear();
@@ -8649,7 +8653,7 @@ void Player::SendLoot(ObjectGuid guid, LootType loot_type)
// Force save the loot and money items that were just rolled
// Also saves the container item ID in Loot struct (not to DB)
if (loot->gold > 0 || loot->unlootedCount > 0)
- item->ItemContainerSaveLootToDB();
+ sLootItemStorage->AddNewStoredLoot(loot, this);
break;
}
@@ -12492,6 +12496,7 @@ void Player::DestroyItem(uint8 bag, uint8 slot, bool update)
ItemRemovedQuestCheck(pItem->GetEntry(), pItem->GetCount());
sScriptMgr->OnItemRemove(this, pItem);
+ ItemTemplate const* pProto = pItem->GetTemplate();
if (bag == INVENTORY_SLOT_BAG_0)
{
SetGuidValue(PLAYER_FIELD_INV_SLOT_HEAD + (slot * 2), ObjectGuid::Empty);
@@ -12499,7 +12504,6 @@ void Player::DestroyItem(uint8 bag, uint8 slot, bool update)
// equipment and equipped bags can have applied bonuses
if (slot < INVENTORY_SLOT_BAG_END)
{
- ItemTemplate const* pProto = pItem->GetTemplate();
// item set bonuses applied only at equip and removed at unequip, and still active for broken items
if (pProto && pProto->ItemSet)
@@ -12537,9 +12541,8 @@ void Player::DestroyItem(uint8 bag, uint8 slot, bool update)
// Delete rolled money / loot from db.
// MUST be done before RemoveFromWorld() or GetTemplate() fails
- if (ItemTemplate const* pTmp = pItem->GetTemplate())
- if (pTmp->Flags & ITEM_FLAG_HAS_LOOT)
- pItem->ItemContainerDeleteLootMoneyAndLootItemsFromDB();
+ if (pProto->Flags & ITEM_FLAG_HAS_LOOT)
+ sLootItemStorage->RemoveStoredLootForContainer(pItem->GetGUID().GetCounter());
if (IsInWorld() && update)
{
@@ -13291,7 +13294,7 @@ void Player::SwapItem(uint16 src, uint16 dst)
{
if (Item* bagItem = bag->GetItemByPos(i))
{
- if (bagItem->m_lootGenerated)
+ if (bagItem->GetGUID() == GetLootGUID())
{
m_session->DoLootRelease(GetLootGUID());
released = true; // so we don't need to look at dstBag
@@ -13308,7 +13311,7 @@ void Player::SwapItem(uint16 src, uint16 dst)
{
if (Item* bagItem = bag->GetItemByPos(i))
{
- if (bagItem->m_lootGenerated)
+ if (bagItem->GetGUID() == GetLootGUID())
{
m_session->DoLootRelease(GetLootGUID());
break;
@@ -13396,7 +13399,12 @@ void Player::RemoveItemFromBuyBackSlot(uint32 slot, bool del)
{
pItem->RemoveFromWorld();
if (del)
+ {
pItem->SetState(ITEM_REMOVED, this);
+ if (ItemTemplate const* itemTemplate = pItem->GetTemplate())
+ if (itemTemplate->Flags & ITEM_FLAG_HAS_LOOT)
+ sLootItemStorage->RemoveStoredLootForContainer(pItem->GetGUID().GetCounter());
+ }
}
m_items[slot] = nullptr;
@@ -19662,8 +19670,17 @@ void Player::_SaveInventory(SQLTransaction& trans)
for (uint8 i = BUYBACK_SLOT_START; i < BUYBACK_SLOT_END; ++i)
{
Item* item = m_items[i];
- if (!item || item->GetState() == ITEM_NEW)
+ if (!item)
continue;
+
+ if (item->GetState() == ITEM_NEW)
+ {
+ if (ItemTemplate const* itemTemplate = item->GetTemplate())
+ if (itemTemplate->Flags & ITEM_FLAG_HAS_LOOT)
+ sLootItemStorage->RemoveStoredLootForContainer(item->GetGUID().GetCounter());
+
+ continue;
+ }
stmt = CharacterDatabase.GetPreparedStatement(CHAR_DEL_CHAR_INVENTORY_BY_ITEM);
stmt->setUInt32(0, item->GetGUID().GetCounter());
@@ -19673,6 +19690,10 @@ void Player::_SaveInventory(SQLTransaction& trans)
stmt->setUInt32(0, item->GetGUID().GetCounter());
trans->Append(stmt);
m_items[i]->FSetState(ITEM_NEW);
+
+ if (ItemTemplate const* itemTemplate = item->GetTemplate())
+ if (itemTemplate->Flags & ITEM_FLAG_HAS_LOOT)
+ sLootItemStorage->RemoveStoredLootForContainer(item->GetGUID().GetCounter());
}
// Updated played time for refundable items. We don't do this in Player::Update because there's simply no need for it,
@@ -24720,7 +24741,7 @@ void Player::StoreLootItem(uint8 lootSlot, Loot* loot)
// LootItem is being removed (looted) from the container, delete it from the DB.
if (loot->containerID > 0)
- loot->DeleteLootItemFromContainerItemDB(item->itemid);
+ sLootItemStorage->RemoveStoredLootItemForContainer(loot->containerID, item->itemid, item->count);
}
else
diff --git a/src/server/game/Handlers/LootHandler.cpp b/src/server/game/Handlers/LootHandler.cpp
index 1e740b33bb9..4a0013b71c1 100644
--- a/src/server/game/Handlers/LootHandler.cpp
+++ b/src/server/game/Handlers/LootHandler.cpp
@@ -22,6 +22,7 @@
#include "Creature.h"
#include "GameObject.h"
#include "Group.h"
+#include "LootItemStorage.h"
#include "LootMgr.h"
#include "ObjectAccessor.h"
#include "Object.h"
@@ -206,7 +207,7 @@ void WorldSession::HandleLootMoneyOpcode(WorldPacket& /*recvData*/)
// Delete the money loot record from the DB
if (loot->containerID > 0)
- loot->DeleteLootMoneyFromContainerItemDB();
+ sLootItemStorage->RemoveStoredMoneyForContainer(loot->containerID);
// Delete container if empty
if (loot->isLooted() && guid.IsItem())
diff --git a/src/server/game/Loot/LootItemStorage.cpp b/src/server/game/Loot/LootItemStorage.cpp
new file mode 100644
index 00000000000..45f1027932b
--- /dev/null
+++ b/src/server/game/Loot/LootItemStorage.cpp
@@ -0,0 +1,353 @@
+/*
+* Copyright (C) 2008-2017 TrinityCore <http://www.trinitycore.org/>
+*
+* This program is free software; you can redistribute it and/or modify it
+* under the terms of the GNU General Public License as published by the
+* Free Software Foundation; either version 2 of the License, or (at your
+* option) any later version.
+*
+* This program is distributed in the hope that it will be useful, but WITHOUT
+* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+* more details.
+*
+* You should have received a copy of the GNU General Public License along
+* with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#include "LootItemStorage.h"
+#include "ItemTemplate.h"
+#include "Log.h"
+#include "LootMgr.h"
+#include "ObjectMgr.h"
+#include "Player.h"
+
+#include <boost/thread/shared_mutex.hpp>
+#include <boost/thread/locks.hpp>
+
+#include <unordered_map>
+
+namespace
+{
+ std::unordered_map<uint32, StoredLootContainer> _lootItemStore;
+}
+
+StoredLootItem::StoredLootItem(LootItem const& lootItem) : ItemId(lootItem.itemid), Count(lootItem.count), FollowRules(lootItem.follow_loot_rules),
+FFA(lootItem.freeforall), Blocked(lootItem.is_blocked), Counted(lootItem.is_counted), UnderThreshold(lootItem.is_underthreshold),
+NeedsQuest(lootItem.needs_quest), RandomPropertyId(lootItem.randomPropertyId), RandomSuffix(lootItem.randomSuffix)
+{
+}
+
+LootItemStorage* LootItemStorage::instance()
+{
+ static LootItemStorage instance;
+ return &instance;
+}
+
+boost::shared_mutex* LootItemStorage::GetLock()
+{
+ static boost::shared_mutex _lock;
+ return &_lock;
+}
+
+void LootItemStorage::LoadStorageFromDB()
+{
+ uint32 oldMSTime = getMSTime();
+ _lootItemStore.clear();
+ uint32 count = 0;
+
+ SQLTransaction trans = SQLTransaction(nullptr);
+ PreparedStatement* stmt = CharacterDatabase.GetPreparedStatement(CHAR_SEL_ITEMCONTAINER_ITEMS);
+ PreparedQueryResult result = CharacterDatabase.Query(stmt);
+ if (result)
+ {
+ do
+ {
+ Field* fields = result->Fetch();
+
+ uint32 key = fields[0].GetUInt32();
+ auto itr = _lootItemStore.find(key);
+ if (itr == _lootItemStore.end())
+ {
+ bool added;
+ std::tie(itr, added) = _lootItemStore.emplace(std::piecewise_construct, std::forward_as_tuple(key), std::forward_as_tuple(key));
+
+ ASSERT(added);
+ }
+
+ StoredLootContainer& storedContainer = itr->second;
+
+ 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.randomPropertyId = fields[9].GetInt32();
+ lootItem.randomSuffix = fields[10].GetUInt32();
+
+ storedContainer.AddLootItem(lootItem, trans);
+
+ ++count;
+ } while (result->NextRow());
+
+ TC_LOG_INFO("server.loading", ">> Loaded %u stored item loots in %u ms", count, GetMSTimeDiffToNow(oldMSTime));
+ }
+ else
+ TC_LOG_INFO("server.loading", ">> Loaded 0 stored item loots");
+
+ stmt = CharacterDatabase.GetPreparedStatement(CHAR_SEL_ITEMCONTAINER_MONEY);
+ result = CharacterDatabase.Query(stmt);
+ if (result)
+ {
+ count = 0;
+ do
+ {
+ Field* fields = result->Fetch();
+
+ uint32 key = fields[0].GetUInt32();
+ auto itr = _lootItemStore.find(key);
+ if (itr == _lootItemStore.end())
+ {
+ bool added;
+ std::tie(itr, added) = _lootItemStore.emplace(std::piecewise_construct, std::forward_as_tuple(key), std::forward_as_tuple(key));
+
+ ASSERT(added);
+ }
+
+ StoredLootContainer& storedContainer = itr->second;
+ storedContainer.AddMoney(fields[1].GetUInt32(), trans);
+
+ ++count;
+ } while (result->NextRow());
+
+ TC_LOG_INFO("server.loading", ">> Loaded %u stored item money in %u ms", count, GetMSTimeDiffToNow(oldMSTime));
+ }
+ else
+ TC_LOG_INFO("server.loading", ">> Loaded 0 stored item money");
+}
+
+bool LootItemStorage::LoadStoredLoot(Item* item, Player* player)
+{
+ Loot* loot = &item->loot;
+ StoredLootContainer const* container = nullptr;
+
+ // read
+ {
+ boost::shared_lock<boost::shared_mutex> lock(*GetLock());
+
+ auto itr = _lootItemStore.find(loot->containerID);
+ if (itr == _lootItemStore.end())
+ return false;
+
+ container = &itr->second;
+ }
+
+ // container is never null at this point
+ loot->gold = container->GetMoney();
+
+ if (LootTemplate const* lt = LootTemplates_Item.GetLootFor(item->GetEntry()))
+ {
+ for (auto const& storedItemPair : container->GetLootItems())
+ {
+ LootItem li;
+ li.itemid = storedItemPair.first;
+ li.count = storedItemPair.second.Count;
+ li.follow_loot_rules = storedItemPair.second.FollowRules;
+ li.freeforall = storedItemPair.second.FFA;
+ li.is_blocked = storedItemPair.second.Blocked;
+ li.is_counted = storedItemPair.second.Counted;
+ li.is_underthreshold = storedItemPair.second.UnderThreshold;
+ li.needs_quest = storedItemPair.second.NeedsQuest;
+ li.randomPropertyId = storedItemPair.second.RandomPropertyId;
+ li.randomSuffix = storedItemPair.second.RandomSuffix;
+
+ // Copy the extra loot conditions from the item in the loot template
+ lt->CopyConditions(&li);
+
+ // If container item is in a bag, add that player as an allowed looter
+ if (item->GetBagSlot())
+ li.AddAllowedLooter(player);
+
+ // Finally add the LootItem to the container
+ loot->items.push_back(li);
+
+ // Increment unlooted count
+ ++loot->unlootedCount;
+ }
+ }
+
+ // Mark the item if it has loot so it won't be generated again on open
+ item->m_lootGenerated = true;
+ return true;
+}
+
+void LootItemStorage::RemoveStoredMoneyForContainer(uint32 containerId)
+{
+ // write
+ boost::unique_lock<boost::shared_mutex> lock(*GetLock());
+
+ auto itr = _lootItemStore.find(containerId);
+ if (itr == _lootItemStore.end())
+ return;
+
+ itr->second.RemoveMoney();
+}
+
+void LootItemStorage::RemoveStoredLootForContainer(uint32 containerId)
+{
+ // write
+ {
+ boost::unique_lock<boost::shared_mutex> lock(*GetLock());
+ _lootItemStore.erase(containerId);
+ }
+
+ SQLTransaction trans = CharacterDatabase.BeginTransaction();
+ PreparedStatement* stmt = CharacterDatabase.GetPreparedStatement(CHAR_DEL_ITEMCONTAINER_ITEMS);
+ stmt->setUInt32(0, containerId);
+ trans->Append(stmt);
+
+ stmt = CharacterDatabase.GetPreparedStatement(CHAR_DEL_ITEMCONTAINER_MONEY);
+ stmt->setUInt32(0, containerId);
+ trans->Append(stmt);
+
+ CharacterDatabase.CommitTransaction(trans);
+}
+
+void LootItemStorage::RemoveStoredLootItemForContainer(uint32 containerId, uint32 itemId, uint32 count)
+{
+ // write
+ boost::unique_lock<boost::shared_mutex> lock(*GetLock());
+
+ auto itr = _lootItemStore.find(containerId);
+ if (itr == _lootItemStore.end())
+ return;
+
+ itr->second.RemoveItem(itemId, count);
+}
+
+void LootItemStorage::AddNewStoredLoot(Loot* loot, Player* player)
+{
+ // Saves the money and item loot associated with an openable item to the DB
+ if (loot->isLooted()) // no money and no loot
+ return;
+
+ // read
+ {
+ boost::shared_lock<boost::shared_mutex> lock(*GetLock());
+
+ auto itr = _lootItemStore.find(loot->containerID);
+ if (itr != _lootItemStore.end())
+ {
+ TC_LOG_ERROR("misc", "Trying to store item loot by player: %s for container id: %u that is already in storage!", player->GetGUID().ToString().c_str(), loot->containerID);
+ return;
+ }
+ }
+
+ StoredLootContainer container(loot->containerID);
+
+ SQLTransaction trans = CharacterDatabase.BeginTransaction();
+ if (loot->gold)
+ container.AddMoney(loot->gold, trans);
+
+ PreparedStatement* stmt = CharacterDatabase.GetPreparedStatement(CHAR_DEL_ITEMCONTAINER_ITEMS);
+ stmt->setUInt32(0, loot->containerID);
+ trans->Append(stmt);
+
+ for (LootItem const& li : loot->items)
+ {
+ // Conditions are not checked when loot is generated, it is checked when loot is sent to a player.
+ // For items that are lootable, loot is saved to the DB immediately, that means that loot can be
+ // saved to the DB that the player never should have gotten. This check prevents that, so that only
+ // items that the player should get in loot are in the DB.
+ // IE: Horde items are not saved to the DB for Ally players.
+ if (!li.AllowedForPlayer(player))
+ continue;
+
+ // Don't save currency tokens
+ ItemTemplate const* itemTemplate = sObjectMgr->GetItemTemplate(li.itemid);
+ if (!itemTemplate || itemTemplate->IsCurrencyToken())
+ continue;
+
+ container.AddLootItem(li, trans);
+ }
+
+ CharacterDatabase.CommitTransaction(trans);
+
+ // write
+ {
+ boost::unique_lock<boost::shared_mutex> lock(*GetLock());
+ _lootItemStore.emplace(loot->containerID, std::move(container));
+ }
+}
+
+void StoredLootContainer::AddLootItem(LootItem const& lootItem, SQLTransaction& trans)
+{
+ _lootItems.emplace(std::piecewise_construct, std::forward_as_tuple(lootItem.itemid), std::forward_as_tuple(lootItem));
+ if (!trans)
+ return;
+
+ PreparedStatement* 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
+ stmt->setUInt32(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.randomPropertyId);
+ stmt->setUInt32(10, lootItem.randomSuffix);
+ trans->Append(stmt);
+}
+
+void StoredLootContainer::AddMoney(uint32 money, SQLTransaction& trans)
+{
+ _money = money;
+ if (!trans)
+ return;
+
+ PreparedStatement* stmt = CharacterDatabase.GetPreparedStatement(CHAR_DEL_ITEMCONTAINER_MONEY);
+ stmt->setUInt32(0, _containerId);
+ trans->Append(stmt);
+
+ stmt = CharacterDatabase.GetPreparedStatement(CHAR_INS_ITEMCONTAINER_MONEY);
+ stmt->setUInt32(0, _containerId);
+ stmt->setUInt32(1, _money);
+ trans->Append(stmt);
+}
+
+void StoredLootContainer::RemoveMoney()
+{
+ _money = 0;
+
+ PreparedStatement* stmt = CharacterDatabase.GetPreparedStatement(CHAR_DEL_ITEMCONTAINER_MONEY);
+ stmt->setUInt32(0, _containerId);
+ CharacterDatabase.Execute(stmt);
+}
+
+void StoredLootContainer::RemoveItem(uint32 itemId, uint32 count)
+{
+ auto bounds = _lootItems.equal_range(itemId);
+ for (auto itr = bounds.first; itr != bounds.second; ++itr)
+ {
+ if (itr->second.Count == count)
+ {
+ _lootItems.erase(itr);
+ break;
+ }
+ }
+
+ // Deletes a single item associated with an openable item from the DB
+ PreparedStatement* stmt = CharacterDatabase.GetPreparedStatement(CHAR_DEL_ITEMCONTAINER_ITEM);
+ stmt->setUInt32(0, _containerId);
+ stmt->setUInt32(1, itemId);
+ stmt->setUInt32(2, count);
+ CharacterDatabase.Execute(stmt);
+}
diff --git a/src/server/game/Loot/LootItemStorage.h b/src/server/game/Loot/LootItemStorage.h
new file mode 100644
index 00000000000..871300e7fcd
--- /dev/null
+++ b/src/server/game/Loot/LootItemStorage.h
@@ -0,0 +1,93 @@
+/*
+* Copyright (C) 2008-2017 TrinityCore <http://www.trinitycore.org/>
+*
+* This program is free software; you can redistribute it and/or modify it
+* under the terms of the GNU General Public License as published by the
+* Free Software Foundation; either version 2 of the License, or (at your
+* option) any later version.
+*
+* This program is distributed in the hope that it will be useful, but WITHOUT
+* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+* more details.
+*
+* You should have received a copy of the GNU General Public License along
+* with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#ifndef __LOOTITEMSTORAGE_H
+#define __LOOTITEMSTORAGE_H
+
+#include "Define.h"
+
+#include <vector>
+
+class Item;
+class Player;
+struct Loot;
+struct LootItem;
+namespace boost
+{
+ class shared_mutex;
+}
+
+struct StoredLootItem
+{
+ explicit StoredLootItem(LootItem const& lootItem);
+
+ uint32 ItemId;
+ uint32 Count;
+ bool FollowRules;
+ bool FFA;
+ bool Blocked;
+ bool Counted;
+ bool UnderThreshold;
+ bool NeedsQuest;
+ int32 RandomPropertyId;
+ uint32 RandomSuffix;
+};
+
+class StoredLootContainer
+{
+ public:
+ typedef std::unordered_multimap<uint32 /*itemId*/, StoredLootItem> StoredLootItemContainer;
+
+ explicit StoredLootContainer(uint32 containerId) : _containerId(containerId), _money(0) { }
+
+ void AddLootItem(LootItem const& lootItem, SQLTransaction& trans);
+ void AddMoney(uint32 money, SQLTransaction& trans);
+
+ void RemoveMoney();
+ void RemoveItem(uint32 itemId, uint32 count);
+
+ uint32 GetContainer() const { return _containerId; }
+ uint32 GetMoney() const { return _money; }
+ StoredLootItemContainer const& GetLootItems() const { return _lootItems; }
+
+ private:
+ StoredLootItemContainer _lootItems;
+ uint32 const _containerId;
+ uint32 _money;
+};
+
+class LootItemStorage
+{
+ public:
+ static LootItemStorage* instance();
+ static boost::shared_mutex* GetLock();
+
+ void LoadStorageFromDB();
+ bool LoadStoredLoot(Item* item, Player* player);
+ void RemoveStoredMoneyForContainer(uint32 containerId);
+ void RemoveStoredLootForContainer(uint32 containerId);
+ void RemoveStoredLootItemForContainer(uint32 containerId, uint32 itemId, uint32 count);
+ void AddNewStoredLoot(Loot* loot, Player* player);
+
+ private:
+ LootItemStorage() { }
+ ~LootItemStorage() { }
+};
+
+#define sLootItemStorage LootItemStorage::instance()
+
+#endif
diff --git a/src/server/game/Loot/LootMgr.cpp b/src/server/game/Loot/LootMgr.cpp
index a301426f556..34712308070 100644
--- a/src/server/game/Loot/LootMgr.cpp
+++ b/src/server/game/Loot/LootMgr.cpp
@@ -366,7 +366,6 @@ LootItem::LootItem(LootStoreItem const& li)
is_underthreshold = 0;
is_counted = 0;
rollWinnerGUID = ObjectGuid::Empty;
- canSave = true;
}
// Basic checks for player/item compatibility - if false no chance to see the item in the loot
@@ -692,33 +691,6 @@ void Loot::generateMoneyLoot(uint32 minAmount, uint32 maxAmount)
}
}
-void Loot::DeleteLootItemFromContainerItemDB(uint32 itemID)
-{
- // Deletes a single item associated with an openable item from the DB
- PreparedStatement* stmt = CharacterDatabase.GetPreparedStatement(CHAR_DEL_ITEMCONTAINER_ITEM);
- stmt->setUInt32(0, containerID);
- stmt->setUInt32(1, itemID);
- CharacterDatabase.Execute(stmt);
-
- // Mark the item looted to prevent resaving
- for (LootItemList::iterator _itr = items.begin(); _itr != items.end(); ++_itr)
- {
- if (_itr->itemid != itemID)
- continue;
-
- _itr->canSave = false;
- break;
- }
-}
-
-void Loot::DeleteLootMoneyFromContainerItemDB()
-{
- // Deletes money loot associated with an openable item from the DB
- PreparedStatement* stmt = CharacterDatabase.GetPreparedStatement(CHAR_DEL_ITEMCONTAINER_MONEY);
- stmt->setUInt32(0, containerID);
- CharacterDatabase.Execute(stmt);
-}
-
LootItem* Loot::LootItemInSlot(uint32 lootSlot, Player* player, NotNormalLootItem* *qitem, NotNormalLootItem* *ffaitem, NotNormalLootItem* *conditem)
{
LootItem* item = NULL;
diff --git a/src/server/game/Loot/LootMgr.h b/src/server/game/Loot/LootMgr.h
index 0aa85bb0186..4069d5731b5 100644
--- a/src/server/game/Loot/LootMgr.h
+++ b/src/server/game/Loot/LootMgr.h
@@ -164,7 +164,6 @@ struct TC_GAME_API LootItem
bool is_counted : 1;
bool needs_quest : 1; // quest drop
bool follow_loot_rules : 1;
- bool canSave;
// Constructor, copies most fields from LootStoreItem, generates random count and random suffixes/properties
// Should be called for non-reference LootStoreItem entries only (reference = 0)
@@ -172,8 +171,8 @@ struct TC_GAME_API LootItem
// Empty constructor for creating an empty LootItem to be filled in with DB data
LootItem() : itemid(0), randomSuffix(0), randomPropertyId(0), count(0), is_looted(false), is_blocked(false),
- freeforall(false), is_underthreshold(false), is_counted(false), needs_quest(false), follow_loot_rules(false),
- canSave(true){ };
+ 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
bool AllowedForPlayer(Player const* player) const;
@@ -328,10 +327,6 @@ struct TC_GAME_API Loot
Loot(uint32 _gold = 0) : gold(_gold), unlootedCount(0), roundRobinPlayer(), loot_type(LOOT_NONE), maxDuplicates(1), containerID(0) { }
~Loot() { clear(); }
- // For deleting items at loot removal since there is no backward interface to the Item()
- void DeleteLootItemFromContainerItemDB(uint32 itemID);
- void DeleteLootMoneyFromContainerItemDB();
-
// if loot becomes invalid this reference is used to inform the listener
void addLootValidatorRef(LootValidatorRef* pLootValidatorRef)
{
diff --git a/src/server/game/World/World.cpp b/src/server/game/World/World.cpp
index 38015c6bdab..6cd5960ab9e 100644
--- a/src/server/game/World/World.cpp
+++ b/src/server/game/World/World.cpp
@@ -47,6 +47,7 @@
#include "InstanceSaveMgr.h"
#include "Language.h"
#include "LFGMgr.h"
+#include "LootItemStorage.h"
#include "MapManager.h"
#include "Memory.h"
#include "MMapFactory.h"
@@ -1841,6 +1842,9 @@ void World::SetInitialWorldSettings()
TC_LOG_INFO("server.loading", "Loading Calendar data...");
sCalendarMgr->LoadFromDB();
+ TC_LOG_INFO("server.loading", "Loading Item loot...");
+ sLootItemStorage->LoadStorageFromDB();
+
TC_LOG_INFO("server.loading", "Initialize query data...");
sObjectMgr->InitializeQueriesData(QUERY_DATA_ALL);