Merge branch 'esmtool_tes4' into 'master'

Support esmtool dump for TES4

See merge request OpenMW/openmw!1800
pull/3226/head
psi29a 3 years ago
commit 07056802eb

@ -4,6 +4,9 @@ set(ESMTOOL
labels.cpp
record.hpp
record.cpp
arguments.hpp
tes4.hpp
tes4.cpp
)
source_group(apps\\esmtool FILES ${ESMTOOL})

@ -0,0 +1,28 @@
#ifndef OPENMW_ESMTOOL_ARGUMENTS_H
#define OPENMW_ESMTOOL_ARGUMENTS_H
#include <vector>
#include <optional>
#include <components/esm/format.hpp>
namespace EsmTool
{
struct Arguments
{
std::optional<ESM::Format> mRawFormat;
bool quiet_given;
bool loadcells_given;
bool plain_given;
std::string mode;
std::string encoding;
std::string filename;
std::string outname;
std::vector<std::string> types;
std::string name;
};
}
#endif

@ -7,17 +7,29 @@
#include <fstream>
#include <cmath>
#include <memory>
#include <optional>
#include <iomanip>
#include <boost/program_options.hpp>
#include <components/esm3/esmreader.hpp>
#include <components/esm3/esmwriter.hpp>
#include <components/esm/records.hpp>
#include <components/esm/format.hpp>
#include <components/files/openfile.hpp>
#include "record.hpp"
#include "labels.hpp"
#include "arguments.hpp"
#include "tes4.hpp"
namespace
{
using namespace EsmTool;
#define ESMTOOL_VERSION 1.2
constexpr unsigned majorVersion = 1;
constexpr unsigned minorVersion = 3;
// Create a local alias for brevity
namespace bpo = boost::program_options;
@ -36,27 +48,6 @@ struct ESMData
};
// Based on the legacy struct
struct Arguments
{
bool raw_given;
bool quiet_given;
bool loadcells_given;
bool plain_given;
std::string mode;
std::string encoding;
std::string filename;
std::string outname;
std::vector<std::string> types;
std::string name;
ESMData data;
ESM::ESMReader reader;
ESM::ESMWriter writer;
};
bool parseOptions (int argc, char** argv, Arguments &info)
{
bpo::options_description desc("Inspect and extract from Morrowind ES files (ESM, ESP, ESS)\nSyntax: esmtool [options] mode infile [outfile]\nAllowed modes:\n dump\t Dumps all readable data from the input file.\n clone\t Clones the input file to the output file.\n comp\t Compares the given files.\n\nAllowed options");
@ -64,7 +55,10 @@ bool parseOptions (int argc, char** argv, Arguments &info)
desc.add_options()
("help,h", "print help message.")
("version,v", "print version information and quit.")
("raw,r", "Show an unformatted list of all records and subrecords.")
("raw,r", bpo::value<std::string>(),
"Show an unformatted list of all records and subrecords of given format:\n"
"\n\tTES3"
"\n\tTES4")
// The intention is that this option would interact better
// with other modes including clone, dump, and raw.
("type,t", bpo::value< std::vector<std::string> >(),
@ -126,7 +120,7 @@ bool parseOptions (int argc, char** argv, Arguments &info)
}
if (variables.count ("version"))
{
std::cout << "ESMTool version " << ESMTOOL_VERSION << std::endl;
std::cout << "ESMTool version " << majorVersion << '.' << minorVersion << std::endl;
return false;
}
if (!variables.count("mode"))
@ -168,7 +162,9 @@ bool parseOptions (int argc, char** argv, Arguments &info)
if (variables["input-file"].as< std::vector<std::string> >().size() > 1)
info.outname = variables["input-file"].as< std::vector<std::string> >()[1];
info.raw_given = variables.count ("raw") != 0;
if (const auto it = variables.find("raw"); it != variables.end())
info.mRawFormat = ESM::parseFormat(it->second.as<std::string>());
info.quiet_given = variables.count ("quiet") != 0;
info.loadcells_given = variables.count ("loadcells") != 0;
info.plain_given = variables.count("plain") != 0;
@ -185,12 +181,13 @@ bool parseOptions (int argc, char** argv, Arguments &info)
return true;
}
void printRaw(ESM::ESMReader &esm);
void loadCell(ESM::Cell &cell, ESM::ESMReader &esm, Arguments& info);
void loadCell(const Arguments& info, ESM::Cell &cell, ESM::ESMReader &esm, ESMData* data);
int load(Arguments& info);
int clone(Arguments& info);
int comp(Arguments& info);
int load(const Arguments& info, ESMData* data);
int clone(const Arguments& info);
int comp(const Arguments& info);
}
int main(int argc, char**argv)
{
@ -201,7 +198,7 @@ int main(int argc, char**argv)
return 1;
if (info.mode == "dump")
return load(info);
return load(info, nullptr);
else if (info.mode == "clone")
return clone(info);
else if (info.mode == "comp")
@ -221,7 +218,10 @@ int main(int argc, char**argv)
return 0;
}
void loadCell(ESM::Cell &cell, ESM::ESMReader &esm, Arguments& info)
namespace
{
void loadCell(const Arguments& info, ESM::Cell &cell, ESM::ESMReader &esm, ESMData* data)
{
bool quiet = (info.quiet_given || info.mode == "clone");
bool save = (info.mode == "clone");
@ -241,9 +241,8 @@ void loadCell(ESM::Cell &cell, ESM::ESMReader &esm, Arguments& info)
bool moved = false;
while(cell.getNextRef(esm, ref, deleted, movedCellRef, moved))
{
if (save) {
info.data.mCellRefs[&cell].push_back(std::make_pair(ref, deleted));
}
if (data != nullptr && save)
data->mCellRefs[&cell].push_back(std::make_pair(ref, deleted));
if(quiet) continue;
@ -289,8 +288,11 @@ void loadCell(ESM::Cell &cell, ESM::ESMReader &esm, Arguments& info)
}
}
void printRaw(ESM::ESMReader &esm)
void printRawTes3(const std::string& path)
{
std::cout << "TES3 RAW file listing: " << path << '\n';
ESM::ESMReader esm;
esm.openRaw(path);
while(esm.hasMoreRecs())
{
ESM::NAME n = esm.getRecName();
@ -310,39 +312,30 @@ void printRaw(ESM::ESMReader &esm)
}
}
int load(Arguments& info)
int loadTes3(const Arguments& info, std::unique_ptr<std::ifstream>&& stream, ESMData* data)
{
ESM::ESMReader& esm = info.reader;
std::cout << "Loading TES3 file: " << info.filename << '\n';
ESM::ESMReader esm;
ToUTF8::Utf8Encoder encoder (ToUTF8::calculateEncoding(info.encoding));
esm.setEncoder(&encoder);
std::string filename = info.filename;
std::cout << "Loading file: " << filename << '\n';
std::unordered_set<uint32_t> skipped;
try {
if(info.raw_given && info.mode == "dump")
{
std::cout << "RAW file listing:\n";
esm.openRaw(filename);
printRaw(esm);
return 0;
}
try
{
bool quiet = (info.quiet_given || info.mode == "clone");
bool loadCells = (info.loadcells_given || info.mode == "clone");
bool save = (info.mode == "clone");
esm.open(filename);
esm.open(std::move(stream), info.filename);
info.data.author = esm.getAuthor();
info.data.description = esm.getDesc();
info.data.masters = esm.getGameFiles();
if (data != nullptr)
{
data->author = esm.getAuthor();
data->description = esm.getDesc();
data->masters = esm.getGameFiles();
}
if (!quiet)
{
@ -387,12 +380,8 @@ int load(Arguments& info)
// Is the user interested in this record type?
bool interested = true;
if (!info.types.empty())
{
std::vector<std::string>::iterator match;
match = std::find(info.types.begin(), info.types.end(), n.toStringView());
if (match == info.types.end()) interested = false;
}
if (!info.types.empty() && std::find(info.types.begin(), info.types.end(), n.toStringView()) == info.types.end())
interested = false;
if (!info.name.empty() && !Misc::StringUtils::ciEqual(info.name, record->getId()))
interested = false;
@ -406,29 +395,73 @@ int load(Arguments& info)
if (record->getType().toInt() == ESM::REC_CELL && loadCells && interested)
{
loadCell(record->cast<ESM::Cell>()->get(), esm, info);
loadCell(info, record->cast<ESM::Cell>()->get(), esm, data);
}
if (save)
if (data != nullptr)
{
info.data.mRecords.push_back(std::move(record));
if (save)
data->mRecords.push_back(std::move(record));
++data->mRecordStats[n.toInt()];
}
++info.data.mRecordStats[n.toInt()];
}
} catch(std::exception &e) {
}
catch (const std::exception &e)
{
std::cout << "\nERROR:\n\n " << e.what() << std::endl;
info.data.mRecords.clear();
if (data != nullptr)
data->mRecords.clear();
return 1;
}
return 0;
}
#include <iomanip>
int load(const Arguments& info, ESMData* data)
{
if (info.mRawFormat.has_value() && info.mode == "dump")
{
switch (*info.mRawFormat)
{
case ESM::Format::Tes3:
printRawTes3(info.filename);
break;
case ESM::Format::Tes4:
std::cout << "Printing raw TES4 file is not supported: " << info.filename << "\n";
break;
}
return 0;
}
int clone(Arguments& info)
auto stream = Files::openBinaryInputFileStream(info.filename);
if (!stream->is_open())
{
std::cout << "Failed to open file: " << std::strerror(errno) << '\n';
return -1;
}
const ESM::Format format = ESM::readFormat(*stream);
stream->seekg(0);
switch (format)
{
case ESM::Format::Tes3:
return loadTes3(info, std::move(stream), data);
case ESM::Format::Tes4:
if (data != nullptr)
{
std::cout << "Collecting data from esm file is not supported for TES4\n";
return -1;
}
return loadTes4(info, std::move(stream));
}
std::cout << "Unsupported ESM format: " << ESM::NAME(format).toStringView() << '\n';
return -1;
}
int clone(const Arguments& info)
{
if (info.outname.empty())
{
@ -436,13 +469,14 @@ int clone(Arguments& info)
return 1;
}
if (load(info) != 0)
ESMData data;
if (load(info, &data) != 0)
{
std::cout << "Failed to load, aborting." << std::endl;
return 1;
}
size_t recordCount = info.data.mRecords.size();
size_t recordCount = data.mRecords.size();
int digitCount = 1; // For a nicer output
if (recordCount > 0)
@ -451,7 +485,7 @@ int clone(Arguments& info)
std::cout << "Loaded " << recordCount << " records:\n\n";
int i = 0;
for (std::pair<int, int> stat : info.data.mRecordStats)
for (std::pair<int, int> stat : data.mRecordStats)
{
ESM::NAME name;
name = stat.first;
@ -466,22 +500,22 @@ int clone(Arguments& info)
std::cout << "\nSaving records to: " << info.outname << "...\n";
ESM::ESMWriter& esm = info.writer;
ESM::ESMWriter esm;
ToUTF8::Utf8Encoder encoder (ToUTF8::calculateEncoding(info.encoding));
esm.setEncoder(&encoder);
esm.setAuthor(info.data.author);
esm.setDescription(info.data.description);
esm.setVersion(info.data.version);
esm.setAuthor(data.author);
esm.setDescription(data.description);
esm.setVersion(data.version);
esm.setRecordCount (recordCount);
for (const ESM::Header::MasterData &master : info.data.masters)
for (const ESM::Header::MasterData &master : data.masters)
esm.addMaster(master.name, master.size);
std::fstream save(info.outname.c_str(), std::fstream::out | std::fstream::binary);
esm.save(save);
int saved = 0;
for (auto& record : info.data.mRecords)
for (auto& record : data.mRecords)
{
if (i <= 0)
break;
@ -493,9 +527,9 @@ int clone(Arguments& info)
record->save(esm);
if (typeName.toInt() == ESM::REC_CELL) {
ESM::Cell *ptr = &record->cast<ESM::Cell>()->get();
if (!info.data.mCellRefs[ptr].empty())
if (!data.mCellRefs[ptr].empty())
{
for (std::pair<ESM::CellRef, bool> &ref : info.data.mCellRefs[ptr])
for (std::pair<ESM::CellRef, bool> &ref : data.mCellRefs[ptr])
ref.first.save(esm, ref.second);
}
}
@ -518,7 +552,7 @@ int clone(Arguments& info)
return 0;
}
int comp(Arguments& info)
int comp(const Arguments& info)
{
if (info.filename.empty() || info.outname.empty())
{
@ -529,9 +563,6 @@ int comp(Arguments& info)
Arguments fileOne;
Arguments fileTwo;
fileOne.raw_given = false;
fileTwo.raw_given = false;
fileOne.mode = "clone";
fileTwo.mode = "clone";
@ -541,19 +572,21 @@ int comp(Arguments& info)
fileOne.filename = info.filename;
fileTwo.filename = info.outname;
if (load(fileOne) != 0)
ESMData dataOne;
if (load(fileOne, &dataOne) != 0)
{
std::cout << "Failed to load " << info.filename << ", aborting comparison." << std::endl;
return 1;
}
if (load(fileTwo) != 0)
ESMData dataTwo;
if (load(fileTwo, &dataTwo) != 0)
{
std::cout << "Failed to load " << info.outname << ", aborting comparison." << std::endl;
return 1;
}
if (fileOne.data.mRecords.size() != fileTwo.data.mRecords.size())
if (dataOne.mRecords.size() != dataTwo.mRecords.size())
{
std::cout << "Not equal, different amount of records." << std::endl;
return 1;
@ -561,3 +594,5 @@ int comp(Arguments& info)
return 0;
}
}

@ -0,0 +1,329 @@
#include "tes4.hpp"
#include "arguments.hpp"
#include "labels.hpp"
#include <fstream>
#include <iostream>
#include <type_traits>
#include <components/esm/esmcommon.hpp>
#include <components/esm4/reader.hpp>
#include <components/esm4/records.hpp>
namespace EsmTool
{
namespace
{
struct Params
{
const bool mQuite;
explicit Params(const Arguments& info)
: mQuite(info.quiet_given || info.mode == "clone")
{}
};
std::string toString(ESM4::GroupType type)
{
switch (type)
{
case ESM4::Grp_RecordType: return "RecordType";
case ESM4::Grp_WorldChild: return "WorldChild";
case ESM4::Grp_InteriorCell: return "InteriorCell";
case ESM4::Grp_InteriorSubCell: return "InteriorSubCell";
case ESM4::Grp_ExteriorCell: return "ExteriorCell";
case ESM4::Grp_ExteriorSubCell: return "ExteriorSubCell";
case ESM4::Grp_CellChild: return "CellChild";
case ESM4::Grp_TopicChild: return "TopicChild";
case ESM4::Grp_CellPersistentChild: return "CellPersistentChild";
case ESM4::Grp_CellTemporaryChild: return "CellTemporaryChild";
case ESM4::Grp_CellVisibleDistChild: return "CellVisibleDistChild";
}
return "Unknown (" + std::to_string(type) + ")";
}
template <class T, class = std::void_t<>>
struct HasFormId : std::false_type {};
template <class T>
struct HasFormId<T, std::void_t<decltype(T::mFormId)>> : std::true_type {};
template <class T>
constexpr bool hasFormId = HasFormId<T>::value;
template <class T, class = std::void_t<>>
struct HasFlags : std::false_type {};
template <class T>
struct HasFlags<T, std::void_t<decltype(T::mFlags)>> : std::true_type {};
template <class T>
constexpr bool hasFlags = HasFlags<T>::value;
template <class T>
void readTypedRecord(const Params& params, ESM4::Reader& reader)
{
reader.getRecordData();
T value;
value.load(reader);
if (params.mQuite)
return;
std::cout << "\n Record: " << ESM::NAME(reader.hdr().record.typeId).toStringView();
if constexpr (hasFormId<T>)
std::cout << ' ' << value.mFormId;
if constexpr (hasFlags<T>)
std::cout << "\n Record flags: " << recordFlags(value.mFlags);
std::cout << '\n';
}
void readRecord(const Params& params, ESM4::Reader& reader)
{
switch (static_cast<ESM4::RecordTypes>(reader.hdr().record.typeId))
{
case ESM4::REC_AACT: break;
case ESM4::REC_ACHR: return readTypedRecord<ESM4::ActorCharacter>(params, reader);
case ESM4::REC_ACRE: return readTypedRecord<ESM4::ActorCreature>(params, reader);
case ESM4::REC_ACTI: return readTypedRecord<ESM4::Activator>(params, reader);
case ESM4::REC_ADDN: break;
case ESM4::REC_ALCH: return readTypedRecord<ESM4::Potion>(params, reader);
case ESM4::REC_ALOC: return readTypedRecord<ESM4::MediaLocationController>(params, reader);
case ESM4::REC_AMMO: return readTypedRecord<ESM4::Ammunition>(params, reader);
case ESM4::REC_ANIO: return readTypedRecord<ESM4::AnimObject>(params, reader);
case ESM4::REC_APPA: return readTypedRecord<ESM4::Apparatus>(params, reader);
case ESM4::REC_ARMA: return readTypedRecord<ESM4::ArmorAddon>(params, reader);
case ESM4::REC_ARMO: return readTypedRecord<ESM4::Armor>(params, reader);
case ESM4::REC_ARTO: break;
case ESM4::REC_ASPC: return readTypedRecord<ESM4::AcousticSpace>(params, reader);
case ESM4::REC_ASTP: break;
case ESM4::REC_AVIF: break;
case ESM4::REC_BOOK: return readTypedRecord<ESM4::Book>(params, reader);
case ESM4::REC_BPTD: return readTypedRecord<ESM4::BodyPartData>(params, reader);
case ESM4::REC_CAMS: break;
case ESM4::REC_CCRD: break;
case ESM4::REC_CELL: return readTypedRecord<ESM4::Cell>(params, reader);
case ESM4::REC_CLAS: return readTypedRecord<ESM4::Class>(params, reader);
case ESM4::REC_CLFM: return readTypedRecord<ESM4::Colour>(params, reader);
case ESM4::REC_CLMT: break;
case ESM4::REC_CLOT: return readTypedRecord<ESM4::Clothing>(params, reader);
case ESM4::REC_CMNY: break;
case ESM4::REC_COBJ: break;
case ESM4::REC_COLL: break;
case ESM4::REC_CONT: return readTypedRecord<ESM4::Container>(params, reader);
case ESM4::REC_CPTH: break;
case ESM4::REC_CREA: return readTypedRecord<ESM4::Creature>(params, reader);
case ESM4::REC_CSTY: break;
case ESM4::REC_DEBR: break;
case ESM4::REC_DIAL: return readTypedRecord<ESM4::Dialogue>(params, reader);
case ESM4::REC_DLBR: break;
case ESM4::REC_DLVW: break;
case ESM4::REC_DOBJ: return readTypedRecord<ESM4::DefaultObj>(params, reader);
case ESM4::REC_DOOR: return readTypedRecord<ESM4::Door>(params, reader);
case ESM4::REC_DUAL: break;
case ESM4::REC_ECZN: break;
case ESM4::REC_EFSH: break;
case ESM4::REC_ENCH: break;
case ESM4::REC_EQUP: break;
case ESM4::REC_EXPL: break;
case ESM4::REC_EYES: return readTypedRecord<ESM4::Eyes>(params, reader);
case ESM4::REC_FACT: break;
case ESM4::REC_FLOR: return readTypedRecord<ESM4::Flora>(params, reader);
case ESM4::REC_FLST: return readTypedRecord<ESM4::FormIdList>(params, reader);
case ESM4::REC_FSTP: break;
case ESM4::REC_FSTS: break;
case ESM4::REC_FURN: return readTypedRecord<ESM4::Furniture>(params, reader);
case ESM4::REC_GLOB: return readTypedRecord<ESM4::GlobalVariable>(params, reader);
case ESM4::REC_GMST: break;
case ESM4::REC_GRAS: return readTypedRecord<ESM4::Grass>(params, reader);
case ESM4::REC_GRUP: break;
case ESM4::REC_HAIR: return readTypedRecord<ESM4::Hair>(params, reader);
case ESM4::REC_HAZD: break;
case ESM4::REC_HDPT: return readTypedRecord<ESM4::HeadPart>(params, reader);
case ESM4::REC_IDLE:
// FIXME: ESM4::IdleAnimation::load does not work with Oblivion.esm
// return readTypedRecord<ESM4::IdleAnimation>(params, reader);
break;
case ESM4::REC_IDLM: return readTypedRecord<ESM4::IdleMarker>(params, reader);
case ESM4::REC_IMAD: break;
case ESM4::REC_IMGS: break;
case ESM4::REC_IMOD: return readTypedRecord<ESM4::ItemMod>(params, reader);
case ESM4::REC_INFO: return readTypedRecord<ESM4::DialogInfo>(params, reader);
case ESM4::REC_INGR: return readTypedRecord<ESM4::Ingredient>(params, reader);
case ESM4::REC_IPCT: break;
case ESM4::REC_IPDS: break;
case ESM4::REC_KEYM: return readTypedRecord<ESM4::Key>(params, reader);
case ESM4::REC_KYWD: break;
case ESM4::REC_LAND: return readTypedRecord<ESM4::Land>(params, reader);
case ESM4::REC_LCRT: break;
case ESM4::REC_LCTN: break;
case ESM4::REC_LGTM: return readTypedRecord<ESM4::LightingTemplate>(params, reader);
case ESM4::REC_LIGH: return readTypedRecord<ESM4::Light>(params, reader);
case ESM4::REC_LSCR: break;
case ESM4::REC_LTEX: return readTypedRecord<ESM4::LandTexture>(params, reader);
case ESM4::REC_LVLC: return readTypedRecord<ESM4::LevelledCreature>(params, reader);
case ESM4::REC_LVLI: return readTypedRecord<ESM4::LevelledItem>(params, reader);
case ESM4::REC_LVLN: return readTypedRecord<ESM4::LevelledNpc>(params, reader);
case ESM4::REC_LVSP: break;
case ESM4::REC_MATO: return readTypedRecord<ESM4::Material>(params, reader);
case ESM4::REC_MATT: break;
case ESM4::REC_MESG: break;
case ESM4::REC_MGEF: break;
case ESM4::REC_MISC: return readTypedRecord<ESM4::MiscItem>(params, reader);
case ESM4::REC_MOVT: break;
case ESM4::REC_MSET: return readTypedRecord<ESM4::MediaSet>(params, reader);
case ESM4::REC_MSTT: return readTypedRecord<ESM4::MovableStatic>(params, reader);
case ESM4::REC_MUSC: return readTypedRecord<ESM4::Music>(params, reader);
case ESM4::REC_MUST: break;
case ESM4::REC_NAVI: return readTypedRecord<ESM4::Navigation>(params, reader);
case ESM4::REC_NAVM: return readTypedRecord<ESM4::NavMesh>(params, reader);
case ESM4::REC_NOTE: return readTypedRecord<ESM4::Note>(params, reader);
case ESM4::REC_NPC_: return readTypedRecord<ESM4::Npc>(params, reader);
case ESM4::REC_OTFT: return readTypedRecord<ESM4::Outfit>(params, reader);
case ESM4::REC_PACK: return readTypedRecord<ESM4::AIPackage>(params, reader);
case ESM4::REC_PERK: break;
case ESM4::REC_PGRD: return readTypedRecord<ESM4::Pathgrid>(params, reader);
case ESM4::REC_PGRE: return readTypedRecord<ESM4::PlacedGrenade>(params, reader);
case ESM4::REC_PHZD: break;
case ESM4::REC_PROJ: break;
case ESM4::REC_PWAT: return readTypedRecord<ESM4::PlaceableWater>(params, reader);
case ESM4::REC_QUST: return readTypedRecord<ESM4::Quest>(params, reader);
case ESM4::REC_RACE: return readTypedRecord<ESM4::Race>(params, reader);
case ESM4::REC_REFR: return readTypedRecord<ESM4::Reference>(params, reader);
case ESM4::REC_REGN: return readTypedRecord<ESM4::Region>(params, reader);
case ESM4::REC_RELA: break;
case ESM4::REC_REVB: break;
case ESM4::REC_RFCT: break;
case ESM4::REC_ROAD: return readTypedRecord<ESM4::Road>(params, reader);
case ESM4::REC_SBSP: return readTypedRecord<ESM4::SubSpace>(params, reader);
case ESM4::REC_SCEN: break;
case ESM4::REC_SCOL: return readTypedRecord<ESM4::StaticCollection>(params, reader);
case ESM4::REC_SCPT: return readTypedRecord<ESM4::Script>(params, reader);
case ESM4::REC_SCRL: return readTypedRecord<ESM4::Scroll>(params, reader);
case ESM4::REC_SGST: return readTypedRecord<ESM4::SigilStone>(params, reader);
case ESM4::REC_SHOU: break;
case ESM4::REC_SLGM: return readTypedRecord<ESM4::SoulGem>(params, reader);
case ESM4::REC_SMBN: break;
case ESM4::REC_SMEN: break;
case ESM4::REC_SMQN: break;
case ESM4::REC_SNCT: break;
case ESM4::REC_SNDR: return readTypedRecord<ESM4::SoundReference>(params, reader);
case ESM4::REC_SOPM: break;
case ESM4::REC_SOUN: return readTypedRecord<ESM4::Sound>(params, reader);
case ESM4::REC_SPEL: break;
case ESM4::REC_SPGD: break;
case ESM4::REC_STAT: return readTypedRecord<ESM4::Static>(params, reader);
case ESM4::REC_TACT: return readTypedRecord<ESM4::TalkingActivator>(params, reader);
case ESM4::REC_TERM: return readTypedRecord<ESM4::Terminal>(params, reader);
case ESM4::REC_TES4: return readTypedRecord<ESM4::Header>(params, reader);
case ESM4::REC_TREE: return readTypedRecord<ESM4::Tree>(params, reader);
case ESM4::REC_TXST: return readTypedRecord<ESM4::TextureSet>(params, reader);
case ESM4::REC_VTYP: break;
case ESM4::REC_WATR: break;
case ESM4::REC_WEAP: return readTypedRecord<ESM4::Weapon>(params, reader);
case ESM4::REC_WOOP: break;
case ESM4::REC_WRLD: return readTypedRecord<ESM4::World>(params, reader);
case ESM4::REC_WTHR: break;
}
if (!params.mQuite)
std::cout << "\n Unsupported record: " << ESM::NAME(reader.hdr().record.typeId).toStringView() << '\n';
reader.skipRecordData();
}
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<ESM4::GroupType>(header.group.type))
<< " " << ESM::NAME(header.group.typeId).toStringView() << '\n';
switch (static_cast<ESM4::GroupType>(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<std::ifstream>&& stream)
{
std::cout << "Loading TES4 file: " << info.filename << '\n';
try
{
const ToUTF8::StatelessUtf8Encoder encoder(ToUTF8::calculateEncoding(info.encoding));
ESM4::Reader reader(std::move(stream), info.filename);
reader.setEncoder(&encoder);
const Params params(info);
if (!params.mQuite)
{
std::cout << "Author: " << reader.getAuthor() << '\n'
<< "Description: " << reader.getDesc() << '\n'
<< "File format version: " << reader.esmVersion() << '\n';
if (const std::vector<ESM::MasterData>& masterData = reader.getGameFiles(); !masterData.empty())
{
std::cout << "Masters:" << '\n';
for (const auto& master : masterData)
std::cout << " " << master.name << ", " << master.size << " bytes\n";
}
}
while (reader.hasMoreRecs())
{
reader.exitGroupCheck();
if (!readItem(params, reader))
break;
}
}
catch (const std::exception& e)
{
std::cout << "\nERROR:\n\n " << e.what() << std::endl;
return -1;
}
return 0;
}
}

@ -0,0 +1,15 @@
#ifndef OPENMW_ESMTOOL_TES4_H
#define OPENMW_ESMTOOL_TES4_H
#include <fstream>
#include <iosfwd>
#include <memory>
namespace EsmTool
{
struct Arguments;
int loadTes4(const Arguments& info, std::unique_ptr<std::ifstream>&& stream);
}
#endif

@ -80,7 +80,7 @@ add_component_dir (to_utf8
to_utf8
)
add_component_dir(esm attr common defs esmcommon reader records util luascripts)
add_component_dir(esm attr common defs esmcommon reader records util luascripts format)
add_component_dir (esm3
esmreader esmwriter loadacti loadalch loadappa loadarmo loadbody loadbook loadbsgn loadcell

@ -0,0 +1,40 @@
#include "format.hpp"
#include <components/esm/esmcommon.hpp>
namespace ESM
{
namespace
{
bool isValidFormat(std::uint32_t value)
{
return value == static_cast<std::uint32_t>(Format::Tes3)
|| value == static_cast<std::uint32_t>(Format::Tes4);
}
Format toFormat(std::uint32_t value)
{
if (!isValidFormat(value))
throw std::runtime_error("Invalid format: " + std::to_string(value));
return static_cast<Format>(value);
}
}
Format readFormat(std::istream& stream)
{
std::uint32_t format = 0;
stream.read(reinterpret_cast<char*>(&format), sizeof(format));
if (stream.gcount() != sizeof(format))
throw std::runtime_error("Not enough bytes to read file header");
return toFormat(format);
}
Format parseFormat(std::string_view value)
{
if (value.size() != sizeof(std::uint32_t))
throw std::logic_error("Invalid format value: " + std::string(value));
std::uint32_t format;
std::memcpy(&format, value.data(), sizeof(std::uint32_t));
return toFormat(format);
}
}

@ -0,0 +1,23 @@
#ifndef COMPONENT_ESM_FORMAT_H
#define COMPONENT_ESM_FORMAT_H
#include "defs.hpp"
#include <cstdint>
#include <istream>
#include <string_view>
namespace ESM
{
enum class Format : std::uint32_t
{
Tes3 = fourCC("TES3"),
Tes4 = fourCC("TES4"),
};
Format readFormat(std::istream& stream);
Format parseFormat(std::string_view value);
}
#endif

@ -38,7 +38,7 @@ namespace ESM
}
bool Reader::getStringImpl(std::string& str, std::size_t size,
std::istream& stream, ToUTF8::StatelessUtf8Encoder* encoder, bool hasNull)
std::istream& stream, const ToUTF8::StatelessUtf8Encoder* encoder, bool hasNull)
{
std::size_t newSize = size;

@ -31,7 +31,7 @@ namespace ESM
virtual inline bool hasMoreRecs() const = 0;
virtual inline void setEncoder(ToUTF8::StatelessUtf8Encoder* encoder) = 0;
virtual inline void setEncoder(const ToUTF8::StatelessUtf8Encoder* encoder) = 0;
// used to check for dependencies e.g. CS::Editor::run()
virtual inline const std::vector<ESM::MasterData>& getGameFiles() const = 0;
@ -53,7 +53,7 @@ namespace ESM
protected:
bool getStringImpl(std::string& str, std::size_t size,
std::istream& stream, ToUTF8::StatelessUtf8Encoder* encoder, bool hasNull = false);
std::istream& stream, const ToUTF8::StatelessUtf8Encoder* encoder, bool hasNull = false);
};
}

@ -76,7 +76,7 @@ namespace ESM4
REC_DOBJ = fourCC("DOBJ"), // Default Object Manager
REC_DOOR = fourCC("DOOR"), // Door
REC_DUAL = fourCC("DUAL"), // Dual Cast Data (possibly unused)
//REC_ECZN = fourCC("ECZN"), // Encounter Zone
REC_ECZN = fourCC("ECZN"), // Encounter Zone
REC_EFSH = fourCC("EFSH"), // Effect Shader
REC_ENCH = fourCC("ENCH"), // Enchantment
REC_EQUP = fourCC("EQUP"), // Equip Slot (flag-type values)
@ -93,7 +93,7 @@ namespace ESM4
REC_GRAS = fourCC("GRAS"), // Grass
REC_GRUP = fourCC("GRUP"), // Form Group
REC_HAIR = fourCC("HAIR"), // Hair
//REC_HAZD = fourCC("HAZD"), // Hazard
REC_HAZD = fourCC("HAZD"), // Hazard
REC_HDPT = fourCC("HDPT"), // Head Part
REC_IDLE = fourCC("IDLE"), // Idle Animation
REC_IDLM = fourCC("IDLM"), // Idle Marker

@ -32,10 +32,6 @@
#include "reader.hpp"
//#include "writer.hpp"
ESM4::ActorCharacter::~ActorCharacter()
{
}
void ESM4::ActorCharacter::load(ESM4::Reader& reader)
{
mFormId = reader.hdr().record.id;

@ -57,10 +57,8 @@ namespace ESM4
EnableParent mEsp;
virtual ~ActorCharacter();
virtual void load(ESM4::Reader& reader);
//virtual void save(ESM4::Writer& writer) const;
void load(ESM4::Reader& reader);
//void save(ESM4::Writer& writer) const;
//void blank();
};

@ -32,10 +32,6 @@
#include "reader.hpp"
//#include "writer.hpp"
ESM4::ActorCreature::~ActorCreature()
{
}
void ESM4::ActorCreature::load(ESM4::Reader& reader)
{
mFormId = reader.hdr().record.id;

@ -54,10 +54,8 @@ namespace ESM4
EnableParent mEsp;
virtual ~ActorCreature();
virtual void load(ESM4::Reader& reader);
//virtual void save(ESM4::Writer& writer) const;
void load(ESM4::Reader& reader);
//void save(ESM4::Writer& writer) const;
//void blank();
};

@ -32,10 +32,6 @@
#include "reader.hpp"
//#include "writer.hpp"
ESM4::Activator::~Activator()
{
}
void ESM4::Activator::load(ESM4::Reader& reader)
{
mFormId = reader.hdr().record.id;

@ -57,10 +57,8 @@ namespace ESM4
std::string mActivationPrompt;
virtual ~Activator();
virtual void load(ESM4::Reader& reader);
//virtual void save(ESM4::Writer& writer) const;
void load(ESM4::Reader& reader);
//void save(ESM4::Writer& writer) const;
//void blank();
};

@ -33,10 +33,6 @@
#include "reader.hpp"
//#include "writer.hpp"
ESM4::Potion::~Potion()
{
}
void ESM4::Potion::load(ESM4::Reader& reader)
{
mFormId = reader.hdr().record.id;

@ -75,10 +75,8 @@ namespace ESM4
Data mData;
EnchantedItem mItem;
virtual ~Potion();
virtual void load(ESM4::Reader& reader);
//virtual void save(ESM4::Writer& writer) const;
void load(ESM4::Reader& reader);
//void save(ESM4::Writer& writer) const;
//void blank();
};

@ -38,10 +38,6 @@
#include "reader.hpp"
//#include "writer.hpp"
ESM4::MediaLocationController::~MediaLocationController()
{
}
void ESM4::MediaLocationController::load(ESM4::Reader& reader)
{
mFormId = reader.hdr().record.id;

@ -75,11 +75,8 @@ namespace ESM4
std::uint32_t mDayStart;
std::uint32_t mNightStart;
MediaLocationController();
virtual ~MediaLocationController();
virtual void load(ESM4::Reader& reader);
//virtual void save(ESM4::Writer& writer) const;
void load(ESM4::Reader& reader);
//void save(ESM4::Writer& writer) const;
//void blank();
};

@ -31,10 +31,6 @@
#include "reader.hpp"
//#include "writer.hpp"
ESM4::Ammunition::~Ammunition()
{
}
void ESM4::Ammunition::load(ESM4::Reader& reader)
{
mFormId = reader.hdr().record.id;

@ -71,10 +71,8 @@ namespace ESM4
Data mData;
virtual ~Ammunition();
virtual void load(ESM4::Reader& reader);
//virtual void save(ESM4::Writer& writer) const;
void load(ESM4::Reader& reader);
//void save(ESM4::Writer& writer) const;
//void blank();
};

@ -31,10 +31,6 @@
#include "reader.hpp"
//#include "writer.hpp"
ESM4::AnimObject::~AnimObject()
{
}
void ESM4::AnimObject::load(ESM4::Reader& reader)
{
mFormId = reader.hdr().record.id;

@ -50,10 +50,8 @@ namespace ESM4
FormId mIdleAnim; // only in TES4
std::string mUnloadEvent; // only in TES5
virtual ~AnimObject();
virtual void load(ESM4::Reader& reader);
//virtual void save(ESM4::Writer& writer) const;
void load(ESM4::Reader& reader);
//void save(ESM4::Writer& writer) const;
//void blank();
};

@ -31,10 +31,6 @@
#include "reader.hpp"
//#include "writer.hpp"
ESM4::Apparatus::~Apparatus()
{
}
void ESM4::Apparatus::load(ESM4::Reader& reader)
{
mFormId = reader.hdr().record.id;

@ -62,10 +62,8 @@ namespace ESM4
Data mData;
virtual ~Apparatus();
virtual void load(ESM4::Reader& reader);
//virtual void save(ESM4::Writer& writer) const;
void load(ESM4::Reader& reader);
//void save(ESM4::Writer& writer) const;
//void blank();
};

@ -32,10 +32,6 @@
#include "reader.hpp"
//#include "writer.hpp"
ESM4::ArmorAddon::~ArmorAddon()
{
}
void ESM4::ArmorAddon::load(ESM4::Reader& reader)
{
mFormId = reader.hdr().record.id;

@ -57,10 +57,8 @@ namespace ESM4
BodyTemplate mBodyTemplate; // TES5
virtual ~ArmorAddon();
virtual void load(ESM4::Reader& reader);
//virtual void save(ESM4::Writer& writer) const;
void load(ESM4::Reader& reader);
//void save(ESM4::Writer& writer) const;
//void blank();
};

@ -32,10 +32,6 @@
#include "reader.hpp"
//#include "writer.hpp"
ESM4::Armor::~Armor()
{
}
void ESM4::Armor::load(ESM4::Reader& reader)
{
mFormId = reader.hdr().record.id;

@ -183,10 +183,8 @@ namespace ESM4
std::vector<FormId> mAddOns; // TES5 ARMA
Data mData;
virtual ~Armor();
virtual void load(ESM4::Reader& reader);
//virtual void save(ESM4::Writer& writer) const;
void load(ESM4::Reader& reader);
//void save(ESM4::Writer& writer) const;
//void blank();
};

@ -32,10 +32,6 @@
#include "reader.hpp"
//#include "writer.hpp"
ESM4::AcousticSpace::~AcousticSpace()
{
}
void ESM4::AcousticSpace::load(ESM4::Reader& reader)
{
mFormId = reader.hdr().record.id;

@ -53,10 +53,8 @@ namespace ESM4
std::uint32_t mIsInterior; // if true only use mAmbientLoopSounds[0]
virtual ~AcousticSpace();
virtual void load(ESM4::Reader& reader);
//virtual void save(ESM4::Writer& writer) const;
void load(ESM4::Reader& reader);
//void save(ESM4::Writer& writer) const;
//void blank();
};

@ -31,10 +31,6 @@
#include "reader.hpp"
//#include "writer.hpp"
ESM4::Book::~Book()
{
}
void ESM4::Book::load(ESM4::Reader& reader)
{
mFormId = reader.hdr().record.id;

@ -101,10 +101,8 @@ namespace ESM4
FormId mPickUpSound;
FormId mDropSound;
virtual ~Book();
virtual void load(ESM4::Reader& reader);
//virtual void save(ESM4::Writer& writer) const;
void load(ESM4::Reader& reader);
//void save(ESM4::Writer& writer) const;
//void blank();
};

@ -43,10 +43,6 @@ void ESM4::BodyPartData::BodyPart::clear()
mGoreEffectsTarget.clear();
}
ESM4::BodyPartData::~BodyPartData()
{
}
void ESM4::BodyPartData::load(ESM4::Reader& reader)
{
mFormId = reader.hdr().record.id;

@ -115,10 +115,8 @@ namespace ESM4
std::vector<BodyPart> mBodyParts;
virtual ~BodyPartData();
virtual void load(ESM4::Reader& reader);
//virtual void save(ESM4::Writer& writer) const;
void load(ESM4::Reader& reader);
//void save(ESM4::Writer& writer) const;
//void blank();
};

@ -39,11 +39,14 @@
#include "reader.hpp"
//#include "writer.hpp"
ESM4::Cell::~Cell()
{
}
void ESM4::Cell::init(ESM4::Reader& reader)
// TODO: Try loading only EDID and XCLC (along with mFormId, mFlags and mParent)
//
// But, for external cells we may be scanning the whole record since we don't know if there is
// going to be an EDID subrecord. And the vast majority of cells are these kinds.
//
// So perhaps some testing needs to be done to see if scanning and skipping takes
// longer/shorter/same as loading the subrecords.
void ESM4::Cell::load(ESM4::Reader& reader)
{
mFormId = reader.hdr().record.id;
reader.adjustFormId(mFormId);
@ -64,33 +67,10 @@ void ESM4::Cell::init(ESM4::Reader& reader)
currCellGrid.grid.y = 0;
reader.setCurrCellGrid(currCellGrid); // side effect: sets mCellGridValid true
}
}
// TODO: Try loading only EDID and XCLC (along with mFormId, mFlags and mParent)
//
// But, for external cells we may be scanning the whole record since we don't know if there is
// going to be an EDID subrecord. And the vast majority of cells are these kinds.
//
// So perhaps some testing needs to be done to see if scanning and skipping takes
// longer/shorter/same as loading the subrecords.
bool ESM4::Cell::preload(ESM4::Reader& reader)
{
if (!mPreloaded)
load(reader);
mPreloaded = true;
return true;
}
void ESM4::Cell::load(ESM4::Reader& reader)
{
if (mPreloaded)
return;
// 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?)
init(reader);
reader.setCurrCell(mFormId); // 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;

@ -91,15 +91,8 @@ namespace ESM4
CellGroup *mCellGroup;
virtual ~Cell();
void init(ESM4::Reader& reader); // common setup for both preload() and load()
bool mPreloaded;
bool preload(ESM4::Reader& reader);
virtual void load(ESM4::Reader& reader);
//virtual void save(ESM4::Writer& writer) const;
void load(ESM4::Reader& reader);
//void save(ESM4::Writer& writer) const;
void blank();
};

@ -36,10 +36,6 @@
#include "reader.hpp"
//#include "writer.hpp"
ESM4::Class::~Class()
{
}
void ESM4::Class::load(ESM4::Reader& reader)
{
//mFormId = reader.adjustFormId(reader.hdr().record.id); // FIXME: use master adjusted?

@ -53,8 +53,6 @@ namespace ESM4
std::string mIcon;
Data mData;
~Class();
void load(ESM4::Reader& reader);
//void save(ESM4::Writer& reader) const;

@ -32,10 +32,6 @@
#include "reader.hpp"
//#include "writer.hpp"
ESM4::Colour::~Colour()
{
}
void ESM4::Colour::load(ESM4::Reader& reader)
{
mFormId = reader.hdr().record.id;

@ -57,10 +57,8 @@ namespace ESM4
ColourRGB mColour;
std::uint32_t mPlayable;
virtual ~Colour();
virtual void load(ESM4::Reader& reader);
//virtual void save(ESM4::Writer& writer) const;
void load(ESM4::Reader& reader);
//void save(ESM4::Writer& writer) const;
//void blank();
};

@ -32,10 +32,6 @@
#include "reader.hpp"
//#include "writer.hpp"
ESM4::Clothing::~Clothing()
{
}
void ESM4::Clothing::load(ESM4::Reader& reader)
{
mFormId = reader.hdr().record.id;

@ -70,10 +70,8 @@ namespace ESM4
Data mData;
virtual ~Clothing();
virtual void load(ESM4::Reader& reader);
//virtual void save(ESM4::Writer& writer) const;
void load(ESM4::Reader& reader);
//void save(ESM4::Writer& writer) const;
//void blank();
};

@ -31,10 +31,6 @@
#include "reader.hpp"
//#include "writer.hpp"
ESM4::Container::~Container()
{
}
void ESM4::Container::load(ESM4::Reader& reader)
{
mFormId = reader.hdr().record.id;

@ -58,10 +58,8 @@ namespace ESM4
std::vector<InventoryItem> mInventory;
virtual ~Container();
virtual void load(ESM4::Reader& reader);
//virtual void save(ESM4::Writer& writer) const;
void load(ESM4::Reader& reader);
//void save(ESM4::Writer& writer) const;
//void blank();
};

@ -40,10 +40,6 @@
#include "reader.hpp"
//#include "writer.hpp"
ESM4::Creature::~Creature()
{
}
void ESM4::Creature::load(ESM4::Reader& reader)
{
mFormId = reader.hdr().record.id;

@ -138,10 +138,8 @@ namespace ESM4
FormId mBaseTemplate; // FO3/FONV
std::vector<FormId> mBodyParts; // FO3/FONV
virtual ~Creature();
virtual void load(ESM4::Reader& reader);
//virtual void save(ESM4::Writer& writer) const;
void load(ESM4::Reader& reader);
//void save(ESM4::Writer& writer) const;
//void blank();
};

@ -33,10 +33,6 @@
#include "reader.hpp"
//#include "writer.hpp"
ESM4::Dialogue::~Dialogue()
{
}
void ESM4::Dialogue::load(ESM4::Reader& reader)
{
mFormId = reader.hdr().record.id;

@ -57,10 +57,8 @@ namespace ESM4
float mPriority;
virtual ~Dialogue();
virtual void load(ESM4::Reader& reader);
//virtual void save(ESM4::Writer& writer) const;
void load(ESM4::Reader& reader);
//void save(ESM4::Writer& writer) const;
//void blank();
};

@ -37,10 +37,6 @@
#include "reader.hpp"
//#include "writer.hpp"
ESM4::DefaultObj::~DefaultObj()
{
}
void ESM4::DefaultObj::load(ESM4::Reader& reader)
{
mFormId = reader.hdr().record.id;

@ -87,10 +87,8 @@ namespace ESM4
Defaults mData;
virtual ~DefaultObj();
virtual void load(ESM4::Reader& reader);
//virtual void save(ESM4::Writer& writer) const;
void load(ESM4::Reader& reader);
//void save(ESM4::Writer& writer) const;
//void blank();
};

@ -31,10 +31,6 @@
#include "reader.hpp"
//#include "writer.hpp"
ESM4::Door::~Door()
{
}
void ESM4::Door::load(ESM4::Reader& reader)
{
mFormId = reader.hdr().record.id;

@ -63,10 +63,8 @@ namespace ESM4
FormId mLoopSound;
FormId mRandomTeleport;
virtual ~Door();
virtual void load(ESM4::Reader& reader);
//virtual void save(ESM4::Writer& writer) const;
void load(ESM4::Reader& reader);
//void save(ESM4::Writer& writer) const;
//void blank();
};

@ -31,10 +31,6 @@
#include "reader.hpp"
//#include "writer.hpp"
ESM4::Eyes::~Eyes()
{
}
void ESM4::Eyes::load(ESM4::Reader& reader)
{
mFormId = reader.hdr().record.id;

@ -55,10 +55,8 @@ namespace ESM4
Data mData;
virtual ~Eyes();
virtual void load(ESM4::Reader& reader);
//virtual void save(ESM4::Writer& writer) const;
void load(ESM4::Reader& reader);
//void save(ESM4::Writer& writer) const;
//void blank();
};

@ -31,10 +31,6 @@
#include "reader.hpp"
//#include "writer.hpp"
ESM4::Flora::~Flora()
{
}
void ESM4::Flora::load(ESM4::Reader& reader)
{
mFormId = reader.hdr().record.id;

@ -65,10 +65,8 @@ namespace ESM4
FormId mSound;
Production mPercentHarvest;
virtual ~Flora();
virtual void load(ESM4::Reader& reader);
//virtual void save(ESM4::Writer& writer) const;
void load(ESM4::Reader& reader);
//void save(ESM4::Writer& writer) const;
//void blank();
};

@ -32,10 +32,6 @@
#include "reader.hpp"
//#include "writer.hpp"
ESM4::FormIdList::~FormIdList()
{
}
void ESM4::FormIdList::load(ESM4::Reader& reader)
{
mFormId = reader.hdr().record.id;

@ -47,10 +47,8 @@ namespace ESM4
std::vector<FormId> mObjects;
virtual ~FormIdList();
virtual void load(ESM4::Reader& reader);
//virtual void save(ESM4::Writer& writer) const;
void load(ESM4::Reader& reader);
//void save(ESM4::Writer& writer) const;
//void blank();
};

@ -31,10 +31,6 @@
#include "reader.hpp"
//#include "writer.hpp"
ESM4::Furniture::~Furniture()
{
}
void ESM4::Furniture::load(ESM4::Reader& reader)
{
mFormId = reader.hdr().record.id;

@ -51,10 +51,8 @@ namespace ESM4
FormId mScriptId;
std::uint32_t mActiveMarkerFlags;
virtual ~Furniture();
virtual void load(ESM4::Reader& reader);
//virtual void save(ESM4::Writer& writer) const;
void load(ESM4::Reader& reader);
//void save(ESM4::Writer& writer) const;
//void blank();
};

@ -32,10 +32,6 @@
#include "reader.hpp"
//#include "writer.hpp"
ESM4::GlobalVariable::~GlobalVariable()
{
}
void ESM4::GlobalVariable::load(ESM4::Reader& reader)
{
mFormId = reader.hdr().record.id;

@ -47,10 +47,8 @@ namespace ESM4
std::uint8_t mType;
float mValue;
virtual ~GlobalVariable();
virtual void load(ESM4::Reader& reader);
//virtual void save(ESM4::Writer& writer) const;
void load(ESM4::Reader& reader);
//void save(ESM4::Writer& writer) const;
//void blank();
};

@ -31,10 +31,6 @@
#include "reader.hpp"
//#include "writer.hpp"
ESM4::Grass::~Grass()
{
}
void ESM4::Grass::load(ESM4::Reader& reader)
{
mFormId = reader.hdr().record.id;

@ -85,10 +85,8 @@ namespace ESM4
Data mData;
virtual ~Grass();
virtual void load(ESM4::Reader& reader);
//virtual void save(ESM4::Writer& writer) const;
void load(ESM4::Reader& reader);
//void save(ESM4::Writer& writer) const;
//void blank();
};

@ -86,8 +86,6 @@ namespace ESM4
FormId mRoad;
std::vector<FormId> mCells; // FIXME should this be CellGroup* instead?
WorldGroup() : mWorld(0), mRoad(0) {}
};
// http://www.uesp.net/wiki/Tes4Mod:Mod_File_Format/CELL
@ -150,8 +148,6 @@ namespace ESM4
// need to keep modindex and context for lazy loading (of all the files that contribute
// to this group)
CellGroup() : mCell(0), mLand(0), mPgrd(0) {}
};
}

