1
0
Fork 0
mirror of https://github.com/OpenMW/openmw.git synced 2025-12-17 22:43:08 +00:00

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
This commit is contained in:
florent.teppe 2022-12-30 11:28:19 +01:00
parent c721a6cafa
commit 077cf97bc4
12 changed files with 440 additions and 340 deletions

View file

@ -8,6 +8,7 @@
#include <components/esm/esmcommon.hpp> #include <components/esm/esmcommon.hpp>
#include <components/esm4/reader.hpp> #include <components/esm4/reader.hpp>
#include <components/esm4/readerutils.hpp>
#include <components/esm4/records.hpp> #include <components/esm4/records.hpp>
#include <components/to_utf8/to_utf8.hpp> #include <components/to_utf8/to_utf8.hpp>
@ -69,6 +70,19 @@ namespace EsmTool
template <class T> template <class T>
constexpr bool hasFormId = HasFormId<T>::value; constexpr bool hasFormId = HasFormId<T>::value;
template <class T, class = std::void_t<>>
struct HasRefId : std::false_type
{
};
template <class T>
struct HasRefId<T, std::void_t<decltype(T::mId)>> : std::true_type
{
};
template <class T>
constexpr bool hasRefId = HasRefId<T>::value;
template <class T, class = std::void_t<>> template <class T, class = std::void_t<>>
struct HasFlags : std::false_type struct HasFlags : std::false_type
{ {
@ -169,6 +183,8 @@ namespace EsmTool
std::cout << "\n Record: " << ESM::NAME(reader.hdr().record.typeId).toStringView(); std::cout << "\n Record: " << ESM::NAME(reader.hdr().record.typeId).toStringView();
if constexpr (hasFormId<T>) if constexpr (hasFormId<T>)
std::cout << "\n FormId: " << value.mFormId; std::cout << "\n FormId: " << value.mFormId;
if constexpr (hasRefId<T>)
std::cout << "\n RefId: " << value.mId;
if constexpr (hasFlags<T>) if constexpr (hasFlags<T>)
std::cout << "\n Record flags: " << recordFlags(value.mFlags); std::cout << "\n Record flags: " << recordFlags(value.mFlags);
if constexpr (hasEditorId<T>) if constexpr (hasEditorId<T>)
@ -180,62 +196,80 @@ namespace EsmTool
if constexpr (hasKf<T>) if constexpr (hasKf<T>)
std::cout << "\n Kf:" << WriteArray("\n - ", value.mKf); std::cout << "\n Kf:" << WriteArray("\n - ", value.mKf);
std::cout << '\n'; std::cout << '\n';
return;
} }
void readRecord(const Params& params, ESM4::Reader& reader) bool readRecord(const Params& params, ESM4::Reader& reader)
{ {
switch (static_cast<ESM4::RecordTypes>(reader.hdr().record.typeId)) switch (static_cast<ESM4::RecordTypes>(reader.hdr().record.typeId))
{ {
case ESM4::REC_AACT: case ESM4::REC_AACT:
break; break;
case ESM4::REC_ACHR: case ESM4::REC_ACHR:
return readTypedRecord<ESM4::ActorCharacter>(params, reader); readTypedRecord<ESM4::ActorCharacter>(params, reader);
return true;
case ESM4::REC_ACRE: case ESM4::REC_ACRE:
return readTypedRecord<ESM4::ActorCreature>(params, reader); readTypedRecord<ESM4::ActorCreature>(params, reader);
return true;
case ESM4::REC_ACTI: case ESM4::REC_ACTI:
return readTypedRecord<ESM4::Activator>(params, reader); readTypedRecord<ESM4::Activator>(params, reader);
return true;
case ESM4::REC_ADDN: case ESM4::REC_ADDN:
break; break;
case ESM4::REC_ALCH: case ESM4::REC_ALCH:
return readTypedRecord<ESM4::Potion>(params, reader); readTypedRecord<ESM4::Potion>(params, reader);
return true;
case ESM4::REC_ALOC: case ESM4::REC_ALOC:
return readTypedRecord<ESM4::MediaLocationController>(params, reader); readTypedRecord<ESM4::MediaLocationController>(params, reader);
return true;
case ESM4::REC_AMMO: case ESM4::REC_AMMO:
return readTypedRecord<ESM4::Ammunition>(params, reader); readTypedRecord<ESM4::Ammunition>(params, reader);
return true;
case ESM4::REC_ANIO: case ESM4::REC_ANIO:
return readTypedRecord<ESM4::AnimObject>(params, reader); readTypedRecord<ESM4::AnimObject>(params, reader);
return true;
case ESM4::REC_APPA: case ESM4::REC_APPA:
return readTypedRecord<ESM4::Apparatus>(params, reader); readTypedRecord<ESM4::Apparatus>(params, reader);
return true;
case ESM4::REC_ARMA: case ESM4::REC_ARMA:
return readTypedRecord<ESM4::ArmorAddon>(params, reader); readTypedRecord<ESM4::ArmorAddon>(params, reader);
return true;
case ESM4::REC_ARMO: case ESM4::REC_ARMO:
return readTypedRecord<ESM4::Armor>(params, reader); readTypedRecord<ESM4::Armor>(params, reader);
return true;
case ESM4::REC_ARTO: case ESM4::REC_ARTO:
break; break;
case ESM4::REC_ASPC: case ESM4::REC_ASPC:
return readTypedRecord<ESM4::AcousticSpace>(params, reader); readTypedRecord<ESM4::AcousticSpace>(params, reader);
return true;
case ESM4::REC_ASTP: case ESM4::REC_ASTP:
break; break;
case ESM4::REC_AVIF: case ESM4::REC_AVIF:
break; break;
case ESM4::REC_BOOK: case ESM4::REC_BOOK:
return readTypedRecord<ESM4::Book>(params, reader); readTypedRecord<ESM4::Book>(params, reader);
return true;
case ESM4::REC_BPTD: case ESM4::REC_BPTD:
return readTypedRecord<ESM4::BodyPartData>(params, reader); readTypedRecord<ESM4::BodyPartData>(params, reader);
return true;
case ESM4::REC_CAMS: case ESM4::REC_CAMS:
break; break;
case ESM4::REC_CCRD: case ESM4::REC_CCRD:
break; break;
case ESM4::REC_CELL: case ESM4::REC_CELL:
return readTypedRecord<ESM4::Cell>(params, reader); readTypedRecord<ESM4::Cell>(params, reader);
return true;
case ESM4::REC_CLAS: case ESM4::REC_CLAS:
return readTypedRecord<ESM4::Class>(params, reader); readTypedRecord<ESM4::Class>(params, reader);
return true;
case ESM4::REC_CLFM: case ESM4::REC_CLFM:
return readTypedRecord<ESM4::Colour>(params, reader); readTypedRecord<ESM4::Colour>(params, reader);
return true;
case ESM4::REC_CLMT: case ESM4::REC_CLMT:
break; break;
case ESM4::REC_CLOT: case ESM4::REC_CLOT:
return readTypedRecord<ESM4::Clothing>(params, reader); readTypedRecord<ESM4::Clothing>(params, reader);
return true;
case ESM4::REC_CMNY: case ESM4::REC_CMNY:
break; break;
case ESM4::REC_COBJ: case ESM4::REC_COBJ:
@ -243,25 +277,30 @@ namespace EsmTool
case ESM4::REC_COLL: case ESM4::REC_COLL:
break; break;
case ESM4::REC_CONT: case ESM4::REC_CONT:
return readTypedRecord<ESM4::Container>(params, reader); readTypedRecord<ESM4::Container>(params, reader);
return true;
case ESM4::REC_CPTH: case ESM4::REC_CPTH:
break; break;
case ESM4::REC_CREA: case ESM4::REC_CREA:
return readTypedRecord<ESM4::Creature>(params, reader); readTypedRecord<ESM4::Creature>(params, reader);
return true;
case ESM4::REC_CSTY: case ESM4::REC_CSTY:
break; break;
case ESM4::REC_DEBR: case ESM4::REC_DEBR:
break; break;
case ESM4::REC_DIAL: case ESM4::REC_DIAL:
return readTypedRecord<ESM4::Dialogue>(params, reader); readTypedRecord<ESM4::Dialogue>(params, reader);
return true;
case ESM4::REC_DLBR: case ESM4::REC_DLBR:
break; break;
case ESM4::REC_DLVW: case ESM4::REC_DLVW:
break; break;
case ESM4::REC_DOBJ: case ESM4::REC_DOBJ:
return readTypedRecord<ESM4::DefaultObj>(params, reader); readTypedRecord<ESM4::DefaultObj>(params, reader);
return true;
case ESM4::REC_DOOR: case ESM4::REC_DOOR:
return readTypedRecord<ESM4::Door>(params, reader); readTypedRecord<ESM4::Door>(params, reader);
return true;
case ESM4::REC_DUAL: case ESM4::REC_DUAL:
break; break;
case ESM4::REC_ECZN: case ESM4::REC_ECZN:
@ -275,81 +314,103 @@ namespace EsmTool
case ESM4::REC_EXPL: case ESM4::REC_EXPL:
break; break;
case ESM4::REC_EYES: case ESM4::REC_EYES:
return readTypedRecord<ESM4::Eyes>(params, reader); readTypedRecord<ESM4::Eyes>(params, reader);
return true;
case ESM4::REC_FACT: case ESM4::REC_FACT:
break; break;
case ESM4::REC_FLOR: case ESM4::REC_FLOR:
return readTypedRecord<ESM4::Flora>(params, reader); readTypedRecord<ESM4::Flora>(params, reader);
return true;
case ESM4::REC_FLST: case ESM4::REC_FLST:
return readTypedRecord<ESM4::FormIdList>(params, reader); readTypedRecord<ESM4::FormIdList>(params, reader);
return true;
case ESM4::REC_FSTP: case ESM4::REC_FSTP:
break; break;
case ESM4::REC_FSTS: case ESM4::REC_FSTS:
break; break;
case ESM4::REC_FURN: case ESM4::REC_FURN:
return readTypedRecord<ESM4::Furniture>(params, reader); readTypedRecord<ESM4::Furniture>(params, reader);
return true;
case ESM4::REC_GLOB: case ESM4::REC_GLOB:
return readTypedRecord<ESM4::GlobalVariable>(params, reader); readTypedRecord<ESM4::GlobalVariable>(params, reader);
return true;
case ESM4::REC_GMST: case ESM4::REC_GMST:
break; break;
case ESM4::REC_GRAS: case ESM4::REC_GRAS:
return readTypedRecord<ESM4::Grass>(params, reader); readTypedRecord<ESM4::Grass>(params, reader);
return true;
case ESM4::REC_GRUP: case ESM4::REC_GRUP:
break; break;
case ESM4::REC_HAIR: case ESM4::REC_HAIR:
return readTypedRecord<ESM4::Hair>(params, reader); readTypedRecord<ESM4::Hair>(params, reader);
return true;
case ESM4::REC_HAZD: case ESM4::REC_HAZD:
break; break;
case ESM4::REC_HDPT: case ESM4::REC_HDPT:
return readTypedRecord<ESM4::HeadPart>(params, reader); readTypedRecord<ESM4::HeadPart>(params, reader);
return true;
case ESM4::REC_IDLE: case ESM4::REC_IDLE:
// FIXME: ESM4::IdleAnimation::load does not work with Oblivion.esm // FIXME: ESM4::IdleAnimation::load does not work with Oblivion.esm
// return readTypedRecord<ESM4::IdleAnimation>(params, reader); // readTypedRecord<ESM4::IdleAnimation>(params, reader);
return true;
break; break;
case ESM4::REC_IDLM: case ESM4::REC_IDLM:
return readTypedRecord<ESM4::IdleMarker>(params, reader); readTypedRecord<ESM4::IdleMarker>(params, reader);
return true;
case ESM4::REC_IMAD: case ESM4::REC_IMAD:
break; break;
case ESM4::REC_IMGS: case ESM4::REC_IMGS:
break; break;
case ESM4::REC_IMOD: case ESM4::REC_IMOD:
return readTypedRecord<ESM4::ItemMod>(params, reader); readTypedRecord<ESM4::ItemMod>(params, reader);
return true;
case ESM4::REC_INFO: case ESM4::REC_INFO:
return readTypedRecord<ESM4::DialogInfo>(params, reader); readTypedRecord<ESM4::DialogInfo>(params, reader);
return true;
case ESM4::REC_INGR: case ESM4::REC_INGR:
return readTypedRecord<ESM4::Ingredient>(params, reader); readTypedRecord<ESM4::Ingredient>(params, reader);
return true;
case ESM4::REC_IPCT: case ESM4::REC_IPCT:
break; break;
case ESM4::REC_IPDS: case ESM4::REC_IPDS:
break; break;
case ESM4::REC_KEYM: case ESM4::REC_KEYM:
return readTypedRecord<ESM4::Key>(params, reader); readTypedRecord<ESM4::Key>(params, reader);
return true;
case ESM4::REC_KYWD: case ESM4::REC_KYWD:
break; break;
case ESM4::REC_LAND: case ESM4::REC_LAND:
return readTypedRecord<ESM4::Land>(params, reader); readTypedRecord<ESM4::Land>(params, reader);
return true;
case ESM4::REC_LCRT: case ESM4::REC_LCRT:
break; break;
case ESM4::REC_LCTN: case ESM4::REC_LCTN:
break; break;
case ESM4::REC_LGTM: case ESM4::REC_LGTM:
return readTypedRecord<ESM4::LightingTemplate>(params, reader); readTypedRecord<ESM4::LightingTemplate>(params, reader);
return true;
case ESM4::REC_LIGH: case ESM4::REC_LIGH:
return readTypedRecord<ESM4::Light>(params, reader); readTypedRecord<ESM4::Light>(params, reader);
return true;
case ESM4::REC_LSCR: case ESM4::REC_LSCR:
break; break;
case ESM4::REC_LTEX: case ESM4::REC_LTEX:
return readTypedRecord<ESM4::LandTexture>(params, reader); readTypedRecord<ESM4::LandTexture>(params, reader);
return true;
case ESM4::REC_LVLC: case ESM4::REC_LVLC:
return readTypedRecord<ESM4::LevelledCreature>(params, reader); readTypedRecord<ESM4::LevelledCreature>(params, reader);
return true;
case ESM4::REC_LVLI: case ESM4::REC_LVLI:
return readTypedRecord<ESM4::LevelledItem>(params, reader); readTypedRecord<ESM4::LevelledItem>(params, reader);
return true;
case ESM4::REC_LVLN: case ESM4::REC_LVLN:
return readTypedRecord<ESM4::LevelledNpc>(params, reader); readTypedRecord<ESM4::LevelledNpc>(params, reader);
return true;
case ESM4::REC_LVSP: case ESM4::REC_LVSP:
break; break;
case ESM4::REC_MATO: case ESM4::REC_MATO:
return readTypedRecord<ESM4::Material>(params, reader); readTypedRecord<ESM4::Material>(params, reader);
return true;
case ESM4::REC_MATT: case ESM4::REC_MATT:
break; break;
case ESM4::REC_MESG: case ESM4::REC_MESG:
@ -357,49 +418,66 @@ namespace EsmTool
case ESM4::REC_MGEF: case ESM4::REC_MGEF:
break; break;
case ESM4::REC_MISC: case ESM4::REC_MISC:
return readTypedRecord<ESM4::MiscItem>(params, reader); readTypedRecord<ESM4::MiscItem>(params, reader);
return true;
case ESM4::REC_MOVT: case ESM4::REC_MOVT:
break; break;
case ESM4::REC_MSET: case ESM4::REC_MSET:
return readTypedRecord<ESM4::MediaSet>(params, reader); readTypedRecord<ESM4::MediaSet>(params, reader);
return true;
case ESM4::REC_MSTT: case ESM4::REC_MSTT:
return readTypedRecord<ESM4::MovableStatic>(params, reader); readTypedRecord<ESM4::MovableStatic>(params, reader);
return true;
case ESM4::REC_MUSC: case ESM4::REC_MUSC:
return readTypedRecord<ESM4::Music>(params, reader); readTypedRecord<ESM4::Music>(params, reader);
return true;
case ESM4::REC_MUST: case ESM4::REC_MUST:
break; break;
case ESM4::REC_NAVI: case ESM4::REC_NAVI:
return readTypedRecord<ESM4::Navigation>(params, reader); readTypedRecord<ESM4::Navigation>(params, reader);
return true;
case ESM4::REC_NAVM: case ESM4::REC_NAVM:
return readTypedRecord<ESM4::NavMesh>(params, reader); readTypedRecord<ESM4::NavMesh>(params, reader);
return true;
case ESM4::REC_NOTE: case ESM4::REC_NOTE:
return readTypedRecord<ESM4::Note>(params, reader); readTypedRecord<ESM4::Note>(params, reader);
return true;
case ESM4::REC_NPC_: case ESM4::REC_NPC_:
return readTypedRecord<ESM4::Npc>(params, reader); readTypedRecord<ESM4::Npc>(params, reader);
return true;
case ESM4::REC_OTFT: case ESM4::REC_OTFT:
return readTypedRecord<ESM4::Outfit>(params, reader); readTypedRecord<ESM4::Outfit>(params, reader);
return true;
case ESM4::REC_PACK: case ESM4::REC_PACK:
return readTypedRecord<ESM4::AIPackage>(params, reader); readTypedRecord<ESM4::AIPackage>(params, reader);
return true;
case ESM4::REC_PERK: case ESM4::REC_PERK:
break; break;
case ESM4::REC_PGRD: case ESM4::REC_PGRD:
return readTypedRecord<ESM4::Pathgrid>(params, reader); readTypedRecord<ESM4::Pathgrid>(params, reader);
return true;
case ESM4::REC_PGRE: case ESM4::REC_PGRE:
return readTypedRecord<ESM4::PlacedGrenade>(params, reader); readTypedRecord<ESM4::PlacedGrenade>(params, reader);
return true;
case ESM4::REC_PHZD: case ESM4::REC_PHZD:
break; break;
case ESM4::REC_PROJ: case ESM4::REC_PROJ:
break; break;
case ESM4::REC_PWAT: case ESM4::REC_PWAT:
return readTypedRecord<ESM4::PlaceableWater>(params, reader); readTypedRecord<ESM4::PlaceableWater>(params, reader);
return true;
case ESM4::REC_QUST: case ESM4::REC_QUST:
return readTypedRecord<ESM4::Quest>(params, reader); readTypedRecord<ESM4::Quest>(params, reader);
return true;
case ESM4::REC_RACE: case ESM4::REC_RACE:
return readTypedRecord<ESM4::Race>(params, reader); readTypedRecord<ESM4::Race>(params, reader);
return true;
case ESM4::REC_REFR: case ESM4::REC_REFR:
return readTypedRecord<ESM4::Reference>(params, reader); readTypedRecord<ESM4::Reference>(params, reader);
return true;
case ESM4::REC_REGN: case ESM4::REC_REGN:
return readTypedRecord<ESM4::Region>(params, reader); readTypedRecord<ESM4::Region>(params, reader);
return true;
case ESM4::REC_RELA: case ESM4::REC_RELA:
break; break;
case ESM4::REC_REVB: case ESM4::REC_REVB:
@ -407,23 +485,30 @@ namespace EsmTool
case ESM4::REC_RFCT: case ESM4::REC_RFCT:
break; break;
case ESM4::REC_ROAD: case ESM4::REC_ROAD:
return readTypedRecord<ESM4::Road>(params, reader); readTypedRecord<ESM4::Road>(params, reader);
return true;
case ESM4::REC_SBSP: case ESM4::REC_SBSP:
return readTypedRecord<ESM4::SubSpace>(params, reader); readTypedRecord<ESM4::SubSpace>(params, reader);
return true;
case ESM4::REC_SCEN: case ESM4::REC_SCEN:
break; break;
case ESM4::REC_SCOL: case ESM4::REC_SCOL:
return readTypedRecord<ESM4::StaticCollection>(params, reader); readTypedRecord<ESM4::StaticCollection>(params, reader);
return true;
case ESM4::REC_SCPT: case ESM4::REC_SCPT:
return readTypedRecord<ESM4::Script>(params, reader); readTypedRecord<ESM4::Script>(params, reader);
return true;
case ESM4::REC_SCRL: case ESM4::REC_SCRL:
return readTypedRecord<ESM4::Scroll>(params, reader); readTypedRecord<ESM4::Scroll>(params, reader);
return true;
case ESM4::REC_SGST: case ESM4::REC_SGST:
return readTypedRecord<ESM4::SigilStone>(params, reader); readTypedRecord<ESM4::SigilStone>(params, reader);
return true;
case ESM4::REC_SHOU: case ESM4::REC_SHOU:
break; break;
case ESM4::REC_SLGM: case ESM4::REC_SLGM:
return readTypedRecord<ESM4::SoulGem>(params, reader); readTypedRecord<ESM4::SoulGem>(params, reader);
return true;
case ESM4::REC_SMBN: case ESM4::REC_SMBN:
break; break;
case ESM4::REC_SMEN: case ESM4::REC_SMEN:
@ -433,97 +518,56 @@ namespace EsmTool
case ESM4::REC_SNCT: case ESM4::REC_SNCT:
break; break;
case ESM4::REC_SNDR: case ESM4::REC_SNDR:
return readTypedRecord<ESM4::SoundReference>(params, reader); readTypedRecord<ESM4::SoundReference>(params, reader);
return true;
case ESM4::REC_SOPM: case ESM4::REC_SOPM:
break; break;
case ESM4::REC_SOUN: case ESM4::REC_SOUN:
return readTypedRecord<ESM4::Sound>(params, reader); readTypedRecord<ESM4::Sound>(params, reader);
return true;
case ESM4::REC_SPEL: case ESM4::REC_SPEL:
break; break;
case ESM4::REC_SPGD: case ESM4::REC_SPGD:
break; break;
case ESM4::REC_STAT: case ESM4::REC_STAT:
return readTypedRecord<ESM4::Static>(params, reader); readTypedRecord<ESM4::Static>(params, reader);
return true;
case ESM4::REC_TACT: case ESM4::REC_TACT:
return readTypedRecord<ESM4::TalkingActivator>(params, reader); readTypedRecord<ESM4::TalkingActivator>(params, reader);
return true;
case ESM4::REC_TERM: case ESM4::REC_TERM:
return readTypedRecord<ESM4::Terminal>(params, reader); readTypedRecord<ESM4::Terminal>(params, reader);
return true;
case ESM4::REC_TES4: case ESM4::REC_TES4:
return readTypedRecord<ESM4::Header>(params, reader); readTypedRecord<ESM4::Header>(params, reader);
return true;
case ESM4::REC_TREE: case ESM4::REC_TREE:
return readTypedRecord<ESM4::Tree>(params, reader); readTypedRecord<ESM4::Tree>(params, reader);
return true;
case ESM4::REC_TXST: case ESM4::REC_TXST:
return readTypedRecord<ESM4::TextureSet>(params, reader); readTypedRecord<ESM4::TextureSet>(params, reader);
return true;
case ESM4::REC_VTYP: case ESM4::REC_VTYP:
break; break;
case ESM4::REC_WATR: case ESM4::REC_WATR:
break; break;
case ESM4::REC_WEAP: case ESM4::REC_WEAP:
return readTypedRecord<ESM4::Weapon>(params, reader); readTypedRecord<ESM4::Weapon>(params, reader);
return true;
case ESM4::REC_WOOP: case ESM4::REC_WOOP:
break; break;
case ESM4::REC_WRLD: case ESM4::REC_WRLD:
return readTypedRecord<ESM4::World>(params, reader); readTypedRecord<ESM4::World>(params, reader);
return true;
case ESM4::REC_WTHR: case ESM4::REC_WTHR:
break; break;
} }
if (!params.mQuite) if (!params.mQuite)
std::cout << "\n Unsupported record: " << ESM::NAME(reader.hdr().record.typeId).toStringView() << '\n'; 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 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) int loadTes4(const Arguments& info, std::unique_ptr<std::ifstream>&& stream)
@ -551,12 +595,15 @@ namespace EsmTool
} }
} }
while (reader.hasMoreRecs()) auto visitorRec = [&params](ESM4::Reader& reader) { return readRecord(params, reader); };
{ auto visistorGroup = [&params](ESM4::Reader& reader) {
reader.exitGroupCheck(); if (params.mQuite)
if (!readItem(params, reader)) return;
break; auto groupType = static_cast<ESM4::GroupType>(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) catch (const std::exception& e)
{ {

View file

@ -1,13 +1,14 @@
#include "esmloader.hpp" #include "esmloader.hpp"
#include "esmstore.hpp" #include "esmstore.hpp"
#include <fstream>
#include <components/esm/format.hpp> #include <components/esm/format.hpp>
#include <components/esm3/esmreader.hpp> #include <components/esm3/esmreader.hpp>
#include <components/esm3/readerscache.hpp> #include <components/esm3/readerscache.hpp>
#include <components/esm4/reader.hpp> #include <components/esm4/reader.hpp>
#include <components/files/conversion.hpp> #include <components/files/conversion.hpp>
#include <components/files/openfile.hpp> #include <components/files/openfile.hpp>
#include <fstream>
namespace MWWorld namespace MWWorld
{ {
@ -30,7 +31,6 @@ namespace MWWorld
if (!stream->is_open()) if (!stream->is_open())
{ {
throw std::runtime_error(std::string("File Failed to open file: ") + std::strerror(errno) + "\n"); throw std::runtime_error(std::string("File Failed to open file: ") + std::strerror(errno) + "\n");
return;
} }
const ESM::Format format = ESM::readFormat(*stream); const ESM::Format format = ESM::readFormat(*stream);
stream->seekg(0); stream->seekg(0);
@ -63,12 +63,16 @@ namespace MWWorld
break; break;
} }
case ESM::Format::Tes4: case ESM::Format::Tes4:
{
if (mEncoder)
{ {
ESM4::Reader readerESM4(std::move(stream), filepath); ESM4::Reader readerESM4(std::move(stream), filepath);
readerESM4.setEncoder(mEncoder->getStatelessEncoder()); auto statelessEncoder = mEncoder->getStatelessEncoder();
readerESM4.setEncoder(&statelessEncoder);
mStore.loadESM4(readerESM4, listener, mDialogue); mStore.loadESM4(readerESM4, listener, mDialogue);
} }
} }
} }
}
} /* namespace MWWorld */ } /* namespace MWWorld */

