mirror of
https://github.com/OpenMW/openmw.git
synced 2025-01-30 07:45:39 +00:00
Make Store<ESM4::Reference> to use FormId instead of RefId
This commit is contained in:
parent
1c3903f155
commit
3546d2b3e5
6 changed files with 100 additions and 81 deletions
|
@ -30,7 +30,7 @@ namespace MWWorld
|
|||
const ESM::RefNum& CellRef::getRefNum() const
|
||||
{
|
||||
return std::visit(ESM::VisitOverload{
|
||||
[&](const ESM4::Reference& ref) -> const ESM::RefNum& { return ref.mFormId; },
|
||||
[&](const ESM4::Reference& ref) -> const ESM::RefNum& { return ref.mId; },
|
||||
[&](const ESM::CellRef& ref) -> const ESM::RefNum& { return ref.mRefNum; },
|
||||
},
|
||||
mCellRef.mVariant);
|
||||
|
@ -39,7 +39,7 @@ namespace MWWorld
|
|||
const ESM::RefNum& CellRef::getOrAssignRefNum(ESM::RefNum& lastAssignedRefNum)
|
||||
{
|
||||
ESM::RefNum& refNum = std::visit(ESM::VisitOverload{
|
||||
[&](ESM4::Reference& ref) -> ESM::RefNum& { return ref.mFormId; },
|
||||
[&](ESM4::Reference& ref) -> ESM::RefNum& { return ref.mId; },
|
||||
[&](ESM::CellRef& ref) -> ESM::RefNum& { return ref.mRefNum; },
|
||||
},
|
||||
mCellRef.mVariant);
|
||||
|
@ -64,7 +64,7 @@ namespace MWWorld
|
|||
void CellRef::unsetRefNum()
|
||||
{
|
||||
std::visit(ESM::VisitOverload{
|
||||
[&](ESM4::Reference& ref) { ref.mFormId = emptyRefNum; },
|
||||
[&](ESM4::Reference& ref) { ref.mId = emptyRefNum; },
|
||||
[&](ESM::CellRef& ref) { ref.mRefNum = emptyRefNum; },
|
||||
},
|
||||
mCellRef.mVariant);
|
||||
|
@ -100,7 +100,7 @@ namespace MWWorld
|
|||
return ESM::RefId::sEmpty;
|
||||
const ESM4::Reference* refDest
|
||||
= MWBase::Environment::get().getWorld()->getStore().get<ESM4::Reference>().searchStatic(
|
||||
ESM::FormIdRefId(ref.mDoor.destDoor));
|
||||
ref.mDoor.destDoor);
|
||||
if (refDest)
|
||||
return refDest->mParent;
|
||||
return ESM::RefId::sEmpty;
|
||||
|
|
|
@ -188,7 +188,7 @@ namespace MWWorld
|
|||
auto recordType = static_cast<ESM4::RecordTypes>(reader.hdr().record.typeId);
|
||||
|
||||
ESM::RecNameInts esm4RecName = static_cast<ESM::RecNameInts>(ESM::esm4Recname(recordType));
|
||||
if constexpr (std::is_convertible_v<Store<T>*, DynamicStore*> && HasRecordId<T>::value)
|
||||
if constexpr (HasRecordId<T>::value)
|
||||
{
|
||||
if constexpr (ESM::isESM4Rec(T::sRecordId))
|
||||
{
|
||||
|
|
|
@ -16,8 +16,8 @@
|
|||
namespace
|
||||
{
|
||||
// TODO: Switch to C++23 to get a working version of std::unordered_map::erase
|
||||
template <class T>
|
||||
bool eraseFromMap(T& map, const ESM::RefId& value)
|
||||
template <class T, class Id>
|
||||
bool eraseFromMap(T& map, const Id& value)
|
||||
{
|
||||
auto it = map.find(value);
|
||||
if (it != map.end())
|
||||
|
@ -95,19 +95,19 @@ namespace MWWorld
|
|||
template class IndexedStore<ESM::MagicEffect>;
|
||||
template class IndexedStore<ESM::Skill>;
|
||||
|
||||
template <typename T>
|
||||
TypedDynamicStore<T>::TypedDynamicStore()
|
||||
template <class T, class Id>
|
||||
TypedDynamicStore<T, Id>::TypedDynamicStore()
|
||||
{
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
TypedDynamicStore<T>::TypedDynamicStore(const TypedDynamicStore<T>& orig)
|
||||
template <class T, class Id>
|
||||
TypedDynamicStore<T, Id>::TypedDynamicStore(const TypedDynamicStore<T, Id>& orig)
|
||||
: mStatic(orig.mStatic)
|
||||
{
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
void TypedDynamicStore<T>::clearDynamic()
|
||||
template <class T, class Id>
|
||||
void TypedDynamicStore<T, Id>::clearDynamic()
|
||||
{
|
||||
// remove the dynamic part of mShared
|
||||
assert(mShared.size() >= mStatic.size());
|
||||
|
@ -115,8 +115,8 @@ namespace MWWorld
|
|||
mDynamic.clear();
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
const T* TypedDynamicStore<T>::search(const ESM::RefId& id) const
|
||||
template <class T, class Id>
|
||||
const T* TypedDynamicStore<T, Id>::search(const Id& id) const
|
||||
{
|
||||
typename Dynamic::const_iterator dit = mDynamic.find(id);
|
||||
if (dit != mDynamic.end())
|
||||
|
@ -128,8 +128,8 @@ namespace MWWorld
|
|||
|
||||
return nullptr;
|
||||
}
|
||||
template <typename T>
|
||||
const T* TypedDynamicStore<T>::searchStatic(const ESM::RefId& id) const
|
||||
template <class T, class Id>
|
||||
const T* TypedDynamicStore<T, Id>::searchStatic(const Id& id) const
|
||||
{
|
||||
typename Static::const_iterator it = mStatic.find(id);
|
||||
if (it != mStatic.end())
|
||||
|
@ -138,24 +138,29 @@ namespace MWWorld
|
|||
return nullptr;
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
bool TypedDynamicStore<T>::isDynamic(const ESM::RefId& id) const
|
||||
template <class T, class Id>
|
||||
bool TypedDynamicStore<T, Id>::isDynamic(const Id& id) const
|
||||
{
|
||||
typename Dynamic::const_iterator dit = mDynamic.find(id);
|
||||
return (dit != mDynamic.end());
|
||||
}
|
||||
template <typename T>
|
||||
const T* TypedDynamicStore<T>::searchRandom(const std::string_view prefix, Misc::Rng::Generator& prng) const
|
||||
template <class T, class Id>
|
||||
const T* TypedDynamicStore<T, Id>::searchRandom(const std::string_view prefix, Misc::Rng::Generator& prng) const
|
||||
{
|
||||
std::vector<const T*> results;
|
||||
std::copy_if(mShared.begin(), mShared.end(), std::back_inserter(results),
|
||||
[prefix](const T* item) { return item->mId.startsWith(prefix); });
|
||||
if (!results.empty())
|
||||
return results[Misc::Rng::rollDice(results.size(), prng)];
|
||||
return nullptr;
|
||||
if constexpr (std::is_same_v<Id, ESM::RefId>)
|
||||
{
|
||||
std::vector<const T*> results;
|
||||
std::copy_if(mShared.begin(), mShared.end(), std::back_inserter(results),
|
||||
[prefix](const T* item) { return item->mId.startsWith(prefix); });
|
||||
if (!results.empty())
|
||||
return results[Misc::Rng::rollDice(results.size(), prng)];
|
||||
return nullptr;
|
||||
}
|
||||
else
|
||||
throw std::runtime_error("Store<T>::searchRandom is supported only if Id is ESM::RefId");
|
||||
}
|
||||
template <typename T>
|
||||
const T* TypedDynamicStore<T>::find(const ESM::RefId& id) const
|
||||
template <class T, class Id>
|
||||
const T* TypedDynamicStore<T, Id>::find(const Id& id) const
|
||||
{
|
||||
const T* ptr = search(id);
|
||||
if (ptr == nullptr)
|
||||
|
@ -174,8 +179,8 @@ namespace MWWorld
|
|||
}
|
||||
return ptr;
|
||||
}
|
||||
template <typename T>
|
||||
RecordId TypedDynamicStore<T>::load(ESM::ESMReader& esm)
|
||||
template <class T, class Id>
|
||||
RecordId TypedDynamicStore<T, Id>::load(ESM::ESMReader& esm)
|
||||
{
|
||||
T record;
|
||||
bool isDeleted = false;
|
||||
|
@ -188,37 +193,41 @@ namespace MWWorld
|
|||
if (inserted.second)
|
||||
mShared.push_back(&inserted.first->second);
|
||||
|
||||
return RecordId(record.mId, isDeleted);
|
||||
if constexpr (std::is_same_v<Id, ESM::RefId>)
|
||||
return RecordId(record.mId, isDeleted);
|
||||
else
|
||||
return RecordId();
|
||||
}
|
||||
template <typename T>
|
||||
void TypedDynamicStore<T>::setUp()
|
||||
|
||||
template <class T, class Id>
|
||||
void TypedDynamicStore<T, Id>::setUp()
|
||||
{
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
typename TypedDynamicStore<T>::iterator TypedDynamicStore<T>::begin() const
|
||||
template <class T, class Id>
|
||||
typename TypedDynamicStore<T, Id>::iterator TypedDynamicStore<T, Id>::begin() const
|
||||
{
|
||||
return mShared.begin();
|
||||
}
|
||||
template <typename T>
|
||||
typename TypedDynamicStore<T>::iterator TypedDynamicStore<T>::end() const
|
||||
template <class T, class Id>
|
||||
typename TypedDynamicStore<T, Id>::iterator TypedDynamicStore<T, Id>::end() const
|
||||
{
|
||||
return mShared.end();
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
size_t TypedDynamicStore<T>::getSize() const
|
||||
template <class T, class Id>
|
||||
size_t TypedDynamicStore<T, Id>::getSize() const
|
||||
{
|
||||
return mShared.size();
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
int TypedDynamicStore<T>::getDynamicSize() const
|
||||
template <class T, class Id>
|
||||
int TypedDynamicStore<T, Id>::getDynamicSize() const
|
||||
{
|
||||
return mDynamic.size();
|
||||
}
|
||||
template <typename T>
|
||||
void TypedDynamicStore<T>::listIdentifier(std::vector<ESM::RefId>& list) const
|
||||
template <class T, class Id>
|
||||
void TypedDynamicStore<T, Id>::listIdentifier(std::vector<Id>& list) const
|
||||
{
|
||||
list.reserve(list.size() + getSize());
|
||||
typename std::vector<T*>::const_iterator it = mShared.begin();
|
||||
|
@ -227,8 +236,8 @@ namespace MWWorld
|
|||
list.push_back((*it)->mId);
|
||||
}
|
||||
}
|
||||
template <typename T>
|
||||
T* TypedDynamicStore<T>::insert(const T& item, bool overrideOnly)
|
||||
template <class T, class Id>
|
||||
T* TypedDynamicStore<T, Id>::insert(const T& item, bool overrideOnly)
|
||||
{
|
||||
if (overrideOnly)
|
||||
{
|
||||
|
@ -242,8 +251,8 @@ namespace MWWorld
|
|||
mShared.push_back(ptr);
|
||||
return ptr;
|
||||
}
|
||||
template <typename T>
|
||||
T* TypedDynamicStore<T>::insertStatic(const T& item)
|
||||
template <class T, class Id>
|
||||
T* TypedDynamicStore<T, Id>::insertStatic(const T& item)
|
||||
{
|
||||
std::pair<typename Static::iterator, bool> result = mStatic.insert_or_assign(item.mId, item);
|
||||
T* ptr = &result.first->second;
|
||||
|
@ -251,8 +260,8 @@ namespace MWWorld
|
|||
mShared.push_back(ptr);
|
||||
return ptr;
|
||||
}
|
||||
template <typename T>
|
||||
bool TypedDynamicStore<T>::eraseStatic(const ESM::RefId& id)
|
||||
template <class T, class Id>
|
||||
bool TypedDynamicStore<T, Id>::eraseStatic(const Id& id)
|
||||
{
|
||||
typename Static::iterator it = mStatic.find(id);
|
||||
|
||||
|
@ -277,8 +286,8 @@ namespace MWWorld
|
|||
return true;
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
bool TypedDynamicStore<T>::erase(const ESM::RefId& id)
|
||||
template <class T, class Id>
|
||||
bool TypedDynamicStore<T, Id>::erase(const Id& id)
|
||||
{
|
||||
if (!eraseFromMap(mDynamic, id))
|
||||
return false;
|
||||
|
@ -292,13 +301,13 @@ namespace MWWorld
|
|||
}
|
||||
return true;
|
||||
}
|
||||
template <typename T>
|
||||
bool TypedDynamicStore<T>::erase(const T& item)
|
||||
template <class T, class Id>
|
||||
bool TypedDynamicStore<T, Id>::erase(const T& item)
|
||||
{
|
||||
return erase(item.mId);
|
||||
}
|
||||
template <typename T>
|
||||
void TypedDynamicStore<T>::write(ESM::ESMWriter& writer, Loading::Listener& progress) const
|
||||
template <class T, class Id>
|
||||
void TypedDynamicStore<T, Id>::write(ESM::ESMWriter& writer, Loading::Listener& progress) const
|
||||
{
|
||||
for (typename Dynamic::const_iterator iter(mDynamic.begin()); iter != mDynamic.end(); ++iter)
|
||||
{
|
||||
|
@ -310,8 +319,8 @@ namespace MWWorld
|
|||
}
|
||||
}
|
||||
}
|
||||
template <typename T>
|
||||
RecordId TypedDynamicStore<T>::read(ESM::ESMReader& reader, bool overrideOnly)
|
||||
template <class T, class Id>
|
||||
RecordId TypedDynamicStore<T, Id>::read(ESM::ESMReader& reader, bool overrideOnly)
|
||||
{
|
||||
T record;
|
||||
bool isDeleted = false;
|
||||
|
@ -321,7 +330,10 @@ namespace MWWorld
|
|||
}
|
||||
insert(record, overrideOnly);
|
||||
|
||||
return RecordId(record.mId, isDeleted);
|
||||
if constexpr (std::is_same_v<Id, ESM::RefId>)
|
||||
return RecordId(record.mId, isDeleted);
|
||||
else
|
||||
return RecordId();
|
||||
}
|
||||
|
||||
// LandTexture
|
||||
|
@ -1232,6 +1244,6 @@ template class MWWorld::TypedDynamicStore<ESM4::Ingredient>;
|
|||
template class MWWorld::TypedDynamicStore<ESM4::MiscItem>;
|
||||
template class MWWorld::TypedDynamicStore<ESM4::Static>;
|
||||
template class MWWorld::TypedDynamicStore<ESM4::Light>;
|
||||
template class MWWorld::TypedDynamicStore<ESM4::Reference>;
|
||||
template class MWWorld::TypedDynamicStore<ESM4::Reference, ESM::FormId>;
|
||||
template class MWWorld::TypedDynamicStore<ESM4::Cell>;
|
||||
template class MWWorld::TypedDynamicStore<ESM4::Weapon>;
|
||||
|
|
|
@ -16,6 +16,7 @@
|
|||
#include <components/esm3/loadland.hpp>
|
||||
#include <components/esm3/loadpgrd.hpp>
|
||||
#include <components/esm4/loadcell.hpp>
|
||||
#include <components/esm4/loadrefr.hpp>
|
||||
#include <components/misc/rng.hpp>
|
||||
#include <components/misc/strings/algorithm.hpp>
|
||||
|
||||
|
@ -52,22 +53,23 @@ namespace MWWorld
|
|||
{
|
||||
}; // Empty interface to be parent of all store types
|
||||
|
||||
class DynamicStore : public StoreBase
|
||||
template <class Id>
|
||||
class DynamicStoreBase : public StoreBase
|
||||
{
|
||||
public:
|
||||
virtual ~DynamicStore() {}
|
||||
virtual ~DynamicStoreBase() {}
|
||||
|
||||
virtual void setUp() {}
|
||||
|
||||
/// List identifiers of records contained in this Store (case-smashed). No-op for Stores that don't use string
|
||||
/// IDs.
|
||||
virtual void listIdentifier(std::vector<ESM::RefId>& list) const {}
|
||||
virtual void listIdentifier(std::vector<Id>& list) const {}
|
||||
|
||||
virtual size_t getSize() const = 0;
|
||||
virtual int getDynamicSize() const { return 0; }
|
||||
virtual RecordId load(ESM::ESMReader& esm) = 0;
|
||||
|
||||
virtual bool eraseStatic(const ESM::RefId& id) { return false; }
|
||||
virtual bool eraseStatic(const Id& id) { return false; }
|
||||
virtual void clearDynamic() {}
|
||||
|
||||
virtual void write(ESM::ESMWriter& writer, Loading::Listener& progress) const {}
|
||||
|
@ -76,6 +78,8 @@ namespace MWWorld
|
|||
///< Read into dynamic storage
|
||||
};
|
||||
|
||||
using DynamicStore = DynamicStoreBase<ESM::RefId>;
|
||||
|
||||
template <class T>
|
||||
class IndexedStore : public StoreBase
|
||||
{
|
||||
|
@ -169,23 +173,23 @@ namespace MWWorld
|
|||
|
||||
class ESMStore;
|
||||
|
||||
template <class T>
|
||||
class TypedDynamicStore : public DynamicStore
|
||||
template <class T, class Id = ESM::RefId>
|
||||
class TypedDynamicStore : public DynamicStoreBase<Id>
|
||||
{
|
||||
typedef std::unordered_map<ESM::RefId, T> Static;
|
||||
typedef std::unordered_map<Id, T> Static;
|
||||
Static mStatic;
|
||||
/// @par mShared usually preserves the record order as it came from the content files (this
|
||||
/// is relevant for the spell autocalc code and selection order
|
||||
/// for heads/hairs in the character creation)
|
||||
std::vector<T*> mShared;
|
||||
typedef std::unordered_map<ESM::RefId, T> Dynamic;
|
||||
typedef std::unordered_map<Id, T> Dynamic;
|
||||
Dynamic mDynamic;
|
||||
|
||||
friend class ESMStore;
|
||||
|
||||
public:
|
||||
TypedDynamicStore();
|
||||
TypedDynamicStore(const TypedDynamicStore<T>& orig);
|
||||
TypedDynamicStore(const TypedDynamicStore<T, Id>& orig);
|
||||
|
||||
typedef SharedIterator<T> iterator;
|
||||
|
||||
|
@ -193,19 +197,19 @@ namespace MWWorld
|
|||
void clearDynamic() override;
|
||||
void setUp() override;
|
||||
|
||||
const T* search(const ESM::RefId& id) const;
|
||||
const T* searchStatic(const ESM::RefId& id) const;
|
||||
const T* search(const Id& id) const;
|
||||
const T* searchStatic(const Id& id) const;
|
||||
|
||||
/**
|
||||
* Does the record with this ID come from the dynamic store?
|
||||
*/
|
||||
bool isDynamic(const ESM::RefId& id) const;
|
||||
bool isDynamic(const Id& id) const;
|
||||
|
||||
/** Returns a random record that starts with the named ID, or nullptr if not found. */
|
||||
const T* searchRandom(const std::string_view prefix, Misc::Rng::Generator& prng) const;
|
||||
|
||||
// calls `search` and throws an exception if not found
|
||||
const T* find(const ESM::RefId& id) const;
|
||||
const T* find(const Id& id) const;
|
||||
|
||||
iterator begin() const;
|
||||
iterator end() const;
|
||||
|
@ -215,13 +219,13 @@ namespace MWWorld
|
|||
int getDynamicSize() const override;
|
||||
|
||||
/// @note The record identifiers are listed in the order that the records were defined by the content files.
|
||||
void listIdentifier(std::vector<ESM::RefId>& list) const override;
|
||||
void listIdentifier(std::vector<Id>& list) const override;
|
||||
|
||||
T* insert(const T& item, bool overrideOnly = false);
|
||||
T* insertStatic(const T& item);
|
||||
|
||||
bool eraseStatic(const ESM::RefId& id) override;
|
||||
bool erase(const ESM::RefId& id);
|
||||
bool eraseStatic(const Id& id) override;
|
||||
bool erase(const Id& id);
|
||||
bool erase(const T& item);
|
||||
|
||||
RecordId load(ESM::ESMReader& esm) override;
|
||||
|
@ -533,6 +537,11 @@ namespace MWWorld
|
|||
const MWDialogue::KeywordSearch<std::string, int>& getDialogIdKeywordSearch() const;
|
||||
};
|
||||
|
||||
template <>
|
||||
class Store<ESM4::Reference> : public TypedDynamicStore<ESM4::Reference, ESM::FormId>
|
||||
{
|
||||
};
|
||||
|
||||
} // end namespace
|
||||
|
||||
#endif
|
||||
|
|
|
@ -34,9 +34,8 @@
|
|||
|
||||
void ESM4::Reference::load(ESM4::Reader& reader)
|
||||
{
|
||||
mFormId = reader.hdr().record.getFormId();
|
||||
reader.adjustFormId(mFormId);
|
||||
mId = ESM::RefId::formIdRefId(mFormId);
|
||||
mId = reader.hdr().record.getFormId();
|
||||
reader.adjustFormId(mId);
|
||||
mFlags = reader.hdr().record.flags;
|
||||
mParentFormId = reader.currCell(); // NOTE: only for persistent refs?
|
||||
mParent = ESM::RefId::formIdRefId(mParentFormId);
|
||||
|
|
|
@ -74,8 +74,7 @@ namespace ESM4
|
|||
|
||||
struct Reference
|
||||
{
|
||||
FormId mFormId; // from the header
|
||||
ESM::RefId mId;
|
||||
FormId mId; // from the header
|
||||
|
||||
FormId mParentFormId; // cell FormId (currently persistent refs only), from the loading sequence
|
||||
// NOTE: for exterior cells it will be the dummy cell FormId
|
||||
|
|
Loading…
Reference in a new issue