@ -32,10 +32,6 @@
#include "reader.hpp"
//#include "writer.hpp"
ESM4::Hair::~Hair()
{
}
void ESM4::Hair::load(ESM4::Reader& reader)
{
mFormId = reader.hdr().record.id;

@ -58,10 +58,8 @@ namespace ESM4
Data mData;
virtual ~Hair();
virtual void load(ESM4::Reader& reader);
//virtual void save(ESM4::Writer& writer) const;
void load(ESM4::Reader& reader);
//void save(ESM4::Writer& writer) const;
//void blank();
};

@ -32,10 +32,6 @@
#include "reader.hpp"
//#include "writer.hpp"
ESM4::HeadPart::~HeadPart()
{
}
void ESM4::HeadPart::load(ESM4::Reader& reader)
{
mFormId = reader.hdr().record.id;

@ -53,11 +53,8 @@ namespace ESM4
std::array<std::string, 3> mTriFile;
FormId mBaseTexture;
HeadPart();
virtual ~HeadPart();
virtual void load(ESM4::Reader& reader);
//virtual void save(ESM4::Writer& writer) const;
void load(ESM4::Reader& reader);
//void save(ESM4::Writer& writer) const;
//void blank();
};

@ -31,10 +31,6 @@
#include "reader.hpp"
//#include "writer.hpp"
ESM4::IdleAnimation::~IdleAnimation()
{
}
void ESM4::IdleAnimation::load(ESM4::Reader& reader)
{
mFormId = reader.hdr().record.id;

@ -49,10 +49,8 @@ namespace ESM4
FormId mParent; // IDLE or AACT
FormId mPrevious;
virtual ~IdleAnimation();
virtual void load(ESM4::Reader& reader);
//virtual void save(ESM4::Writer& writer) const;
void load(ESM4::Reader& reader);
//void save(ESM4::Writer& writer) const;
//void blank();
};

