Merge branch '7803-esmtool-json-export' into 'master'
Some checks failed
Build and test / Ubuntu (push) Has been cancelled
Build and test / MacOS (push) Has been cancelled
Build and test / Read .env file and expose it as output (push) Has been cancelled
Build and test / Windows (2019) (push) Has been cancelled
Build and test / Windows (2022) (push) Has been cancelled

Draft: Support JSON output in ESMTool

See merge request OpenMW/openmw!4037
This commit is contained in:
Shi Han 2025-04-26 03:49:56 +00:00
commit 8161558562
8 changed files with 25539 additions and 18 deletions

View file

@ -7,6 +7,10 @@ set(ESMTOOL
arguments.hpp arguments.hpp
tes4.hpp tes4.hpp
tes4.cpp tes4.cpp
util.hpp
util.cpp
jsonexport.hpp
nlohmannjson.hpp
) )
source_group(apps\\esmtool FILES ${ESMTOOL}) source_group(apps\\esmtool FILES ${ESMTOOL})

View file

@ -15,6 +15,7 @@ namespace EsmTool
bool quiet_given = false; bool quiet_given = false;
bool loadcells_given = false; bool loadcells_given = false;
bool plain_given = false; bool plain_given = false;
bool json_given = false;
std::string mode; std::string mode;
std::string encoding; std::string encoding;

View file