View file

@ -13,12 +13,12 @@
#include <components/lua/configuration.hpp> #include <components/lua/configuration.hpp>
#include <components/misc/algorithm.hpp> #include <components/misc/algorithm.hpp>
#include <components/esm4/common.hpp>
#include <components/esm4/loadcell.hpp> #include <components/esm4/loadcell.hpp>
#include <components/esm4/loadrefr.hpp> #include <components/esm4/loadrefr.hpp>
#include <components/esm4/loadstat.hpp> #include <components/esm4/loadstat.hpp>
#include <components/esm4/reader.hpp> #include <components/esm4/reader.hpp>
#include <components/esm4/readerutils.hpp>
#include <components/esm4/common.hpp>
#include <components/esmloader/load.hpp> #include <components/esmloader/load.hpp>
#include "../mwmechanics/spelllist.hpp" #include "../mwmechanics/spelllist.hpp"
@ -186,13 +186,23 @@ namespace MWWorld
} }
} }
template <class T, class = std::void_t<>>
struct HasRecordId : std::false_type
{
};
template <class T>
struct HasRecordId<T, std::void_t<decltype(T::sRecordId)>> : std::true_type
{
};
template <typename T> template <typename T>
static void typedReadRecordESM4(ESM4::Reader& reader, ESMStore& stores, Store<T>& store, int& found) static void typedReadRecordESM4(ESM4::Reader& reader, ESMStore& stores, Store<T>& store, int& found)
{ {
auto recordType = static_cast<ESM4::RecordTypes>(reader.hdr().record.typeId); auto recordType = static_cast<ESM4::RecordTypes>(reader.hdr().record.typeId);
ESM::RecNameInts esm4RecName = static_cast<ESM::RecNameInts>(ESM::esm4Recname(recordType)); ESM::RecNameInts esm4RecName = static_cast<ESM::RecNameInts>(ESM::esm4Recname(recordType));
if constexpr (std::is_convertible_v<Store<T>*, DynamicStore*>) if constexpr (std::is_convertible_v<Store<T>*, DynamicStore*> && HasRecordId<T>::value)
{ {
if constexpr (ESM::isESM4Rec(T::sRecordId)) 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; int found = 0;
std::apply([&reader, &store, &found]( std::apply([&reader, &store, &found](
auto&... x) { (ESMStoreImp::typedReadRecordESM4(reader, store, x, found), ...); }, auto&... x) { (ESMStoreImp::typedReadRecordESM4(reader, store, x, found), ...); },
store.mStoreImp->mStores); store.mStoreImp->mStores);
assert(found <= 1); assert(found <= 1);
if (found == 0) // unhandled record return found;
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<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(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;
} }
}; };
@ -423,12 +387,8 @@ namespace MWWorld
void ESMStore::loadESM4(ESM4::Reader& reader, Loading::Listener* listener, ESM::Dialogue*& dialogue) void ESMStore::loadESM4(ESM4::Reader& reader, Loading::Listener* listener, ESM::Dialogue*& dialogue)
{ {
while (reader.hasMoreRecs()) auto visitorRec = [this](ESM4::Reader& reader) { return ESMStoreImp::readRecord(reader, *this); };
{ ESM4::ReaderUtils::readAll(reader, visitorRec, [](ESM4::Reader&) {});
reader.exitGroupCheck();
if (!ESMStoreImp::readItem(reader, *this))
break;
}
} }
void ESMStore::setIdType(const ESM::RefId& id, ESM::RecNameInts type) void ESMStore::setIdType(const ESM::RefId& id, ESM::RecNameInts type)

View file

@ -1,21 +1,18 @@
#include "store.hpp" #include "store.hpp"
#include <components/debug/debuglog.hpp>
#include <components/esm/records.hpp>
#include <components/esm3/esmreader.hpp>
#include <components/esm3/esmwriter.hpp>
#include <components/loadinglistener/loadinglistener.hpp>
#include <components/misc/rng.hpp>
#include <iterator> #include <iterator>
#include <sstream> #include <sstream>
#include <stdexcept> #include <stdexcept>
#include <components/debug/debuglog.hpp>
#include <components/esm/records.hpp>
#include <components/esm3/esmreader.hpp>
#include <components/esm3/esmwriter.hpp>
#include <components/esm4/loadcell.hpp> #include <components/esm4/loadcell.hpp>
#include <components/esm4/loadrefr.hpp> #include <components/esm4/loadrefr.hpp>
#include <components/esm4/loadstat.hpp> #include <components/esm4/loadstat.hpp>
#include <components/loadinglistener/loadinglistener.hpp>
#include <components/misc/rng.hpp>
namespace namespace
{ {

View file

@ -4,6 +4,7 @@ project (Components)
set(VERSION_IN_FILE "${OpenMW_SOURCE_DIR}/files/version.in") set(VERSION_IN_FILE "${OpenMW_SOURCE_DIR}/files/version.in")
set(VERSION_FILE_PATH_BASE "${OpenMW_BINARY_DIR}") set(VERSION_FILE_PATH_BASE "${OpenMW_BINARY_DIR}")
set(VERSION_FILE_PATH_RELATIVE resources/version) set(VERSION_FILE_PATH_RELATIVE resources/version)
if(GIT_CHECKOUT) if(GIT_CHECKOUT)
get_generator_is_multi_config(multi_config) get_generator_is_multi_config(multi_config)
add_custom_target(git-version add_custom_target(git-version
@ -27,7 +28,6 @@ else (GIT_CHECKOUT)
endif(GIT_CHECKOUT) endif(GIT_CHECKOUT)
# source files # source files
add_component_dir(lua add_component_dir(lua
luastate scriptscontainer utilpackage serialization configuration l10n storage luastate scriptscontainer utilpackage serialization configuration l10n storage
) )
@ -191,6 +191,7 @@ add_component_dir (esm4
loadweap loadweap
loadwrld loadwrld
reader reader
readerutils
reference reference
script script
) )
@ -212,6 +213,7 @@ IF(NOT WIN32 AND NOT APPLE)
add_definitions(-DGLOBAL_DATA_PATH="${GLOBAL_DATA_PATH}") add_definitions(-DGLOBAL_DATA_PATH="${GLOBAL_DATA_PATH}")
add_definitions(-DGLOBAL_CONFIG_PATH="${GLOBAL_CONFIG_PATH}") add_definitions(-DGLOBAL_CONFIG_PATH="${GLOBAL_CONFIG_PATH}")
ENDIF() ENDIF()
add_component_dir(files add_component_dir(files
linuxpath androidpath windowspath macospath fixedpath multidircollection collections configurationmanager linuxpath androidpath windowspath macospath fixedpath multidircollection collections configurationmanager
constrainedfilestream memorystream hash configfileparser openfile constrainedfilestreambuf conversion constrainedfilestream memorystream hash configfileparser openfile constrainedfilestreambuf conversion
@ -272,7 +274,6 @@ add_component_dir (lua_ui
adapter text textedit window image container flex adapter text textedit window image container flex
) )
if(WIN32) if(WIN32)
add_component_dir(crashcatcher add_component_dir(crashcatcher
windows_crashcatcher windows_crashcatcher
@ -464,6 +465,7 @@ if (OSG_STATIC AND CMAKE_SYSTEM_NAME MATCHES "Linux")
find_package(X11 REQUIRED COMPONENTS Xinerama Xrandr) find_package(X11 REQUIRED COMPONENTS Xinerama Xrandr)
target_link_libraries(components ${CMAKE_DL_LIBS} X11::X11 X11::Xinerama X11::Xrandr) target_link_libraries(components ${CMAKE_DL_LIBS} X11::X11 X11::Xinerama X11::Xrandr)
find_package(Fontconfig MODULE) find_package(Fontconfig MODULE)
if(Fontconfig_FOUND) if(Fontconfig_FOUND)
target_link_libraries(components Fontconfig::Fontconfig) target_link_libraries(components Fontconfig::Fontconfig)
endif() endif()
@ -483,7 +485,6 @@ if (BUILD_WITH_CODE_COVERAGE)
target_link_libraries(components gcov) target_link_libraries(components gcov)
endif() endif()
# Make the variable accessible for other subdirectories # Make the variable accessible for other subdirectories
set(COMPONENT_FILES ${COMPONENT_FILES} PARENT_SCOPE) set(COMPONENT_FILES ${COMPONENT_FILES} PARENT_SCOPE)
@ -492,8 +493,10 @@ target_compile_definitions(components PUBLIC BT_USE_DOUBLE_PRECISION)
if(OSG_STATIC) if(OSG_STATIC)
unset(_osg_plugins_static_files) unset(_osg_plugins_static_files)
add_library(components_osg_plugins INTERFACE) add_library(components_osg_plugins INTERFACE)
foreach(_plugin ${USED_OSG_PLUGINS}) foreach(_plugin ${USED_OSG_PLUGINS})
string(TOUPPER ${_plugin} _plugin_uc) string(TOUPPER ${_plugin} _plugin_uc)
if(OPENMW_USE_SYSTEM_OSG) if(OPENMW_USE_SYSTEM_OSG)
list(APPEND _osg_plugins_static_files ${${_plugin_uc}_LIBRARY}) list(APPEND _osg_plugins_static_files ${${_plugin_uc}_LIBRARY})
else() else()
@ -502,6 +505,7 @@ if(OSG_STATIC)
add_dependencies(components_osg_plugins ${${_plugin_uc}_LIBRARY}) add_dependencies(components_osg_plugins ${${_plugin_uc}_LIBRARY})
endif() endif()
endforeach() endforeach()
# We use --whole-archive because OSG plugins use registration. # We use --whole-archive because OSG plugins use registration.
get_whole_archive_options(_opts ${_osg_plugins_static_files}) get_whole_archive_options(_opts ${_osg_plugins_static_files})
target_link_options(components_osg_plugins INTERFACE ${_opts}) target_link_options(components_osg_plugins INTERFACE ${_opts})

View file

@ -1,12 +1,13 @@
#ifndef OPENMW_COMPONENTS_ESM_REFID_HPP #ifndef OPENMW_COMPONENTS_ESM_REFID_HPP
#define OPENMW_COMPONENTS_ESM_REFID_HPP #define OPENMW_COMPONENTS_ESM_REFID_HPP
#include <compare> #include <compare>
#include <components/esm4/formid.hpp>
#include <functional> #include <functional>
#include <iosfwd> #include <iosfwd>
#include <string> #include <string>
#include <string_view> #include <string_view>
#include <components/esm4/formid.hpp>
namespace ESM namespace ESM
{ {
struct RefId struct RefId

View file

@ -32,11 +32,11 @@
#include <cassert> #include <cassert>
#include <cfloat> // FLT_MAX for gcc #include <cfloat> // FLT_MAX for gcc
#include <iostream> // FIXME: debug only
#include <stdexcept> #include <stdexcept>
#include <iostream> // FIXME: debug only
#include "reader.hpp" #include "reader.hpp"
#include <components/esm/refid.hpp> #include <components/esm/refid.hpp>
// #include "writer.hpp" // #include "writer.hpp"

View file

@ -33,6 +33,7 @@
#include "formid.hpp" #include "formid.hpp"
#include "lighting.hpp" #include "lighting.hpp"
#include <components/esm/defs.hpp> #include <components/esm/defs.hpp>
#include <components/esm/refid.hpp> #include <components/esm/refid.hpp>

View file

@ -30,6 +30,7 @@
#include <cstdint> #include <cstdint>
#include "reference.hpp" // FormId, Placement, EnableParent #include "reference.hpp" // FormId, Placement, EnableParent
#include <components/esm/defs.hpp> #include <components/esm/defs.hpp>
#include <components/esm/refid.hpp> #include <components/esm/refid.hpp>

View file

@ -32,6 +32,7 @@
#include <vector> #include <vector>
#include "formid.hpp" #include "formid.hpp"
#include <components/esm/defs.hpp> #include <components/esm/defs.hpp>
#include <components/esm/refid.hpp> #include <components/esm/refid.hpp>

View file

@ -0,0 +1,84 @@
#ifndef OPENMW_COMPONENTS_ESM4_READERUTILS
#define OPENMW_COMPONENTS_ESM4_READERUTILS
#include <components/esm4/reader.hpp>
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 <typename RecordInvocable, typename GroupInvocable>
static void readAll(ESM4::Reader& reader, RecordInvocable&& recordInvocable, GroupInvocable&& groupInvocable)
{
while (reader.hasMoreRecs())
{
reader.exitGroupCheck();
if (!readItem(reader, recordInvocable, groupInvocable))
break;
}
}
template <typename RecordInvocable>
static void readRecord(ESM4::Reader& reader, RecordInvocable&& recordInvocable)
{
if (!recordInvocable(reader))
reader.skipRecordData();
}
template <typename RecordInvocable, typename GroupInvocable>
static bool readGroup(ESM4::Reader& reader, RecordInvocable&& recordInvocable, GroupInvocable&& groupInvocable)
{
const ESM4::RecordHeader& header = reader.hdr();
groupInvocable(reader);
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(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 <typename RecordInvocable, typename GroupInvocable>
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

View file

@ -68,7 +68,7 @@ namespace ToUTF8
/// ASCII-only string. Otherwise returns a view to the input. /// ASCII-only string. Otherwise returns a view to the input.
std::string_view getLegacyEnc(std::string_view input); std::string_view getLegacyEnc(std::string_view input);
const StatelessUtf8Encoder* getStatelessEncoder() const { return &mImpl; } const StatelessUtf8Encoder getStatelessEncoder() const { return mImpl; }
private: private:
std::string mBuffer; std::string mBuffer;