@ -32,10 +32,6 @@
#include "reader.hpp"
//#include "writer.hpp"
ESM4::IdleMarker::~IdleMarker()
{
}
void ESM4::IdleMarker::load(ESM4::Reader& reader)
{
mFormId = reader.hdr().record.id;

@ -50,10 +50,8 @@ namespace ESM4
float mIdleTimer;
std::vector<FormId> mIdleAnim;
virtual ~IdleMarker();
virtual void load(ESM4::Reader& reader);
//virtual void save(ESM4::Writer& writer) const;
void load(ESM4::Reader& reader);
//void save(ESM4::Writer& writer) const;
//void blank();
};

@ -34,10 +34,6 @@
#include "reader.hpp"
//#include "writer.hpp"
ESM4::ItemMod::~ItemMod()
{
}
void ESM4::ItemMod::load(ESM4::Reader& reader)
{
mFormId = reader.hdr().record.id;

@ -46,10 +46,8 @@ namespace ESM4
std::string mEditorId;
virtual ~ItemMod();
virtual void load(ESM4::Reader& reader);
//virtual void save(ESM4::Writer& writer) const;
void load(ESM4::Reader& reader);
//void save(ESM4::Writer& writer) const;
//void blank();
};

@ -33,10 +33,6 @@
#include "reader.hpp"
//#include "writer.hpp"
ESM4::DialogInfo::~DialogInfo()
{
}
void ESM4::DialogInfo::load(ESM4::Reader& reader)
{
mFormId = reader.hdr().record.id;

@ -77,10 +77,8 @@ namespace ESM4
ScriptDefinition mScript; // FIXME: ignoring the second one after the NEXT sub-record
virtual ~DialogInfo();
virtual void load(ESM4::Reader& reader);
//virtual void save(ESM4::Writer& writer) const;
void load(ESM4::Reader& reader);
//void save(ESM4::Writer& writer) const;
//void blank();
};