@ -20,7 +20,9 @@
#include <components/misc/strings/algorithm.hpp> #include <components/misc/strings/algorithm.hpp>
#include "arguments.hpp" #include "arguments.hpp"
#include "jsonexport.hpp"
#include "labels.hpp" #include "labels.hpp"
#include "nlohmannjson.hpp"
#include "record.hpp" #include "record.hpp"
#include "tes4.hpp" #include "tes4.hpp"
@ -71,6 +73,9 @@ Allowed options)");
"Print contents of dialogs, books and scripts. " "Print contents of dialogs, books and scripts. "
"(skipped by default) " "(skipped by default) "
"Only affects dump mode."); "Only affects dump mode.");
addOption("json,j",
"Exports data as JSON. "
"Only affects dump mode.");
addOption("quiet,q", "Suppress all record information. Useful for speed tests."); addOption("quiet,q", "Suppress all record information. Useful for speed tests.");
addOption("loadcells,C", "Browse through contents of all cells."); addOption("loadcells,C", "Browse through contents of all cells.");
@ -169,6 +174,7 @@ Allowed options)");
info.quiet_given = variables.count("quiet") != 0; info.quiet_given = variables.count("quiet") != 0;
info.loadcells_given = variables.count("loadcells") != 0; info.loadcells_given = variables.count("loadcells") != 0;
info.plain_given = variables.count("plain") != 0; info.plain_given = variables.count("plain") != 0;
info.json_given = variables.count("json") != 0;
// Font encoding settings // Font encoding settings
info.encoding = variables["encoding"].as<std::string>(); info.encoding = variables["encoding"].as<std::string>();
@ -177,7 +183,11 @@ Allowed options)");
std::cout << info.encoding << " is not a valid encoding option.\n"; std::cout << info.encoding << " is not a valid encoding option.\n";
info.encoding = "win1252"; info.encoding = "win1252";
} }
std::cout << ToUTF8::encodingUsingMessage(info.encoding) << std::endl;
if (!info.quiet_given && !info.json_given && info.mode != "clone")
{
std::cout << ToUTF8::encodingUsingMessage(info.encoding) << std::endl;
}
return true; return true;
} }
@ -318,7 +328,12 @@ namespace
int loadTes3(const Arguments& info, std::unique_ptr<std::ifstream>&& stream, ESMData* data) int loadTes3(const Arguments& info, std::unique_ptr<std::ifstream>&& stream, ESMData* data)
{ {
std::cout << "Loading TES3 file: " << info.filename << '\n'; bool quiet = (info.quiet_given || info.json_given || info.mode == "clone");
bool loadCells = (info.loadcells_given || info.mode == "clone");
bool save = (info.mode == "clone");
if (!quiet)
std::cout << "Loading TES3 file: " << info.filename << '\n';
ESM::ESMReader esm; ESM::ESMReader esm;
ToUTF8::Utf8Encoder encoder(ToUTF8::calculateEncoding(info.encoding)); ToUTF8::Utf8Encoder encoder(ToUTF8::calculateEncoding(info.encoding));
@ -328,15 +343,15 @@ namespace
try try
{ {
bool quiet = (info.quiet_given || info.mode == "clone");
bool loadCells = (info.loadcells_given || info.mode == "clone");
bool save = (info.mode == "clone");
esm.open(std::move(stream), info.filename); esm.open(std::move(stream), info.filename);
if (data != nullptr) if (data != nullptr)
data->mHeader = esm.getHeader(); data->mHeader = esm.getHeader();
nlohmann::json esmJson;
esmJson["header"] = esm.getHeader();
esmJson["records"] = nlohmann::json::array();
if (!quiet) if (!quiet)
{ {
std::cout << "Author: " << esm.getAuthor() << '\n' std::cout << "Author: " << esm.getAuthor() << '\n'
@ -395,6 +410,11 @@ namespace
record->print(); record->print();
} }
if (info.json_given)
{
esmJson["records"].push_back(record->toJsonObj());
}
if (record->getType().toInt() == ESM::REC_CELL && loadCells && interested) if (record->getType().toInt() == ESM::REC_CELL && loadCells && interested)
{ {
loadCell(info, record->cast<ESM::Cell>()->get(), esm, data); loadCell(info, record->cast<ESM::Cell>()->get(), esm, data);
@ -407,6 +427,11 @@ namespace
++data->mRecordStats[n.toInt()]; ++data->mRecordStats[n.toInt()];
} }
} }
if (info.json_given)
{
std::cout << esmJson.dump(4) << std::endl;
}
} }
catch (const std::exception& e) catch (const std::exception& e)
{ {

630
apps/esmtool/jsonexport.hpp Normal file
View file

@ -0,0 +1,630 @@
#ifndef OPENMW_ESMTOOL_JSONEXPORT_HPP
#define OPENMW_ESMTOOL_JSONEXPORT_HPP
#include <components/esm/records.hpp>
#include <components/esm3/loadtes3.hpp>
#include <components/esm3/variant.hpp>
#include <components/misc/strings/format.hpp>
#include "labels.hpp"
#include "nlohmannjson.hpp"
#include "util.hpp"
namespace nlohmann
{
template <>
struct adl_serializer<ESM::Header>
{
static void to_json(json& j, const ESM::Header& obj)
{
j["type"] = obj.mData.type;
j["version"] = Misc::StringUtils::format("%.1f", obj.mData.version.f);
j["formatVersion"] = obj.mFormatVersion;
j["author"] = obj.mData.author;
j["description"] = obj.mData.desc;
j["recordCount"] = obj.mData.records;
j["masters"] = json::array();
for (const auto& master : obj.mMaster)
{
j["masters"].push_back({ { "name", master.name }, { "size", master.size } });
}
}
static void from_json(const json& j, ESM::Header& obj)
{
// obj = ESM::Header();
}
};
template <>
struct adl_serializer<ESM::Variant>
{
static void to_json(json& j, const ESM::Variant& obj)
{
switch (obj.getType())
{
case ESM::VT_Unknown:
j["type"] = "unknown";
j["value"] = nullptr;
break;
case ESM::VT_None:
j["type"] = "none";
j["value"] = nullptr;
break;
case ESM::VT_Short:
j["type"] = "short";
j["value"] = obj.getInteger();
break;
case ESM::VT_Int:
j["type"] = "int";
j["value"] = obj.getInteger();
break;
case ESM::VT_Long:
j["type"] = "long";
j["value"] = obj.getInteger();
break;
case ESM::VT_Float:
j["type"] = "float";
j["value"] = obj.getFloat();
break;
case ESM::VT_String:
j["type"] = "string";
j["value"] = obj.getString();
break;
}
}
static void from_json(const json& j, ESM::Variant& obj)
{
// obj = ESM::Variant();
}
};
template <>
struct adl_serializer<ESM::Activator>
{
static void to_json(json& j, const ESM::Activator& obj) { j = json{ { "name", "ESM::Activator" } }; }
static void from_json(const json& j, ESM::Activator& obj)
{
// obj = ESM::Activator();
}
};
template <>
struct adl_serializer<ESM::Potion>
{
static void to_json(json& j, const ESM::Potion& obj) { j = json{ { "name", "ESM::Potion" } }; }
static void from_json(const json& j, ESM::Potion& obj)
{
// obj = ESM::Potion();
}
};
template <>
struct adl_serializer<ESM::Apparatus>
{
static void to_json(json& j, const ESM::Apparatus& obj) { j = json{ { "name", "ESM::Apparatus" } }; }
static void from_json(const json& j, ESM::Apparatus& obj)
{
// obj = ESM::Apparatus();
}
};
template <>
struct adl_serializer<ESM::Armor>
{
static void to_json(json& j, const ESM::Armor& obj) { j = json{ { "name", "ESM::Armor" } }; }
static void from_json(const json& j, ESM::Armor& obj)
{
// obj = ESM::Armor();
}
};
template <>
struct adl_serializer<ESM::BodyPart>
{
static void to_json(json& j, const ESM::BodyPart& obj) { j = json{ { "name", "ESM::BodyPart" } }; }
static void from_json(const json& j, ESM::BodyPart& obj)
{
// obj = ESM::BodyPart();
}
};
template <>
struct adl_serializer<ESM::Book>
{
static void to_json(json& j, const ESM::Book& obj)
{
j["name"] = obj.mName;
j["model"] = obj.mModel;
j["icon"] = obj.mIcon;
if (!obj.mScript.empty())
{
j["script"] = obj.mScript.getRefIdString();
}
if (!obj.mEnchant.empty())
{
j["enchantment"] = obj.mEnchant.getRefIdString();
}
j["weight"] = obj.mData.mWeight;
j["value"] = obj.mData.mValue;
j["scroll"] = obj.mData.mIsScroll != 0;
j["enchantmentPoints"] = obj.mData.mEnchant;
j["text"] = obj.mText;
if (obj.mData.mSkillId != -1)
{
j["skillId"] = obj.mData.mSkillId;
j["skillName"] = skillLabel(obj.mData.mSkillId);
}
}
static void from_json(const json& j, ESM::Book& obj)
{
// obj = ESM::Book();
}
};
template <>
struct adl_serializer<ESM::BirthSign>
{
static void to_json(json& j, const ESM::BirthSign& obj) { j = json{ { "name", "ESM::BirthSign" } }; }
static void from_json(const json& j, ESM::BirthSign& obj)
{
// obj = ESM::BirthSign();
}
};
template <>
struct adl_serializer<ESM::Cell>
{
static void to_json(json& j, const ESM::Cell& obj) { j = json{ { "name", "ESM::Cell" } }; }
static void from_json(const json& j, ESM::Cell& obj)
{
// obj = ESM::Cell();
}
};
template <>
struct adl_serializer<ESM::Class>
{
static void to_json(json& j, const ESM::Class& obj) { j = json{ { "name", "ESM::Class" } }; }
static void from_json(const json& j, ESM::Class& obj)
{
// obj = ESM::Class();
}
};
template <>
struct adl_serializer<ESM::Clothing>
{
static void to_json(json& j, const ESM::Clothing& obj) { j = json{ { "name", "ESM::Clothing" } }; }
static void from_json(const json& j, ESM::Clothing& obj)
{
// obj = ESM::Clothing();
}
};
template <>
struct adl_serializer<ESM::Container>
{
static void to_json(json& j, const ESM::Container& obj) { j = json{ { "name", "ESM::Container" } }; }
static void from_json(const json& j, ESM::Container& obj)
{
// obj = ESM::Container();
}
};
template <>
struct adl_serializer<ESM::Creature>
{
static void to_json(json& j, const ESM::Creature& obj) { j = json{ { "name", "ESM::Creature" } }; }
static void from_json(const json& j, ESM::Creature& obj)
{
// obj = ESM::Creature();
}
};
template <>
struct adl_serializer<ESM::Dialogue>
{
static void to_json(json& j, const ESM::Dialogue& obj) { j = json{ { "name", "ESM::Dialogue" } }; }
static void from_json(const json& j, ESM::Dialogue& obj)
{
// obj = ESM::Dialogue();
}
};
template <>
struct adl_serializer<ESM::Door>
{
static void to_json(json& j, const ESM::Door& obj) { j = json{ { "name", "ESM::Door" } }; }
static void from_json(const json& j, ESM::Door& obj)
{
// obj = ESM::Door();
}
};
template <>
struct adl_serializer<ESM::Enchantment>
{
static void to_json(json& j, const ESM::Enchantment& obj) { j = json{ { "name", "ESM::Enchantment" } }; }
static void from_json(const json& j, ESM::Enchantment& obj)
{
// obj = ESM::Enchantment();
}
};
template <>
struct adl_serializer<ESM::Faction>
{
static void to_json(json& j, const ESM::Faction& obj) { j = json{ { "name", "ESM::Faction" } }; }
static void from_json(const json& j, ESM::Faction& obj)
{
// obj = ESM::Faction();
}
};
template <>
struct adl_serializer<ESM::Global>
{
static void to_json(json& j, const ESM::Global& obj) { j = obj.mValue; }
static void from_json(const json& j, ESM::Global& obj)
{
// obj = ESM::Global();
}
};
template <>
struct adl_serializer<ESM::GameSetting>
{
static void to_json(json& j, const ESM::GameSetting& obj) { j = obj.mValue; }
static void from_json(const json& j, ESM::GameSetting& obj)
{
// obj = ESM::GameSetting();
}
};
template <>
struct adl_serializer<ESM::DialInfo>
{
static void to_json(json& j, const ESM::DialInfo& obj) { j = json{ { "name", "ESM::DialInfo" } }; }
static void from_json(const json& j, ESM::DialInfo& obj)
{
// obj = ESM::DialInfo();
}
};
template <>
struct adl_serializer<ESM::Ingredient>
{
static void to_json(json& j, const ESM::Ingredient& obj) { j = json{ { "name", "ESM::Ingredient" } }; }
static void from_json(const json& j, ESM::Ingredient& obj)
{
// obj = ESM::Ingredient();
}
};
template <>
struct adl_serializer<ESM::Land>
{
static void to_json(json& j, const ESM::Land& obj) { j = json{ { "name", "ESM::Land" } }; }
static void from_json(const json& j, ESM::Land& obj)
{
// obj = ESM::Land();
}
};
template <>
struct adl_serializer<ESM::ItemLevList>
{
static void to_json(json& j, const ESM::ItemLevList& obj) { j = json{ { "name", "ESM::ItemLevList" } }; }
static void from_json(const json& j, ESM::ItemLevList& obj)
{
// obj = ESM::ItemLevList();
}
};
template <>
struct adl_serializer<ESM::CreatureLevList>
{
static void to_json(json& j, const ESM::CreatureLevList& obj)
{
j = json{ { "name", "ESM::CreatureLevList" } };
}
static void from_json(const json& j, ESM::CreatureLevList& obj)
{
// obj = ESM::CreatureLevList();
}
};
template <>
struct adl_serializer<ESM::Light>
{
static void to_json(json& j, const ESM::Light& obj) { j = json{ { "name", "ESM::Light" } }; }
static void from_json(const json& j, ESM::Light& obj)
{
// obj = ESM::Light();
}
};
template <>
struct adl_serializer<ESM::Lockpick>
{
static void to_json(json& j, const ESM::Lockpick& obj) { j = json{ { "name", "ESM::Lockpick" } }; }
static void from_json(const json& j, ESM::Lockpick& obj)
{
// obj = ESM::Lockpick();
}
};
template <>
struct adl_serializer<ESM::LandTexture>
{
static void to_json(json& j, const ESM::LandTexture& obj) { j = json{ { "name", "ESM::LandTexture" } }; }
static void from_json(const json& j, ESM::LandTexture& obj)
{
// obj = ESM::LandTexture();
}
};
template <>
struct adl_serializer<ESM::Miscellaneous>
{
static void to_json(json& j, const ESM::Miscellaneous& obj) { j = json{ { "name", "ESM::Miscellaneous" } }; }
static void from_json(const json& j, ESM::Miscellaneous& obj)
{
// obj = ESM::Miscellaneous();
}
};
template <>
struct adl_serializer<ESM::MagicEffect>
{
static void to_json(json& j, const ESM::MagicEffect& obj) { j = json{ { "name", "ESM::MagicEffect" } }; }
static void from_json(const json& j, ESM::MagicEffect& obj)
{
// obj = ESM::MagicEffect();
}
};
template <>
struct adl_serializer<ESM::NPC>
{
static void to_json(json& j, const ESM::NPC& obj) { j = json{ { "name", "ESM::NPC" } }; }
static void from_json(const json& j, ESM::NPC& obj)
{
// obj = ESM::NPC();
}
};
template <>
struct adl_serializer<ESM::Pathgrid>
{
static void to_json(json& j, const ESM::Pathgrid& obj) { j = json{ { "name", "ESM::Pathgrid" } }; }
static void from_json(const json& j, ESM::Pathgrid& obj)
{
// obj = ESM::Pathgrid();
}
};
template <>
struct adl_serializer<ESM::Probe>
{
static void to_json(json& j, const ESM::Probe& obj) { j = json{ { "name", "ESM::Probe" } }; }
static void from_json(const json& j, ESM::Probe& obj)
{
// obj = ESM::Probe();
}
};
template <>
struct adl_serializer<ESM::Race>
{
static void to_json(json& j, const ESM::Race& obj) { j = json{ { "name", "ESM::Race" } }; }
static void from_json(const json& j, ESM::Race& obj)
{
// obj = ESM::Race();
}
};
template <>
struct adl_serializer<ESM::Region>
{
static void to_json(json& j, const ESM::Region& obj) { j = json{ { "name", "ESM::Region" } }; }
static void from_json(const json& j, ESM::Region& obj)
{
// obj = ESM::Region();
}
};
template <>
struct adl_serializer<ESM::Repair>
{
static void to_json(json& j, const ESM::Repair& obj) { j = json{ { "name", "ESM::Repair" } }; }
static void from_json(const json& j, ESM::Repair& obj)
{
// obj = ESM::Repair();
}
};
template <>
struct adl_serializer<ESM::StartScript>
{
static void to_json(json& j, const ESM::StartScript& obj) { j = json{ { "name", "ESM::StartScript" } }; }
static void from_json(const json& j, ESM::StartScript& obj)
{
// obj = ESM::StartScript();
}
};
template <>
struct adl_serializer<ESM::Script>
{
static void to_json(json& j, const ESM::Script& obj) { j = json{ { "name", "ESM::Script" } }; }
static void from_json(const json& j, ESM::Script& obj)
{
// obj = ESM::Script();
}
};
template <>
struct adl_serializer<ESM::Skill>
{
static void to_json(json& j, const ESM::Skill& obj) { j = json{ { "name", "ESM::Skill" } }; }
static void from_json(const json& j, ESM::Skill& obj)
{
// obj = ESM::Skill();
}
};
template <>
struct adl_serializer<ESM::SoundGenerator>
{
static void to_json(json& j, const ESM::SoundGenerator& obj) { j = json{ { "name", "ESM::SoundGenerator" } }; }
static void from_json(const json& j, ESM::SoundGenerator& obj)
{
// obj = ESM::SoundGenerator();
}
};
template <>
struct adl_serializer<ESM::Sound>
{
static void to_json(json& j, const ESM::Sound& obj) { j = json{ { "name", "ESM::Sound" } }; }
static void from_json(const json& j, ESM::Sound& obj)
{
// obj = ESM::Sound();
}
};
template <>
struct adl_serializer<ESM::Spell>
{
static void to_json(json& j, const ESM::Spell& obj)
{
j["name"] = obj.mName;
j["type"] = obj.mData.mType;
j["typeString"] = spellTypeLabel(obj.mData.mType);
j["cost"] = obj.mData.mCost;
j["flags"] = EsmTool::getSpellFlags(obj.mData.mFlags);
j["effects"] = json::array();
for (const auto& effect : obj.mEffects.mList)
{
json e;
e["effectId"] = effect.mData.mEffectID;
e["effectName"] = magicEffectLabel(effect.mData.mEffectID);
if (effect.mData.mAttribute != -1)
{
e["attributeId"] = effect.mData.mAttribute;
e["attributeName"] = attributeLabel(effect.mData.mAttribute);
}
if (effect.mData.mSkill != -1)
{
e["skillId"] = effect.mData.mSkill;
e["skillName"] = skillLabel(effect.mData.mSkill);
}
e["range"] = effect.mData.mRange;
e["rangeLabel"] = rangeTypeLabel(effect.mData.mRange);
e["area"] = effect.mData.mArea;
e["duration"] = effect.mData.mDuration;
e["magnitudeMin"] = effect.mData.mMagnMin;
e["magnitudeMax"] = effect.mData.mMagnMax;
j["effects"].push_back(e);
}
}
static void from_json(const json& j, ESM::Spell& obj)
{
// obj = ESM::Spell();
}
};
template <>
struct adl_serializer<ESM::Static>
{
static void to_json(json& j, const ESM::Static& obj)
{
j["id"] = obj.mId.getRefIdString();
j["model"] = obj.mModel;
}
static void from_json(const json& j, ESM::Static& obj)
{
// obj = ESM::Static();
}
};
template <>
struct adl_serializer<ESM::Weapon>
{
static void to_json(json& j, const ESM::Weapon& obj) { j = json{ { "name", "ESM::Weapon" } }; }
static void from_json(const json& j, ESM::Weapon& obj)
{
// obj = ESM::Weapon();
}
};
template <>
struct adl_serializer<EsmTool::CellState>
{
static void to_json(json& j, const EsmTool::CellState& obj) { j = json{ { "name", "ESM::CellState" } }; }
static void from_json(const json& j, EsmTool::CellState& obj)
{
// obj = ESM::CellState();
}
};
}
#endif

24766
apps/esmtool/nlohmannjson.hpp Normal file

File diff suppressed because it is too large Load diff

View file

@ -5,8 +5,10 @@
#include <string> #include <string>
#include <components/esm/records.hpp> #include <components/esm/records.hpp>
#include <components/esm3/cellstate.hpp>
#include <components/esm3/fogstate.hpp> #include "jsonexport.hpp"
#include "nlohmannjson.hpp"
#include "util.hpp"
namespace ESM namespace ESM
{ {
@ -49,6 +51,7 @@ namespace EsmTool
virtual void load(ESM::ESMReader& esm) = 0; virtual void load(ESM::ESMReader& esm) = 0;
virtual void save(ESM::ESMWriter& esm) = 0; virtual void save(ESM::ESMWriter& esm) = 0;
virtual void print() = 0; virtual void print() = 0;
virtual nlohmann::json toJsonObj() const = 0;
static std::unique_ptr<RecordBase> create(ESM::NAME type); static std::unique_ptr<RecordBase> create(ESM::NAME type);
@ -60,16 +63,6 @@ namespace EsmTool
} }
}; };
struct CellState
{
ESM::CellState mCellState;
ESM::FogState mFogState;
void load(ESM::ESMReader& reader, bool& deleted);
void save(ESM::ESMWriter& /*writer*/, bool /*deleted*/) {}
};
template <class T> template <class T>
class Record : public RecordBase class Record : public RecordBase
{ {
@ -91,6 +84,17 @@ namespace EsmTool
void load(ESM::ESMReader& esm) override { mData.load(esm, mIsDeleted); } void load(ESM::ESMReader& esm) override { mData.load(esm, mIsDeleted); }
void print() override; void print() override;
nlohmann::json toJsonObj() const override
{
nlohmann::json j;
j["type"] = mType.toString();
j["id"] = trimQuotes(getId());
j["flags"] = getRecordFlags(mFlags);
j["deleted"] = mIsDeleted;
j["data"] = mData;
return j;
}
}; };
template <> template <>

