mirror of
https://github.com/TrinityCore/TrinityCore.git
synced 2026-01-15 23:20:36 +01:00
Core/Loot: implement Loot Item Storage (#19018)
* Created Item Loot Storage, no more synchronous DB selects
* Fixed buyback case, where stored loot was not removed from db
* Added Primary key, and changed field types to be unsigned for table item_loot_money
(cherry picked from commit 9dc3de10f0)
This commit is contained in:
@@ -3181,7 +3181,7 @@ DROP TABLE IF EXISTS `item_loot_money`;
|
||||
/*!40101 SET character_set_client = utf8 */;
|
||||
CREATE TABLE `item_loot_money` (
|
||||
`container_id` bigint(20) 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=utf8;
|
||||
/*!40101 SET character_set_client = @saved_cs_client */;
|
||||
@@ -3772,7 +3772,9 @@ INSERT INTO `updates` VALUES
|
||||
('2020_02_17_00_characters.sql','E1519A81D35F19B48B3C75A83A270CB4BA0B84F2','RELEASED','2020-02-17 21:55:17',0),
|
||||
('2020_04_20_00_characters.sql','977B5E0C894E0A7E80B2A9626F17CA636A69BD22','RELEASED','2020-04-20 19:08:18',0),
|
||||
('2020_04_24_00_characters.sql','85E2E0395A9457A53D73A9E0A7BB39B7E4C429BF','RELEASED','2020-04-24 22:04:59',0),
|
||||
('2020_04_25_00_characters_2017_04_03_00_characters.sql','00FA3EFADAF807AC96619A3FE47216E21C3FCB19','RELEASED','2020-04-25 00:00:00',0);
|
||||
('2020_04_25_00_characters_2017_04_03_00_characters.sql','00FA3EFADAF807AC96619A3FE47216E21C3FCB19','RELEASED','2020-04-25 00:00:00',0),
|
||||
('2020_04_26_00_characters_2017_04_12_00_characters.sql','86AA94DA9B1EA283101100886C10F648C0CE6494','RELEASED','2020-04-26 00:00:00',0);
|
||||
|
||||
/*!40000 ALTER TABLE `updates` ENABLE KEYS */;
|
||||
UNLOCK TABLES;
|
||||
|
||||
|
||||
@@ -0,0 +1,2 @@
|
||||
ALTER TABLE `item_loot_money`
|
||||
CHANGE `money` `money` int(10) unsigned NOT NULL DEFAULT '0' COMMENT 'money loot (in copper)';
|
||||
@@ -689,11 +689,11 @@ void CharacterDatabaseConnection::DoPrepareStatements()
|
||||
PrepareStatement(CHAR_DEL_GUILD_FINDER_GUILD_SETTINGS, "DELETE FROM guild_finder_guild_settings WHERE guildId = ?", 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_bonus, context, bonus_list_ids 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_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 = ?", 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_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);
|
||||
|
||||
|
||||
@@ -30,6 +30,7 @@
|
||||
#include "ItemEnchantmentMgr.h"
|
||||
#include "ItemPackets.h"
|
||||
#include "Log.h"
|
||||
#include "LootItemStorage.h"
|
||||
#include "LootMgr.h"
|
||||
#include "Map.h"
|
||||
#include "ObjectAccessor.h"
|
||||
@@ -763,7 +764,7 @@ void Item::SaveToDB(CharacterDatabaseTransaction& trans)
|
||||
|
||||
// Delete the items if this is a container
|
||||
if (!loot.isLooted())
|
||||
ItemContainerDeleteLootMoneyAndLootItemsFromDB();
|
||||
sLootItemStorage->RemoveStoredLootForContainer(GetGUID().GetCounter());
|
||||
|
||||
delete this;
|
||||
return;
|
||||
@@ -1058,7 +1059,7 @@ void Item::DeleteFromDB(CharacterDatabaseTransaction& trans)
|
||||
|
||||
// Delete the items if this is a container
|
||||
if (!loot.isLooted())
|
||||
ItemContainerDeleteLootMoneyAndLootItemsFromDB();
|
||||
sLootItemStorage->RemoveStoredLootForContainer(GetGUID().GetCounter());
|
||||
}
|
||||
|
||||
/*static*/
|
||||
@@ -2141,191 +2142,6 @@ uint32 Item::GetSellPrice(ItemTemplate const* proto, uint32 quality, uint32 item
|
||||
return 0;
|
||||
}
|
||||
|
||||
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;
|
||||
|
||||
CharacterDatabaseTransaction trans = CharacterDatabase.BeginTransaction();
|
||||
|
||||
loot.containerID = GetGUID(); // Save this for when a LootItem is removed
|
||||
|
||||
// Save money
|
||||
if (loot.gold > 0)
|
||||
{
|
||||
CharacterDatabasePreparedStatement* stmt_money = CharacterDatabase.GetPreparedStatement(CHAR_DEL_ITEMCONTAINER_MONEY);
|
||||
stmt_money->setUInt64(0, loot.containerID.GetCounter());
|
||||
trans->Append(stmt_money);
|
||||
|
||||
stmt_money = CharacterDatabase.GetPreparedStatement(CHAR_INS_ITEMCONTAINER_MONEY);
|
||||
stmt_money->setUInt64(0, loot.containerID.GetCounter());
|
||||
stmt_money->setUInt32(1, loot.gold);
|
||||
trans->Append(stmt_money);
|
||||
}
|
||||
|
||||
// Save items
|
||||
if (!loot.isLooted())
|
||||
{
|
||||
CharacterDatabasePreparedStatement* stmt_items = CharacterDatabase.GetPreparedStatement(CHAR_DEL_ITEMCONTAINER_ITEMS);
|
||||
stmt_items->setUInt64(0, loot.containerID.GetCounter());
|
||||
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, context, bonus_list_ids
|
||||
stmt_items->setUInt64(0, loot.containerID.GetCounter());
|
||||
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->setUInt32(9, _li->randomBonusListId);
|
||||
stmt_items->setUInt8(10, AsUnderlyingType(_li->context));
|
||||
std::ostringstream bonusListIDs;
|
||||
for (int32 bonusListID : _li->BonusListIDs)
|
||||
bonusListIDs << bonusListID << ' ';
|
||||
stmt_items->setString(11, bonusListIDs.str());
|
||||
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;
|
||||
|
||||
// Save this for later use
|
||||
loot.containerID = GetGUID();
|
||||
|
||||
// First, see if there was any money loot. This gets added directly to the container.
|
||||
CharacterDatabasePreparedStatement* stmt = CharacterDatabase.GetPreparedStatement(CHAR_SEL_ITEMCONTAINER_MONEY);
|
||||
stmt->setUInt64(0, loot.containerID.GetCounter());
|
||||
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->setUInt64(0, loot.containerID.GetCounter());
|
||||
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, context, bonus_list_ids
|
||||
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.randomBonusListId = fields[8].GetUInt32();
|
||||
loot_item.context = ItemContext(fields[9].GetUInt8());
|
||||
Tokenizer bonusLists(fields[10].GetString(), ' ');
|
||||
std::transform(bonusLists.begin(), bonusLists.end(), std::back_inserter(loot_item.BonusListIDs), [](char const* token)
|
||||
{
|
||||
return int32(strtol(token, NULL, 10));
|
||||
});
|
||||
|
||||
// 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
|
||||
CharacterDatabasePreparedStatement* stmt = CharacterDatabase.GetPreparedStatement(CHAR_DEL_ITEMCONTAINER_ITEMS);
|
||||
stmt->setUInt64(0, GetGUID().GetCounter());
|
||||
CharacterDatabase.Execute(stmt);
|
||||
}
|
||||
|
||||
void Item::ItemContainerDeleteLootItemFromDB(uint32 itemID)
|
||||
{
|
||||
// Deletes a single item associated with an openable item from the DB
|
||||
CharacterDatabasePreparedStatement* stmt = CharacterDatabase.GetPreparedStatement(CHAR_DEL_ITEMCONTAINER_ITEM);
|
||||
stmt->setUInt64(0, GetGUID().GetCounter());
|
||||
stmt->setUInt32(1, itemID);
|
||||
CharacterDatabase.Execute(stmt);
|
||||
}
|
||||
|
||||
void Item::ItemContainerDeleteLootMoneyFromDB()
|
||||
{
|
||||
// Deletes the money loot associated with an openable item from the DB
|
||||
CharacterDatabasePreparedStatement* stmt = CharacterDatabase.GetPreparedStatement(CHAR_DEL_ITEMCONTAINER_MONEY);
|
||||
stmt->setUInt64(0, GetGUID().GetCounter());
|
||||
CharacterDatabase.Execute(stmt);
|
||||
}
|
||||
|
||||
void Item::ItemContainerDeleteLootMoneyAndLootItemsFromDB()
|
||||
{
|
||||
// Deletes money and items associated with an openable item from the DB
|
||||
ItemContainerDeleteLootMoneyFromDB();
|
||||
ItemContainerDeleteLootItemsFromDB();
|
||||
}
|
||||
|
||||
uint32 Item::GetItemLevel(Player const* owner) const
|
||||
{
|
||||
ItemTemplate const* itemTemplate = GetTemplate();
|
||||
|
||||
@@ -231,14 +231,6 @@ class TC_GAME_API Item : public Object
|
||||
virtual void DeleteFromDB(CharacterDatabaseTransaction& trans);
|
||||
static void DeleteFromInventoryDB(CharacterDatabaseTransaction& 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(CharacterDatabaseTransaction& trans);
|
||||
void SaveRefundDataToDB();
|
||||
void DeleteRefundDataFromDB(CharacterDatabaseTransaction* trans);
|
||||
|
||||
@@ -75,6 +75,7 @@
|
||||
#include "LFGMgr.h"
|
||||
#include "Language.h"
|
||||
#include "Log.h"
|
||||
#include "LootItemStorage.h"
|
||||
#include "LootMgr.h"
|
||||
#include "LootPackets.h"
|
||||
#include "Mail.h"
|
||||
@@ -8838,9 +8839,12 @@ void Player::SendLoot(ObjectGuid guid, LootType loot_type, bool aeLooting/* = fa
|
||||
|
||||
loot = &item->loot;
|
||||
|
||||
// Store container id
|
||||
loot->containerID = item->GetGUID();
|
||||
|
||||
// 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();
|
||||
@@ -8863,7 +8867,7 @@ void Player::SendLoot(ObjectGuid guid, LootType loot_type, bool aeLooting/* = fa
|
||||
// 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;
|
||||
}
|
||||
@@ -12803,6 +12807,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)
|
||||
{
|
||||
SetInvSlot(slot, ObjectGuid::Empty);
|
||||
@@ -12810,8 +12815,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->GetItemSet())
|
||||
RemoveItemsSetItem(this, pProto);
|
||||
@@ -12847,9 +12850,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->GetFlags() & ITEM_FLAG_HAS_LOOT)
|
||||
pItem->ItemContainerDeleteLootMoneyAndLootItemsFromDB();
|
||||
if (pProto->GetFlags() & ITEM_FLAG_HAS_LOOT)
|
||||
sLootItemStorage->RemoveStoredLootForContainer(pItem->GetGUID().GetCounter());
|
||||
|
||||
if (IsInWorld() && update)
|
||||
{
|
||||
@@ -13766,7 +13768,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
|
||||
@@ -13783,7 +13785,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;
|
||||
@@ -13872,7 +13874,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->GetFlags() & ITEM_FLAG_HAS_LOOT)
|
||||
sLootItemStorage->RemoveStoredLootForContainer(pItem->GetGUID().GetCounter());
|
||||
}
|
||||
}
|
||||
|
||||
m_items[slot] = nullptr;
|
||||
@@ -20846,12 +20853,25 @@ void Player::_SaveInventory(CharacterDatabaseTransaction& 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->GetFlags() & ITEM_FLAG_HAS_LOOT)
|
||||
sLootItemStorage->RemoveStoredLootForContainer(item->GetGUID().GetCounter());
|
||||
|
||||
continue;
|
||||
}
|
||||
|
||||
item->DeleteFromInventoryDB(trans);
|
||||
item->DeleteFromDB(trans);
|
||||
m_items[i]->FSetState(ITEM_NEW);
|
||||
|
||||
if (ItemTemplate const* itemTemplate = item->GetTemplate())
|
||||
if (itemTemplate->GetFlags() & 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,
|
||||
@@ -26197,7 +26217,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())
|
||||
loot->DeleteLootItemFromContainerItemDB(item->itemid);
|
||||
sLootItemStorage->RemoveStoredLootItemForContainer(loot->containerID.GetCounter(), item->itemid, item->count);
|
||||
}
|
||||
else
|
||||
SendEquipError(msg, nullptr, nullptr, item->itemid);
|
||||
|
||||
@@ -28,6 +28,7 @@
|
||||
#include "GuildMgr.h"
|
||||
#include "Item.h"
|
||||
#include "Log.h"
|
||||
#include "LootItemStorage.h"
|
||||
#include "LootMgr.h"
|
||||
#include "LootPackets.h"
|
||||
#include "Object.h"
|
||||
@@ -255,7 +256,7 @@ void WorldSession::HandleLootMoneyOpcode(WorldPackets::Loot::LootMoney& /*packet
|
||||
|
||||
// Delete the money loot record from the DB
|
||||
if (!loot->containerID.IsEmpty())
|
||||
loot->DeleteLootMoneyFromContainerItemDB();
|
||||
sLootItemStorage->RemoveStoredMoneyForContainer(loot->containerID.GetCounter());
|
||||
|
||||
// Delete container if empty
|
||||
if (loot->isLooted() && guid.IsItem())
|
||||
|
||||
@@ -54,7 +54,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
|
||||
@@ -104,33 +103,6 @@ Loot::~Loot()
|
||||
clear();
|
||||
}
|
||||
|
||||
void Loot::DeleteLootItemFromContainerItemDB(uint32 itemID)
|
||||
{
|
||||
// Deletes a single item associated with an openable item from the DB
|
||||
CharacterDatabasePreparedStatement* stmt = CharacterDatabase.GetPreparedStatement(CHAR_DEL_ITEMCONTAINER_ITEM);
|
||||
stmt->setUInt64(0, containerID.GetCounter());
|
||||
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
|
||||
CharacterDatabasePreparedStatement* stmt = CharacterDatabase.GetPreparedStatement(CHAR_DEL_ITEMCONTAINER_MONEY);
|
||||
stmt->setUInt64(0, containerID.GetCounter());
|
||||
CharacterDatabase.Execute(stmt);
|
||||
}
|
||||
|
||||
void Loot::clear()
|
||||
{
|
||||
for (NotNormalLootItemMap::const_iterator itr = PlayerQuestItems.begin(); itr != PlayerQuestItems.end(); ++itr)
|
||||
|
||||
@@ -148,7 +148,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)
|
||||
@@ -156,8 +155,7 @@ struct TC_GAME_API LootItem
|
||||
|
||||
// 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),
|
||||
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;
|
||||
@@ -230,10 +228,6 @@ struct TC_GAME_API Loot
|
||||
ObjectGuid const& GetGUID() const { return _GUID; }
|
||||
void SetGUID(ObjectGuid const& guid) { _GUID = guid; }
|
||||
|
||||
// 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)
|
||||
{
|
||||
|
||||
365
src/server/game/Loot/LootItemStorage.cpp
Normal file
365
src/server/game/Loot/LootItemStorage.cpp
Normal file
@@ -0,0 +1,365 @@
|
||||
/*
|
||||
* This file is part of the TrinityCore Project. See AUTHORS file for Copyright information
|
||||
*
|
||||
* 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 "DatabaseEnv.h"
|
||||
#include "Item.h"
|
||||
#include "ItemTemplate.h"
|
||||
#include "Log.h"
|
||||
#include "LootItemStorage.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<uint64, 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), RandomBonusListId(lootItem.randomBonusListId), Context(lootItem.context), BonusListIDs(lootItem.BonusListIDs)
|
||||
{
|
||||
}
|
||||
|
||||
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;
|
||||
|
||||
CharacterDatabaseTransaction trans = CharacterDatabaseTransaction(nullptr);
|
||||
CharacterDatabasePreparedStatement* stmt = CharacterDatabase.GetPreparedStatement(CHAR_SEL_ITEMCONTAINER_ITEMS);
|
||||
PreparedQueryResult result = CharacterDatabase.Query(stmt);
|
||||
if (result)
|
||||
{
|
||||
do
|
||||
{
|
||||
Field* fields = result->Fetch();
|
||||
|
||||
uint64 key = fields[0].GetUInt64();
|
||||
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.randomBonusListId = fields[9].GetUInt32();
|
||||
lootItem.context = ItemContext(fields[10].GetUInt8());
|
||||
Tokenizer bonusLists(fields[11].GetString(), ' ');
|
||||
std::transform(bonusLists.begin(), bonusLists.end(), std::back_inserter(lootItem.BonusListIDs), [](char const* token)
|
||||
{
|
||||
return int32(strtol(token, NULL, 10));
|
||||
});
|
||||
|
||||
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();
|
||||
|
||||
uint64 key = fields[0].GetUInt64();
|
||||
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.GetCounter());
|
||||
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.randomBonusListId = storedItemPair.second.RandomBonusListId;
|
||||
li.context = storedItemPair.second.Context;
|
||||
li.BonusListIDs = storedItemPair.second.BonusListIDs;
|
||||
|
||||
// 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(uint64 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(uint64 containerId)
|
||||
{
|
||||
// write
|
||||
{
|
||||
boost::unique_lock<boost::shared_mutex> lock(*GetLock());
|
||||
_lootItemStore.erase(containerId);
|
||||
}
|
||||
|
||||
CharacterDatabaseTransaction trans = CharacterDatabase.BeginTransaction();
|
||||
CharacterDatabasePreparedStatement* stmt = CharacterDatabase.GetPreparedStatement(CHAR_DEL_ITEMCONTAINER_ITEMS);
|
||||
stmt->setUInt64(0, containerId);
|
||||
trans->Append(stmt);
|
||||
|
||||
stmt = CharacterDatabase.GetPreparedStatement(CHAR_DEL_ITEMCONTAINER_MONEY);
|
||||
stmt->setUInt64(0, containerId);
|
||||
trans->Append(stmt);
|
||||
|
||||
CharacterDatabase.CommitTransaction(trans);
|
||||
}
|
||||
|
||||
void LootItemStorage::RemoveStoredLootItemForContainer(uint64 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.GetCounter());
|
||||
if (itr != _lootItemStore.end())
|
||||
{
|
||||
TC_LOG_ERROR("misc", "Trying to store item loot by player: %s for container id: %lu that is already in storage!", player->GetGUID().ToString().c_str(), loot->containerID.GetCounter());
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
StoredLootContainer container(loot->containerID.GetCounter());
|
||||
|
||||
CharacterDatabaseTransaction trans = CharacterDatabase.BeginTransaction();
|
||||
if (loot->gold)
|
||||
container.AddMoney(loot->gold, trans);
|
||||
|
||||
CharacterDatabasePreparedStatement* stmt = CharacterDatabase.GetPreparedStatement(CHAR_DEL_ITEMCONTAINER_ITEMS);
|
||||
stmt->setUInt64(0, loot->containerID.GetCounter());
|
||||
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.GetCounter(), std::move(container));
|
||||
}
|
||||
}
|
||||
|
||||
void StoredLootContainer::AddLootItem(LootItem const& lootItem, CharacterDatabaseTransaction& trans)
|
||||
{
|
||||
_lootItems.emplace(std::piecewise_construct, std::forward_as_tuple(lootItem.itemid), std::forward_as_tuple(lootItem));
|
||||
if (!trans)
|
||||
return;
|
||||
|
||||
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
|
||||
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));
|
||||
std::ostringstream bonusListIDs;
|
||||
for (int32 bonusListID : lootItem.BonusListIDs)
|
||||
bonusListIDs << bonusListID << ' ';
|
||||
stmt->setString(11, bonusListIDs.str());
|
||||
trans->Append(stmt);
|
||||
}
|
||||
|
||||
void StoredLootContainer::AddMoney(uint32 money, CharacterDatabaseTransaction& trans)
|
||||
{
|
||||
_money = money;
|
||||
if (!trans)
|
||||
return;
|
||||
|
||||
CharacterDatabasePreparedStatement* stmt = CharacterDatabase.GetPreparedStatement(CHAR_DEL_ITEMCONTAINER_MONEY);
|
||||
stmt->setUInt64(0, _containerId);
|
||||
trans->Append(stmt);
|
||||
|
||||
stmt = CharacterDatabase.GetPreparedStatement(CHAR_INS_ITEMCONTAINER_MONEY);
|
||||
stmt->setUInt64(0, _containerId);
|
||||
stmt->setUInt32(1, _money);
|
||||
trans->Append(stmt);
|
||||
}
|
||||
|
||||
void StoredLootContainer::RemoveMoney()
|
||||
{
|
||||
_money = 0;
|
||||
|
||||
CharacterDatabasePreparedStatement* stmt = CharacterDatabase.GetPreparedStatement(CHAR_DEL_ITEMCONTAINER_MONEY);
|
||||
stmt->setUInt64(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
|
||||
CharacterDatabasePreparedStatement* stmt = CharacterDatabase.GetPreparedStatement(CHAR_DEL_ITEMCONTAINER_ITEM);
|
||||
stmt->setUInt64(0, _containerId);
|
||||
stmt->setUInt32(1, itemId);
|
||||
stmt->setUInt32(2, count);
|
||||
CharacterDatabase.Execute(stmt);
|
||||
}
|
||||
96
src/server/game/Loot/LootItemStorage.h
Normal file
96
src/server/game/Loot/LootItemStorage.h
Normal file
@@ -0,0 +1,96 @@
|
||||
/*
|
||||
* This file is part of the TrinityCore Project. See AUTHORS file for Copyright information
|
||||
*
|
||||
* 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 "DBCEnums.h"
|
||||
#include "ItemEnchantmentMgr.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;
|
||||
ItemRandomBonusListId RandomBonusListId;
|
||||
ItemContext Context;
|
||||
std::vector<int32> BonusListIDs;
|
||||
};
|
||||
|
||||
class StoredLootContainer
|
||||
{
|
||||
public:
|
||||
typedef std::unordered_multimap<uint32 /*itemId*/, StoredLootItem> StoredLootItemContainer;
|
||||
|
||||
explicit StoredLootContainer(uint64 containerId) : _containerId(containerId), _money(0) { }
|
||||
|
||||
void AddLootItem(LootItem const& lootItem, CharacterDatabaseTransaction& trans);
|
||||
void AddMoney(uint32 money, CharacterDatabaseTransaction& 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;
|
||||
uint64 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(uint64 containerId);
|
||||
void RemoveStoredLootForContainer(uint64 containerId);
|
||||
void RemoveStoredLootItemForContainer(uint64 containerId, uint32 itemId, uint32 count);
|
||||
void AddNewStoredLoot(Loot* loot, Player* player);
|
||||
|
||||
private:
|
||||
LootItemStorage() { }
|
||||
~LootItemStorage() { }
|
||||
};
|
||||
|
||||
#define sLootItemStorage LootItemStorage::instance()
|
||||
|
||||
#endif
|
||||
@@ -60,6 +60,7 @@
|
||||
#include "IPLocation.h"
|
||||
#include "Language.h"
|
||||
#include "LFGMgr.h"
|
||||
#include "LootItemStorage.h"
|
||||
#include "LootMgr.h"
|
||||
#include "M2Stores.h"
|
||||
#include "MapManager.h"
|
||||
@@ -2073,6 +2074,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);
|
||||
|
||||
|
||||
Reference in New Issue
Block a user