@ -32,10 +32,6 @@
#include "reader.hpp"
//#include "writer.hpp"
ESM4::Ingredient::~Ingredient()
{
}
void ESM4::Ingredient::load(ESM4::Reader& reader)
{
mFormId = reader.hdr().record.id;

@ -70,10 +70,8 @@ namespace ESM4
Data mData;
virtual ~Ingredient();
virtual void load(ESM4::Reader& reader);
//virtual void save(ESM4::Writer& writer) const;
void load(ESM4::Reader& reader);
//void save(ESM4::Writer& writer) const;
//void blank();
};

@ -31,10 +31,6 @@
#include "reader.hpp"
//#include "writer.hpp"
ESM4::Key::~Key()
{
}
void ESM4::Key::load(ESM4::Reader& reader)
{
mFormId = reader.hdr().record.id;

@ -64,10 +64,8 @@ namespace ESM4
Data mData;
virtual ~Key();
virtual void load(ESM4::Reader& reader);
//virtual void save(ESM4::Writer& writer) const;
void load(ESM4::Reader& reader);
//void save(ESM4::Writer& writer) const;
//void blank();
};

@ -38,10 +38,6 @@
#include "reader.hpp"
//#include "writer.hpp"
ESM4::Land::~Land()
{
}
// overlap north
//
// 32

