diff --git a/.gitmodules b/.gitmodules index c9c3988cb..d6f35cdb8 100644 --- a/.gitmodules +++ b/.gitmodules @@ -16,3 +16,6 @@ [submodule "submodules/recastnavigation"] path = submodules/recastnavigation url = https://github.com/EQEmu/recastnavigation.git +[submodule "submodules/expected"] + path = submodules/expected + url = https://github.com/TartanLlama/expected.git diff --git a/CMakeLists.txt b/CMakeLists.txt index 2b12e2ee1..1b9b25e9e 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -270,6 +270,7 @@ INCLUDE_DIRECTORIES(SYSTEM "${ZLIB_LIBRARY_INCLUDE}") INCLUDE_DIRECTORIES(SYSTEM "${Boost_INCLUDE_DIRS}") INCLUDE_DIRECTORIES(SYSTEM "${CMAKE_CURRENT_SOURCE_DIR}/submodules/glm") INCLUDE_DIRECTORIES(SYSTEM "${CMAKE_CURRENT_SOURCE_DIR}/submodules/cereal/include") +INCLUDE_DIRECTORIES(SYSTEM "${CMAKE_CURRENT_SOURCE_DIR}/submodules/expected/include") INCLUDE_DIRECTORIES(SYSTEM "${CMAKE_CURRENT_SOURCE_DIR}/submodules/fmt/include") INCLUDE_DIRECTORIES(SYSTEM "${CMAKE_CURRENT_SOURCE_DIR}/submodules/libuv/include" ) INCLUDE_DIRECTORIES(SYSTEM "${CMAKE_CURRENT_SOURCE_DIR}/submodules/recastnavigation/DebugUtils/Include") diff --git a/common/CMakeLists.txt b/common/CMakeLists.txt index e312c202d..a3c2a8f68 100644 --- a/common/CMakeLists.txt +++ b/common/CMakeLists.txt @@ -151,6 +151,7 @@ SET(common_headers eqtime.h errmsg.h event_sub.h + expected.h extprofile.h faction.h file_util.h @@ -267,6 +268,13 @@ SET(common_headers patches/uf_limits.h patches/uf_ops.h patches/uf_structs.h + shared/shared_memory.h + shared/shared_memory_error.h + shared/shared_memory_handle.h + shared/shared_memory_list.h + shared/shared_memory_map.h + shared/shared_memory_string.h + shared/shared_memory_vector.h StackWalker/StackWalker.h util/memory_stream.h util/directory.h @@ -365,6 +373,16 @@ SOURCE_GROUP(Patches FILES patches/uf_limits.cpp ) +SOURCE_GROUP(shared FILES + shared/shared_memory.h + shared/shared_memory_error.h + shared/shared_memory_handle.h + shared/shared_memory_list.h + shared/shared_memory_map.h + shared/shared_memory_string.h + shared/shared_memory_vector.h +) + SOURCE_GROUP(StackWalker FILES StackWalker/StackWalker.h StackWalker/StackWalker.cpp diff --git a/common/expected.h b/common/expected.h new file mode 100644 index 000000000..a807ceca4 --- /dev/null +++ b/common/expected.h @@ -0,0 +1,27 @@ +/* EQEMu: Everquest Server Emulator + Copyright (C) EQEMu Development Team (http://eqemulator.net) + + 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 04111-1307 USA +*/ + +#pragma once + +#include + +namespace eq +{ + using tl::expected; + using tl::make_unexpected; +} diff --git a/common/shared/shared_memory.h b/common/shared/shared_memory.h new file mode 100644 index 000000000..4b110104b --- /dev/null +++ b/common/shared/shared_memory.h @@ -0,0 +1,82 @@ +/* EQEMu: Everquest Server Emulator + Copyright (C) EQEMu Development Team (http://eqemulator.net) + + 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 04111-1307 USA +*/ + +#pragma once + +#include "../expected.h" +#include "shared_memory_error.h" +#include "shared_memory_handle.h" + +#include +#include + +namespace eq +{ + namespace shared + { + namespace detail { + typedef boost::interprocess::managed_mapped_file::segment_manager segment_manager_t; + typedef boost::interprocess::allocator allocator; + } + + using allocator = detail::allocator; + + class shared_memory + { + public: + shared_memory(const std::string &path, size_t sz) { + _path = path; + _sz = sz; + } + + ~shared_memory() = default; + + template + expected, shared_memory_error> map(const std::string& key) { + if (!_memory) { + try { + _memory.reset(new boost::interprocess::managed_mapped_file(boost::interprocess::open_or_create, _path.c_str(), _sz)); + } + catch (boost::interprocess::interprocess_exception) { + return eq::make_unexpected(shared_memory_error::error_mapping_memory); + } + } + + handle inst; + auto ir = inst.initialize(key, _memory.get()); + if (ir) { + return eq::expected, shared_memory_error>(inst); + } + else { + return make_unexpected(ir.error()); + } + + return expected, shared_memory_error>(inst); + } + + template + Ty construct(Args&&... args) { + return Ty(std::forward(args)..., _memory->get_allocator()); + } + private: + std::unique_ptr _memory; + std::string _path; + size_t _sz; + }; + } +} diff --git a/common/shared/shared_memory_error.h b/common/shared/shared_memory_error.h new file mode 100644 index 000000000..1c5421d3c --- /dev/null +++ b/common/shared/shared_memory_error.h @@ -0,0 +1,32 @@ +/* EQEMu: Everquest Server Emulator + Copyright (C) EQEMu Development Team (http://eqemulator.net) + + 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 04111-1307 USA +*/ + +#pragma once + +namespace eq +{ + namespace shared + { + enum class shared_memory_error + { + no_error, + error_mapping_memory, + error_alloc + }; + } +} diff --git a/common/shared/shared_memory_handle.h b/common/shared/shared_memory_handle.h new file mode 100644 index 000000000..d622821bc --- /dev/null +++ b/common/shared/shared_memory_handle.h @@ -0,0 +1,70 @@ +/* EQEMu: Everquest Server Emulator + Copyright (C) EQEMu Development Team (http://eqemulator.net) + + 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 04111-1307 USA +*/ + +#pragma once + +#include "shared_memory_error.h" +#include "../expected.h" + +#include +#include +#include + +namespace eq +{ + namespace shared + { + namespace detail + { + template + struct type_factory { + static_assert(std::is_trivially_constructible::value, + "Non-specialized types must be trivially constructible, consider creating a type_factory in eq::shared::detail if you want to use this type."); + Ty* create(const std::string& key, boost::interprocess::managed_mapped_file* mmf) { + return mmf->find_or_construct(key.c_str())(); + } + }; + } + + template + class handle { + public: + handle() = default; + ~handle() = default; + + expected initialize(const std::string& key, boost::interprocess::managed_mapped_file* mmf) { + try { + _mmf = mmf; + detail::type_factory fac; + _ptr = fac.create(key, mmf); + return expected(); + } + catch (boost::interprocess::interprocess_exception) { + return make_unexpected(shared_memory_error::error_mapping_memory); + } + } + + operator Ty& () { + return *_ptr; + } + private: + Ty* _ptr; + boost::interprocess::managed_mapped_file* _mmf; + }; + } +} diff --git a/common/shared/shared_memory_list.h b/common/shared/shared_memory_list.h new file mode 100644 index 000000000..96b8b76ce --- /dev/null +++ b/common/shared/shared_memory_list.h @@ -0,0 +1,43 @@ +/* EQEMu: Everquest Server Emulator + Copyright (C) EQEMu Development Team (http://eqemulator.net) + + 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 04111-1307 USA +*/ + +#pragma once + +#include "shared_memory_handle.h" + +#include + +namespace eq +{ + namespace shared + { + template + using list = boost::interprocess::list>; + + namespace detail + { + template + struct type_factory> + { + list* create(const std::string& key, boost::interprocess::managed_mapped_file* mmf) { + return mmf->find_or_construct>(key.c_str())(mmf->get_allocator()); + } + }; + } + } +} diff --git a/common/shared/shared_memory_map.h b/common/shared/shared_memory_map.h new file mode 100644 index 000000000..513eb568b --- /dev/null +++ b/common/shared/shared_memory_map.h @@ -0,0 +1,77 @@ +/* EQEMu: Everquest Server Emulator + Copyright (C) EQEMu Development Team (http://eqemulator.net) + + 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 04111-1307 USA +*/ + +#pragma once + +#include "shared_memory_handle.h" + +#include +#include +#include + +namespace eq +{ + namespace shared + { + template + using unordered_map = boost::unordered_map, + std::equal_to, + boost::interprocess::allocator, boost::interprocess::managed_mapped_file::segment_manager>>; + + template + using map = boost::interprocess::map, + boost::interprocess::allocator, boost::interprocess::managed_mapped_file::segment_manager>>; + + template + using flat_map = boost::interprocess::flat_map, + boost::interprocess::allocator, boost::interprocess::managed_mapped_file::segment_manager>>; + + namespace detail + { + template + struct type_factory> + { + unordered_map* create(const std::string& key, boost::interprocess::managed_mapped_file* mmf) { + return mmf->find_or_construct>(key.c_str())(3, boost::hash(), std::equal_to(), mmf->get_allocator()); + } + }; + + template + struct type_factory> + { + map* create(const std::string& key, boost::interprocess::managed_mapped_file* mmf) { + return mmf->find_or_construct>(key.c_str())(std::less(), mmf->get_allocator()); + } + }; + + template + struct type_factory> + { + flat_map* create(const std::string& key, boost::interprocess::managed_mapped_file* mmf) { + return mmf->find_or_construct>(key.c_str())(std::less(), mmf->get_allocator()); + } + }; + } + } +} diff --git a/common/shared/shared_memory_string.h b/common/shared/shared_memory_string.h new file mode 100644 index 000000000..3ac4591c5 --- /dev/null +++ b/common/shared/shared_memory_string.h @@ -0,0 +1,52 @@ +/* EQEMu: Everquest Server Emulator + Copyright (C) EQEMu Development Team (http://eqemulator.net) + + 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 04111-1307 USA +*/ + +#pragma once + +#pragma once + +#include "shared_memory_handle.h" + +#include + +namespace eq +{ + namespace shared + { + template + using basic_string = boost::interprocess::basic_string, boost::interprocess::allocator>; + + using string = basic_string; + + namespace detail + { + template + struct type_factory> + { + list* create(const std::string& key, boost::interprocess::managed_mapped_file* mmf) { + return mmf->find_or_construct>(key.c_str())(mmf->get_allocator()); + } + }; + } + + template + std::basic_string to_std_string(const eq::shared::basic_string &in) { + return std::basic_string(in.begin(), in.end()); + } + } +} diff --git a/common/shared/shared_memory_vector.h b/common/shared/shared_memory_vector.h new file mode 100644 index 000000000..d575c23f2 --- /dev/null +++ b/common/shared/shared_memory_vector.h @@ -0,0 +1,43 @@ +/* EQEMu: Everquest Server Emulator + Copyright (C) EQEMu Development Team (http://eqemulator.net) + + 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 04111-1307 USA +*/ + +#pragma once + +#include "shared_memory_handle.h" + +#include + +namespace eq +{ + namespace shared + { + template + using vector = boost::interprocess::vector>; + + namespace detail + { + template + struct type_factory> + { + vector* create(const std::string& key, boost::interprocess::managed_mapped_file* mmf) { + return mmf->find_or_construct>(key.c_str())(mmf->get_allocator()); + } + }; + } + } +} diff --git a/common/shareddb.cpp b/common/shareddb.cpp index 48cc1309d..08bc2557b 100644 --- a/common/shareddb.cpp +++ b/common/shareddb.cpp @@ -1656,21 +1656,19 @@ uint8 SharedDatabase::GetTrainLevel(uint8 Class_, EQEmu::skills::SkillType Skill return ret; } -void SharedDatabase::LoadDamageShieldTypes(SPDat_Spell_Struct* sp, int32 iMaxSpellID) { +int SharedDatabase::LoadDamageShieldType(int spell_id) { - std::string query = StringFormat("SELECT `spellid`, `type` FROM `damageshieldtypes` WHERE `spellid` > 0 " - "AND `spellid` <= %i", iMaxSpellID); + std::string query = StringFormat("SELECT `type` FROM `damageshieldtypes` WHERE `spellid` = %i", spell_id); auto results = QueryDatabase(query); if (!results.Success()) { - return; + return 0; } - for(auto row = results.begin(); row != results.end(); ++row) { - int spellID = atoi(row[0]); - if((spellID > 0) && (spellID <= iMaxSpellID)) - sp[spellID].DamageShieldType = atoi(row[1]); + for(auto &row : results) { + return atoi(row[0]); } + return 0; } const EvolveInfo* SharedDatabase::GetEvolveInfo(uint32 loregroup) { @@ -1689,6 +1687,18 @@ int SharedDatabase::GetMaxSpellID() { return atoi(row[0]); } +int SharedDatabase::GetSpellCount() { + std::string query = "SELECT COUNT(id) FROM spells_new"; + auto results = QueryDatabase(query); + if (!results.Success()) { + return -1; + } + + auto row = results.begin(); + + return atoi(row[0]); +} + bool SharedDatabase::LoadSpells(const std::string &prefix, int32 *records, const SPDat_Spell_Struct **sp) { spells_mmf.reset(nullptr); @@ -1710,175 +1720,163 @@ bool SharedDatabase::LoadSpells(const std::string &prefix, int32 *records, const return true; } -void SharedDatabase::LoadSpells(void *data, int max_spells) { - *(uint32*)data = max_spells; - SPDat_Spell_Struct *sp = reinterpret_cast((char*)data + sizeof(uint32)); - +void SharedDatabase::LoadSpells(std::function on_load) { const std::string query = "SELECT * FROM spells_new ORDER BY id ASC"; auto results = QueryDatabase(query); if (!results.Success()) { return; } - + if(results.ColumnCount() <= SPELL_LOAD_FIELD_COUNT) { LogSpells("Fatal error loading spells: Spell field count < SPELL_LOAD_FIELD_COUNT([{}])", SPELL_LOAD_FIELD_COUNT); return; } - int tempid = 0; - int counter = 0; + for (auto &row : results) { + SPDat_Spell_Struct sp; - for (auto row = results.begin(); row != results.end(); ++row) { - tempid = atoi(row[0]); - if(tempid >= max_spells) { - LogSpells("Non fatal error: spell.id >= max_spells, ignoring"); - continue; - } + sp.id = atoi(row[0]); + strn0cpy(sp.name, row[1], sizeof(sp.name)); + strn0cpy(sp.player_1, row[2], sizeof(sp.player_1)); + strn0cpy(sp.teleport_zone, row[3], sizeof(sp.teleport_zone)); + strn0cpy(sp.you_cast, row[4], sizeof(sp.you_cast)); + strn0cpy(sp.other_casts, row[5], sizeof(sp.other_casts)); + strn0cpy(sp.cast_on_you, row[6], sizeof(sp.cast_on_you)); + strn0cpy(sp.cast_on_other, row[7], sizeof(sp.cast_on_other)); + strn0cpy(sp.spell_fades, row[8], sizeof(sp.spell_fades)); - ++counter; - sp[tempid].id = tempid; - strn0cpy(sp[tempid].name, row[1], sizeof(sp[tempid].name)); - strn0cpy(sp[tempid].player_1, row[2], sizeof(sp[tempid].player_1)); - strn0cpy(sp[tempid].teleport_zone, row[3], sizeof(sp[tempid].teleport_zone)); - strn0cpy(sp[tempid].you_cast, row[4], sizeof(sp[tempid].you_cast)); - strn0cpy(sp[tempid].other_casts, row[5], sizeof(sp[tempid].other_casts)); - strn0cpy(sp[tempid].cast_on_you, row[6], sizeof(sp[tempid].cast_on_you)); - strn0cpy(sp[tempid].cast_on_other, row[7], sizeof(sp[tempid].cast_on_other)); - strn0cpy(sp[tempid].spell_fades, row[8], sizeof(sp[tempid].spell_fades)); + sp.range = static_cast(atof(row[9])); + sp.aoerange = static_cast(atof(row[10])); + sp.pushback = static_cast(atof(row[11])); + sp.pushup = static_cast(atof(row[12])); + sp.cast_time = atoi(row[13]); + sp.recovery_time = atoi(row[14]); + sp.recast_time = atoi(row[15]); + sp.buffdurationformula = atoi(row[16]); + sp.buffduration = atoi(row[17]); + sp.AEDuration = atoi(row[18]); + sp.mana = atoi(row[19]); - sp[tempid].range=static_cast(atof(row[9])); - sp[tempid].aoerange=static_cast(atof(row[10])); - sp[tempid].pushback=static_cast(atof(row[11])); - sp[tempid].pushup=static_cast(atof(row[12])); - sp[tempid].cast_time=atoi(row[13]); - sp[tempid].recovery_time=atoi(row[14]); - sp[tempid].recast_time=atoi(row[15]); - sp[tempid].buffdurationformula=atoi(row[16]); - sp[tempid].buffduration=atoi(row[17]); - sp[tempid].AEDuration=atoi(row[18]); - sp[tempid].mana=atoi(row[19]); + int y = 0; + for (y = 0; y < EFFECT_COUNT; y++) + sp.base[y] = atoi(row[20 + y]); // effect_base_value - int y=0; - for(y=0; y< EFFECT_COUNT;y++) - sp[tempid].base[y]=atoi(row[20+y]); // effect_base_value + for (y = 0; y < EFFECT_COUNT; y++) + sp.base2[y] = atoi(row[32 + y]); // effect_limit_value - for(y=0; y < EFFECT_COUNT; y++) - sp[tempid].base2[y]=atoi(row[32+y]); // effect_limit_value + for (y = 0; y < EFFECT_COUNT; y++) + sp.max[y] = atoi(row[44 + y]); - for(y=0; y< EFFECT_COUNT;y++) - sp[tempid].max[y]=atoi(row[44+y]); + for (y = 0; y < 4; y++) + sp.components[y] = atoi(row[58 + y]); - for(y=0; y< 4;y++) - sp[tempid].components[y]=atoi(row[58+y]); + for (y = 0; y < 4; y++) + sp.component_counts[y] = atoi(row[62 + y]); - for(y=0; y< 4;y++) - sp[tempid].component_counts[y]=atoi(row[62+y]); + for (y = 0; y < 4; y++) + sp.NoexpendReagent[y] = atoi(row[66 + y]); - for(y=0; y< 4;y++) - sp[tempid].NoexpendReagent[y]=atoi(row[66+y]); + for (y = 0; y < EFFECT_COUNT; y++) + sp.formula[y] = atoi(row[70 + y]); - for(y=0; y< EFFECT_COUNT;y++) - sp[tempid].formula[y]=atoi(row[70+y]); + sp.goodEffect = atoi(row[83]); + sp.Activated = atoi(row[84]); + sp.resisttype = atoi(row[85]); - sp[tempid].goodEffect=atoi(row[83]); - sp[tempid].Activated=atoi(row[84]); - sp[tempid].resisttype=atoi(row[85]); + for (y = 0; y < EFFECT_COUNT; y++) + sp.effectid[y] = atoi(row[86 + y]); - for(y=0; y< EFFECT_COUNT;y++) - sp[tempid].effectid[y]=atoi(row[86+y]); - - sp[tempid].targettype = (SpellTargetType) atoi(row[98]); - sp[tempid].basediff=atoi(row[99]); + sp.targettype = (SpellTargetType)atoi(row[98]); + sp.basediff = atoi(row[99]); int tmp_skill = atoi(row[100]);; if (tmp_skill < 0 || tmp_skill > EQEmu::skills::HIGHEST_SKILL) - sp[tempid].skill = EQEmu::skills::SkillBegging; /* not much better we can do. */ // can probably be changed to client-based 'SkillNone' once activated - else - sp[tempid].skill = (EQEmu::skills::SkillType) tmp_skill; + sp.skill = EQEmu::skills::SkillBegging; /* not much better we can do. */ // can probably be changed to client-based 'SkillNone' once activated + else + sp.skill = (EQEmu::skills::SkillType) tmp_skill; - sp[tempid].zonetype=atoi(row[101]); - sp[tempid].EnvironmentType=atoi(row[102]); - sp[tempid].TimeOfDay=atoi(row[103]); + sp.zonetype = atoi(row[101]); + sp.EnvironmentType = atoi(row[102]); + sp.TimeOfDay = atoi(row[103]); - for(y=0; y < PLAYER_CLASS_COUNT;y++) - sp[tempid].classes[y]=atoi(row[104+y]); + for (y = 0; y < PLAYER_CLASS_COUNT; y++) + sp.classes[y] = atoi(row[104 + y]); - sp[tempid].CastingAnim=atoi(row[120]); - sp[tempid].SpellAffectIndex=atoi(row[123]); - sp[tempid].disallow_sit=atoi(row[124]); - sp[tempid].diety_agnostic=atoi(row[125]); + sp.CastingAnim = atoi(row[120]); + sp.SpellAffectIndex = atoi(row[123]); + sp.disallow_sit = atoi(row[124]); + sp.diety_agnostic = atoi(row[125]); for (y = 0; y < 16; y++) - sp[tempid].deities[y]=atoi(row[126+y]); + sp.deities[y] = atoi(row[126 + y]); - sp[tempid].new_icon=atoi(row[144]); - sp[tempid].uninterruptable=atoi(row[146]) != 0; - sp[tempid].ResistDiff=atoi(row[147]); - sp[tempid].dot_stacking_exempt = atoi(row[148]) != 0; - sp[tempid].RecourseLink = atoi(row[150]); - sp[tempid].no_partial_resist = atoi(row[151]) != 0; + sp.new_icon = atoi(row[144]); + sp.uninterruptable = atoi(row[146]) != 0; + sp.ResistDiff = atoi(row[147]); + sp.dot_stacking_exempt = atoi(row[148]) != 0; + sp.RecourseLink = atoi(row[150]); + sp.no_partial_resist = atoi(row[151]) != 0; - sp[tempid].short_buff_box = atoi(row[154]); - sp[tempid].descnum = atoi(row[155]); - sp[tempid].typedescnum = atoi(row[156]); - sp[tempid].effectdescnum = atoi(row[157]); + sp.short_buff_box = atoi(row[154]); + sp.descnum = atoi(row[155]); + sp.typedescnum = atoi(row[156]); + sp.effectdescnum = atoi(row[157]); - sp[tempid].npc_no_los = atoi(row[159]) != 0; - sp[tempid].reflectable = atoi(row[161]) != 0; - sp[tempid].bonushate=atoi(row[162]); + sp.npc_no_los = atoi(row[159]) != 0; + sp.reflectable = atoi(row[161]) != 0; + sp.bonushate = atoi(row[162]); - sp[tempid].ldon_trap = atoi(row[165]) != 0; - sp[tempid].EndurCost=atoi(row[166]); - sp[tempid].EndurTimerIndex=atoi(row[167]); - sp[tempid].IsDisciplineBuff = atoi(row[168]) != 0; - sp[tempid].HateAdded=atoi(row[173]); - sp[tempid].EndurUpkeep=atoi(row[174]); - sp[tempid].numhitstype = atoi(row[175]); - sp[tempid].numhits = atoi(row[176]); - sp[tempid].pvpresistbase=atoi(row[177]); - sp[tempid].pvpresistcalc=atoi(row[178]); - sp[tempid].pvpresistcap=atoi(row[179]); - sp[tempid].spell_category=atoi(row[180]); - sp[tempid].pcnpc_only_flag=atoi(row[183]); - sp[tempid].cast_not_standing = atoi(row[184]) != 0; - sp[tempid].can_mgb=atoi(row[185]); - sp[tempid].dispel_flag = atoi(row[186]); - sp[tempid].MinResist = atoi(row[189]); - sp[tempid].MaxResist = atoi(row[190]); - sp[tempid].viral_targets = atoi(row[191]); - sp[tempid].viral_timer = atoi(row[192]); - sp[tempid].NimbusEffect = atoi(row[193]); - sp[tempid].directional_start = static_cast(atoi(row[194])); - sp[tempid].directional_end = static_cast(atoi(row[195])); - sp[tempid].sneak = atoi(row[196]) != 0; - sp[tempid].not_focusable = atoi(row[197]) != 0; - sp[tempid].no_detrimental_spell_aggro = atoi(row[198]) != 0; - sp[tempid].suspendable = atoi(row[200]) != 0; - sp[tempid].viral_range = atoi(row[201]); - sp[tempid].songcap = atoi(row[202]); - sp[tempid].no_block = atoi(row[205]); - sp[tempid].spellgroup=atoi(row[207]); - sp[tempid].rank = atoi(row[208]); - sp[tempid].no_resist=atoi(row[209]); - sp[tempid].CastRestriction = atoi(row[211]); - sp[tempid].AllowRest = atoi(row[212]) != 0; - sp[tempid].InCombat = atoi(row[213]) != 0; - sp[tempid].OutofCombat = atoi(row[214]) != 0; - sp[tempid].override_crit_chance = atoi(row[217]); - sp[tempid].aemaxtargets = atoi(row[218]); - sp[tempid].no_heal_damage_item_mod = atoi(row[219]); - sp[tempid].persistdeath = atoi(row[224]) != 0; - sp[tempid].min_dist = atof(row[227]); - sp[tempid].min_dist_mod = atof(row[228]); - sp[tempid].max_dist = atof(row[229]); - sp[tempid].max_dist_mod = atof(row[230]); - sp[tempid].min_range = static_cast(atoi(row[231])); - sp[tempid].no_remove = atoi(row[232]) != 0; - sp[tempid].DamageShieldType = 0; + sp.ldon_trap = atoi(row[165]) != 0; + sp.EndurCost = atoi(row[166]); + sp.EndurTimerIndex = atoi(row[167]); + sp.IsDisciplineBuff = atoi(row[168]) != 0; + sp.HateAdded = atoi(row[173]); + sp.EndurUpkeep = atoi(row[174]); + sp.numhitstype = atoi(row[175]); + sp.numhits = atoi(row[176]); + sp.pvpresistbase = atoi(row[177]); + sp.pvpresistcalc = atoi(row[178]); + sp.pvpresistcap = atoi(row[179]); + sp.spell_category = atoi(row[180]); + sp.pcnpc_only_flag = atoi(row[183]); + sp.cast_not_standing = atoi(row[184]) != 0; + sp.can_mgb = atoi(row[185]); + sp.dispel_flag = atoi(row[186]); + sp.MinResist = atoi(row[189]); + sp.MaxResist = atoi(row[190]); + sp.viral_targets = atoi(row[191]); + sp.viral_timer = atoi(row[192]); + sp.NimbusEffect = atoi(row[193]); + sp.directional_start = static_cast(atoi(row[194])); + sp.directional_end = static_cast(atoi(row[195])); + sp.sneak = atoi(row[196]) != 0; + sp.not_focusable = atoi(row[197]) != 0; + sp.no_detrimental_spell_aggro = atoi(row[198]) != 0; + sp.suspendable = atoi(row[200]) != 0; + sp.viral_range = atoi(row[201]); + sp.songcap = atoi(row[202]); + sp.no_block = atoi(row[205]); + sp.spellgroup = atoi(row[207]); + sp.rank = atoi(row[208]); + sp.no_resist = atoi(row[209]); + sp.CastRestriction = atoi(row[211]); + sp.AllowRest = atoi(row[212]) != 0; + sp.InCombat = atoi(row[213]) != 0; + sp.OutofCombat = atoi(row[214]) != 0; + sp.override_crit_chance = atoi(row[217]); + sp.aemaxtargets = atoi(row[218]); + sp.no_heal_damage_item_mod = atoi(row[219]); + sp.persistdeath = atoi(row[224]) != 0; + sp.min_dist = atof(row[227]); + sp.min_dist_mod = atof(row[228]); + sp.max_dist = atof(row[229]); + sp.max_dist_mod = atof(row[230]); + sp.min_range = static_cast(atoi(row[231])); + sp.no_remove = atoi(row[232]) != 0; + sp.DamageShieldType = LoadDamageShieldType(sp.id); //ideally we could do this with a simple join but we need to formalize the table first. + on_load(sp); } - - LoadDamageShieldTypes(sp, max_spells); } int SharedDatabase::GetMaxBaseDataLevel() { diff --git a/common/shareddb.h b/common/shareddb.h index 8deb65126..eccecd91c 100644 --- a/common/shareddb.h +++ b/common/shareddb.h @@ -140,9 +140,10 @@ class SharedDatabase : public Database uint8 GetTrainLevel(uint8 Class_, EQEmu::skills::SkillType Skill, uint8 Level); int GetMaxSpellID(); + int GetSpellCount(); bool LoadSpells(const std::string &prefix, int32 *records, const SPDat_Spell_Struct **sp); - void LoadSpells(void *data, int max_spells); - void LoadDamageShieldTypes(SPDat_Spell_Struct* sp, int32 iMaxSpellID); + void LoadSpells(std::function on_load); + int LoadDamageShieldType(int spell_id); int GetMaxBaseDataLevel(); bool LoadBaseData(const std::string &prefix); diff --git a/shared_memory/spells.cpp b/shared_memory/spells.cpp index c653e26f5..279ba8f54 100644 --- a/shared_memory/spells.cpp +++ b/shared_memory/spells.cpp @@ -19,28 +19,35 @@ #include "spells.h" #include "../common/global_define.h" #include "../common/shareddb.h" -#include "../common/ipc_mutex.h" -#include "../common/memory_mapped_file.h" -#include "../common/eqemu_exception.h" #include "../common/spdat.h" +#include "../common/shared/shared_memory.h" +#include "../common/shared/shared_memory_map.h" + +namespace eqs = eq::shared; void LoadSpells(SharedDatabase *database, const std::string &prefix) { - EQEmu::IPCMutex mutex("spells"); - mutex.Lock(); - int records = database->GetMaxSpellID() + 1; - if(records == 0) { - EQ_EXCEPT("Shared Memory", "Unable to get any spells from the database."); + int records = database->GetSpellCount(); + int max_spell_id = database->GetMaxSpellID() + 1; + auto size = records * sizeof(SPDat_Spell_Struct) * 125 / 100 + (64 * 1024); + eqs::shared_memory shared("shared/spells", size); + + auto spells_result = shared.map>("spells"); + if (!spells_result) { + //todo: get rid of the exceptions entirely. + EQ_EXCEPT("Shared Memory", "Unable to map shared memory"); } - uint32 size = records * sizeof(SPDat_Spell_Struct) + sizeof(uint32); + auto max_spell_id_result = shared.map("max_spell_id"); + if (!max_spell_id_result) { + EQ_EXCEPT("Shared Memory", "Unable to map shared memory"); + } - auto Config = EQEmuConfig::get(); - std::string file_name = Config->SharedMemDir + prefix + std::string("spells"); - EQEmu::MemoryMappedFile mmf(file_name, size); - mmf.ZeroFile(); + eqs::unordered_map& spells_shm = spells_result.value(); + int& max_spell_id_shm = max_spell_id_result.value(); + max_spell_id_shm = max_spell_id; - void *ptr = mmf.Get(); - database->LoadSpells(ptr, records); - mutex.Unlock(); + database->LoadSpells([&spells_shm](const SPDat_Spell_Struct &spell) { + spells_shm.insert_or_assign(spell.id, spell); + }); } diff --git a/submodules/expected b/submodules/expected new file mode 160000 index 000000000..3d741708b --- /dev/null +++ b/submodules/expected @@ -0,0 +1 @@ +Subproject commit 3d741708b967b83ca1e2888239196c4a67f9f9b0