1
0
Fork 0
mirror of https://github.com/OpenMW/openmw.git synced 2025-06-20 19:11:33 +00:00

gets rid of the macros, we use a tuple instead, with a mechanism to assign an index to each type.

so the tuple is only defined in the cpp, but we can still have template functions in the header that can ge tthe index with the type
This commit is contained in:
florent.teppe 2022-09-03 11:08:23 +02:00
parent 16482243fa
commit ee06cccbe1
3 changed files with 94 additions and 116 deletions

View file

@ -2,6 +2,7 @@
#include <algorithm> #include <algorithm>
#include <fstream> #include <fstream>
#include <tuple>
#include <components/debug/debuglog.hpp> #include <components/debug/debuglog.hpp>
#include <components/esm3/esmreader.hpp> #include <components/esm3/esmreader.hpp>
@ -130,68 +131,6 @@ namespace
} }
template <int storeIndex>
struct StoreIndexToRecordType {
typedef void recordType;
};
static int sRecordTypeCounter = 0;
#define OPENMW_ESM_ADD_STORE_TYPE(__Type, __REC_NAME,__ID_NUM) template<> const int MWWorld::SRecordType<__Type>::sStoreIndex = sRecordTypeCounter ++; \
template<> struct StoreIndexToRecordType<__ID_NUM > {typedef __Type recordType;}; \
OPENMW_ESM_ADD_STORE_TYPE(ESM::Activator,ESM::REC_ACTI,0);
OPENMW_ESM_ADD_STORE_TYPE(ESM::Potion,ESM::REC_ALCH,1);
OPENMW_ESM_ADD_STORE_TYPE(ESM::Apparatus,ESM::REC_APPA,2);
OPENMW_ESM_ADD_STORE_TYPE(ESM::Armor, ESM::REC_ARMO , 3);
OPENMW_ESM_ADD_STORE_TYPE(ESM::BodyPart, ESM::REC_BODY , 4);
OPENMW_ESM_ADD_STORE_TYPE(ESM::Book, ESM::REC_BOOK , 5);
OPENMW_ESM_ADD_STORE_TYPE(ESM::BirthSign, ESM::REC_BSGN , 6);
OPENMW_ESM_ADD_STORE_TYPE(ESM::Class, ESM::REC_CLAS , 7);
OPENMW_ESM_ADD_STORE_TYPE(ESM::Clothing, ESM::REC_CLOT , 8);
OPENMW_ESM_ADD_STORE_TYPE(ESM::Container, ESM::REC_CONT , 9);
OPENMW_ESM_ADD_STORE_TYPE(ESM::Creature, ESM::REC_CREA , 10);
OPENMW_ESM_ADD_STORE_TYPE(ESM::Dialogue, ESM::REC_DIAL , 11);
OPENMW_ESM_ADD_STORE_TYPE(ESM::Door, ESM::REC_DOOR , 12);
OPENMW_ESM_ADD_STORE_TYPE(ESM::Enchantment, ESM::REC_ENCH , 13);
OPENMW_ESM_ADD_STORE_TYPE(ESM::Faction, ESM::REC_FACT , 14);
OPENMW_ESM_ADD_STORE_TYPE(ESM::Global, ESM::REC_GLOB , 15);
OPENMW_ESM_ADD_STORE_TYPE(ESM::Ingredient, ESM::REC_INGR , 16);
OPENMW_ESM_ADD_STORE_TYPE(ESM::CreatureLevList, ESM::REC_LEVC , 17);
OPENMW_ESM_ADD_STORE_TYPE(ESM::ItemLevList, ESM::REC_LEVI , 18);
OPENMW_ESM_ADD_STORE_TYPE(ESM::Light, ESM::REC_LIGH , 19);
OPENMW_ESM_ADD_STORE_TYPE(ESM::Lockpick, ESM::REC_LOCK , 20);
OPENMW_ESM_ADD_STORE_TYPE(ESM::Miscellaneous, ESM::REC_MISC , 21);
OPENMW_ESM_ADD_STORE_TYPE(ESM::NPC, ESM::REC_NPC_ , 22);
OPENMW_ESM_ADD_STORE_TYPE(ESM::Probe, ESM::REC_PROB , 23);
OPENMW_ESM_ADD_STORE_TYPE(ESM::Race, ESM::REC_RACE , 24);
OPENMW_ESM_ADD_STORE_TYPE(ESM::Region, ESM::REC_REGN , 25);
OPENMW_ESM_ADD_STORE_TYPE(ESM::Repair, ESM::REC_REPA , 26);
OPENMW_ESM_ADD_STORE_TYPE(ESM::SoundGenerator, ESM::REC_SNDG , 27);
OPENMW_ESM_ADD_STORE_TYPE(ESM::Sound, ESM::REC_SOUN , 28);
OPENMW_ESM_ADD_STORE_TYPE(ESM::Spell, ESM::REC_SPEL , 29);
OPENMW_ESM_ADD_STORE_TYPE(ESM::StartScript, ESM::REC_SSCR , 30);
OPENMW_ESM_ADD_STORE_TYPE(ESM::Static, ESM::REC_STAT , 31);
OPENMW_ESM_ADD_STORE_TYPE(ESM::Weapon, ESM::REC_WEAP , 32);
OPENMW_ESM_ADD_STORE_TYPE(ESM::GameSetting, ESM::REC_GMST , 33);
OPENMW_ESM_ADD_STORE_TYPE(ESM::Script, ESM::REC_SCPT , 34);
// Lists that need special rules
OPENMW_ESM_ADD_STORE_TYPE(ESM::Cell, ESM::REC_CELL , 35);
OPENMW_ESM_ADD_STORE_TYPE(ESM::Land, ESM::REC_LAND , 36);
OPENMW_ESM_ADD_STORE_TYPE(ESM::LandTexture, ESM::REC_LTEX , 37);
OPENMW_ESM_ADD_STORE_TYPE(ESM::Pathgrid, ESM::REC_PGRD , 38);
OPENMW_ESM_ADD_STORE_TYPE(ESM::MagicEffect, ESM::REC_MGEF , 39);
OPENMW_ESM_ADD_STORE_TYPE(ESM::Skill, ESM::REC_SKIL , 40);
// Special entry which is hardcoded and not loaded from an ESM
OPENMW_ESM_ADD_STORE_TYPE(ESM::Attribute, ESM::REC_INTERNAL_PLAYER , 41);
static const int sRecordTypeCount = sRecordTypeCounter;
constexpr int sRecordIndexCount = 42;
template <auto Start, auto End, auto Inc, class F> template <auto Start, auto End, auto Inc, class F>
constexpr void constexpr_for(F&& f) constexpr void constexpr_for(F&& f)
{ {
@ -210,10 +149,54 @@ namespace MWWorld
struct ESMStoreImp struct ESMStoreImp
{ {
//These 3 don't inherit from store base std::tuple <
Store<ESM::MagicEffect> mMagicEffect; Store<ESM::Activator>,
Store<ESM::Skill> mSkills; Store<ESM::Potion>,
Store<ESM::Attribute> mAttributes; Store<ESM::Apparatus>,
Store<ESM::Armor>,
Store<ESM::BodyPart>,
Store<ESM::Book>,
Store<ESM::BirthSign>,
Store<ESM::Class>,
Store<ESM::Clothing>,
Store<ESM::Container>,
Store<ESM::Creature>,
Store<ESM::Dialogue>,
Store<ESM::Door>,
Store<ESM::Enchantment>,
Store<ESM::Faction>,
Store<ESM::Global>,
Store<ESM::Ingredient>,
Store<ESM::CreatureLevList>,
Store<ESM::ItemLevList>,
Store<ESM::Light>,
Store<ESM::Lockpick>,
Store<ESM::Miscellaneous>,
Store<ESM::NPC>,
Store<ESM::Probe>,
Store<ESM::Race>,
Store<ESM::Region>,
Store<ESM::Repair>,
Store<ESM::SoundGenerator>,
Store<ESM::Sound>,
Store<ESM::Spell>,
Store<ESM::StartScript>,
Store<ESM::Static>,
Store<ESM::Weapon>,
Store<ESM::GameSetting>,
Store<ESM::Script>,
// Lists that need special rules
Store<ESM::Cell>,
Store<ESM::Land>,
Store<ESM::LandTexture>,
Store<ESM::Pathgrid>,
Store<ESM::MagicEffect>,
Store<ESM::Skill>,
// Special entry which is hardcoded and not loaded from an ESM
Store<ESM::Attribute >> mStores;
std::map<ESM::RecNameInts, DynamicStore*> mRecNameToStore; std::map<ESM::RecNameInts, DynamicStore*> mRecNameToStore;
std::unordered_map<const DynamicStore*, ESM::RecNameInts> mStoreToRecName; std::unordered_map<const DynamicStore*, ESM::RecNameInts> mStoreToRecName;
@ -284,23 +267,32 @@ namespace MWWorld
return ptr; return ptr;
} }
ESMStoreImp(ESMStore& store)
{
}
template<typename T> template<typename T>
static void createStore(ESMStore& stores) static int AssignStoreToIndex(ESMStore& stores, Store<T>& store)
{ {
const int storeIndex = ESMStore::getTypeIndex<T>();
assert(ESMStore::getTypeIndex<T>() == storeIndex);
if (stores.mStores.size() <= storeIndex)
stores.mStores.resize(storeIndex + 1);
assert(&store == &std::get<Store<T>>(stores.mStoreImp->mStores));
stores.mStores[storeIndex] = &store;
if constexpr (std::is_convertible<Store<T>*, DynamicStore*>::value) if constexpr (std::is_convertible<Store<T>*, DynamicStore*>::value)
{ {
int storeIndex = SRecordType<T>::sStoreIndex; stores.mDynamicStores.push_back(&store);
stores.mStores[storeIndex] = std::make_unique<Store<T>>();
constexpr ESM::RecNameInts recName = T::sRecordId; constexpr ESM::RecNameInts recName = T::sRecordId;
if constexpr (recName != ESM::REC_INTERNAL_PLAYER) if constexpr (recName != ESM::REC_INTERNAL_PLAYER)
{ {
stores.mStoreImp->mRecNameToStore[recName] = stores.mStores[storeIndex].get(); stores.mStoreImp->mRecNameToStore[recName] = &store;
} }
} }
return 0;
}
ESMStoreImp(ESMStore& store)
{
} }
void SetupAfterStoresCreation(ESMStore& store) void SetupAfterStoresCreation(ESMStore& store)
@ -336,15 +328,8 @@ namespace MWWorld
ESMStore::ESMStore() ESMStore::ESMStore()
{ {
mStores.resize(sRecordTypeCount);
assert(sRecordTypeCounter == sRecordIndexCount); //Otherwise something wen wrong with assigning index to stores
mStoreImp = std::make_unique<ESMStoreImp>(*this); mStoreImp = std::make_unique<ESMStoreImp>(*this);
std::apply([this](auto& ...x){std::make_tuple(ESMStoreImp::AssignStoreToIndex(*this, x)...);} , mStoreImp->mStores);
constexpr_for<0, sRecordIndexCount,1> ([this](auto storeIndex)
{
ESMStoreImp::createStore<typename StoreIndexToRecordType<storeIndex>::recordType>(*this);
});
mDynamicCount = 0; mDynamicCount = 0;
mStoreImp->SetupAfterStoresCreation(*this); mStoreImp->SetupAfterStoresCreation(*this);
getWritable<ESM::Pathgrid>().setCells(getWritable<ESM::Cell>()); getWritable<ESM::Pathgrid>().setCells(getWritable<ESM::Cell>());
@ -356,7 +341,7 @@ namespace MWWorld
void ESMStore::clearDynamic() void ESMStore::clearDynamic()
{ {
for (const auto& store : mStores) for (const auto& store : mDynamicStores)
store->clearDynamic(); store->clearDynamic();
movePlayerRecord(); movePlayerRecord();
@ -451,6 +436,13 @@ void ESMStore::load(ESM::ESMReader &esm, Loading::Listener* listener, ESM::Dialo
} }
} }
static int sTypeIndexCounter = 0;
int& ESMStore::getTypeIndexCounter()
{
return sTypeIndexCounter;
}
ESM::LuaScriptsCfg ESMStore::getLuaScriptsCfg() const ESM::LuaScriptsCfg ESMStore::getLuaScriptsCfg() const
{ {
ESM::LuaScriptsCfg cfg; ESM::LuaScriptsCfg cfg;
@ -827,14 +819,4 @@ void ESMStore::removeMissingObjects(Store<T>& store)
template<> const ESM::Door* ESMStore::overrideRecord<ESM::Door>(const ESM::Door &toInsert) { return ESMStoreImp::esm3overrideRecord(*this, toInsert); } template<> const ESM::Door* ESMStore::overrideRecord<ESM::Door>(const ESM::Door &toInsert) { return ESMStoreImp::esm3overrideRecord(*this, toInsert); }
template<> const ESM::ItemLevList* ESMStore::overrideRecord<ESM::ItemLevList>(const ESM::ItemLevList &toInsert) { return ESMStoreImp::esm3overrideRecord(*this, toInsert); } template<> const ESM::ItemLevList* ESMStore::overrideRecord<ESM::ItemLevList>(const ESM::ItemLevList &toInsert) { return ESMStoreImp::esm3overrideRecord(*this, toInsert); }
template<> const ESM::NPC* ESMStore::overrideRecord<ESM::NPC>(const ESM::NPC &toInsert) { return ESMStoreImp::esm3overrideRecord(*this, toInsert); } template<> const ESM::NPC* ESMStore::overrideRecord<ESM::NPC>(const ESM::NPC &toInsert) { return ESMStoreImp::esm3overrideRecord(*this, toInsert); }
template <> const Store<ESM::MagicEffect>& ESMStore::get<ESM::MagicEffect>() const { return mStoreImp->mMagicEffect; }
template <> Store<ESM::MagicEffect>& ESMStore::getWritable<ESM::MagicEffect>() { return mStoreImp->mMagicEffect; }
template <> const Store<ESM::Skill>& ESMStore::get<ESM::Skill>() const { return mStoreImp->mSkills; }
template <> Store<ESM::Skill>& ESMStore::getWritable<ESM::Skill>() { return mStoreImp->mSkills; }
template <> const Store<ESM::Attribute>& ESMStore::get<ESM::Attribute>() const { return mStoreImp->mAttributes; }
template <> Store<ESM::Attribute>& ESMStore::getWritable<ESM::Attribute>() { return mStoreImp->mAttributes; }
} // end namespace } // end namespace

View file

@ -26,26 +26,33 @@ namespace ESM
namespace MWWorld namespace MWWorld
{ {
struct ESMStoreImp; struct ESMStoreImp;
template<typename T> struct SRecordType
{
static const int sStoreIndex;
};
class ESMStore class ESMStore
{ {
friend struct ESMStoreImp; //This allows StoreImp to extend esmstore without beeing included everywhere friend struct ESMStoreImp; //This allows StoreImp to extend esmstore without beeing included everywhere
static int& getTypeIndexCounter();
template<typename T>
static int getTypeIndex()
{
static int index = getTypeIndexCounter()++;
return index;
}
std::unique_ptr<ESMStoreImp> mStoreImp; std::unique_ptr<ESMStoreImp> mStoreImp;
std::unordered_map<std::string, int> mRefCount; std::unordered_map<std::string, int> mRefCount;
std::vector<std::unique_ptr< DynamicStore >> mStores; std::vector<StoreBase*> mStores;
std::vector<DynamicStore*> mDynamicStores;
unsigned int mDynamicCount; unsigned int mDynamicCount;
mutable std::unordered_map<std::string, std::weak_ptr<MWMechanics::SpellList>, Misc::StringUtils::CiHash, Misc::StringUtils::CiEqual> mSpellListCache; mutable std::unordered_map<std::string, std::weak_ptr<MWMechanics::SpellList>, Misc::StringUtils::CiHash, Misc::StringUtils::CiEqual> mSpellListCache;
template <class T> template <class T>
Store<T>& getWritable() {return static_cast<Store<T>&>(*mStores[SRecordType<T>::sStoreIndex]);} Store<T>& getWritable() {return static_cast<Store<T>&>(*mStores[getTypeIndex<T>()]);}
/// Validate entries in store after setup /// Validate entries in store after setup
void validate(); void validate();
@ -65,14 +72,14 @@ namespace MWWorld
ESM::LuaScriptsCfg getLuaScriptsCfg() const; ESM::LuaScriptsCfg getLuaScriptsCfg() const;
/// \todo replace with SharedIterator<StoreBase> /// \todo replace with SharedIterator<StoreBase>
typedef std::vector<std::unique_ptr< DynamicStore>>::const_iterator iterator; typedef std::vector<DynamicStore*>::const_iterator iterator;
iterator begin() const { iterator begin() const {
return mStores.begin(); return mDynamicStores.begin();
} }
iterator end() const { iterator end() const {
return mStores.end(); return mDynamicStores.end();
} }
/// Look up the given ID in 'all'. Returns 0 if not found. /// Look up the given ID in 'all'. Returns 0 if not found.
@ -94,7 +101,7 @@ namespace MWWorld
void load(ESM::ESMReader &esm, Loading::Listener* listener, ESM::Dialogue*& dialogue); void load(ESM::ESMReader &esm, Loading::Listener* listener, ESM::Dialogue*& dialogue);
template <class T> template <class T>
const Store<T>& get() const {return static_cast<const Store<T>&>(*mStores[SRecordType<T>::sStoreIndex]);} const Store<T>& get() const {return static_cast<const Store<T>&>(*mStores[getTypeIndex<T>()]);}
/// Insert a custom record (i.e. with a generated ID that will not clash will pre-existing records) /// Insert a custom record (i.e. with a generated ID that will not clash will pre-existing records)
template <class T> template <class T>
@ -129,17 +136,6 @@ namespace MWWorld
/// @return The shared spell list to use for this actor and whether or not it has already been initialized. /// @return The shared spell list to use for this actor and whether or not it has already been initialized.
std::pair<std::shared_ptr<MWMechanics::SpellList>, bool> getSpellList(const std::string& id) const; std::pair<std::shared_ptr<MWMechanics::SpellList>, bool> getSpellList(const std::string& id) const;
}; };
//Special cases these aren't DynamicStore, but IndexedStore
template <> const Store<ESM::MagicEffect>& ESMStore::get<ESM::MagicEffect>() const;
template <> Store<ESM::MagicEffect>& ESMStore::getWritable<ESM::MagicEffect>();
template <> const Store<ESM::Skill>& ESMStore::get<ESM::Skill>() const;
template <> Store<ESM::Skill>& ESMStore::getWritable<ESM::Skill>();
template <> const Store<ESM::Attribute>& ESMStore::get<ESM::Attribute>() const;
template <> Store<ESM::Attribute>& ESMStore::getWritable<ESM::Attribute>();
} }
#endif #endif

View file

@ -45,7 +45,7 @@ namespace MWWorld
class StoreBase {}; //Empty interface to be parent of all store types class StoreBase {}; //Empty interface to be parent of all store types
class DynamicStore : StoreBase class DynamicStore : public StoreBase
{ {
public: public:
virtual ~DynamicStore() {} virtual ~DynamicStore() {}
@ -69,7 +69,7 @@ namespace MWWorld
}; };
template <class T> template <class T>
class IndexedStore : StoreBase class IndexedStore : public StoreBase
{ {
protected: protected:
typedef typename std::map<int, T> Static; typedef typename std::map<int, T> Static;