@ -123,8 +123,6 @@ namespace ESM4
Texture mTextures[4]; // 0 = bottom left, 1 = bottom right, 2 = top left, 3 = top right
std::vector<FormId> mIds; // land texture (LTEX) formids
virtual ~Land();
virtual void load(Reader& reader);
//virtual void save(Writer& writer) const;

@ -35,10 +35,6 @@
#include "reader.hpp"
//#include "writer.hpp"
ESM4::LightingTemplate::~LightingTemplate()
{
}
void ESM4::LightingTemplate::load(ESM4::Reader& reader)
{
mFormId = reader.hdr().record.id;

@ -50,10 +50,8 @@ namespace ESM4
Lighting mLighting;
virtual ~LightingTemplate();
virtual void load(ESM4::Reader& reader);
//virtual void save(ESM4::Writer& writer) const;
void load(ESM4::Reader& reader);
//void save(ESM4::Writer& writer) const;
//void blank();
};

@ -31,10 +31,6 @@
#include "reader.hpp"
//#include "writer.hpp"
ESM4::Light::~Light()
{
}
void ESM4::Light::load(ESM4::Reader& reader)
{
mFormId = reader.hdr().record.id;

@ -84,10 +84,8 @@ namespace ESM4
Data mData;
virtual ~Light();
virtual void load(ESM4::Reader& reader);
//virtual void save(ESM4::Writer& writer) const;
void load(ESM4::Reader& reader);
//void save(ESM4::Writer& writer) const;
//void blank();
};