64
apps/esmtool/util.cpp Normal file
View file

@ -0,0 +1,64 @@
#include "util.hpp"
#include <boost/algorithm/string/join.hpp>
#include <components/esm3/loadspel.hpp>
namespace EsmTool
{
std::string trimQuotes(std::string str)
{
if (!str.empty() && str.front() == '\"')
{
str.erase(0, 1);
}
if (!str.empty() && str.back() == '\"')
{
str.pop_back();
}
return str;
}
std::string hexString8(const uint32_t v)
{
std::ostringstream ss;
ss << "0x" << std::hex << std::setw(8) << std::setfill('0') << v;
return ss.str();
}
nlohmann::json getRecordFlags(const uint32_t flags)
{
nlohmann::json properties = nlohmann::json::array();
if (flags & ESM::FLAG_Deleted)
properties.push_back("deleted");
if (flags & ESM::FLAG_Persistent)
properties.push_back("persistent");
if (flags & ESM::FLAG_Ignored)
properties.push_back("ignored");
if (flags & ESM::FLAG_Blocked)
properties.push_back("blocked");
if (flags & (~(ESM::FLAG_Deleted | ESM::FLAG_Persistent | ESM::FLAG_Ignored | ESM::FLAG_Blocked)))
properties.push_back("invalid flag");
return properties;
}
nlohmann::json getSpellFlags(const uint32_t flags)
{
nlohmann::json properties = nlohmann::json::array();
if (flags & ESM::Spell::F_Autocalc)
properties.push_back("autocalc");
if (flags & ESM::Spell::F_PCStart)
properties.push_back("pcStart");
if (flags & ESM::Spell::F_Always)
properties.push_back("always");
if (flags & (0xFFFFFFFF ^ (ESM::Spell::F_Autocalc | ESM::Spell::F_PCStart | ESM::Spell::F_Always)))
properties.push_back("invalid flag");
return properties;
}
}

27
apps/esmtool/util.hpp Normal file
View file

@ -0,0 +1,27 @@
#ifndef OPENMW_ESMTOOL_UTIL_H
#define OPENMW_ESMTOOL_UTIL_H
#include <components/esm3/cellstate.hpp>
#include <components/esm3/fogstate.hpp>
#include "nlohmannjson.hpp"
namespace EsmTool
{
struct CellState
{
ESM::CellState mCellState;
ESM::FogState mFogState;
void load(ESM::ESMReader& reader, bool& deleted);
void save(ESM::ESMWriter& /*writer*/, bool /*deleted*/) {}
};
std::string trimQuotes(std::string str);
std::string hexString8(uint32_t v);
nlohmann::json getRecordFlags(uint32_t flags);
nlohmann::json getSpellFlags(uint32_t flags);
}
#endif