From 87ac85223a25aaa72586ab77570834e12c1e0c02 Mon Sep 17 00:00:00 2001 From: elsid Date: Tue, 4 Apr 2023 09:58:49 +0200 Subject: [PATCH] Support loading ESM4 GMST records --- apps/esmtool/tes4.cpp | 28 +++++++++++++- components/CMakeLists.txt | 1 + components/esm4/loadgmst.cpp | 68 ++++++++++++++++++++++++++++++++++ components/esm4/loadgmst.hpp | 27 ++++++++++++++ components/esm4/records.hpp | 1 + components/esm4/typetraits.hpp | 13 +++++++ 6 files changed, 137 insertions(+), 1 deletion(-) create mode 100644 components/esm4/loadgmst.cpp create mode 100644 components/esm4/loadgmst.hpp diff --git a/apps/esmtool/tes4.cpp b/apps/esmtool/tes4.cpp index 25054b614a..ecc80eded6 100644 --- a/apps/esmtool/tes4.cpp +++ b/apps/esmtool/tes4.cpp @@ -72,6 +72,17 @@ namespace EsmTool } }; + template + struct WriteData + { + const T& mValue; + + explicit WriteData(const T& value) + : mValue(value) + { + } + }; + template std::ostream& operator<<(std::ostream& stream, const WriteArray& write) { @@ -80,6 +91,18 @@ namespace EsmTool return stream; } + template + std::ostream& operator<<(std::ostream& stream, const WriteData& /*write*/) + { + return stream << " ?"; + } + + std::ostream& operator<<(std::ostream& stream, const WriteData& write) + { + std::visit([&](const auto& v) { stream << v; }, write.mValue); + return stream; + } + template void readTypedRecord(const Params& params, ESM4::Reader& reader) { @@ -114,6 +137,8 @@ namespace EsmTool std::cout << "\n Type: " << value.mType; if constexpr (ESM4::hasValue) std::cout << "\n Value: " << value.mValue; + if constexpr (ESM4::hasData) + std::cout << "\n Data: " << WriteData(value.mData); std::cout << '\n'; } @@ -253,7 +278,8 @@ namespace EsmTool readTypedRecord(params, reader); return true; case ESM4::REC_GMST: - break; + readTypedRecord(params, reader); + return true; case ESM4::REC_GRAS: readTypedRecord(params, reader); return true; diff --git a/components/CMakeLists.txt b/components/CMakeLists.txt index b8463c8af0..34be828cb9 100644 --- a/components/CMakeLists.txt +++ b/components/CMakeLists.txt @@ -151,6 +151,7 @@ add_component_dir (esm4 loadflst loadfurn loadglob + loadgmst loadgras loadgrup loadhair diff --git a/components/esm4/loadgmst.cpp b/components/esm4/loadgmst.cpp new file mode 100644 index 0000000000..7fb5d7af5c --- /dev/null +++ b/components/esm4/loadgmst.cpp @@ -0,0 +1,68 @@ +#include "loadgmst.hpp" + +#include + +#include "reader.hpp" + +namespace ESM4 +{ + namespace + { + GameSetting::Data readData(FormId formId, std::string_view editorId, Reader& reader) + { + if (editorId.empty()) + throw std::runtime_error( + "Unknown ESM4 GMST (" + std::to_string(formId) + ") data type: editor id is empty"); + const char type = editorId[0]; + switch (type) + { + case 'i': + { + std::int32_t value = 0; + reader.get(value); + return value; + } + case 'f': + { + float value = 0; + reader.get(value); + return value; + } + case 's': + { + std::string value; + reader.getZString(value); + return value; + } + default: + throw std::runtime_error( + "Unsupported ESM4 GMST (" + std::to_string(formId) + ") data type: " + std::string(editorId)); + } + } + } + + void GameSetting::load(Reader& reader) + { + mFormId = reader.hdr().record.id; + reader.adjustFormId(mFormId); + mFlags = reader.hdr().record.flags; + + while (reader.getSubRecordHeader()) + { + const ESM4::SubRecordHeader& subHdr = reader.subRecordHeader(); + switch (subHdr.typeId) + { + case ESM4::SUB_EDID: + reader.getZString(mEditorId); + break; + case ESM4::SUB_DATA: + mData = readData(mFormId, mEditorId, reader); + break; + default: + throw std::runtime_error("Unknown ESM4 GMST (" + std::to_string(mFormId) + ") subrecord " + + ESM::printName(subHdr.typeId)); + } + } + } + +} diff --git a/components/esm4/loadgmst.hpp b/components/esm4/loadgmst.hpp new file mode 100644 index 0000000000..62a5071eb3 --- /dev/null +++ b/components/esm4/loadgmst.hpp @@ -0,0 +1,27 @@ +#ifndef OPENMW_COMPONENTS_ESM4_LOADGMST_H +#define OPENMW_COMPONENTS_ESM4_LOADGMST_H + +#include +#include +#include + +#include "formid.hpp" + +namespace ESM4 +{ + class Reader; + + struct GameSetting + { + using Data = std::variant; + + FormId mFormId; // from the header + std::uint32_t mFlags; // from the header, see enum type RecordFlag for details + std::string mEditorId; + Data mData; + + void load(Reader& reader); + }; +} + +#endif // OPENMW_COMPONENTS_ESM4_LOADGMST_H diff --git a/components/esm4/records.hpp b/components/esm4/records.hpp index ae2a7a78f7..25bcba5cf2 100644 --- a/components/esm4/records.hpp +++ b/components/esm4/records.hpp @@ -28,6 +28,7 @@ #include #include #include +#include #include #include #include diff --git a/components/esm4/typetraits.hpp b/components/esm4/typetraits.hpp index 1d39a23018..bbac3a6ac1 100644 --- a/components/esm4/typetraits.hpp +++ b/components/esm4/typetraits.hpp @@ -121,6 +121,19 @@ namespace ESM4 template inline constexpr bool hasValue = HasValue::value; + + template > + struct HasData : std::false_type + { + }; + + template + struct HasData> : std::true_type + { + }; + + template + inline constexpr bool hasData = HasData::value; } #endif // OPENMW_COMPONENTS_ESM4_TYPETRAITS