@ -37,10 +37,6 @@
#include "reader.hpp"
//#include "writer.hpp"
ESM4::LandTexture::~LandTexture()
{
}
void ESM4::LandTexture::load(ESM4::Reader& reader)
{
mFormId = reader.hdr().record.id;

@ -62,10 +62,8 @@ namespace ESM4
// ----------------------
virtual ~LandTexture();
virtual void load(ESM4::Reader& reader);
//virtual void save(ESM4::Writer& writer) const;
void load(ESM4::Reader& reader);
//void save(ESM4::Writer& writer) const;
//void blank();
};

@ -32,10 +32,6 @@
#include "reader.hpp"
//#include "writer.hpp"
ESM4::LevelledCreature::~LevelledCreature()
{
}
void ESM4::LevelledCreature::load(ESM4::Reader& reader)
{
mFormId = reader.hdr().record.id;

@ -58,10 +58,8 @@ namespace ESM4
bool calcEachItemInCount() const;
std::int8_t chanceNone() const;
virtual ~LevelledCreature();
virtual void load(ESM4::Reader& reader);
//virtual void save(ESM4::Writer& writer) const;
void load(ESM4::Reader& reader);
//void save(ESM4::Writer& writer) const;
//void blank();
};

@ -32,10 +32,6 @@
#include "reader.hpp"
//#include "writer.hpp"
ESM4::LevelledItem::~LevelledItem()
{
}
void ESM4::LevelledItem::load(ESM4::Reader& reader)
{
mFormId = reader.hdr().record.id;

@ -54,15 +54,13 @@ namespace ESM4
std::vector<LVLO> mLvlObject;
virtual ~LevelledItem();
bool calcAllLvlLessThanPlayer() const;
bool calcEachItemInCount() const;
bool useAll() const;
std::int8_t chanceNone() const;
virtual void load(ESM4::Reader& reader);
//virtual void save(ESM4::Writer& writer) const;
void load(ESM4::Reader& reader);
//void save(ESM4::Writer& writer) const;
//void blank();
};

