From c721a6cafa2d1a4d31a2e84e888b24685ae13478 Mon Sep 17 00:00:00 2001 From: "florent.teppe" Date: Wed, 28 Dec 2022 20:48:25 +0100 Subject: [PATCH 01/10] Initial commit to load ESM4 Some data is actually loaded and store in ESM Store Any new ESM4 will go through the same code path and be automatically sent to the right store --- apps/openmw/mwworld/esmloader.cpp | 56 ++++++++++++++----- apps/openmw/mwworld/esmstore.cpp | 93 +++++++++++++++++++++++++++++++ apps/openmw/mwworld/esmstore.hpp | 13 ++++- apps/openmw/mwworld/store.cpp | 31 +++++++++-- components/esm/defs.hpp | 5 ++ components/esm/refid.cpp | 5 ++ components/esm/refid.hpp | 2 + components/esm4/loadcell.cpp | 10 ++-- components/esm4/loadcell.hpp | 6 +- components/esm4/loadrefr.cpp | 13 +++-- components/esm4/loadrefr.hpp | 12 ++-- components/esm4/loadstat.cpp | 7 ++- components/esm4/loadstat.hpp | 6 +- components/to_utf8/to_utf8.hpp | 2 + 14 files changed, 221 insertions(+), 40 deletions(-) diff --git a/apps/openmw/mwworld/esmloader.cpp b/apps/openmw/mwworld/esmloader.cpp index 3c1b6acc47..3265059a13 100644 --- a/apps/openmw/mwworld/esmloader.cpp +++ b/apps/openmw/mwworld/esmloader.cpp @@ -1,9 +1,13 @@ #include "esmloader.hpp" #include "esmstore.hpp" +#include #include #include +#include #include +#include +#include namespace MWWorld { @@ -21,28 +25,50 @@ namespace MWWorld void EsmLoader::load(const std::filesystem::path& filepath, int& index, Loading::Listener* listener) { - const ESM::ReadersCache::BusyItem reader = mReaders.get(static_cast(index)); - reader->setEncoder(mEncoder); - reader->setIndex(index); - reader->open(filepath); - reader->resolveParentFileIndices(mReaders); + auto stream = Files::openBinaryInputFileStream(filepath); + if (!stream->is_open()) + { + throw std::runtime_error(std::string("File Failed to open file: ") + std::strerror(errno) + "\n"); + return; + } + const ESM::Format format = ESM::readFormat(*stream); + stream->seekg(0); - assert(reader->getGameFiles().size() == reader->getParentFileIndices().size()); - for (std::size_t i = 0, n = reader->getParentFileIndices().size(); i < n; ++i) - if (i == static_cast(reader->getIndex())) - throw std::runtime_error("File " + Files::pathToUnicodeString(reader->getName()) + " asks for parent file " + switch (format) + { + case ESM::Format::Tes3: + { + const ESM::ReadersCache::BusyItem reader = mReaders.get(static_cast(index)); + reader->setEncoder(mEncoder); + reader->setIndex(index); + reader->open(filepath); + reader->resolveParentFileIndices(mReaders); + + assert(reader->getGameFiles().size() == reader->getParentFileIndices().size()); + for (std::size_t i = 0, n = reader->getParentFileIndices().size(); i < n; ++i) + if (i == static_cast(reader->getIndex())) + throw std::runtime_error("File " + Files::pathToUnicodeString(reader->getName()) + " asks for parent file " + reader->getGameFiles()[i].name + ", but it is not available or has been loaded in the wrong order. " "Please run the launcher to fix this issue."); - mESMVersions[index] = reader->getVer(); - mStore.load(*reader, listener, mDialogue); + mESMVersions[index] = reader->getVer(); + mStore.load(*reader, listener, mDialogue); - if (!mMasterFileFormat.has_value() - && (Misc::StringUtils::ciEndsWith(reader->getName().u8string(), u8".esm") - || Misc::StringUtils::ciEndsWith(reader->getName().u8string(), u8".omwgame"))) - mMasterFileFormat = reader->getFormat(); + if (!mMasterFileFormat.has_value() + && (Misc::StringUtils::ciEndsWith(reader->getName().u8string(), u8".esm") + || Misc::StringUtils::ciEndsWith(reader->getName().u8string(), u8".omwgame"))) + mMasterFileFormat = reader->getFormat(); + break; + } + case ESM::Format::Tes4: + { + ESM4::Reader readerESM4(std::move(stream), filepath); + readerESM4.setEncoder(mEncoder->getStatelessEncoder()); + mStore.loadESM4(readerESM4, listener, mDialogue); + } + } } } /* namespace MWWorld */ diff --git a/apps/openmw/mwworld/esmstore.cpp b/apps/openmw/mwworld/esmstore.cpp index 03de9fda5d..15bf52757e 100644 --- a/apps/openmw/mwworld/esmstore.cpp +++ b/apps/openmw/mwworld/esmstore.cpp @@ -13,6 +13,11 @@ #include #include +#include +#include +#include +#include + #include #include @@ -180,6 +185,84 @@ namespace MWWorld } } } + + template + static void typedReadRecordESM4(ESM4::Reader& reader, ESMStore& stores, Store& store, int& found) + { + auto recordType = static_cast(reader.hdr().record.typeId); + + ESM::RecNameInts esm4RecName = static_cast(ESM::esm4Recname(recordType)); + if constexpr (std::is_convertible_v*, DynamicStore*>) + { + if constexpr (ESM::isESM4Rec(T::sRecordId)) + { + if (T::sRecordId == esm4RecName) + { + reader.getRecordData(); + T value; + value.load(reader); + store.insertStatic(value); + found++; + } + } + } + } + + static void readRecord(ESM4::Reader& reader, ESMStore& store) + { + int found = 0; + std::apply([&reader, &store, &found]( + auto&... x) { (ESMStoreImp::typedReadRecordESM4(reader, store, x, found), ...); }, + store.mStoreImp->mStores); + assert(found <= 1); + if (found == 0) // unhandled record + reader.skipRecordData(); + } + + static bool readItem(ESM4::Reader& reader, ESMStore& store) + { + if (!reader.getRecordHeader() || !reader.hasMoreRecs()) + return false; + + const ESM4::RecordHeader& header = reader.hdr(); + + if (header.record.typeId == ESM4::REC_GRUP) + return readGroup(reader, store); + + readRecord(reader, store); + return true; + } + + static bool readGroup(ESM4::Reader& reader, ESMStore& store) + { + const ESM4::RecordHeader& header = reader.hdr(); + + switch (static_cast(header.group.type)) + { + case ESM4::Grp_RecordType: + case ESM4::Grp_InteriorCell: + case ESM4::Grp_InteriorSubCell: + case ESM4::Grp_ExteriorCell: + case ESM4::Grp_ExteriorSubCell: + reader.enterGroup(); + return readItem(reader, store); + case ESM4::Grp_WorldChild: + case ESM4::Grp_CellChild: + case ESM4::Grp_TopicChild: + case ESM4::Grp_CellPersistentChild: + case ESM4::Grp_CellTemporaryChild: + case ESM4::Grp_CellVisibleDistChild: + reader.adjustGRUPFormId(); + reader.enterGroup(); + if (!reader.hasMoreRecs()) + return false; + return readItem(reader, store); + } + + reader.skipGroup(); + + return true; + } }; int ESMStore::find(const ESM::RefId& id) const @@ -338,6 +421,16 @@ namespace MWWorld } } + void ESMStore::loadESM4(ESM4::Reader& reader, Loading::Listener* listener, ESM::Dialogue*& dialogue) + { + while (reader.hasMoreRecs()) + { + reader.exitGroupCheck(); + if (!ESMStoreImp::readItem(reader, *this)) + break; + } + } + void ESMStore::setIdType(const ESM::RefId& id, ESM::RecNameInts type) { mStoreImp->mIds[id] = type; diff --git a/apps/openmw/mwworld/esmstore.hpp b/apps/openmw/mwworld/esmstore.hpp index 7f5773c957..1ed66a1c71 100644 --- a/apps/openmw/mwworld/esmstore.hpp +++ b/apps/openmw/mwworld/esmstore.hpp @@ -24,6 +24,14 @@ namespace MWMechanics class SpellList; } +namespace ESM4 +{ + class Reader; + struct Static; + struct Cell; + struct Reference; +} + namespace ESM { class ReadersCache; @@ -95,7 +103,9 @@ namespace MWWorld Store, Store, // Special entry which is hardcoded and not loaded from an ESM - Store>; + Store, + + Store, Store, Store>; template static constexpr std::size_t getTypeIndex() @@ -162,6 +172,7 @@ namespace MWWorld void validateDynamic(); void load(ESM::ESMReader& esm, Loading::Listener* listener, ESM::Dialogue*& dialogue); + void loadESM4(ESM4::Reader& esm, Loading::Listener* listener, ESM::Dialogue*& dialogue); template const Store& get() const diff --git a/apps/openmw/mwworld/store.cpp b/apps/openmw/mwworld/store.cpp index 11e58c0edb..27d74ddf59 100644 --- a/apps/openmw/mwworld/store.cpp +++ b/apps/openmw/mwworld/store.cpp @@ -13,6 +13,10 @@ #include #include +#include +#include +#include + namespace { // TODO: Switch to C++23 to get a working version of std::unordered_map::erase @@ -161,7 +165,10 @@ namespace MWWorld if (ptr == nullptr) { std::stringstream msg; - msg << T::getRecordType() << " '" << id << "' not found"; + if constexpr (!ESM::isESM4Rec(T::sRecordId)) + { + msg << T::getRecordType() << " '" << id << "' not found"; + } throw std::runtime_error(msg.str()); } return ptr; @@ -171,8 +178,10 @@ namespace MWWorld { T record; bool isDeleted = false; - - record.load(esm, isDeleted); + if constexpr (!ESM::isESM4Rec(T::sRecordId)) + { + record.load(esm, isDeleted); + } std::pair inserted = mStatic.insert_or_assign(record.mId, record); if (inserted.second) @@ -293,7 +302,11 @@ namespace MWWorld for (typename Dynamic::const_iterator iter(mDynamic.begin()); iter != mDynamic.end(); ++iter) { writer.startRecord(T::sRecordId); - iter->second.save(writer); + if constexpr (!ESM::isESM4Rec(T::sRecordId)) + { + iter->second.save(writer); + } + writer.endRecord(T::sRecordId); } } @@ -302,8 +315,10 @@ namespace MWWorld { T record; bool isDeleted = false; - - record.load(reader, isDeleted); + if constexpr (!ESM::isESM4Rec(T::sRecordId)) + { + record.load(reader, isDeleted); + } insert(record, overrideOnly); return RecordId(record.mId, isDeleted); @@ -1196,3 +1211,7 @@ template class MWWorld::TypedDynamicStore; template class MWWorld::TypedDynamicStore; template class MWWorld::TypedDynamicStore; template class MWWorld::TypedDynamicStore; + +template class MWWorld::TypedDynamicStore; +template class MWWorld::TypedDynamicStore; +template class MWWorld::TypedDynamicStore; diff --git a/components/esm/defs.hpp b/components/esm/defs.hpp index f3e1ad640e..431b85b9ae 100644 --- a/components/esm/defs.hpp +++ b/components/esm/defs.hpp @@ -333,6 +333,11 @@ namespace ESM REC_MSET4 = esm4Recname(ESM4::REC_MSET) // Media Set }; + constexpr bool isESM4Rec(RecNameInts RecName) + { + return RecName & sEsm4RecnameFlag; + } + /// Common subrecords enum SubRecNameInts { diff --git a/components/esm/refid.cpp b/components/esm/refid.cpp index ec18c4c642..3470ebd3d3 100644 --- a/components/esm/refid.cpp +++ b/components/esm/refid.cpp @@ -34,6 +34,11 @@ namespace ESM return newRefId; } + RefId RefId::formIdRefId(const ESM4::FormId id) + { + return ESM::RefId::stringRefId(ESM4::formIdToString(id)); + } + bool RefId::operator==(std::string_view rhs) const { return Misc::StringUtils::ciEqual(mId, rhs); diff --git a/components/esm/refid.hpp b/components/esm/refid.hpp index 6bc49313d0..8900f7ce75 100644 --- a/components/esm/refid.hpp +++ b/components/esm/refid.hpp @@ -1,6 +1,7 @@ #ifndef OPENMW_COMPONENTS_ESM_REFID_HPP #define OPENMW_COMPONENTS_ESM_REFID_HPP #include +#include #include #include #include @@ -26,6 +27,7 @@ namespace ESM // RefIds that are as string in the code. For serialization, and display. Using explicit conversions make it // very clear where in the code we need to convert from string to RefId and Vice versa. static RefId stringRefId(std::string_view id); + static RefId formIdRefId(const ESM4::FormId id); const std::string& getRefIdString() const { return mId; } private: diff --git a/components/esm4/loadcell.cpp b/components/esm4/loadcell.cpp index 919c81b8e9..1321e31578 100644 --- a/components/esm4/loadcell.cpp +++ b/components/esm4/loadcell.cpp @@ -37,7 +37,8 @@ #include // FIXME: debug only #include "reader.hpp" -//#include "writer.hpp" +#include +// #include "writer.hpp" // TODO: Try loading only EDID and XCLC (along with mFormId, mFlags and mParent) // @@ -48,8 +49,9 @@ // longer/shorter/same as loading the subrecords. void ESM4::Cell::load(ESM4::Reader& reader) { - mFormId = reader.hdr().record.id; - reader.adjustFormId(mFormId); + auto formId = reader.hdr().record.id; + reader.adjustFormId(formId); + mId = ESM::RefId::formIdRefId(formId); mFlags = reader.hdr().record.flags; mParent = reader.currWorld(); @@ -71,7 +73,7 @@ void ESM4::Cell::load(ESM4::Reader& reader) // WARN: we need to call setCurrCell (and maybe setCurrCellGrid?) again before loading // cell child groups if we are loading them after restoring the context // (may be easier to update the context before saving?) - reader.setCurrCell(mFormId); // save for LAND (and other children) to access later + reader.setCurrCell(formId); // save for LAND (and other children) to access later std::uint32_t esmVer = reader.esmVersion(); bool isFONV = esmVer == ESM::VER_132 || esmVer == ESM::VER_133 || esmVer == ESM::VER_134; diff --git a/components/esm4/loadcell.hpp b/components/esm4/loadcell.hpp index ee77bd2bfc..bcc95f652f 100644 --- a/components/esm4/loadcell.hpp +++ b/components/esm4/loadcell.hpp @@ -33,6 +33,8 @@ #include "formid.hpp" #include "lighting.hpp" +#include +#include namespace ESM4 { @@ -61,7 +63,7 @@ namespace ESM4 { FormId mParent; // world formId (for grouping cells), from the loading sequence - FormId mFormId; // from the header + ESM::RefId mId; // from the header std::uint32_t mFlags; // from the header, see enum type RecordFlag for details std::string mEditorId; @@ -95,6 +97,8 @@ namespace ESM4 // void save(ESM4::Writer& writer) const; void blank(); + + static constexpr ESM::RecNameInts sRecordId = ESM::REC_CELL4; }; } diff --git a/components/esm4/loadrefr.cpp b/components/esm4/loadrefr.cpp index d96f52a741..b95f24e73a 100644 --- a/components/esm4/loadrefr.cpp +++ b/components/esm4/loadrefr.cpp @@ -30,14 +30,15 @@ #include #include "reader.hpp" -//#include "writer.hpp" +// #include "writer.hpp" void ESM4::Reference::load(ESM4::Reader& reader) { - mFormId = reader.hdr().record.id; - reader.adjustFormId(mFormId); + auto formId = reader.hdr().record.id; + reader.adjustFormId(formId); + mId = ESM::RefId::formIdRefId(formId); mFlags = reader.hdr().record.flags; - mParent = reader.currCell(); // NOTE: only for persistent refs? + mParent = ESM::RefId::formIdRefId(reader.currCell()); // NOTE: only for persistent refs? // TODO: Let the engine apply this? Saved games? // mInitiallyDisabled = ((mFlags & ESM4::Rec_Disabled) != 0) ? true : false; @@ -60,7 +61,9 @@ void ESM4::Reference::load(ESM4::Reader& reader) break; case ESM4::SUB_NAME: { - reader.getFormId(mBaseObj); + FormId BaseId; + reader.getFormId(BaseId); + mBaseObj = ESM::RefId::formIdRefId(BaseId); #if 0 if (mFlags & ESM4::Rec_Disabled) std::cout << "REFR disable at start " << formIdToString(mFormId) << diff --git a/components/esm4/loadrefr.hpp b/components/esm4/loadrefr.hpp index 04d537932e..baf199c4c4 100644 --- a/components/esm4/loadrefr.hpp +++ b/components/esm4/loadrefr.hpp @@ -30,6 +30,8 @@ #include #include "reference.hpp" // FormId, Placement, EnableParent +#include +#include namespace ESM4 { @@ -71,15 +73,15 @@ namespace ESM4 struct Reference { - FormId mParent; // cell FormId (currently persistent refs only), from the loading sequence - // NOTE: for exterior cells it will be the dummy cell FormId + ESM::RefId mParent; // cell FormId (currently persistent refs only), from the loading sequence + // NOTE: for exterior cells it will be the dummy cell FormId - FormId mFormId; // from the header + ESM::RefId mId; // from the header std::uint32_t mFlags; // from the header, see enum type RecordFlag for details std::string mEditorId; std::string mFullName; - FormId mBaseObj; + ESM::RefId mBaseObj; Placement mPlacement; float mScale = 1.0f; @@ -110,6 +112,8 @@ namespace ESM4 // void save(ESM4::Writer& writer) const; void blank(); + + static constexpr ESM::RecNameInts sRecordId = ESM::REC_REFR4; }; } diff --git a/components/esm4/loadstat.cpp b/components/esm4/loadstat.cpp index e8e789cb1b..edfbf0e4e6 100644 --- a/components/esm4/loadstat.cpp +++ b/components/esm4/loadstat.cpp @@ -30,12 +30,13 @@ #include #include "reader.hpp" -//#include "writer.hpp" +// #include "writer.hpp" void ESM4::Static::load(ESM4::Reader& reader) { - mFormId = reader.hdr().record.id; - reader.adjustFormId(mFormId); + FormId formId = reader.hdr().record.id; + reader.adjustFormId(formId); + mId = ESM::RefId::formIdRefId(formId); mFlags = reader.hdr().record.flags; while (reader.getSubRecordHeader()) diff --git a/components/esm4/loadstat.hpp b/components/esm4/loadstat.hpp index f34ba6a1cf..5d79f84d6f 100644 --- a/components/esm4/loadstat.hpp +++ b/components/esm4/loadstat.hpp @@ -32,6 +32,8 @@ #include #include "formid.hpp" +#include +#include namespace ESM4 { @@ -40,7 +42,7 @@ namespace ESM4 struct Static { - FormId mFormId; // from the header + ESM::RefId mId; // from the header std::uint32_t mFlags; // from the header, see enum type RecordFlag for details std::string mEditorId; @@ -53,6 +55,8 @@ namespace ESM4 // void save(ESM4::Writer& writer) const; // void blank(); + + static constexpr ESM::RecNameInts sRecordId = ESM::REC_STAT4; }; } diff --git a/components/to_utf8/to_utf8.hpp b/components/to_utf8/to_utf8.hpp index df5462dbb9..e72e24a753 100644 --- a/components/to_utf8/to_utf8.hpp +++ b/components/to_utf8/to_utf8.hpp @@ -68,6 +68,8 @@ namespace ToUTF8 /// ASCII-only string. Otherwise returns a view to the input. std::string_view getLegacyEnc(std::string_view input); + const StatelessUtf8Encoder* getStatelessEncoder() const { return &mImpl; } + private: std::string mBuffer; StatelessUtf8Encoder mImpl; From 077cf97bc4684d0a002f50d33717db668dad9881 Mon Sep 17 00:00:00 2001 From: "florent.teppe" Date: Fri, 30 Dec 2022 11:28:19 +0100 Subject: [PATCH 02/10] The esm4 reader logic is mutualised to avoid copy pasting code, readerutils gives functions that take visitors as params to decide how a record must be handled Check encoder exists, and get value of stateless encoder. fixes code formatting conventions Fixed output of record with RefId also fixed readTypedRecord and readRecord to have the proper return types Check if the type has a sRecordId --- apps/esmtool/tes4.cpp | 321 +++++++++++++++++------------- apps/openmw/mwworld/esmloader.cpp | 14 +- apps/openmw/mwworld/esmstore.cpp | 74 ++----- apps/openmw/mwworld/store.cpp | 15 +- components/CMakeLists.txt | 260 ++++++++++++------------ components/esm/refid.hpp | 3 +- components/esm4/loadcell.cpp | 4 +- components/esm4/loadcell.hpp | 1 + components/esm4/loadrefr.hpp | 1 + components/esm4/loadstat.hpp | 1 + components/esm4/readerutils.hpp | 84 ++++++++ components/to_utf8/to_utf8.hpp | 2 +- 12 files changed, 440 insertions(+), 340 deletions(-) create mode 100644 components/esm4/readerutils.hpp diff --git a/apps/esmtool/tes4.cpp b/apps/esmtool/tes4.cpp index f72175ec93..50c7d24b7c 100644 --- a/apps/esmtool/tes4.cpp +++ b/apps/esmtool/tes4.cpp @@ -8,6 +8,7 @@ #include #include +#include #include #include @@ -69,6 +70,19 @@ namespace EsmTool template constexpr bool hasFormId = HasFormId::value; + template > + struct HasRefId : std::false_type + { + }; + + template + struct HasRefId> : std::true_type + { + }; + + template + constexpr bool hasRefId = HasRefId::value; + template > struct HasFlags : std::false_type { @@ -169,6 +183,8 @@ namespace EsmTool std::cout << "\n Record: " << ESM::NAME(reader.hdr().record.typeId).toStringView(); if constexpr (hasFormId) std::cout << "\n FormId: " << value.mFormId; + if constexpr (hasRefId) + std::cout << "\n RefId: " << value.mId; if constexpr (hasFlags) std::cout << "\n Record flags: " << recordFlags(value.mFlags); if constexpr (hasEditorId) @@ -180,62 +196,80 @@ namespace EsmTool if constexpr (hasKf) std::cout << "\n Kf:" << WriteArray("\n - ", value.mKf); std::cout << '\n'; + return; } - void readRecord(const Params& params, ESM4::Reader& reader) + bool readRecord(const Params& params, ESM4::Reader& reader) { switch (static_cast(reader.hdr().record.typeId)) { case ESM4::REC_AACT: break; case ESM4::REC_ACHR: - return readTypedRecord(params, reader); + readTypedRecord(params, reader); + return true; case ESM4::REC_ACRE: - return readTypedRecord(params, reader); + readTypedRecord(params, reader); + return true; case ESM4::REC_ACTI: - return readTypedRecord(params, reader); + readTypedRecord(params, reader); + return true; case ESM4::REC_ADDN: break; case ESM4::REC_ALCH: - return readTypedRecord(params, reader); + readTypedRecord(params, reader); + return true; case ESM4::REC_ALOC: - return readTypedRecord(params, reader); + readTypedRecord(params, reader); + return true; case ESM4::REC_AMMO: - return readTypedRecord(params, reader); + readTypedRecord(params, reader); + return true; case ESM4::REC_ANIO: - return readTypedRecord(params, reader); + readTypedRecord(params, reader); + return true; case ESM4::REC_APPA: - return readTypedRecord(params, reader); + readTypedRecord(params, reader); + return true; case ESM4::REC_ARMA: - return readTypedRecord(params, reader); + readTypedRecord(params, reader); + return true; case ESM4::REC_ARMO: - return readTypedRecord(params, reader); + readTypedRecord(params, reader); + return true; case ESM4::REC_ARTO: break; case ESM4::REC_ASPC: - return readTypedRecord(params, reader); + readTypedRecord(params, reader); + return true; case ESM4::REC_ASTP: break; case ESM4::REC_AVIF: break; case ESM4::REC_BOOK: - return readTypedRecord(params, reader); + readTypedRecord(params, reader); + return true; case ESM4::REC_BPTD: - return readTypedRecord(params, reader); + readTypedRecord(params, reader); + return true; case ESM4::REC_CAMS: break; case ESM4::REC_CCRD: break; case ESM4::REC_CELL: - return readTypedRecord(params, reader); + readTypedRecord(params, reader); + return true; case ESM4::REC_CLAS: - return readTypedRecord(params, reader); + readTypedRecord(params, reader); + return true; case ESM4::REC_CLFM: - return readTypedRecord(params, reader); + readTypedRecord(params, reader); + return true; case ESM4::REC_CLMT: break; case ESM4::REC_CLOT: - return readTypedRecord(params, reader); + readTypedRecord(params, reader); + return true; case ESM4::REC_CMNY: break; case ESM4::REC_COBJ: @@ -243,25 +277,30 @@ namespace EsmTool case ESM4::REC_COLL: break; case ESM4::REC_CONT: - return readTypedRecord(params, reader); + readTypedRecord(params, reader); + return true; case ESM4::REC_CPTH: break; case ESM4::REC_CREA: - return readTypedRecord(params, reader); + readTypedRecord(params, reader); + return true; case ESM4::REC_CSTY: break; case ESM4::REC_DEBR: break; case ESM4::REC_DIAL: - return readTypedRecord(params, reader); + readTypedRecord(params, reader); + return true; case ESM4::REC_DLBR: break; case ESM4::REC_DLVW: break; case ESM4::REC_DOBJ: - return readTypedRecord(params, reader); + readTypedRecord(params, reader); + return true; case ESM4::REC_DOOR: - return readTypedRecord(params, reader); + readTypedRecord(params, reader); + return true; case ESM4::REC_DUAL: break; case ESM4::REC_ECZN: @@ -275,81 +314,103 @@ namespace EsmTool case ESM4::REC_EXPL: break; case ESM4::REC_EYES: - return readTypedRecord(params, reader); + readTypedRecord(params, reader); + return true; case ESM4::REC_FACT: break; case ESM4::REC_FLOR: - return readTypedRecord(params, reader); + readTypedRecord(params, reader); + return true; case ESM4::REC_FLST: - return readTypedRecord(params, reader); + readTypedRecord(params, reader); + return true; case ESM4::REC_FSTP: break; case ESM4::REC_FSTS: break; case ESM4::REC_FURN: - return readTypedRecord(params, reader); + readTypedRecord(params, reader); + return true; case ESM4::REC_GLOB: - return readTypedRecord(params, reader); + readTypedRecord(params, reader); + return true; case ESM4::REC_GMST: break; case ESM4::REC_GRAS: - return readTypedRecord(params, reader); + readTypedRecord(params, reader); + return true; case ESM4::REC_GRUP: break; case ESM4::REC_HAIR: - return readTypedRecord(params, reader); + readTypedRecord(params, reader); + return true; case ESM4::REC_HAZD: break; case ESM4::REC_HDPT: - return readTypedRecord(params, reader); + readTypedRecord(params, reader); + return true; case ESM4::REC_IDLE: // FIXME: ESM4::IdleAnimation::load does not work with Oblivion.esm - // return readTypedRecord(params, reader); + // readTypedRecord(params, reader); + return true; break; case ESM4::REC_IDLM: - return readTypedRecord(params, reader); + readTypedRecord(params, reader); + return true; case ESM4::REC_IMAD: break; case ESM4::REC_IMGS: break; case ESM4::REC_IMOD: - return readTypedRecord(params, reader); + readTypedRecord(params, reader); + return true; case ESM4::REC_INFO: - return readTypedRecord(params, reader); + readTypedRecord(params, reader); + return true; case ESM4::REC_INGR: - return readTypedRecord(params, reader); + readTypedRecord(params, reader); + return true; case ESM4::REC_IPCT: break; case ESM4::REC_IPDS: break; case ESM4::REC_KEYM: - return readTypedRecord(params, reader); + readTypedRecord(params, reader); + return true; case ESM4::REC_KYWD: break; case ESM4::REC_LAND: - return readTypedRecord(params, reader); + readTypedRecord(params, reader); + return true; case ESM4::REC_LCRT: break; case ESM4::REC_LCTN: break; case ESM4::REC_LGTM: - return readTypedRecord(params, reader); + readTypedRecord(params, reader); + return true; case ESM4::REC_LIGH: - return readTypedRecord(params, reader); + readTypedRecord(params, reader); + return true; case ESM4::REC_LSCR: break; case ESM4::REC_LTEX: - return readTypedRecord(params, reader); + readTypedRecord(params, reader); + return true; case ESM4::REC_LVLC: - return readTypedRecord(params, reader); + readTypedRecord(params, reader); + return true; case ESM4::REC_LVLI: - return readTypedRecord(params, reader); + readTypedRecord(params, reader); + return true; case ESM4::REC_LVLN: - return readTypedRecord(params, reader); + readTypedRecord(params, reader); + return true; case ESM4::REC_LVSP: break; case ESM4::REC_MATO: - return readTypedRecord(params, reader); + readTypedRecord(params, reader); + return true; case ESM4::REC_MATT: break; case ESM4::REC_MESG: @@ -357,49 +418,66 @@ namespace EsmTool case ESM4::REC_MGEF: break; case ESM4::REC_MISC: - return readTypedRecord(params, reader); + readTypedRecord(params, reader); + return true; case ESM4::REC_MOVT: break; case ESM4::REC_MSET: - return readTypedRecord(params, reader); + readTypedRecord(params, reader); + return true; case ESM4::REC_MSTT: - return readTypedRecord(params, reader); + readTypedRecord(params, reader); + return true; case ESM4::REC_MUSC: - return readTypedRecord(params, reader); + readTypedRecord(params, reader); + return true; case ESM4::REC_MUST: break; case ESM4::REC_NAVI: - return readTypedRecord(params, reader); + readTypedRecord(params, reader); + return true; case ESM4::REC_NAVM: - return readTypedRecord(params, reader); + readTypedRecord(params, reader); + return true; case ESM4::REC_NOTE: - return readTypedRecord(params, reader); + readTypedRecord(params, reader); + return true; case ESM4::REC_NPC_: - return readTypedRecord(params, reader); + readTypedRecord(params, reader); + return true; case ESM4::REC_OTFT: - return readTypedRecord(params, reader); + readTypedRecord(params, reader); + return true; case ESM4::REC_PACK: - return readTypedRecord(params, reader); + readTypedRecord(params, reader); + return true; case ESM4::REC_PERK: break; case ESM4::REC_PGRD: - return readTypedRecord(params, reader); + readTypedRecord(params, reader); + return true; case ESM4::REC_PGRE: - return readTypedRecord(params, reader); + readTypedRecord(params, reader); + return true; case ESM4::REC_PHZD: break; case ESM4::REC_PROJ: break; case ESM4::REC_PWAT: - return readTypedRecord(params, reader); + readTypedRecord(params, reader); + return true; case ESM4::REC_QUST: - return readTypedRecord(params, reader); + readTypedRecord(params, reader); + return true; case ESM4::REC_RACE: - return readTypedRecord(params, reader); + readTypedRecord(params, reader); + return true; case ESM4::REC_REFR: - return readTypedRecord(params, reader); + readTypedRecord(params, reader); + return true; case ESM4::REC_REGN: - return readTypedRecord(params, reader); + readTypedRecord(params, reader); + return true; case ESM4::REC_RELA: break; case ESM4::REC_REVB: @@ -407,23 +485,30 @@ namespace EsmTool case ESM4::REC_RFCT: break; case ESM4::REC_ROAD: - return readTypedRecord(params, reader); + readTypedRecord(params, reader); + return true; case ESM4::REC_SBSP: - return readTypedRecord(params, reader); + readTypedRecord(params, reader); + return true; case ESM4::REC_SCEN: break; case ESM4::REC_SCOL: - return readTypedRecord(params, reader); + readTypedRecord(params, reader); + return true; case ESM4::REC_SCPT: - return readTypedRecord(params, reader); + readTypedRecord(params, reader); + return true; case ESM4::REC_SCRL: - return readTypedRecord(params, reader); + readTypedRecord(params, reader); + return true; case ESM4::REC_SGST: - return readTypedRecord(params, reader); + readTypedRecord(params, reader); + return true; case ESM4::REC_SHOU: break; case ESM4::REC_SLGM: - return readTypedRecord(params, reader); + readTypedRecord(params, reader); + return true; case ESM4::REC_SMBN: break; case ESM4::REC_SMEN: @@ -433,97 +518,56 @@ namespace EsmTool case ESM4::REC_SNCT: break; case ESM4::REC_SNDR: - return readTypedRecord(params, reader); + readTypedRecord(params, reader); + return true; case ESM4::REC_SOPM: break; case ESM4::REC_SOUN: - return readTypedRecord(params, reader); + readTypedRecord(params, reader); + return true; case ESM4::REC_SPEL: break; case ESM4::REC_SPGD: break; case ESM4::REC_STAT: - return readTypedRecord(params, reader); + readTypedRecord(params, reader); + return true; case ESM4::REC_TACT: - return readTypedRecord(params, reader); + readTypedRecord(params, reader); + return true; case ESM4::REC_TERM: - return readTypedRecord(params, reader); + readTypedRecord(params, reader); + return true; case ESM4::REC_TES4: - return readTypedRecord(params, reader); + readTypedRecord(params, reader); + return true; case ESM4::REC_TREE: - return readTypedRecord(params, reader); + readTypedRecord(params, reader); + return true; case ESM4::REC_TXST: - return readTypedRecord(params, reader); + readTypedRecord(params, reader); + return true; case ESM4::REC_VTYP: break; case ESM4::REC_WATR: break; case ESM4::REC_WEAP: - return readTypedRecord(params, reader); + readTypedRecord(params, reader); + return true; case ESM4::REC_WOOP: break; case ESM4::REC_WRLD: - return readTypedRecord(params, reader); + readTypedRecord(params, reader); + return true; case ESM4::REC_WTHR: break; } if (!params.mQuite) std::cout << "\n Unsupported record: " << ESM::NAME(reader.hdr().record.typeId).toStringView() << '\n'; - - reader.skipRecordData(); + return false; } - bool readItem(const Params& params, ESM4::Reader& reader); - - bool readGroup(const Params& params, ESM4::Reader& reader) - { - const ESM4::RecordHeader& header = reader.hdr(); - - if (!params.mQuite) - std::cout << "\nGroup: " << toString(static_cast(header.group.type)) << " " - << ESM::NAME(header.group.typeId).toStringView() << '\n'; - - switch (static_cast(header.group.type)) - { - case ESM4::Grp_RecordType: - case ESM4::Grp_InteriorCell: - case ESM4::Grp_InteriorSubCell: - case ESM4::Grp_ExteriorCell: - case ESM4::Grp_ExteriorSubCell: - reader.enterGroup(); - return readItem(params, reader); - case ESM4::Grp_WorldChild: - case ESM4::Grp_CellChild: - case ESM4::Grp_TopicChild: - case ESM4::Grp_CellPersistentChild: - case ESM4::Grp_CellTemporaryChild: - case ESM4::Grp_CellVisibleDistChild: - reader.adjustGRUPFormId(); - reader.enterGroup(); - if (!reader.hasMoreRecs()) - return false; - return readItem(params, reader); - } - - reader.skipGroup(); - - return true; - } - - bool readItem(const Params& params, ESM4::Reader& reader) - { - if (!reader.getRecordHeader() || !reader.hasMoreRecs()) - return false; - - const ESM4::RecordHeader& header = reader.hdr(); - - if (header.record.typeId == ESM4::REC_GRUP) - return readGroup(params, reader); - - readRecord(params, reader); - return true; - } } int loadTes4(const Arguments& info, std::unique_ptr&& stream) @@ -551,12 +595,15 @@ namespace EsmTool } } - while (reader.hasMoreRecs()) - { - reader.exitGroupCheck(); - if (!readItem(params, reader)) - break; - } + auto visitorRec = [¶ms](ESM4::Reader& reader) { return readRecord(params, reader); }; + auto visistorGroup = [¶ms](ESM4::Reader& reader) { + if (params.mQuite) + return; + auto groupType = static_cast(reader.hdr().group.type); + std::cout << "\nGroup: " << toString(groupType) << " " + << ESM::NAME(reader.hdr().group.typeId).toStringView() << '\n'; + }; + ESM4::ReaderUtils::readAll(reader, visitorRec, visistorGroup); } catch (const std::exception& e) { diff --git a/apps/openmw/mwworld/esmloader.cpp b/apps/openmw/mwworld/esmloader.cpp index 3265059a13..c529a9834c 100644 --- a/apps/openmw/mwworld/esmloader.cpp +++ b/apps/openmw/mwworld/esmloader.cpp @@ -1,13 +1,14 @@ #include "esmloader.hpp" #include "esmstore.hpp" +#include + #include #include #include #include #include #include -#include namespace MWWorld { @@ -30,7 +31,6 @@ namespace MWWorld if (!stream->is_open()) { throw std::runtime_error(std::string("File Failed to open file: ") + std::strerror(errno) + "\n"); - return; } const ESM::Format format = ESM::readFormat(*stream); stream->seekg(0); @@ -64,9 +64,13 @@ namespace MWWorld } case ESM::Format::Tes4: { - ESM4::Reader readerESM4(std::move(stream), filepath); - readerESM4.setEncoder(mEncoder->getStatelessEncoder()); - mStore.loadESM4(readerESM4, listener, mDialogue); + if (mEncoder) + { + ESM4::Reader readerESM4(std::move(stream), filepath); + auto statelessEncoder = mEncoder->getStatelessEncoder(); + readerESM4.setEncoder(&statelessEncoder); + mStore.loadESM4(readerESM4, listener, mDialogue); + } } } } diff --git a/apps/openmw/mwworld/esmstore.cpp b/apps/openmw/mwworld/esmstore.cpp index 15bf52757e..31c788283d 100644 --- a/apps/openmw/mwworld/esmstore.cpp +++ b/apps/openmw/mwworld/esmstore.cpp @@ -13,12 +13,12 @@ #include #include +#include #include #include #include #include - -#include +#include #include #include "../mwmechanics/spelllist.hpp" @@ -186,13 +186,23 @@ namespace MWWorld } } + template > + struct HasRecordId : std::false_type + { + }; + + template + struct HasRecordId> : std::true_type + { + }; + template static void typedReadRecordESM4(ESM4::Reader& reader, ESMStore& stores, Store& store, int& found) { auto recordType = static_cast(reader.hdr().record.typeId); ESM::RecNameInts esm4RecName = static_cast(ESM::esm4Recname(recordType)); - if constexpr (std::is_convertible_v*, DynamicStore*>) + if constexpr (std::is_convertible_v*, DynamicStore*> && HasRecordId::value) { if constexpr (ESM::isESM4Rec(T::sRecordId)) { @@ -208,60 +218,14 @@ namespace MWWorld } } - static void readRecord(ESM4::Reader& reader, ESMStore& store) + static bool readRecord(ESM4::Reader& reader, ESMStore& store) { int found = 0; std::apply([&reader, &store, &found]( auto&... x) { (ESMStoreImp::typedReadRecordESM4(reader, store, x, found), ...); }, store.mStoreImp->mStores); assert(found <= 1); - if (found == 0) // unhandled record - reader.skipRecordData(); - } - - static bool readItem(ESM4::Reader& reader, ESMStore& store) - { - if (!reader.getRecordHeader() || !reader.hasMoreRecs()) - return false; - - const ESM4::RecordHeader& header = reader.hdr(); - - if (header.record.typeId == ESM4::REC_GRUP) - return readGroup(reader, store); - - readRecord(reader, store); - return true; - } - - static bool readGroup(ESM4::Reader& reader, ESMStore& store) - { - const ESM4::RecordHeader& header = reader.hdr(); - - switch (static_cast(header.group.type)) - { - case ESM4::Grp_RecordType: - case ESM4::Grp_InteriorCell: - case ESM4::Grp_InteriorSubCell: - case ESM4::Grp_ExteriorCell: - case ESM4::Grp_ExteriorSubCell: - reader.enterGroup(); - return readItem(reader, store); - case ESM4::Grp_WorldChild: - case ESM4::Grp_CellChild: - case ESM4::Grp_TopicChild: - case ESM4::Grp_CellPersistentChild: - case ESM4::Grp_CellTemporaryChild: - case ESM4::Grp_CellVisibleDistChild: - reader.adjustGRUPFormId(); - reader.enterGroup(); - if (!reader.hasMoreRecs()) - return false; - return readItem(reader, store); - } - - reader.skipGroup(); - - return true; + return found; } }; @@ -423,12 +387,8 @@ namespace MWWorld void ESMStore::loadESM4(ESM4::Reader& reader, Loading::Listener* listener, ESM::Dialogue*& dialogue) { - while (reader.hasMoreRecs()) - { - reader.exitGroupCheck(); - if (!ESMStoreImp::readItem(reader, *this)) - break; - } + auto visitorRec = [this](ESM4::Reader& reader) { return ESMStoreImp::readRecord(reader, *this); }; + ESM4::ReaderUtils::readAll(reader, visitorRec, [](ESM4::Reader&) {}); } void ESMStore::setIdType(const ESM::RefId& id, ESM::RecNameInts type) diff --git a/apps/openmw/mwworld/store.cpp b/apps/openmw/mwworld/store.cpp index 27d74ddf59..71161fa6a4 100644 --- a/apps/openmw/mwworld/store.cpp +++ b/apps/openmw/mwworld/store.cpp @@ -1,21 +1,18 @@ #include "store.hpp" -#include - -#include -#include -#include - -#include -#include - #include #include #include +#include +#include +#include +#include #include #include #include +#include +#include namespace { diff --git a/components/CMakeLists.txt b/components/CMakeLists.txt index 243ea5841c..9646aae695 100644 --- a/components/CMakeLists.txt +++ b/components/CMakeLists.txt @@ -1,84 +1,84 @@ -project (Components) +project(Components) # Version file -set (VERSION_IN_FILE "${OpenMW_SOURCE_DIR}/files/version.in") -set (VERSION_FILE_PATH_BASE "${OpenMW_BINARY_DIR}") -set (VERSION_FILE_PATH_RELATIVE resources/version) -if (GIT_CHECKOUT) +set(VERSION_IN_FILE "${OpenMW_SOURCE_DIR}/files/version.in") +set(VERSION_FILE_PATH_BASE "${OpenMW_BINARY_DIR}") +set(VERSION_FILE_PATH_RELATIVE resources/version) + +if(GIT_CHECKOUT) get_generator_is_multi_config(multi_config) - add_custom_target (git-version - COMMAND ${CMAKE_COMMAND} - -DGIT_EXECUTABLE=${GIT_EXECUTABLE} - -DPROJECT_SOURCE_DIR=${PROJECT_SOURCE_DIR} - -DVERSION_IN_FILE=${VERSION_IN_FILE} - -DVERSION_FILE_PATH_BASE=${VERSION_FILE_PATH_BASE} - -DVERSION_FILE_PATH_RELATIVE=${VERSION_FILE_PATH_RELATIVE} - -DOPENMW_VERSION_MAJOR=${OPENMW_VERSION_MAJOR} - -DOPENMW_VERSION_MINOR=${OPENMW_VERSION_MINOR} - -DOPENMW_VERSION_RELEASE=${OPENMW_VERSION_RELEASE} - -DOPENMW_VERSION=${OPENMW_VERSION} - -DMACROSFILE=${CMAKE_SOURCE_DIR}/cmake/OpenMWMacros.cmake - "-DCMAKE_CONFIGURATION_TYPES=${CMAKE_CONFIGURATION_TYPES}" - -Dgenerator_is_multi_config_var=${multi_config} - -P ${CMAKE_CURRENT_SOURCE_DIR}/../cmake/GitVersion.cmake - VERBATIM) -else (GIT_CHECKOUT) + add_custom_target(git-version + COMMAND ${CMAKE_COMMAND} + -DGIT_EXECUTABLE=${GIT_EXECUTABLE} + -DPROJECT_SOURCE_DIR=${PROJECT_SOURCE_DIR} + -DVERSION_IN_FILE=${VERSION_IN_FILE} + -DVERSION_FILE_PATH_BASE=${VERSION_FILE_PATH_BASE} + -DVERSION_FILE_PATH_RELATIVE=${VERSION_FILE_PATH_RELATIVE} + -DOPENMW_VERSION_MAJOR=${OPENMW_VERSION_MAJOR} + -DOPENMW_VERSION_MINOR=${OPENMW_VERSION_MINOR} + -DOPENMW_VERSION_RELEASE=${OPENMW_VERSION_RELEASE} + -DOPENMW_VERSION=${OPENMW_VERSION} + -DMACROSFILE=${CMAKE_SOURCE_DIR}/cmake/OpenMWMacros.cmake + "-DCMAKE_CONFIGURATION_TYPES=${CMAKE_CONFIGURATION_TYPES}" + -Dgenerator_is_multi_config_var=${multi_config} + -P ${CMAKE_CURRENT_SOURCE_DIR}/../cmake/GitVersion.cmake + VERBATIM) +else(GIT_CHECKOUT) configure_resource_file(${VERSION_IN_FILE} ${VERSION_FILE_PATH_BASE} ${VERSION_FILE_PATH_RELATIVE}) -endif (GIT_CHECKOUT) +endif(GIT_CHECKOUT) # source files - -add_component_dir (lua +add_component_dir(lua luastate scriptscontainer utilpackage serialization configuration l10n storage - ) +) -add_component_dir (l10n +add_component_dir(l10n messagebundles manager - ) +) -add_component_dir (settings +add_component_dir(settings settings parser - ) +) -add_component_dir (bsa +add_component_dir(bsa bsa_file compressedbsafile - ) +) -add_component_dir (vfs +add_component_dir(vfs manager archive bsaarchive filesystemarchive registerarchives - ) +) -add_component_dir (resource +add_component_dir(resource scenemanager keyframemanager imagemanager bulletshapemanager bulletshape niffilemanager objectcache multiobjectcache resourcesystem resourcemanager stats animation foreachbulletobject errormarker - ) +) -add_component_dir (shader +add_component_dir(shader shadermanager shadervisitor removedalphafunc - ) +) -add_component_dir (sceneutil +add_component_dir(sceneutil clone attach visitor util statesetupdater controller skeleton riggeometry morphgeometry lightcontroller lightmanager lightutil positionattitudetransform workqueue pathgridutil waterutil writescene serialize optimizer actorutil detourdebugdraw navmesh agentpath shadow mwshadowtechnique recastmesh shadowsbin osgacontroller rtt screencapture depth color riggeometryosgaextension extradata unrefqueue - ) +) -add_component_dir (nif +add_component_dir(nif controlled effect niftypes record controller extra node record_ptr data niffile property nifkey base nifstream physics - ) +) -add_component_dir (nifosg +add_component_dir(nifosg nifloader controller particle matrixtransform - ) +) -add_component_dir (nifbullet +add_component_dir(nifbullet bulletnifloader - ) +) -add_component_dir (to_utf8 +add_component_dir(to_utf8 to_utf8 - ) +) add_component_dir(esm attr common defs esmcommon records util luascripts format refid) @@ -86,7 +86,7 @@ add_component_dir(fx pass technique lexer widgets stateupdater) add_component_dir(std140 ubo) -add_component_dir (esm3 +add_component_dir(esm3 esmreader esmwriter loadacti loadalch loadappa loadarmo loadbody loadbook loadbsgn loadcell loadclas loadclot loadcont loadcrea loaddial loaddoor loadench loadfact loadglob loadgmst loadinfo loadingr loadland loadlevlist loadligh loadlock loadprob loadrepa loadltex loadmgef loadmisc @@ -96,13 +96,13 @@ add_component_dir (esm3 inventorystate containerstate npcstate creaturestate dialoguestate statstate npcstats creaturestats weatherstate quickkeys fogstate spellstate activespells creaturelevliststate doorstate projectilestate debugprofile aisequence magiceffects custommarkerstate stolenitems transport animationstate controlsstate mappings readerscache - ) +) -add_component_dir (esm3terrain +add_component_dir(esm3terrain storage - ) +) -add_component_dir (esm4 +add_component_dir(esm4 acti actor common @@ -191,96 +191,97 @@ add_component_dir (esm4 loadweap loadwrld reader + readerutils reference script ) -add_component_dir (misc +add_component_dir(misc constants utf8stream resourcehelpers rng messageformatparser weakcache thread compression osguservalues color tuplemeta tuplehelpers - ) +) -add_component_dir (stereo +add_component_dir(stereo frustum multiview stereomanager types - ) +) -add_component_dir (debug +add_component_dir(debug debugging debuglog gldebug debugdraw - ) +) IF(NOT WIN32 AND NOT APPLE) add_definitions(-DGLOBAL_DATA_PATH="${GLOBAL_DATA_PATH}") add_definitions(-DGLOBAL_CONFIG_PATH="${GLOBAL_CONFIG_PATH}") ENDIF() -add_component_dir (files + +add_component_dir(files linuxpath androidpath windowspath macospath fixedpath multidircollection collections configurationmanager constrainedfilestream memorystream hash configfileparser openfile constrainedfilestreambuf conversion - ) +) -add_component_dir (compiler +add_component_dir(compiler context controlparser errorhandler exception exprparser extensions fileparser generator lineparser literals locals output parser scanner scriptparser skipparser streamerrorhandler stringparser tokenloc nullerrorhandler opcodes extensions0 declarationparser quickfileparser discardparser junkparser - ) +) -add_component_dir (interpreter +add_component_dir(interpreter context controlopcodes genericopcodes installopcodes interpreter localopcodes mathopcodes miscopcodes opcodes runtime types defines - ) +) -add_component_dir (translation +add_component_dir(translation translation - ) +) -add_component_dir (terrain +add_component_dir(terrain storage world buffercache defs terraingrid material terraindrawable texturemanager chunkmanager compositemaprenderer quadtreeworld quadtreenode viewdata cellborder view heightcull - ) +) -add_component_dir (loadinglistener +add_component_dir(loadinglistener loadinglistener - ) +) -add_component_dir (myguiplatform +add_component_dir(myguiplatform myguirendermanager myguidatamanager myguiplatform myguitexture myguiloglistener additivelayer scalinglayer - ) +) -add_component_dir (widgets +add_component_dir(widgets box fontwrapper imagebutton tags list numericeditbox sharedstatebutton windowcaption widgets - ) +) -add_component_dir (fontloader +add_component_dir(fontloader fontloader - ) +) -add_component_dir (sdlutil +add_component_dir(sdlutil gl4es_init sdlgraphicswindow imagetosurface sdlinputwrapper sdlvideowrapper events sdlcursormanager sdlmappings - ) +) -add_component_dir (version +add_component_dir(version version - ) +) -add_component_dir (fallback +add_component_dir(fallback fallback validate - ) +) -add_component_dir (lua_ui +add_component_dir(lua_ui registerscriptsettings scriptsettings properties widget element util layers content alignment resources adapter text textedit window image container flex - ) - +) if(WIN32) - add_component_dir (crashcatcher + add_component_dir(crashcatcher windows_crashcatcher windows_crashmonitor windows_crashshm ) elseif(NOT ANDROID) - add_component_dir (crashcatcher + add_component_dir(crashcatcher crashcatcher ) endif() @@ -316,11 +317,11 @@ add_component_dir(detournavigator stats commulativeaabb recastcontext - ) +) add_component_dir(loadinglistener reporter - ) +) add_component_dir(sqlite3 db @@ -335,63 +336,63 @@ add_component_dir(esmloader add_component_dir(navmeshtool protocol - ) +) add_component_dir(platform platform file - ) +) -if (WIN32) +if(WIN32) add_component_dir(platform file.win32 - ) -elseif (UNIX) + ) +elseif(UNIX) add_component_dir(platform file.posix - ) -else () + ) +else() add_component_dir(platform file.stdio - ) + ) endif() -set (ESM_UI ${CMAKE_SOURCE_DIR}/files/ui/contentselector.ui - ) +set(ESM_UI ${CMAKE_SOURCE_DIR}/files/ui/contentselector.ui +) -if (USE_QT) - add_component_qt_dir (contentselector +if(USE_QT) + add_component_qt_dir(contentselector model/modelitem model/esmfile model/naturalsort model/contentmodel model/loadordererror view/combobox view/contentselector - ) - add_component_qt_dir (config + ) + add_component_qt_dir(config gamesettings launchersettings settingsbase - ) + ) - add_component_qt_dir (process + add_component_qt_dir(process processinvoker - ) + ) - add_component_qt_dir (misc + add_component_qt_dir(misc helpviewer - ) + ) - add_component_qt_dir (files + add_component_qt_dir(files qtconversion - ) + ) QT5_WRAP_UI(ESM_UI_HDR ${ESM_UI}) endif() -if (CMAKE_COMPILER_IS_GNUCXX OR CMAKE_CXX_COMPILER_ID MATCHES "Clang") +if(CMAKE_COMPILER_IS_GNUCXX OR CMAKE_CXX_COMPILER_ID MATCHES "Clang") if("${CMAKE_SYSTEM_PROCESSOR}" STREQUAL "x86_64" AND NOT APPLE) add_definitions(-fPIC) endif() -endif () +endif() include_directories(${BULLET_INCLUDE_DIRS} ${CMAKE_CURRENT_BINARY_DIR}) @@ -436,7 +437,7 @@ target_link_libraries(components smhasher ${ICU_LIBRARIES} yaml-cpp - ) +) if(Boost_VERSION_STRING VERSION_GREATER_EQUAL 1.77.0) target_link_libraries(components ${Boost_ATOMIC_LIBRARY}) @@ -444,46 +445,46 @@ endif() target_link_libraries(components ${BULLET_LIBRARIES}) -if (WIN32) +if(WIN32) target_link_libraries(components - ${Boost_LOCALE_LIBRARY} - ${Boost_ZLIB_LIBRARY}) + ${Boost_LOCALE_LIBRARY} + ${Boost_ZLIB_LIBRARY}) endif() -if (USE_QT) +if(USE_QT) add_library(components_qt STATIC ${COMPONENT_QT_FILES} ${ESM_UI_HDR}) target_link_libraries(components_qt components Qt5::Widgets Qt5::Core) target_compile_definitions(components_qt PRIVATE OPENMW_DOC_BASEURL="${OPENMW_DOC_BASEURL}") endif() -if (GIT_CHECKOUT) - add_dependencies (components git-version) -endif (GIT_CHECKOUT) +if(GIT_CHECKOUT) + add_dependencies(components git-version) +endif(GIT_CHECKOUT) -if (OSG_STATIC AND CMAKE_SYSTEM_NAME MATCHES "Linux") +if(OSG_STATIC AND CMAKE_SYSTEM_NAME MATCHES "Linux") find_package(X11 REQUIRED COMPONENTS Xinerama Xrandr) target_link_libraries(components ${CMAKE_DL_LIBS} X11::X11 X11::Xinerama X11::Xrandr) find_package(Fontconfig MODULE) + if(Fontconfig_FOUND) target_link_libraries(components Fontconfig::Fontconfig) endif() endif() -if (WIN32) +if(WIN32) target_link_libraries(components shlwapi) endif() # Fix for not visible pthreads functions for linker with glibc 2.15 -if (UNIX AND NOT APPLE) -target_link_libraries(components ${CMAKE_THREAD_LIBS_INIT}) +if(UNIX AND NOT APPLE) + target_link_libraries(components ${CMAKE_THREAD_LIBS_INIT}) endif() -if (BUILD_WITH_CODE_COVERAGE) +if(BUILD_WITH_CODE_COVERAGE) add_definitions(--coverage) target_link_libraries(components gcov) endif() - # Make the variable accessible for other subdirectories set(COMPONENT_FILES ${COMPONENT_FILES} PARENT_SCOPE) @@ -492,8 +493,10 @@ target_compile_definitions(components PUBLIC BT_USE_DOUBLE_PRECISION) if(OSG_STATIC) unset(_osg_plugins_static_files) add_library(components_osg_plugins INTERFACE) + foreach(_plugin ${USED_OSG_PLUGINS}) string(TOUPPER ${_plugin} _plugin_uc) + if(OPENMW_USE_SYSTEM_OSG) list(APPEND _osg_plugins_static_files ${${_plugin_uc}_LIBRARY}) else() @@ -502,6 +505,7 @@ if(OSG_STATIC) add_dependencies(components_osg_plugins ${${_plugin_uc}_LIBRARY}) endif() endforeach() + # We use --whole-archive because OSG plugins use registration. get_whole_archive_options(_opts ${_osg_plugins_static_files}) target_link_options(components_osg_plugins INTERFACE ${_opts}) @@ -521,7 +525,7 @@ if(USE_QT) set_property(TARGET components_qt PROPERTY AUTOMOC ON) endif(USE_QT) -if (CMAKE_VERSION VERSION_GREATER_EQUAL 3.16 AND MSVC) +if(CMAKE_VERSION VERSION_GREATER_EQUAL 3.16 AND MSVC) target_precompile_headers(components PUBLIC diff --git a/components/esm/refid.hpp b/components/esm/refid.hpp index 8900f7ce75..0195d31ea4 100644 --- a/components/esm/refid.hpp +++ b/components/esm/refid.hpp @@ -1,12 +1,13 @@ #ifndef OPENMW_COMPONENTS_ESM_REFID_HPP #define OPENMW_COMPONENTS_ESM_REFID_HPP #include -#include #include #include #include #include +#include + namespace ESM { struct RefId diff --git a/components/esm4/loadcell.cpp b/components/esm4/loadcell.cpp index 1321e31578..adf8a13180 100644 --- a/components/esm4/loadcell.cpp +++ b/components/esm4/loadcell.cpp @@ -32,11 +32,11 @@ #include #include // FLT_MAX for gcc +#include // FIXME: debug only #include -#include // FIXME: debug only - #include "reader.hpp" + #include // #include "writer.hpp" diff --git a/components/esm4/loadcell.hpp b/components/esm4/loadcell.hpp index bcc95f652f..49e5d048b0 100644 --- a/components/esm4/loadcell.hpp +++ b/components/esm4/loadcell.hpp @@ -33,6 +33,7 @@ #include "formid.hpp" #include "lighting.hpp" + #include #include diff --git a/components/esm4/loadrefr.hpp b/components/esm4/loadrefr.hpp index baf199c4c4..fb54c35863 100644 --- a/components/esm4/loadrefr.hpp +++ b/components/esm4/loadrefr.hpp @@ -30,6 +30,7 @@ #include #include "reference.hpp" // FormId, Placement, EnableParent + #include #include diff --git a/components/esm4/loadstat.hpp b/components/esm4/loadstat.hpp index 5d79f84d6f..3b8a78d8fb 100644 --- a/components/esm4/loadstat.hpp +++ b/components/esm4/loadstat.hpp @@ -32,6 +32,7 @@ #include #include "formid.hpp" + #include #include diff --git a/components/esm4/readerutils.hpp b/components/esm4/readerutils.hpp new file mode 100644 index 0000000000..dd202a5f71 --- /dev/null +++ b/components/esm4/readerutils.hpp @@ -0,0 +1,84 @@ +#ifndef OPENMW_COMPONENTS_ESM4_READERUTILS +#define OPENMW_COMPONENTS_ESM4_READERUTILS + +#include +namespace ESM4 +{ + struct ReaderUtils + { + + /* RecordInvocable must be an invocable, takes an ESM4::Reader& as input, and outputs a boolean that indicates + if the record was read or ignored. Will be invoked for every record + + GroupInvocable's invocable must take a ESM4::Reader& as input, doesn't need to output anything. Will be invoked + for every group*/ + template + static void readAll(ESM4::Reader& reader, RecordInvocable&& recordInvocable, GroupInvocable&& groupInvocable) + { + while (reader.hasMoreRecs()) + { + reader.exitGroupCheck(); + if (!readItem(reader, recordInvocable, groupInvocable)) + break; + } + } + + template + static void readRecord(ESM4::Reader& reader, RecordInvocable&& recordInvocable) + { + if (!recordInvocable(reader)) + reader.skipRecordData(); + } + + template + static bool readGroup(ESM4::Reader& reader, RecordInvocable&& recordInvocable, GroupInvocable&& groupInvocable) + { + const ESM4::RecordHeader& header = reader.hdr(); + + groupInvocable(reader); + + switch (static_cast(header.group.type)) + { + case ESM4::Grp_RecordType: + case ESM4::Grp_InteriorCell: + case ESM4::Grp_InteriorSubCell: + case ESM4::Grp_ExteriorCell: + case ESM4::Grp_ExteriorSubCell: + reader.enterGroup(); + return readItem(reader, recordInvocable, groupInvocable); + case ESM4::Grp_WorldChild: + case ESM4::Grp_CellChild: + case ESM4::Grp_TopicChild: + case ESM4::Grp_CellPersistentChild: + case ESM4::Grp_CellTemporaryChild: + case ESM4::Grp_CellVisibleDistChild: + reader.adjustGRUPFormId(); + reader.enterGroup(); + if (!reader.hasMoreRecs()) + return false; + return readItem(reader, recordInvocable, groupInvocable); + } + + reader.skipGroup(); + + return true; + } + + template + static bool readItem(ESM4::Reader& reader, RecordInvocable&& recordInvocable, GroupInvocable&& groupInvocable) + { + if (!reader.getRecordHeader() || !reader.hasMoreRecs()) + return false; + + const ESM4::RecordHeader& header = reader.hdr(); + + if (header.record.typeId == ESM4::REC_GRUP) + return readGroup(reader, recordInvocable, groupInvocable); + + readRecord(reader, recordInvocable); + return true; + } + }; +} + +#endif // !OPENMW_COMPONENTS_ESM4_READERUTILS diff --git a/components/to_utf8/to_utf8.hpp b/components/to_utf8/to_utf8.hpp index e72e24a753..f7197fe553 100644 --- a/components/to_utf8/to_utf8.hpp +++ b/components/to_utf8/to_utf8.hpp @@ -68,7 +68,7 @@ namespace ToUTF8 /// ASCII-only string. Otherwise returns a view to the input. std::string_view getLegacyEnc(std::string_view input); - const StatelessUtf8Encoder* getStatelessEncoder() const { return &mImpl; } + const StatelessUtf8Encoder getStatelessEncoder() const { return mImpl; } private: std::string mBuffer; From e9190bedc86f6b84b96980dadf9058195bde4777 Mon Sep 17 00:00:00 2001 From: "florent.teppe" Date: Mon, 2 Jan 2023 18:35:05 +0100 Subject: [PATCH 03/10] Reverts useless CmakeList formatting --- components/CMakeLists.txt | 261 +++++++++++++++++++------------------- 1 file changed, 129 insertions(+), 132 deletions(-) diff --git a/components/CMakeLists.txt b/components/CMakeLists.txt index 9646aae695..c1dbe36798 100644 --- a/components/CMakeLists.txt +++ b/components/CMakeLists.txt @@ -1,84 +1,84 @@ -project(Components) +project (Components) # Version file -set(VERSION_IN_FILE "${OpenMW_SOURCE_DIR}/files/version.in") -set(VERSION_FILE_PATH_BASE "${OpenMW_BINARY_DIR}") -set(VERSION_FILE_PATH_RELATIVE resources/version) - -if(GIT_CHECKOUT) +set (VERSION_IN_FILE "${OpenMW_SOURCE_DIR}/files/version.in") +set (VERSION_FILE_PATH_BASE "${OpenMW_BINARY_DIR}") +set (VERSION_FILE_PATH_RELATIVE resources/version) +if (GIT_CHECKOUT) get_generator_is_multi_config(multi_config) - add_custom_target(git-version - COMMAND ${CMAKE_COMMAND} - -DGIT_EXECUTABLE=${GIT_EXECUTABLE} - -DPROJECT_SOURCE_DIR=${PROJECT_SOURCE_DIR} - -DVERSION_IN_FILE=${VERSION_IN_FILE} - -DVERSION_FILE_PATH_BASE=${VERSION_FILE_PATH_BASE} - -DVERSION_FILE_PATH_RELATIVE=${VERSION_FILE_PATH_RELATIVE} - -DOPENMW_VERSION_MAJOR=${OPENMW_VERSION_MAJOR} - -DOPENMW_VERSION_MINOR=${OPENMW_VERSION_MINOR} - -DOPENMW_VERSION_RELEASE=${OPENMW_VERSION_RELEASE} - -DOPENMW_VERSION=${OPENMW_VERSION} - -DMACROSFILE=${CMAKE_SOURCE_DIR}/cmake/OpenMWMacros.cmake - "-DCMAKE_CONFIGURATION_TYPES=${CMAKE_CONFIGURATION_TYPES}" - -Dgenerator_is_multi_config_var=${multi_config} - -P ${CMAKE_CURRENT_SOURCE_DIR}/../cmake/GitVersion.cmake - VERBATIM) -else(GIT_CHECKOUT) + add_custom_target (git-version + COMMAND ${CMAKE_COMMAND} + -DGIT_EXECUTABLE=${GIT_EXECUTABLE} + -DPROJECT_SOURCE_DIR=${PROJECT_SOURCE_DIR} + -DVERSION_IN_FILE=${VERSION_IN_FILE} + -DVERSION_FILE_PATH_BASE=${VERSION_FILE_PATH_BASE} + -DVERSION_FILE_PATH_RELATIVE=${VERSION_FILE_PATH_RELATIVE} + -DOPENMW_VERSION_MAJOR=${OPENMW_VERSION_MAJOR} + -DOPENMW_VERSION_MINOR=${OPENMW_VERSION_MINOR} + -DOPENMW_VERSION_RELEASE=${OPENMW_VERSION_RELEASE} + -DOPENMW_VERSION=${OPENMW_VERSION} + -DMACROSFILE=${CMAKE_SOURCE_DIR}/cmake/OpenMWMacros.cmake + "-DCMAKE_CONFIGURATION_TYPES=${CMAKE_CONFIGURATION_TYPES}" + -Dgenerator_is_multi_config_var=${multi_config} + -P ${CMAKE_CURRENT_SOURCE_DIR}/../cmake/GitVersion.cmake + VERBATIM) +else (GIT_CHECKOUT) configure_resource_file(${VERSION_IN_FILE} ${VERSION_FILE_PATH_BASE} ${VERSION_FILE_PATH_RELATIVE}) -endif(GIT_CHECKOUT) +endif (GIT_CHECKOUT) # source files -add_component_dir(lua + +add_component_dir (lua luastate scriptscontainer utilpackage serialization configuration l10n storage -) + ) -add_component_dir(l10n +add_component_dir (l10n messagebundles manager -) + ) -add_component_dir(settings +add_component_dir (settings settings parser -) + ) -add_component_dir(bsa +add_component_dir (bsa bsa_file compressedbsafile -) + ) -add_component_dir(vfs +add_component_dir (vfs manager archive bsaarchive filesystemarchive registerarchives -) + ) -add_component_dir(resource +add_component_dir (resource scenemanager keyframemanager imagemanager bulletshapemanager bulletshape niffilemanager objectcache multiobjectcache resourcesystem resourcemanager stats animation foreachbulletobject errormarker -) + ) -add_component_dir(shader +add_component_dir (shader shadermanager shadervisitor removedalphafunc -) + ) -add_component_dir(sceneutil +add_component_dir (sceneutil clone attach visitor util statesetupdater controller skeleton riggeometry morphgeometry lightcontroller lightmanager lightutil positionattitudetransform workqueue pathgridutil waterutil writescene serialize optimizer actorutil detourdebugdraw navmesh agentpath shadow mwshadowtechnique recastmesh shadowsbin osgacontroller rtt screencapture depth color riggeometryosgaextension extradata unrefqueue -) + ) -add_component_dir(nif +add_component_dir (nif controlled effect niftypes record controller extra node record_ptr data niffile property nifkey base nifstream physics -) + ) -add_component_dir(nifosg +add_component_dir (nifosg nifloader controller particle matrixtransform -) + ) -add_component_dir(nifbullet +add_component_dir (nifbullet bulletnifloader -) + ) -add_component_dir(to_utf8 +add_component_dir (to_utf8 to_utf8 -) + ) add_component_dir(esm attr common defs esmcommon records util luascripts format refid) @@ -86,7 +86,7 @@ add_component_dir(fx pass technique lexer widgets stateupdater) add_component_dir(std140 ubo) -add_component_dir(esm3 +add_component_dir (esm3 esmreader esmwriter loadacti loadalch loadappa loadarmo loadbody loadbook loadbsgn loadcell loadclas loadclot loadcont loadcrea loaddial loaddoor loadench loadfact loadglob loadgmst loadinfo loadingr loadland loadlevlist loadligh loadlock loadprob loadrepa loadltex loadmgef loadmisc @@ -96,13 +96,13 @@ add_component_dir(esm3 inventorystate containerstate npcstate creaturestate dialoguestate statstate npcstats creaturestats weatherstate quickkeys fogstate spellstate activespells creaturelevliststate doorstate projectilestate debugprofile aisequence magiceffects custommarkerstate stolenitems transport animationstate controlsstate mappings readerscache -) + ) -add_component_dir(esm3terrain +add_component_dir (esm3terrain storage -) + ) -add_component_dir(esm4 +add_component_dir (esm4 acti actor common @@ -191,97 +191,97 @@ add_component_dir(esm4 loadweap loadwrld reader - readerutils reference script + readerutils ) -add_component_dir(misc +add_component_dir (misc constants utf8stream resourcehelpers rng messageformatparser weakcache thread compression osguservalues color tuplemeta tuplehelpers -) + ) -add_component_dir(stereo +add_component_dir (stereo frustum multiview stereomanager types -) + ) -add_component_dir(debug +add_component_dir (debug debugging debuglog gldebug debugdraw -) + ) IF(NOT WIN32 AND NOT APPLE) add_definitions(-DGLOBAL_DATA_PATH="${GLOBAL_DATA_PATH}") add_definitions(-DGLOBAL_CONFIG_PATH="${GLOBAL_CONFIG_PATH}") ENDIF() - -add_component_dir(files +add_component_dir (files linuxpath androidpath windowspath macospath fixedpath multidircollection collections configurationmanager constrainedfilestream memorystream hash configfileparser openfile constrainedfilestreambuf conversion -) + ) -add_component_dir(compiler +add_component_dir (compiler context controlparser errorhandler exception exprparser extensions fileparser generator lineparser literals locals output parser scanner scriptparser skipparser streamerrorhandler stringparser tokenloc nullerrorhandler opcodes extensions0 declarationparser quickfileparser discardparser junkparser -) + ) -add_component_dir(interpreter +add_component_dir (interpreter context controlopcodes genericopcodes installopcodes interpreter localopcodes mathopcodes miscopcodes opcodes runtime types defines -) + ) -add_component_dir(translation +add_component_dir (translation translation -) + ) -add_component_dir(terrain +add_component_dir (terrain storage world buffercache defs terraingrid material terraindrawable texturemanager chunkmanager compositemaprenderer quadtreeworld quadtreenode viewdata cellborder view heightcull -) + ) -add_component_dir(loadinglistener +add_component_dir (loadinglistener loadinglistener -) + ) -add_component_dir(myguiplatform +add_component_dir (myguiplatform myguirendermanager myguidatamanager myguiplatform myguitexture myguiloglistener additivelayer scalinglayer -) + ) -add_component_dir(widgets +add_component_dir (widgets box fontwrapper imagebutton tags list numericeditbox sharedstatebutton windowcaption widgets -) + ) -add_component_dir(fontloader +add_component_dir (fontloader fontloader -) + ) -add_component_dir(sdlutil +add_component_dir (sdlutil gl4es_init sdlgraphicswindow imagetosurface sdlinputwrapper sdlvideowrapper events sdlcursormanager sdlmappings -) + ) -add_component_dir(version +add_component_dir (version version -) + ) -add_component_dir(fallback +add_component_dir (fallback fallback validate -) + ) -add_component_dir(lua_ui +add_component_dir (lua_ui registerscriptsettings scriptsettings properties widget element util layers content alignment resources adapter text textedit window image container flex -) + ) + if(WIN32) - add_component_dir(crashcatcher + add_component_dir (crashcatcher windows_crashcatcher windows_crashmonitor windows_crashshm ) elseif(NOT ANDROID) - add_component_dir(crashcatcher + add_component_dir (crashcatcher crashcatcher ) endif() @@ -317,11 +317,11 @@ add_component_dir(detournavigator stats commulativeaabb recastcontext -) + ) add_component_dir(loadinglistener reporter -) + ) add_component_dir(sqlite3 db @@ -336,63 +336,63 @@ add_component_dir(esmloader add_component_dir(navmeshtool protocol -) + ) add_component_dir(platform platform file -) + ) -if(WIN32) +if (WIN32) add_component_dir(platform file.win32 - ) -elseif(UNIX) + ) +elseif (UNIX) add_component_dir(platform file.posix - ) -else() + ) +else () add_component_dir(platform file.stdio - ) + ) endif() -set(ESM_UI ${CMAKE_SOURCE_DIR}/files/ui/contentselector.ui -) +set (ESM_UI ${CMAKE_SOURCE_DIR}/files/ui/contentselector.ui + ) -if(USE_QT) - add_component_qt_dir(contentselector +if (USE_QT) + add_component_qt_dir (contentselector model/modelitem model/esmfile model/naturalsort model/contentmodel model/loadordererror view/combobox view/contentselector - ) - add_component_qt_dir(config + ) + add_component_qt_dir (config gamesettings launchersettings settingsbase - ) + ) - add_component_qt_dir(process + add_component_qt_dir (process processinvoker - ) + ) - add_component_qt_dir(misc + add_component_qt_dir (misc helpviewer - ) + ) - add_component_qt_dir(files + add_component_qt_dir (files qtconversion - ) + ) QT5_WRAP_UI(ESM_UI_HDR ${ESM_UI}) endif() -if(CMAKE_COMPILER_IS_GNUCXX OR CMAKE_CXX_COMPILER_ID MATCHES "Clang") +if (CMAKE_COMPILER_IS_GNUCXX OR CMAKE_CXX_COMPILER_ID MATCHES "Clang") if("${CMAKE_SYSTEM_PROCESSOR}" STREQUAL "x86_64" AND NOT APPLE) add_definitions(-fPIC) endif() -endif() +endif () include_directories(${BULLET_INCLUDE_DIRS} ${CMAKE_CURRENT_BINARY_DIR}) @@ -437,7 +437,7 @@ target_link_libraries(components smhasher ${ICU_LIBRARIES} yaml-cpp -) + ) if(Boost_VERSION_STRING VERSION_GREATER_EQUAL 1.77.0) target_link_libraries(components ${Boost_ATOMIC_LIBRARY}) @@ -445,46 +445,46 @@ endif() target_link_libraries(components ${BULLET_LIBRARIES}) -if(WIN32) +if (WIN32) target_link_libraries(components - ${Boost_LOCALE_LIBRARY} - ${Boost_ZLIB_LIBRARY}) + ${Boost_LOCALE_LIBRARY} + ${Boost_ZLIB_LIBRARY}) endif() -if(USE_QT) +if (USE_QT) add_library(components_qt STATIC ${COMPONENT_QT_FILES} ${ESM_UI_HDR}) target_link_libraries(components_qt components Qt5::Widgets Qt5::Core) target_compile_definitions(components_qt PRIVATE OPENMW_DOC_BASEURL="${OPENMW_DOC_BASEURL}") endif() -if(GIT_CHECKOUT) - add_dependencies(components git-version) -endif(GIT_CHECKOUT) +if (GIT_CHECKOUT) + add_dependencies (components git-version) +endif (GIT_CHECKOUT) -if(OSG_STATIC AND CMAKE_SYSTEM_NAME MATCHES "Linux") +if (OSG_STATIC AND CMAKE_SYSTEM_NAME MATCHES "Linux") find_package(X11 REQUIRED COMPONENTS Xinerama Xrandr) target_link_libraries(components ${CMAKE_DL_LIBS} X11::X11 X11::Xinerama X11::Xrandr) find_package(Fontconfig MODULE) - if(Fontconfig_FOUND) target_link_libraries(components Fontconfig::Fontconfig) endif() endif() -if(WIN32) +if (WIN32) target_link_libraries(components shlwapi) endif() # Fix for not visible pthreads functions for linker with glibc 2.15 -if(UNIX AND NOT APPLE) - target_link_libraries(components ${CMAKE_THREAD_LIBS_INIT}) +if (UNIX AND NOT APPLE) +target_link_libraries(components ${CMAKE_THREAD_LIBS_INIT}) endif() -if(BUILD_WITH_CODE_COVERAGE) +if (BUILD_WITH_CODE_COVERAGE) add_definitions(--coverage) target_link_libraries(components gcov) endif() + # Make the variable accessible for other subdirectories set(COMPONENT_FILES ${COMPONENT_FILES} PARENT_SCOPE) @@ -493,10 +493,8 @@ target_compile_definitions(components PUBLIC BT_USE_DOUBLE_PRECISION) if(OSG_STATIC) unset(_osg_plugins_static_files) add_library(components_osg_plugins INTERFACE) - foreach(_plugin ${USED_OSG_PLUGINS}) string(TOUPPER ${_plugin} _plugin_uc) - if(OPENMW_USE_SYSTEM_OSG) list(APPEND _osg_plugins_static_files ${${_plugin_uc}_LIBRARY}) else() @@ -505,7 +503,6 @@ if(OSG_STATIC) add_dependencies(components_osg_plugins ${${_plugin_uc}_LIBRARY}) endif() endforeach() - # We use --whole-archive because OSG plugins use registration. get_whole_archive_options(_opts ${_osg_plugins_static_files}) target_link_options(components_osg_plugins INTERFACE ${_opts}) @@ -525,7 +522,7 @@ if(USE_QT) set_property(TARGET components_qt PROPERTY AUTOMOC ON) endif(USE_QT) -if(CMAKE_VERSION VERSION_GREATER_EQUAL 3.16 AND MSVC) +if (CMAKE_VERSION VERSION_GREATER_EQUAL 3.16 AND MSVC) target_precompile_headers(components PUBLIC From 3b2d9161c4189bb3dac9ad07f5a396269f4caadd Mon Sep 17 00:00:00 2001 From: "florent.teppe" Date: Mon, 2 Jan 2023 19:20:03 +0100 Subject: [PATCH 04/10] Applied review advice better deals with templated functions meant for esm3 used by esm4s. simplified loading of esm4 and dealing with unhandled record types. --- apps/esmtool/tes4.cpp | 3 +-- apps/openmw/mwworld/esmloader.cpp | 7 ++----- apps/openmw/mwworld/esmstore.cpp | 11 ++++------- apps/openmw/mwworld/store.cpp | 8 ++++---- components/esm4/loadcell.cpp | 2 +- 5 files changed, 12 insertions(+), 19 deletions(-) diff --git a/apps/esmtool/tes4.cpp b/apps/esmtool/tes4.cpp index 50c7d24b7c..78e5931c0e 100644 --- a/apps/esmtool/tes4.cpp +++ b/apps/esmtool/tes4.cpp @@ -184,7 +184,7 @@ namespace EsmTool if constexpr (hasFormId) std::cout << "\n FormId: " << value.mFormId; if constexpr (hasRefId) - std::cout << "\n RefId: " << value.mId; + std::cout << "\n FormId: " << value.mId; if constexpr (hasFlags) std::cout << "\n Record flags: " << recordFlags(value.mFlags); if constexpr (hasEditorId) @@ -196,7 +196,6 @@ namespace EsmTool if constexpr (hasKf) std::cout << "\n Kf:" << WriteArray("\n - ", value.mKf); std::cout << '\n'; - return; } bool readRecord(const Params& params, ESM4::Reader& reader) diff --git a/apps/openmw/mwworld/esmloader.cpp b/apps/openmw/mwworld/esmloader.cpp index c529a9834c..be2b3abda9 100644 --- a/apps/openmw/mwworld/esmloader.cpp +++ b/apps/openmw/mwworld/esmloader.cpp @@ -28,10 +28,6 @@ namespace MWWorld { auto stream = Files::openBinaryInputFileStream(filepath); - if (!stream->is_open()) - { - throw std::runtime_error(std::string("File Failed to open file: ") + std::strerror(errno) + "\n"); - } const ESM::Format format = ESM::readFormat(*stream); stream->seekg(0); @@ -64,13 +60,14 @@ namespace MWWorld } case ESM::Format::Tes4: { - if (mEncoder) + if (mEncoder != nullptr) { ESM4::Reader readerESM4(std::move(stream), filepath); auto statelessEncoder = mEncoder->getStatelessEncoder(); readerESM4.setEncoder(&statelessEncoder); mStore.loadESM4(readerESM4, listener, mDialogue); } + break; } } } diff --git a/apps/openmw/mwworld/esmstore.cpp b/apps/openmw/mwworld/esmstore.cpp index 31c788283d..6f39a3e602 100644 --- a/apps/openmw/mwworld/esmstore.cpp +++ b/apps/openmw/mwworld/esmstore.cpp @@ -197,7 +197,7 @@ namespace MWWorld }; template - static void typedReadRecordESM4(ESM4::Reader& reader, ESMStore& stores, Store& store, int& found) + static bool typedReadRecordESM4(ESM4::Reader& reader, Store& store) { auto recordType = static_cast(reader.hdr().record.typeId); @@ -212,20 +212,17 @@ namespace MWWorld T value; value.load(reader); store.insertStatic(value); - found++; + return true; } } } + return false; } static bool readRecord(ESM4::Reader& reader, ESMStore& store) { - int found = 0; - std::apply([&reader, &store, &found]( - auto&... x) { (ESMStoreImp::typedReadRecordESM4(reader, store, x, found), ...); }, + return std::apply([&reader](auto&... x) { return (ESMStoreImp::typedReadRecordESM4(reader, x) || ...); }, store.mStoreImp->mStores); - assert(found <= 1); - return found; } }; diff --git a/apps/openmw/mwworld/store.cpp b/apps/openmw/mwworld/store.cpp index 71161fa6a4..60179f01b5 100644 --- a/apps/openmw/mwworld/store.cpp +++ b/apps/openmw/mwworld/store.cpp @@ -164,8 +164,9 @@ namespace MWWorld std::stringstream msg; if constexpr (!ESM::isESM4Rec(T::sRecordId)) { - msg << T::getRecordType() << " '" << id << "' not found"; + msg << T::getRecordType(); } + msg << " '" << id << "' not found"; throw std::runtime_error(msg.str()); } return ptr; @@ -298,13 +299,12 @@ namespace MWWorld { for (typename Dynamic::const_iterator iter(mDynamic.begin()); iter != mDynamic.end(); ++iter) { - writer.startRecord(T::sRecordId); if constexpr (!ESM::isESM4Rec(T::sRecordId)) { + writer.startRecord(T::sRecordId); iter->second.save(writer); + writer.endRecord(T::sRecordId); } - - writer.endRecord(T::sRecordId); } } template diff --git a/components/esm4/loadcell.cpp b/components/esm4/loadcell.cpp index adf8a13180..0b829d657f 100644 --- a/components/esm4/loadcell.cpp +++ b/components/esm4/loadcell.cpp @@ -36,9 +36,9 @@ #include #include "reader.hpp" +// #include "writer.hpp" #include -// #include "writer.hpp" // TODO: Try loading only EDID and XCLC (along with mFormId, mFlags and mParent) // From 9b1c4054673700efd3453592dfe7d4bdd1be6213 Mon Sep 17 00:00:00 2001 From: "florent.teppe" Date: Tue, 3 Jan 2023 22:16:42 +0100 Subject: [PATCH 05/10] On store creation checks that each record has a different RecordId. --- apps/openmw/mwworld/esmstore.cpp | 30 ++++++++++++++++++++++++++++++ 1 file changed, 30 insertions(+) diff --git a/apps/openmw/mwworld/esmstore.cpp b/apps/openmw/mwworld/esmstore.cpp index 6f39a3e602..d69d4e8804 100644 --- a/apps/openmw/mwworld/esmstore.cpp +++ b/apps/openmw/mwworld/esmstore.cpp @@ -219,6 +219,35 @@ namespace MWWorld return false; } + template + static unsigned int hasSameRecordId(const Store& store, ESM::RecNameInts RecName) + { + if constexpr (HasRecordId::value) + { + return T::sRecordId == RecName ? 1 : 0; + } + else + { + return 0; + } + } + + template + static void testRecNameIntCount(const Store& store, const ESMStore::StoreTuple& stores) + { + if constexpr (HasRecordId::value) + { + const unsigned int recordIdCount + = std::apply([](auto&&... x) { return (hasSameRecordId(x, T::sRecordId) + ...); }, stores); + assert(recordIdCount == 1); + } + } + + static void testAllRecNameIntUnique(const ESMStore::StoreTuple& stores) + { + std::apply([&stores](auto&&... x) { (testRecNameIntCount(x, stores), ...); }, stores); + } + static bool readRecord(ESM4::Reader& reader, ESMStore& store) { return std::apply([&reader](auto&... x) { return (ESMStoreImp::typedReadRecordESM4(reader, x) || ...); }, @@ -250,6 +279,7 @@ namespace MWWorld { mStoreImp = std::make_unique(); std::apply([this](auto&... x) { (ESMStoreImp::assignStoreToIndex(*this, x), ...); }, mStoreImp->mStores); + ESMStoreImp::testAllRecNameIntUnique(mStoreImp->mStores); mDynamicCount = 0; getWritable().setCells(getWritable()); } From 64a9f742da453b04824ce0b9af96919e11b7b9d6 Mon Sep 17 00:00:00 2001 From: "florent.teppe" Date: Tue, 3 Jan 2023 23:28:31 +0100 Subject: [PATCH 06/10] Improves check: throws an error that says which RecName is used twice. --- apps/openmw/mwworld/esmstore.cpp | 28 +++++++++++++++++++++++++++- 1 file changed, 27 insertions(+), 1 deletion(-) diff --git a/apps/openmw/mwworld/esmstore.cpp b/apps/openmw/mwworld/esmstore.cpp index d69d4e8804..29d014afd1 100644 --- a/apps/openmw/mwworld/esmstore.cpp +++ b/apps/openmw/mwworld/esmstore.cpp @@ -196,6 +196,28 @@ namespace MWWorld { }; + struct RecNameIntChar + { + char name[6]; + RecNameIntChar(ESM::RecNameInts recName) + { + unsigned int FourCC = recName & ~ESM::sEsm4RecnameFlag; // Removes the flag + name[0] = FourCC & 0xFF; + name[1] = (FourCC >> 8) & 0xFF; + name[2] = (FourCC >> 16) & 0xFF; + name[3] = (FourCC >> 24) & 0xFF; + if (ESM::isESM4Rec(recName)) + { + name[4] = '4'; + name[5] = '\0'; + } + else + { + name[4] = '\0'; + } + } + }; + template static bool typedReadRecordESM4(ESM4::Reader& reader, Store& store) { @@ -239,7 +261,11 @@ namespace MWWorld { const unsigned int recordIdCount = std::apply([](auto&&... x) { return (hasSameRecordId(x, T::sRecordId) + ...); }, stores); - assert(recordIdCount == 1); + if (recordIdCount != 1) + { + throw std::runtime_error( + "The same RecNameInt is used twice ESM::REC_" + std::string(RecNameIntChar(T::sRecordId).name)); + } } } From e80dbd7c9566d369e9250bac425c49e81e58ae71 Mon Sep 17 00:00:00 2001 From: "florent.teppe" Date: Wed, 4 Jan 2023 00:17:45 +0100 Subject: [PATCH 07/10] Moved the test to test_store.cpp where it belongs --- apps/openmw/mwworld/esmstore.cpp | 56 -------------- apps/openmw/mwworld/esmstore.hpp | 3 +- apps/openmw_test_suite/mwworld/test_store.cpp | 77 +++++++++++++++++++ 3 files changed, 79 insertions(+), 57 deletions(-) diff --git a/apps/openmw/mwworld/esmstore.cpp b/apps/openmw/mwworld/esmstore.cpp index 29d014afd1..6f39a3e602 100644 --- a/apps/openmw/mwworld/esmstore.cpp +++ b/apps/openmw/mwworld/esmstore.cpp @@ -196,28 +196,6 @@ namespace MWWorld { }; - struct RecNameIntChar - { - char name[6]; - RecNameIntChar(ESM::RecNameInts recName) - { - unsigned int FourCC = recName & ~ESM::sEsm4RecnameFlag; // Removes the flag - name[0] = FourCC & 0xFF; - name[1] = (FourCC >> 8) & 0xFF; - name[2] = (FourCC >> 16) & 0xFF; - name[3] = (FourCC >> 24) & 0xFF; - if (ESM::isESM4Rec(recName)) - { - name[4] = '4'; - name[5] = '\0'; - } - else - { - name[4] = '\0'; - } - } - }; - template static bool typedReadRecordESM4(ESM4::Reader& reader, Store& store) { @@ -241,39 +219,6 @@ namespace MWWorld return false; } - template - static unsigned int hasSameRecordId(const Store& store, ESM::RecNameInts RecName) - { - if constexpr (HasRecordId::value) - { - return T::sRecordId == RecName ? 1 : 0; - } - else - { - return 0; - } - } - - template - static void testRecNameIntCount(const Store& store, const ESMStore::StoreTuple& stores) - { - if constexpr (HasRecordId::value) - { - const unsigned int recordIdCount - = std::apply([](auto&&... x) { return (hasSameRecordId(x, T::sRecordId) + ...); }, stores); - if (recordIdCount != 1) - { - throw std::runtime_error( - "The same RecNameInt is used twice ESM::REC_" + std::string(RecNameIntChar(T::sRecordId).name)); - } - } - } - - static void testAllRecNameIntUnique(const ESMStore::StoreTuple& stores) - { - std::apply([&stores](auto&&... x) { (testRecNameIntCount(x, stores), ...); }, stores); - } - static bool readRecord(ESM4::Reader& reader, ESMStore& store) { return std::apply([&reader](auto&... x) { return (ESMStoreImp::typedReadRecordESM4(reader, x) || ...); }, @@ -305,7 +250,6 @@ namespace MWWorld { mStoreImp = std::make_unique(); std::apply([this](auto&... x) { (ESMStoreImp::assignStoreToIndex(*this, x), ...); }, mStoreImp->mStores); - ESMStoreImp::testAllRecNameIntUnique(mStoreImp->mStores); mDynamicCount = 0; getWritable().setCells(getWritable()); } diff --git a/apps/openmw/mwworld/esmstore.hpp b/apps/openmw/mwworld/esmstore.hpp index 1ed66a1c71..61083b3ec0 100644 --- a/apps/openmw/mwworld/esmstore.hpp +++ b/apps/openmw/mwworld/esmstore.hpp @@ -86,7 +86,7 @@ namespace MWWorld class ESMStore { friend struct ESMStoreImp; // This allows StoreImp to extend esmstore without beeing included everywhere - + public: using StoreTuple = std::tuple, Store, Store, Store, Store, Store, Store, Store, Store, Store, Store, Store, Store, @@ -107,6 +107,7 @@ namespace MWWorld Store, Store, Store>; + private: template static constexpr std::size_t getTypeIndex() { diff --git a/apps/openmw_test_suite/mwworld/test_store.cpp b/apps/openmw_test_suite/mwworld/test_store.cpp index f869f0e448..b69678c4d6 100644 --- a/apps/openmw_test_suite/mwworld/test_store.cpp +++ b/apps/openmw_test_suite/mwworld/test_store.cpp @@ -8,6 +8,12 @@ #include #include #include +#include +#include +#include +#include +#include +#include #include #include #include @@ -289,6 +295,77 @@ TEST_F(StoreTest, delete_test) ASSERT_TRUE(mEsmStore.get().getSize() == 1); } +template > +struct HasRecordId : std::false_type +{ +}; + +template +struct HasRecordId> : std::true_type +{ +}; + +struct RecNameIntChar +{ + char name[6]; + RecNameIntChar(ESM::RecNameInts recName) + { + unsigned int FourCC = recName & ~ESM::sEsm4RecnameFlag; // Removes the flag + name[0] = FourCC & 0xFF; + name[1] = (FourCC >> 8) & 0xFF; + name[2] = (FourCC >> 16) & 0xFF; + name[3] = (FourCC >> 24) & 0xFF; + if (ESM::isESM4Rec(recName)) + { + name[4] = '4'; + name[5] = '\0'; + } + else + { + name[4] = '\0'; + } + } +}; + +template +static unsigned int hasSameRecordId(const MWWorld::Store& store, ESM::RecNameInts RecName) +{ + if constexpr (HasRecordId::value) + { + return T::sRecordId == RecName ? 1 : 0; + } + else + { + return 0; + } +} + +template +static void testRecNameIntCount(const MWWorld::Store& store, const MWWorld::ESMStore::StoreTuple& stores) +{ + if constexpr (HasRecordId::value) + { + const unsigned int recordIdCount + = std::apply([](auto&&... x) { return (hasSameRecordId(x, T::sRecordId) + ...); }, stores); + if (recordIdCount != 1) + { + std::cout << "The same RecNameInt is used twice ESM::REC_" + std::string(RecNameIntChar(T::sRecordId).name) + << std::endl; + } + ASSERT_TRUE(recordIdCount == 1); + } +} + +static void testAllRecNameIntUnique(const MWWorld::ESMStore::StoreTuple& stores) +{ + std::apply([&stores](auto&&... x) { (testRecNameIntCount(x, stores), ...); }, stores); +} + +TEST_F(StoreTest, recordId_Unique) // Test that each type has a unique recordId +{ + testAllRecNameIntUnique(MWWorld::ESMStore::StoreTuple()); +} + /// Tests overwriting of records. TEST_F(StoreTest, overwrite_test) { From 631fa26872a1e646e3ff6b6a923b32b839d79960 Mon Sep 17 00:00:00 2001 From: "florent.teppe" Date: Wed, 4 Jan 2023 12:20:02 +0100 Subject: [PATCH 08/10] Applies review advice. --- apps/esmtool/tes4.cpp | 4 +- apps/openmw/mwworld/esmloader.cpp | 11 ++--- apps/openmw/mwworld/esmstore.cpp | 12 +---- apps/openmw/mwworld/esmstore.hpp | 12 ++++- apps/openmw_test_suite/mwworld/test_store.cpp | 49 +++---------------- components/to_utf8/to_utf8.hpp | 2 +- 6 files changed, 27 insertions(+), 63 deletions(-) diff --git a/apps/esmtool/tes4.cpp b/apps/esmtool/tes4.cpp index 78e5931c0e..1b85c37c11 100644 --- a/apps/esmtool/tes4.cpp +++ b/apps/esmtool/tes4.cpp @@ -595,14 +595,14 @@ namespace EsmTool } auto visitorRec = [¶ms](ESM4::Reader& reader) { return readRecord(params, reader); }; - auto visistorGroup = [¶ms](ESM4::Reader& reader) { + auto visitorGroup = [¶ms](ESM4::Reader& reader) { if (params.mQuite) return; auto groupType = static_cast(reader.hdr().group.type); std::cout << "\nGroup: " << toString(groupType) << " " << ESM::NAME(reader.hdr().group.typeId).toStringView() << '\n'; }; - ESM4::ReaderUtils::readAll(reader, visitorRec, visistorGroup); + ESM4::ReaderUtils::readAll(reader, visitorRec, visitorGroup); } catch (const std::exception& e) { diff --git a/apps/openmw/mwworld/esmloader.cpp b/apps/openmw/mwworld/esmloader.cpp index be2b3abda9..e0280c91b5 100644 --- a/apps/openmw/mwworld/esmloader.cpp +++ b/apps/openmw/mwworld/esmloader.cpp @@ -60,13 +60,10 @@ namespace MWWorld } case ESM::Format::Tes4: { - if (mEncoder != nullptr) - { - ESM4::Reader readerESM4(std::move(stream), filepath); - auto statelessEncoder = mEncoder->getStatelessEncoder(); - readerESM4.setEncoder(&statelessEncoder); - mStore.loadESM4(readerESM4, listener, mDialogue); - } + ESM4::Reader readerESM4(std::move(stream), filepath); + auto statelessEncoder = mEncoder->getStatelessEncoder(); + readerESM4.setEncoder(&statelessEncoder); + mStore.loadESM4(readerESM4); break; } } diff --git a/apps/openmw/mwworld/esmstore.cpp b/apps/openmw/mwworld/esmstore.cpp index 6f39a3e602..71f4e1e40d 100644 --- a/apps/openmw/mwworld/esmstore.cpp +++ b/apps/openmw/mwworld/esmstore.cpp @@ -186,16 +186,6 @@ namespace MWWorld } } - template > - struct HasRecordId : std::false_type - { - }; - - template - struct HasRecordId> : std::true_type - { - }; - template static bool typedReadRecordESM4(ESM4::Reader& reader, Store& store) { @@ -382,7 +372,7 @@ namespace MWWorld } } - void ESMStore::loadESM4(ESM4::Reader& reader, Loading::Listener* listener, ESM::Dialogue*& dialogue) + void ESMStore::loadESM4(ESM4::Reader& reader) { auto visitorRec = [this](ESM4::Reader& reader) { return ESMStoreImp::readRecord(reader, *this); }; ESM4::ReaderUtils::readAll(reader, visitorRec, [](ESM4::Reader&) {}); diff --git a/apps/openmw/mwworld/esmstore.hpp b/apps/openmw/mwworld/esmstore.hpp index 61083b3ec0..9d737c3f53 100644 --- a/apps/openmw/mwworld/esmstore.hpp +++ b/apps/openmw/mwworld/esmstore.hpp @@ -173,7 +173,7 @@ namespace MWWorld void validateDynamic(); void load(ESM::ESMReader& esm, Loading::Listener* listener, ESM::Dialogue*& dialogue); - void loadESM4(ESM4::Reader& esm, Loading::Listener* listener, ESM::Dialogue*& dialogue); + void loadESM4(ESM4::Reader& esm); template const Store& get() const @@ -264,6 +264,16 @@ namespace MWWorld template <> const ESM::NPC* ESMStore::insert(const ESM::NPC& npc); + + template > + struct HasRecordId : std::false_type + { + }; + + template + struct HasRecordId> : std::true_type + { + }; } #endif diff --git a/apps/openmw_test_suite/mwworld/test_store.cpp b/apps/openmw_test_suite/mwworld/test_store.cpp index b69678c4d6..19363064f0 100644 --- a/apps/openmw_test_suite/mwworld/test_store.cpp +++ b/apps/openmw_test_suite/mwworld/test_store.cpp @@ -295,42 +295,10 @@ TEST_F(StoreTest, delete_test) ASSERT_TRUE(mEsmStore.get().getSize() == 1); } -template > -struct HasRecordId : std::false_type -{ -}; - -template -struct HasRecordId> : std::true_type -{ -}; - -struct RecNameIntChar -{ - char name[6]; - RecNameIntChar(ESM::RecNameInts recName) - { - unsigned int FourCC = recName & ~ESM::sEsm4RecnameFlag; // Removes the flag - name[0] = FourCC & 0xFF; - name[1] = (FourCC >> 8) & 0xFF; - name[2] = (FourCC >> 16) & 0xFF; - name[3] = (FourCC >> 24) & 0xFF; - if (ESM::isESM4Rec(recName)) - { - name[4] = '4'; - name[5] = '\0'; - } - else - { - name[4] = '\0'; - } - } -}; - template static unsigned int hasSameRecordId(const MWWorld::Store& store, ESM::RecNameInts RecName) { - if constexpr (HasRecordId::value) + if constexpr (MWWorld::HasRecordId::value) { return T::sRecordId == RecName ? 1 : 0; } @@ -343,16 +311,15 @@ static unsigned int hasSameRecordId(const MWWorld::Store& store, ESM::RecName template static void testRecNameIntCount(const MWWorld::Store& store, const MWWorld::ESMStore::StoreTuple& stores) { - if constexpr (HasRecordId::value) + if constexpr (MWWorld::HasRecordId::value) { const unsigned int recordIdCount = std::apply([](auto&&... x) { return (hasSameRecordId(x, T::sRecordId) + ...); }, stores); - if (recordIdCount != 1) - { - std::cout << "The same RecNameInt is used twice ESM::REC_" + std::string(RecNameIntChar(T::sRecordId).name) - << std::endl; - } - ASSERT_TRUE(recordIdCount == 1); + std::string RecordIdName(ESM::NAME(T::sRecordId & ~ESM::sEsm4RecnameFlag).toStringView()); + if (ESM::isESM4Rec(T::sRecordId)) + RecordIdName += '4'; + + ASSERT_EQ(recordIdCount, 1) << "The same RecNameInt is used twice ESM::REC_" << RecordIdName; } } @@ -361,7 +328,7 @@ static void testAllRecNameIntUnique(const MWWorld::ESMStore::StoreTuple& stores) std::apply([&stores](auto&&... x) { (testRecNameIntCount(x, stores), ...); }, stores); } -TEST_F(StoreTest, recordId_Unique) // Test that each type has a unique recordId +TEST_F(StoreTest, eachRecordTypeShouldHaveUniqueRecordId) { testAllRecNameIntUnique(MWWorld::ESMStore::StoreTuple()); } diff --git a/components/to_utf8/to_utf8.hpp b/components/to_utf8/to_utf8.hpp index f7197fe553..11a466e44c 100644 --- a/components/to_utf8/to_utf8.hpp +++ b/components/to_utf8/to_utf8.hpp @@ -68,7 +68,7 @@ namespace ToUTF8 /// ASCII-only string. Otherwise returns a view to the input. std::string_view getLegacyEnc(std::string_view input); - const StatelessUtf8Encoder getStatelessEncoder() const { return mImpl; } + StatelessUtf8Encoder getStatelessEncoder() const { return mImpl; } private: std::string mBuffer; From b88eee08c228f63febc2feab9c9dfdd493020b02 Mon Sep 17 00:00:00 2001 From: "florent.teppe" Date: Wed, 4 Jan 2023 14:07:47 +0100 Subject: [PATCH 09/10] Store display's the ESM4's RecnameInt when not found --- apps/openmw/mwworld/store.cpp | 18 ++++++++++++++++++ apps/openmw/mwworld/store.hpp | 2 ++ apps/openmw_test_suite/mwworld/test_store.cpp | 7 ++----- 3 files changed, 22 insertions(+), 5 deletions(-) diff --git a/apps/openmw/mwworld/store.cpp b/apps/openmw/mwworld/store.cpp index 60179f01b5..bf8d656ecd 100644 --- a/apps/openmw/mwworld/store.cpp +++ b/apps/openmw/mwworld/store.cpp @@ -166,6 +166,10 @@ namespace MWWorld { msg << T::getRecordType(); } + else + { + msg << "ESM::REC_" << getRecNameString(T::sRecordId).toStringView(); + } msg << " '" << id << "' not found"; throw std::runtime_error(msg.str()); } @@ -1164,6 +1168,20 @@ namespace MWWorld return mKeywordSearch; } + + ESM::FixedString<6> getRecNameString(ESM::RecNameInts recName) + { + ESM::FixedString<6> name; + name.assign(""); + ESM::NAME fourCCName(recName & ~ESM::sEsm4RecnameFlag); + for (int i = 0; i < 4; i++) + name.mData[i] = fourCCName.mData[i]; + if (ESM::isESM4Rec(recName)) + { + name.mData[4] = '4'; + } + return name; + } } template class MWWorld::TypedDynamicStore; diff --git a/apps/openmw/mwworld/store.hpp b/apps/openmw/mwworld/store.hpp index a6f869e362..6acfb6d41e 100644 --- a/apps/openmw/mwworld/store.hpp +++ b/apps/openmw/mwworld/store.hpp @@ -517,6 +517,8 @@ namespace MWWorld const MWDialogue::KeywordSearch& getDialogIdKeywordSearch() const; }; + ESM::FixedString<6> getRecNameString(ESM::RecNameInts recName); + } // end namespace #endif diff --git a/apps/openmw_test_suite/mwworld/test_store.cpp b/apps/openmw_test_suite/mwworld/test_store.cpp index 19363064f0..e8c4dbc8a7 100644 --- a/apps/openmw_test_suite/mwworld/test_store.cpp +++ b/apps/openmw_test_suite/mwworld/test_store.cpp @@ -315,11 +315,8 @@ static void testRecNameIntCount(const MWWorld::Store& store, const MWWorld::E { const unsigned int recordIdCount = std::apply([](auto&&... x) { return (hasSameRecordId(x, T::sRecordId) + ...); }, stores); - std::string RecordIdName(ESM::NAME(T::sRecordId & ~ESM::sEsm4RecnameFlag).toStringView()); - if (ESM::isESM4Rec(T::sRecordId)) - RecordIdName += '4'; - - ASSERT_EQ(recordIdCount, 1) << "The same RecNameInt is used twice ESM::REC_" << RecordIdName; + ASSERT_EQ(recordIdCount, 1) << "The same RecNameInt is used twice ESM::REC_" + << MWWorld::getRecNameString(T::sRecordId).toStringView(); } } From 400d51c09977f22775f0f95eb18b369ea3477889 Mon Sep 17 00:00:00 2001 From: "florent.teppe" Date: Wed, 4 Jan 2023 14:19:12 +0100 Subject: [PATCH 10/10] Fix compile MSVC --- apps/openmw_test_suite/mwworld/test_store.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/apps/openmw_test_suite/mwworld/test_store.cpp b/apps/openmw_test_suite/mwworld/test_store.cpp index e8c4dbc8a7..d2163520f7 100644 --- a/apps/openmw_test_suite/mwworld/test_store.cpp +++ b/apps/openmw_test_suite/mwworld/test_store.cpp @@ -315,8 +315,8 @@ static void testRecNameIntCount(const MWWorld::Store& store, const MWWorld::E { const unsigned int recordIdCount = std::apply([](auto&&... x) { return (hasSameRecordId(x, T::sRecordId) + ...); }, stores); - ASSERT_EQ(recordIdCount, 1) << "The same RecNameInt is used twice ESM::REC_" - << MWWorld::getRecNameString(T::sRecordId).toStringView(); + ASSERT_EQ(recordIdCount, static_cast(1)) + << "The same RecNameInt is used twice ESM::REC_" << MWWorld::getRecNameString(T::sRecordId).toStringView(); } }