1
0
Fork 0
mirror of https://github.com/OpenMW/openmw.git synced 2025-06-19 20:41: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 <fstream>
#include <tuple>
#include <components/debug/debuglog.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>
constexpr void constexpr_for(F&& f)
{
@ -210,10 +149,54 @@ namespace MWWorld
struct ESMStoreImp
{
//These 3 don't inherit from store base
Store<ESM::MagicEffect> mMagicEffect;
Store<ESM::Skill> mSkills;
Store<ESM::Attribute> mAttributes;
std::tuple <
Store<ESM::Activator>,
Store<ESM::Potion>,
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::unordered_map<const DynamicStore*, ESM::RecNameInts> mStoreToRecName;
@ -284,23 +267,32 @@ namespace MWWorld
return ptr;
}
ESMStoreImp(ESMStore& store)
template<typename T>
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);
template<typename T>
static void createStore(ESMStore& stores)
{
assert(&store == &std::get<Store<T>>(stores.mStoreImp->mStores));
stores.mStores[storeIndex] = &store;
if constexpr (std::is_convertible<Store<T>*, DynamicStore*>::value)
{
int storeIndex = SRecordType<T>::sStoreIndex;
stores.mStores[storeIndex] = std::make_unique<Store<T>>();
stores.mDynamicStores.push_back(&store);
constexpr ESM::RecNameInts recName = T::sRecordId;
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)
@ -336,15 +328,8 @@ namespace MWWorld
ESMStore::ESMStore()
{
mStores.resize(sRecordTypeCount);
assert(sRecordTypeCounter == sRecordIndexCount); //Otherwise something wen wrong with assigning index to stores
mStoreImp = std::make_unique<ESMStoreImp>(*this);
constexpr_for<0, sRecordIndexCount,1> ([this](auto storeIndex)
{
ESMStoreImp::createStore<typename StoreIndexToRecordType<storeIndex>::recordType>(*this);
});
std::apply([this](auto& ...x){std::make_tuple(ESMStoreImp::AssignStoreToIndex(*this, x)...);} , mStoreImp->mStores);
mDynamicCount = 0;
mStoreImp->SetupAfterStoresCreation(*this);
getWritable<ESM::Pathgrid>().setCells(getWritable<ESM::Cell>());
@ -356,7 +341,7 @@ namespace MWWorld
void ESMStore::clearDynamic()
{
for (const auto& store : mStores)
for (const auto& store : mDynamicStores)
store->clearDynamic();
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 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::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 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

View file

@ -26,26 +26,33 @@ namespace ESM
namespace MWWorld
{
struct ESMStoreImp;
template<typename T> struct SRecordType
{
static const int sStoreIndex;
};
class ESMStore
{
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::unordered_map<std::string, int> mRefCount;
std::vector<std::unique_ptr< DynamicStore >> mStores;
std::vector<StoreBase*> mStores;
std::vector<DynamicStore*> mDynamicStores;
unsigned int mDynamicCount;
mutable std::unordered_map<std::string, std::weak_ptr<MWMechanics::SpellList>, Misc::StringUtils::CiHash, Misc::StringUtils::CiEqual> mSpellListCache;
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
void validate();
@ -65,14 +72,14 @@ namespace MWWorld
ESM::LuaScriptsCfg getLuaScriptsCfg() const;
/// \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 {
return mStores.begin();
return mDynamicStores.begin();
}
iterator end() const {
return mStores.end();
return mDynamicStores.end();
}
/// 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);
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)
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.
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

View file

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