@ -32,10 +32,6 @@
#include "reader.hpp"
//#include "writer.hpp"
ESM4::LevelledNpc::~LevelledNpc()
{
}
void ESM4::LevelledNpc::load(ESM4::Reader& reader)
{
mFormId = reader.hdr().record.id;

@ -52,14 +52,12 @@ namespace ESM4
std::uint8_t mListCount;
std::vector<LVLO> mLvlObject;
virtual ~LevelledNpc();
inline bool calcAllLvlLessThanPlayer() const { return (mLvlActorFlags & 0x01) != 0; }
inline bool calcEachItemInCount() const { return (mLvlActorFlags & 0x02) != 0; }
inline std::int8_t chanceNone() const { return mChanceNone; }
virtual void load(ESM4::Reader& reader);
//virtual void save(ESM4::Writer& writer) const;
void load(ESM4::Reader& reader);
//void save(ESM4::Writer& writer) const;
//void blank();
};

@ -31,10 +31,6 @@
#include "reader.hpp"
//#include "writer.hpp"
ESM4::Material::~Material()
{
}
void ESM4::Material::load(ESM4::Reader& reader)
{
//mFormId = reader.adjustFormId(reader.hdr().record.id); // FIXME: use master adjusted?

@ -45,10 +45,8 @@ namespace ESM4
std::string mEditorId;
std::string mModel;
virtual ~Material();
virtual void load(ESM4::Reader& reader);
//virtual void save(ESM4::Writer& writer) const;
void load(ESM4::Reader& reader);
//void save(ESM4::Writer& writer) const;
//void blank();
};

Some files were not shown because too many files have changed in this diff Show More

Loading…
Cancel
Save