[Loot] Remove from shared memory, simplification (#3988)

* First pass of pulling loot out of shared memory, functional

* More code cleanup

* More cleanup

* More cleanup

* More cleanup

* Add loot reload type

* Reload, logging

* Update npc.h

* Cleanup

* Logging, don't load attempt to load loottable id 0

* Update worldserver.cpp

* Update client.cpp

* Update zone_loot.cpp

* PR feedback

* Update zone.cpp

* Memory leak suggestion

* Update CMakeLists.txt

* Post rebase issues
This commit is contained in:
Chris Miles
2024-02-05 15:17:53 -06:00
committed by GitHub
parent fcbf5cae47
commit c654c1d674
55 changed files with 1595 additions and 1890 deletions
+1 -1
View File
@@ -561,7 +561,7 @@ SET(common_headers
json_config.h
light_source.h
linked_list.h
loottable.h
loot.h
mail_oplist.h
md5.h
memory_buffer.h
-1
View File
@@ -22,7 +22,6 @@
#include "../database.h"
#include "../rulesys.h"
#include "../eqemu_logsys.h"
#include "../loottable.h"
#include "../repositories/content_flags_repository.h"
+7 -1
View File
@@ -23,11 +23,17 @@
#include <string>
#include <vector>
#include "../loottable.h"
#include "../repositories/content_flags_repository.h"
class Database;
struct ContentFlags {
int16 min_expansion;
int16 max_expansion;
std::string content_flags;
std::string content_flags_disabled;
};
namespace Expansion {
static const int EXPANSION_ALL = -1;
static const int EXPANSION_FILTER_MAX = 99;
-25
View File
@@ -5553,28 +5553,6 @@ struct MercenaryMerchantResponse_Struct {
/*0004*/
};
struct ServerLootItem_Struct {
uint32 item_id; // uint32 item_id;
int16 equip_slot; // int16 equip_slot;
uint16 charges; // uint8 charges;
uint16 lootslot; // uint16 lootslot;
uint32 aug_1; // uint32 aug_1;
uint32 aug_2; // uint32 aug_2;
uint32 aug_3; // uint32 aug_3;
uint32 aug_4; // uint32 aug_4;
uint32 aug_5; // uint32 aug_5;
uint32 aug_6; // uint32 aug_5;
bool attuned;
std::string custom_data;
uint32 ornamenticon {};
uint32 ornamentidfile {};
uint32 ornament_hero_model {};
uint16 trivial_min_level;
uint16 trivial_max_level;
uint16 npc_min_level;
uint16 npc_max_level;
};
//Found in client near a ref to the string:
//"Got a broadcast message for ... %s ...\n"
struct ClientMarqueeMessage_Struct {
@@ -5593,9 +5571,6 @@ struct ClientMarqueeMessage_Struct {
};
typedef std::list<ServerLootItem_Struct*> ItemList;
struct fling_struct {
/* 00 */ uint32 collision; // 0 collision is off, anything else it's on
/* 04 */ int32 travel_time; // ms -- UF we need to calc this, RoF+ -1 auto calcs
+33
View File
@@ -0,0 +1,33 @@
#ifndef CODE_LOOT_H
#define CODE_LOOT_H
#include <list>
#include <string>
#include "../common/types.h"
struct LootItem {
uint32 item_id;
int16 equip_slot;
uint16 charges;
uint16 lootslot;
uint32 aug_1;
uint32 aug_2;
uint32 aug_3;
uint32 aug_4;
uint32 aug_5;
uint32 aug_6;
bool attuned;
std::string custom_data;
uint32 ornamenticon{};
uint32 ornamentidfile{};
uint32 ornament_hero_model{};
uint16 trivial_min_level;
uint16 trivial_max_level;
uint16 npc_min_level;
uint16 npc_max_level;
};
typedef std::list<LootItem*> LootItems;
#endif //CODE_LOOT_H
-68
View File
@@ -1,68 +0,0 @@
/* EQEMu: Everquest Server Emulator
Copyright (C) 2001-2013 EQEMu Development Team (http://eqemu.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; version 2 of the License.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY except by those people which sell it, which
are required to give you total support for your newly bought product;
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, write to the Free Software
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
#ifndef _EQEMU_LOOTTABLE_H
#define _EQEMU_LOOTTABLE_H
#include "types.h"
#pragma pack(1)
struct LootTableEntries_Struct {
uint32 lootdrop_id;
uint8 droplimit;
uint8 mindrop;
uint8 multiplier;
float probability;
};
struct ContentFlags {
int16 min_expansion;
int16 max_expansion;
char content_flags[100];
char content_flags_disabled[100];
};
struct LootTable_Struct {
uint32 mincash;
uint32 maxcash;
uint32 avgcoin;
uint32 NumEntries;
ContentFlags content_flags;
LootTableEntries_Struct Entries[0];
};
struct LootDropEntries_Struct {
uint32 item_id;
int8 item_charges;
uint8 equip_item;
float chance;
uint16 trivial_min_level;
uint16 trivial_max_level;
uint16 npc_min_level;
uint16 npc_max_level;
uint8 multiplier;
};
struct LootDrop_Struct {
uint32 NumEntries;
ContentFlags content_flags;
LootDropEntries_Struct Entries[0];
};
#pragma pack()
#endif
@@ -8,42 +8,24 @@
class LootdropEntriesRepository: public BaseLootdropEntriesRepository {
public:
/**
* This file was auto generated and can be modified and extended upon
*
* Base repository methods are automatically
* generated in the "base" version of this repository. The base repository
* is immutable and to be left untouched, while methods in this class
* are used as extension methods for more specific persistence-layer
* accessors or mutators.
*
* Base Methods (Subject to be expanded upon in time)
*
* Note: Not all tables are designed appropriately to fit functionality with all base methods
*
* InsertOne
* UpdateOne
* DeleteOne
* FindOne
* GetWhere(std::string where_filter)
* DeleteWhere(std::string where_filter)
* InsertMany
* All
*
* Example custom methods in a repository
*
* LootdropEntriesRepository::GetByZoneAndVersion(int zone_id, int zone_version)
* LootdropEntriesRepository::GetWhereNeverExpires()
* LootdropEntriesRepository::GetWhereXAndY()
* LootdropEntriesRepository::DeleteWhereXAndY()
*
* Most of the above could be covered by base methods, but if you as a developer
* find yourself re-using logic for other parts of the code, its best to just make a
* method that can be re-used easily elsewhere especially if it can use a base repository
* method and encapsulate filters there
*/
static LootdropEntries NewNpcEntity()
{
LootdropEntries e{};
// Custom extended repository methods here
e.lootdrop_id = 0;
e.item_id = 0;
e.item_charges = 1;
e.equip_item = 1;
e.chance = 0;
e.disabled_chance = 0;
e.trivial_min_level = 0;
e.trivial_max_level = 0;
e.multiplier = 0;
e.npc_min_level = 0;
e.npc_max_level = 0;
return e;
}
};
+6 -5
View File
@@ -24,8 +24,9 @@
#include <string>
#include "repositories/saylink_repository.h"
#include "loot.h"
struct ServerLootItem_Struct;
struct LootItem;
namespace EQ
{
@@ -73,7 +74,7 @@ namespace EQ
void SetLinkType(saylink::SayLinkType link_type) { m_LinkType = link_type; }
void SetItemData(const EQ::ItemData* item_data) { m_ItemData = item_data; }
void SetLootData(const ServerLootItem_Struct* loot_data) { m_LootData = loot_data; }
void SetLootData(const LootItem* loot_data) { m_LootData = loot_data; }
void SetItemInst(const ItemInstance* item_inst) { m_ItemInst = item_inst; }
// mainly for saylinks..but, not limited to
@@ -112,9 +113,9 @@ namespace EQ
void generate_text();
int m_LinkType;
const ItemData* m_ItemData;
const ServerLootItem_Struct* m_LootData;
const ItemInstance* m_ItemInst;
const ItemData * m_ItemData;
const LootItem * m_LootData;
const ItemInstance * m_ItemInst;
SayLinkBody_Struct m_LinkBodyStruct;
SayLinkProxy_Struct m_LinkProxyStruct;
bool m_TaskUse;
+1
View File
@@ -252,6 +252,7 @@
#define ServerOP_ReloadZoneData 0x4124
#define ServerOP_ReloadDataBucketsCache 0x4125
#define ServerOP_ReloadFactions 0x4126
#define ServerOP_ReloadLoot 0x4127
#define ServerOP_CZDialogueWindow 0x4500
#define ServerOP_CZLDoNUpdate 0x4501
-289
View File
@@ -30,7 +30,6 @@
#include "features.h"
#include "ipc_mutex.h"
#include "inventory_profile.h"
#include "loottable.h"
#include "memory_mapped_file.h"
#include "mysql.h"
#include "rulesys.h"
@@ -2086,294 +2085,6 @@ const BaseDataStruct* SharedDatabase::GetBaseData(int lvl, int cl) const
return bd;
}
void SharedDatabase::GetLootTableInfo(uint32 &loot_table_count, uint32 &max_loot_table, uint32 &loot_table_entries) {
loot_table_count = 0;
max_loot_table = 0;
loot_table_entries = 0;
const std::string query =
fmt::format(
"SELECT COUNT(*), MAX(id), (SELECT COUNT(*) FROM loottable_entries) FROM loottable WHERE TRUE {}",
ContentFilterCriteria::apply()
);
auto results = QueryDatabase(query);
if (!results.Success()) {
return;
}
if (results.RowCount() == 0)
return;
auto& row = results.begin();
loot_table_count = Strings::ToUnsignedInt(row[0]);
max_loot_table = Strings::ToUnsignedInt(row[1] ? row[1] : "0");
loot_table_entries = Strings::ToUnsignedInt(row[2]);
}
void SharedDatabase::GetLootDropInfo(uint32 &loot_drop_count, uint32 &max_loot_drop, uint32 &loot_drop_entries) {
loot_drop_count = 0;
max_loot_drop = 0;
loot_drop_entries = 0;
const std::string query = fmt::format(
"SELECT COUNT(*), MAX(id), (SELECT COUNT(*) FROM lootdrop_entries) FROM lootdrop WHERE TRUE {}",
ContentFilterCriteria::apply()
);
auto results = QueryDatabase(query);
if (!results.Success()) {
return;
}
if (results.RowCount() == 0)
return;
auto& row =results.begin();
loot_drop_count = Strings::ToUnsignedInt(row[0]);
max_loot_drop = Strings::ToUnsignedInt(row[1] ? row[1] : "0");
loot_drop_entries = Strings::ToUnsignedInt(row[2]);
}
void SharedDatabase::LoadLootTables(void *data, uint32 size) {
EQ::FixedMemoryVariableHashSet<LootTable_Struct> hash(static_cast<uint8*>(data), size);
uint8 loot_table[sizeof(LootTable_Struct) + (sizeof(LootTableEntries_Struct) * 128)];
LootTable_Struct *lt = reinterpret_cast<LootTable_Struct*>(loot_table);
const std::string query = fmt::format(
SQL(
SELECT
loottable.id,
loottable.mincash,
loottable.maxcash,
loottable.avgcoin,
loottable_entries.lootdrop_id,
loottable_entries.multiplier,
loottable_entries.droplimit,
loottable_entries.mindrop,
loottable_entries.probability,
loottable.min_expansion,
loottable.max_expansion,
loottable.content_flags,
loottable.content_flags_disabled
FROM
loottable
LEFT JOIN loottable_entries ON loottable.id = loottable_entries.loottable_id
WHERE TRUE {}
ORDER BY
id
),
ContentFilterCriteria::apply()
);
auto results = QueryDatabase(query);
if (!results.Success()) {
return;
}
uint32 current_id = 0;
uint32 current_entry = 0;
for (auto& row = results.begin(); row != results.end(); ++row) {
const uint32 id = Strings::ToUnsignedInt(row[0]);
if (id != current_id) {
if (current_id != 0) {
hash.insert(
current_id,
loot_table,
(sizeof(LootTable_Struct) + (sizeof(LootTableEntries_Struct) * lt->NumEntries)));
}
memset(loot_table, 0, sizeof(LootTable_Struct) + (sizeof(LootTableEntries_Struct) * 128));
current_entry = 0;
current_id = id;
lt->mincash = Strings::ToUnsignedInt(row[1]);
lt->maxcash = Strings::ToUnsignedInt(row[2]);
lt->avgcoin = Strings::ToUnsignedInt(row[3]);
lt->content_flags.min_expansion = static_cast<int16>(Strings::ToInt(row[9]));
lt->content_flags.max_expansion = static_cast<int16>(Strings::ToInt(row[10]));
strn0cpy(lt->content_flags.content_flags, row[11], sizeof(lt->content_flags.content_flags));
strn0cpy(lt->content_flags.content_flags_disabled, row[12], sizeof(lt->content_flags.content_flags_disabled));
}
if (current_entry > 128) {
continue;
}
if (!row[4]) {
continue;
}
lt->Entries[current_entry].lootdrop_id = Strings::ToUnsignedInt(row[4]);
lt->Entries[current_entry].multiplier = static_cast<uint8>(Strings::ToUnsignedInt(row[5]));
lt->Entries[current_entry].droplimit = static_cast<uint8>(Strings::ToUnsignedInt(row[6]));
lt->Entries[current_entry].mindrop = static_cast<uint8>(Strings::ToUnsignedInt(row[7]));
lt->Entries[current_entry].probability = Strings::ToFloat(row[8]);
++(lt->NumEntries);
++current_entry;
}
if (current_id != 0) {
hash.insert(
current_id,
loot_table,
(sizeof(LootTable_Struct) + (sizeof(LootTableEntries_Struct) * lt->NumEntries))
);
}
}
void SharedDatabase::LoadLootDrops(void *data, uint32 size) {
EQ::FixedMemoryVariableHashSet<LootDrop_Struct> hash(static_cast<uint8*>(data), size);
uint8 loot_drop[sizeof(LootDrop_Struct) + (sizeof(LootDropEntries_Struct) * 1260)];
LootDrop_Struct *p_loot_drop_struct = reinterpret_cast<LootDrop_Struct*>(loot_drop);
const std::string query = fmt::format(
SQL(
SELECT
lootdrop.id,
lootdrop_entries.item_id,
lootdrop_entries.item_charges,
lootdrop_entries.equip_item,
lootdrop_entries.chance,
lootdrop_entries.trivial_min_level,
lootdrop_entries.trivial_max_level,
lootdrop_entries.npc_min_level,
lootdrop_entries.npc_max_level,
lootdrop_entries.multiplier,
lootdrop.min_expansion,
lootdrop.max_expansion,
lootdrop.content_flags,
lootdrop.content_flags_disabled
FROM
lootdrop
JOIN lootdrop_entries ON lootdrop.id = lootdrop_entries.lootdrop_id
WHERE
TRUE {}
ORDER BY
lootdrop_id
),
ContentFilterCriteria::apply()
);
auto results = QueryDatabase(query);
if (!results.Success()) {
return;
}
uint32 current_id = 0;
uint32 current_entry = 0;
for (auto& row = results.begin(); row != results.end(); ++row) {
const auto id = Strings::ToUnsignedInt(row[0]);
if (id != current_id) {
if (current_id != 0) {
hash.insert(
current_id,
loot_drop,
(sizeof(LootDrop_Struct) + (sizeof(LootDropEntries_Struct) * p_loot_drop_struct->NumEntries)));
}
memset(loot_drop, 0, sizeof(LootDrop_Struct) + (sizeof(LootDropEntries_Struct) * 1260));
current_entry = 0;
current_id = id;
p_loot_drop_struct->content_flags.min_expansion = static_cast<int16>(Strings::ToInt(row[10]));
p_loot_drop_struct->content_flags.max_expansion = static_cast<int16>(Strings::ToUnsignedInt(row[11]));
strn0cpy(p_loot_drop_struct->content_flags.content_flags, row[12], sizeof(p_loot_drop_struct->content_flags.content_flags));
strn0cpy(p_loot_drop_struct->content_flags.content_flags_disabled, row[13], sizeof(p_loot_drop_struct->content_flags.content_flags_disabled));
}
if (current_entry >= 1260) {
continue;
}
p_loot_drop_struct->Entries[current_entry].item_id = Strings::ToUnsignedInt(row[1]);
p_loot_drop_struct->Entries[current_entry].item_charges = static_cast<int8>(Strings::ToUnsignedInt(row[2]));
p_loot_drop_struct->Entries[current_entry].equip_item = static_cast<uint8>(Strings::ToUnsignedInt(row[3]));
p_loot_drop_struct->Entries[current_entry].chance = Strings::ToFloat(row[4]);
p_loot_drop_struct->Entries[current_entry].trivial_min_level = static_cast<uint16>(Strings::ToUnsignedInt(row[5]));
p_loot_drop_struct->Entries[current_entry].trivial_max_level = static_cast<uint16>(Strings::ToUnsignedInt(row[6]));
p_loot_drop_struct->Entries[current_entry].npc_min_level = static_cast<uint16>(Strings::ToUnsignedInt(row[7]));
p_loot_drop_struct->Entries[current_entry].npc_max_level = static_cast<uint16>(Strings::ToUnsignedInt(row[8]));
p_loot_drop_struct->Entries[current_entry].multiplier = static_cast<uint8>(Strings::ToUnsignedInt(row[9]));
++(p_loot_drop_struct->NumEntries);
++current_entry;
}
if(current_id != 0)
hash.insert(current_id, loot_drop, (sizeof(LootDrop_Struct) + (sizeof(LootDropEntries_Struct) * p_loot_drop_struct->NumEntries)));
}
bool SharedDatabase::LoadLoot(const std::string &prefix) {
loot_table_mmf.reset(nullptr);
loot_drop_mmf.reset(nullptr);
try {
const auto Config = EQEmuConfig::get();
EQ::IPCMutex mutex("loot");
mutex.Lock();
std::string file_name_lt = fmt::format("{}/{}{}", path.GetSharedMemoryPath(), prefix, std::string("loot_table"));
loot_table_mmf = std::make_unique<EQ::MemoryMappedFile>(file_name_lt);
loot_table_hash = std::make_unique<EQ::FixedMemoryVariableHashSet<LootTable_Struct>>(
static_cast<uint8*>(loot_table_mmf->Get()),
loot_table_mmf->Size());
LogInfo("Loaded loot tables via shared memory");
std::string file_name_ld = fmt::format("{}/{}{}", path.GetSharedMemoryPath(), prefix, std::string("loot_drop"));
loot_drop_mmf = std::make_unique<EQ::MemoryMappedFile>(file_name_ld);
loot_drop_hash = std::make_unique<EQ::FixedMemoryVariableHashSet<LootDrop_Struct>>(
static_cast<uint8*>(loot_drop_mmf->Get()),
loot_drop_mmf->Size());
mutex.Unlock();
} catch(std::exception &ex) {
LogError("Error loading loot: {}", ex.what());
return false;
}
return true;
}
const LootTable_Struct* SharedDatabase::GetLootTable(uint32 loottable_id) const
{
if(!loot_table_hash)
return nullptr;
try {
if(loot_table_hash->exists(loottable_id)) {
return &loot_table_hash->at(loottable_id);
}
} catch(std::exception &ex) {
LogError("Could not get loot table: {}", ex.what());
}
return nullptr;
}
const LootDrop_Struct* SharedDatabase::GetLootDrop(uint32 lootdrop_id) const
{
if(!loot_drop_hash)
return nullptr;
try {
if(loot_drop_hash->exists(lootdrop_id)) {
return &loot_drop_hash->at(lootdrop_id);
}
} catch(std::exception &ex) {
LogError("Could not get loot drop: {}", ex.what());
}
return nullptr;
}
void SharedDatabase::LoadCharacterInspectMessage(uint32 character_id, InspectMessage_Struct* message) {
const std::string query = StringFormat("SELECT `inspect_message` FROM `character_inspect_messages` WHERE `id` = %u LIMIT 1", character_id);
auto results = QueryDatabase(query);
+9 -26
View File
@@ -41,8 +41,6 @@ struct PlayerProfile_Struct;
struct SPDat_Spell_Struct;
struct NPCFactionList;
struct FactionAssociations;
struct LootTable_Struct;
struct LootDrop_Struct;
namespace EQ
@@ -164,17 +162,6 @@ public:
uint32 GetSharedItemsCount() { return m_shared_items_count; }
uint32 GetItemsCount();
/**
* loot
*/
void GetLootTableInfo(uint32 &loot_table_count, uint32 &max_loot_table, uint32 &loot_table_entries);
void GetLootDropInfo(uint32 &loot_drop_count, uint32 &max_loot_drop, uint32 &loot_drop_entries);
void LoadLootTables(void *data, uint32 size);
void LoadLootDrops(void *data, uint32 size);
bool LoadLoot(const std::string &prefix);
const LootTable_Struct *GetLootTable(uint32 loottable_id) const;
const LootDrop_Struct *GetLootDrop(uint32 lootdrop_id) const;
/**
* skills
*/
@@ -212,19 +199,15 @@ public:
protected:
std::unique_ptr<EQ::MemoryMappedFile> skill_caps_mmf;
std::unique_ptr<EQ::MemoryMappedFile> items_mmf;
std::unique_ptr<EQ::FixedMemoryHashSet<EQ::ItemData>> items_hash;
std::unique_ptr<EQ::MemoryMappedFile> faction_mmf;
std::unique_ptr<EQ::FixedMemoryHashSet<NPCFactionList>> faction_hash;
std::unique_ptr<EQ::MemoryMappedFile> faction_associations_mmf;
std::unique_ptr<EQ::FixedMemoryHashSet<FactionAssociations>> faction_associations_hash;
std::unique_ptr<EQ::MemoryMappedFile> loot_table_mmf;
std::unique_ptr<EQ::FixedMemoryVariableHashSet<LootTable_Struct>> loot_table_hash;
std::unique_ptr<EQ::MemoryMappedFile> loot_drop_mmf;
std::unique_ptr<EQ::FixedMemoryVariableHashSet<LootDrop_Struct>> loot_drop_hash;
std::unique_ptr<EQ::MemoryMappedFile> base_data_mmf;
std::unique_ptr<EQ::MemoryMappedFile> spells_mmf;
std::unique_ptr<EQ::MemoryMappedFile> skill_caps_mmf;
std::unique_ptr<EQ::MemoryMappedFile> items_mmf;
std::unique_ptr<EQ::FixedMemoryHashSet<EQ::ItemData>> items_hash;
std::unique_ptr<EQ::MemoryMappedFile> faction_mmf;
std::unique_ptr<EQ::FixedMemoryHashSet<NPCFactionList>> faction_hash;
std::unique_ptr<EQ::MemoryMappedFile> faction_associations_mmf;
std::unique_ptr<EQ::FixedMemoryHashSet<FactionAssociations>> faction_associations_hash;
std::unique_ptr<EQ::MemoryMappedFile> base_data_mmf;
std::unique_ptr<EQ::MemoryMappedFile> spells_mmf;
public:
void SetSharedItemsCount(uint32 shared_items_count);