Make Store<ESM4::Reference> to use FormId instead of RefId

7344-support-launching-the-example-suite
Petr Mikheev 2 years ago
parent 1c3903f155
commit 3546d2b3e5

@ -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…
Cancel
Save