From ab6eae3d1c3a10be458e849422e8c221bf0f2560 Mon Sep 17 00:00:00 2001 From: William Miles Date: Mon, 24 Oct 2022 15:49:07 +1100 Subject: [PATCH] Implemented LUT codegen, untested. --- Navmesher/esx_reader.hpp | 41 +- Navmesher/esx_reader_lut.cpp | 880 +++++++++++++++++-------- Navmesher/utility.hpp | 70 +- reference/esx_reader.hpp.fragment | 19 + reference/esx_reader_lut.cpp | 614 +++++++++++++++++ reference/group_type.json | 42 ++ reference/record_codegen.py | 179 +++++ reference/record_filter.py | 7 +- reference/{flags.json => records.json} | 307 +++++---- reference/refr_flag_filter.py | 90 +++ reference/refr_flags.json | 805 ++++++++++++++++++++++ 11 files changed, 2573 insertions(+), 481 deletions(-) create mode 100644 reference/esx_reader.hpp.fragment create mode 100644 reference/esx_reader_lut.cpp create mode 100644 reference/group_type.json create mode 100644 reference/record_codegen.py rename reference/{flags.json => records.json} (85%) create mode 100644 reference/refr_flag_filter.py create mode 100644 reference/refr_flags.json diff --git a/Navmesher/esx_reader.hpp b/Navmesher/esx_reader.hpp index 5db8e67..102993b 100644 --- a/Navmesher/esx_reader.hpp +++ b/Navmesher/esx_reader.hpp @@ -38,14 +38,18 @@ enum class GroupType : int32_t { }; enum class RecordType { - None, - AACT, ACHR, ACTI, ADDN, ALCH, AMMO, ANIO, APPA, ARMA, ARMO, ARTO, ASPC, ASTP, AVIF, BOOK, BPTD, CAMS, CELL, CLAS, CLDC, CLFM, - CLMT, COBJ, COLL, CONT, CPTH, CSTY, DEBR, DIAL, DLBR, DLVW, DOBJ, DOOR, DUAL, ECZN, EFSH, ENCH, EQUP, EXPL, EYES, FACT, FLOR, - FLST, FSTP, FSTS, FURN, GLOB, GMST, GRAS, GRUP, HAIR, HAZD, HDPT, IDLE, IDLM, IMAD, IMGS, INFO, INGR, IPCT, IPDS, KEYM, KYWD, - LAND, LCRT, LCTN, LENS, LGTM, LIGH, LSCR, LTEX, LVLI, LVLN, LVSP, MATO, MATT, MESG, MGEF, MISC, MOVT, MSTT, MUSC, MUST, NAVI, - NAVM, NOTE, NPC_, OTFT, PACK, PARW, PBAR, PBEA, PCON, PERK, PFLA, PGRE, PHZD, PLYR, PMIS, PROJ, PWAT, QUST, RACE, REFR, REGN, - RELA, REVB, RFCT, RGDL, SCEN, SCOL, SCOL, SCPT, SCRL, SHOU, SLGM, SMBN, SMEN, SMQN, SNCT, SNDR, SOPM, SOUN, SPEL, SPGD, STAT, - TACT, TES4, TREE, TXST, VOLI, VTYP, WATR, WEAP, WOOP, WRLD, WTHR + AACT, ACHR, ACTI, ADDN, ALCH, AMMO, ANIO, APPA, ARMA, ARMO, ARTO, ASPC, + ASTP, AVIF, BOOK, BPTD, CAMS, CELL, CLAS, CLDC, CLFM, CLMT, COBJ, COLL, + CONT, CPTH, CSTY, DEBR, DIAL, DLBR, DLVW, DOBJ, DOOR, DUAL, ECZN, EFSH, + ENCH, EQUP, EXPL, EYES, FACT, FLOR, FLST, FSTP, FSTS, FURN, GLOB, GMST, + GRAS, GRUP, HAIR, HAZD, HDPT, IDLE, IDLM, IMAD, IMGS, INFO, INGR, IPCT, + IPDS, KEYM, KYWD, LAND, LCRT, LCTN, LENS, LGTM, LIGH, LSCR, LTEX, LVLI, + LVLN, LVSP, MATO, MATT, MESG, MGEF, MISC, MOVT, MSTT, MUSC, MUST, NAVI, + NAVM, NOTE, NPC_, OTFT, PACK, PARW, PBAR, PBEA, PCON, PERK, PFLA, PGRE, + PHZD, PLYR, PMIS, PROJ, PWAT, QUST, RACE, REFR, REGN, RELA, REVB, RFCT, + RGDL, SCEN, SCOL, SCPT, SCRL, SHOU, SLGM, SMBN, SMEN, SMQN, SNCT, SNDR, + SOPM, SOUN, SPEL, SPGD, STAT, TACT, TES4, TREE, TXST, VOLI, VTYP, WATR, + WEAP, WOOP, WRLD, WTHR, }; // @@ -58,9 +62,9 @@ using Node = std::variant; // Aggregate types // -struct FourCC : utility::Store> { +struct FourCC : utility::Store { constexpr FourCC() noexcept = default; - explicit constexpr FourCC(const char (&str)[5]) noexcept : Store{ utility::literal_to_array(str) } { } + explicit constexpr FourCC(const char (&str)[5]) noexcept : Store{ utility::fourcc_lit_to_val(str) } { } }; static_assert(std::is_trivial_v); @@ -68,6 +72,16 @@ struct FormID : utility::Store { }; struct Timestamp : utility::Store { }; struct VCInfo : utility::Store { }; +struct Flag { + RecordType type; + unsigned bit; +}; + +struct RefrFlag { + RecordType refr_type; + unsigned bit; +}; + struct GroupHeader { struct Coord { int16_t y, x; @@ -138,5 +152,12 @@ private: // Free functions // +[[nodiscard]] constexpr std::optional esxr_lut::group_type_to_name(GroupType group_type) noexcept; +[[nodiscard]] constexpr std::optional esxr_lut::record_type_to_fourcc(RecordType record_type) noexcept; +[[nodiscard]] constexpr std::optional esxr_lut::fourcc_to_record_type(FourCC fourcc) noexcept; +[[nodiscard]] constexpr std::optional esxr_lut::record_type_to_name(RecordType record_type) noexcept; +[[nodiscard]] constexpr std::optional esxr_lut::flag_to_description(Flag flag) noexcept; +[[nodiscard]] constexpr std::optional esxr_lut::refr_flag_to_description(RefrFlag refr_flag) noexcept; + } #endif diff --git a/Navmesher/esx_reader_lut.cpp b/Navmesher/esx_reader_lut.cpp index ef78d85..373ad7c 100644 --- a/Navmesher/esx_reader_lut.cpp +++ b/Navmesher/esx_reader_lut.cpp @@ -4,287 +4,7 @@ using namespace esxr; namespace esxr_lut { -static constexpr std::pair record_type_name_map[] = { - {RecordType::AACT, "Action"}, - {RecordType::ACHR, "Placed NPC"}, - {RecordType::ACTI, "Activator"}, - {RecordType::ADDN, "Addon Node"}, - {RecordType::ALCH, "Ingestible"}, - {RecordType::AMMO, "Ammunition"}, - {RecordType::ANIO, "Animated Object"}, - {RecordType::APPA, "Alchemical Apparatus"}, - {RecordType::ARMA, "Armor Addon"}, - {RecordType::ARMO, "Armor"}, - {RecordType::ARTO, "Art Object"}, - {RecordType::ASPC, "Acoustic Space"}, - {RecordType::ASTP, "Association Type"}, - {RecordType::AVIF, "Actor Value Information"}, - {RecordType::BOOK, "Book"}, - {RecordType::BPTD, "Body Part Data"}, - {RecordType::CAMS, "Camera Shot"}, - {RecordType::CELL, "Cell"}, - {RecordType::CLAS, "Class"}, - {RecordType::CLDC, "CLDC"}, - {RecordType::CLFM, "Color"}, - {RecordType::CLMT, "Climate"}, - {RecordType::COBJ, "Constructible Object"}, - {RecordType::COLL, "Collision Layer"}, - {RecordType::CONT, "Container"}, - {RecordType::CPTH, "Camera Path"}, - {RecordType::CSTY, "Combat Style"}, - {RecordType::DEBR, "Debris"}, - {RecordType::DIAL, "Dialog Topic"}, - {RecordType::DLBR, "Dialog Branch"}, - {RecordType::DLVW, "Dialog View"}, - {RecordType::DOBJ, "Default Object Manager"}, - {RecordType::DOOR, "Door"}, - {RecordType::DUAL, "Dual Cast Data"}, - {RecordType::ECZN, "Encounter Zone"}, - {RecordType::EFSH, "Effect Shader"}, - {RecordType::ENCH, "Object Effect"}, - {RecordType::EQUP, "Equip Type"}, - {RecordType::EXPL, "Explosion"}, - {RecordType::EYES, "Eyes"}, - {RecordType::FACT, "Faction"}, - {RecordType::FLOR, "Flora"}, - {RecordType::FLST, "FormID List"}, - {RecordType::FSTP, "Footstep"}, - {RecordType::FSTS, "Footstep Set"}, - {RecordType::FURN, "Furniture"}, - {RecordType::GLOB, "Global"}, - {RecordType::GMST, "Game Setting"}, - {RecordType::GRAS, "Grass"}, - {RecordType::GRUP, "Internal File Structure Group"}, - {RecordType::HAIR, "HAIR"}, - {RecordType::HAZD, "Hazard"}, - {RecordType::HDPT, "Head Part"}, - {RecordType::IDLE, "Idle Animation"}, - {RecordType::IDLM, "Idle Marker"}, - {RecordType::IMAD, "Image Space Adapter"}, - {RecordType::IMGS, "Image Space"}, - {RecordType::INFO, "Dialog response"}, - {RecordType::INGR, "Ingredient"}, - {RecordType::IPCT, "Impact"}, - {RecordType::IPDS, "Impact Data Set"}, - {RecordType::KEYM, "Key"}, - {RecordType::KYWD, "Keyword"}, - {RecordType::LAND, "Landscape"}, - {RecordType::LCRT, "Location Reference Type"}, - {RecordType::LCTN, "Location"}, - {RecordType::LENS, "Lens Flare"}, - {RecordType::LGTM, "Lighting Template"}, - {RecordType::LIGH, "Light"}, - {RecordType::LSCR, "Load Screen"}, - {RecordType::LTEX, "Landscape Texture"}, - {RecordType::LVLI, "Leveled Item"}, - {RecordType::LVLN, "Leveled NPC"}, - {RecordType::LVSP, "Leveled Spell"}, - {RecordType::MATO, "Material Object"}, - {RecordType::MATT, "Material Type"}, - {RecordType::MESG, "Message"}, - {RecordType::MGEF, "Magic Effect"}, - {RecordType::MISC, "Misc.Item"}, - {RecordType::MOVT, "Movement Type"}, - {RecordType::MSTT, "Moveable Static"}, - {RecordType::MUSC, "Music Type"}, - {RecordType::MUST, "Music Track"}, - {RecordType::NAVI, "Navigation Mesh Info Map"}, - {RecordType::NAVM, "Navigation Mesh"}, - {RecordType::NOTE, "NOTE"}, - {RecordType::NPC_, "Non - Player Character(Actor)"}, - {RecordType::OTFT, "Outfit"}, - {RecordType::PACK, "Package"}, - {RecordType::PARW, "Placed Arrow"}, - {RecordType::PBAR, "Placed Barrier"}, - {RecordType::PBEA, "Placed Beam"}, - {RecordType::PCON, "Placed Cone / Voice"}, - {RecordType::PERK, "Perk"}, - {RecordType::PFLA, "Placed Flame"}, - {RecordType::PGRE, "Placed Projectile"}, - {RecordType::PHZD, "Placed Hazard"}, - {RecordType::PLYR, "Player Reference"}, - {RecordType::PMIS, "Placed Missile"}, - {RecordType::PROJ, "Projectile"}, - {RecordType::PWAT, "PWAT"}, - {RecordType::QUST, "Quest"}, - {RecordType::RACE, "Race"}, - {RecordType::REFR, "Placed Object"}, - {RecordType::REGN, "Region"}, - {RecordType::RELA, "Relationship"}, - {RecordType::REVB, "Reverb Parameters"}, - {RecordType::RFCT, "Visual Effect"}, - {RecordType::RGDL, "RGDL"}, - {RecordType::SCEN, "Scene"}, - {RecordType::SCOL, "SCOL"}, - {RecordType::SCOL, "Static Collection"}, - {RecordType::SCPT, "SCPT"}, - {RecordType::SCRL, "Scroll"}, - {RecordType::SHOU, "Shout"}, - {RecordType::SLGM, "Soul Gem"}, - {RecordType::SMBN, "Story Manager Branch Node"}, - {RecordType::SMEN, "Story Manager Event Node"}, - {RecordType::SMQN, "Story Manager Quest Node"}, - {RecordType::SNCT, "Sound Category"}, - {RecordType::SNDR, "Sound Descriptor"}, - {RecordType::SOPM, "Sound Output Model"}, - {RecordType::SOUN, "Sound Marker"}, - {RecordType::SPEL, "Spell"}, - {RecordType::SPGD, "Shader Particle Geometry"}, - {RecordType::STAT, "Static"}, - {RecordType::TACT, "Talking Activator"}, - {RecordType::TES4, "Main File Header"}, - {RecordType::TREE, "Tree"}, - {RecordType::TXST, "Texture Set"}, - {RecordType::VOLI, "Volumetric Lighting"}, - {RecordType::VTYP, "Voice Type"}, - {RecordType::WATR, "Water"}, - {RecordType::WEAP, "Weapon"}, - {RecordType::WOOP, "Word of Power"}, - {RecordType::WRLD, "Worldspace"}, - {RecordType::WTHR, "Weather"} -}; - -static constexpr std::pair record_type_fourcc_map[] = { - {RecordType::AACT, FourCC("AACT")}, - {RecordType::ACHR, FourCC("ACHR")}, - {RecordType::ACTI, FourCC("ACTI")}, - {RecordType::ADDN, FourCC("ADDN")}, - {RecordType::ALCH, FourCC("ALCH")}, - {RecordType::AMMO, FourCC("AMMO")}, - {RecordType::ANIO, FourCC("ANIO")}, - {RecordType::APPA, FourCC("APPA")}, - {RecordType::ARMA, FourCC("ARMA")}, - {RecordType::ARMO, FourCC("ARMO")}, - {RecordType::ARTO, FourCC("ARTO")}, - {RecordType::ASPC, FourCC("ASPC")}, - {RecordType::ASTP, FourCC("ASTP")}, - {RecordType::AVIF, FourCC("AVIF")}, - {RecordType::BOOK, FourCC("BOOK")}, - {RecordType::BPTD, FourCC("BPTD")}, - {RecordType::CAMS, FourCC("CAMS")}, - {RecordType::CELL, FourCC("CELL")}, - {RecordType::CLAS, FourCC("CLAS")}, - {RecordType::CLDC, FourCC("CLDC")}, - {RecordType::CLFM, FourCC("CLFM")}, - {RecordType::CLMT, FourCC("CLMT")}, - {RecordType::COBJ, FourCC("COBJ")}, - {RecordType::COLL, FourCC("COLL")}, - {RecordType::CONT, FourCC("CONT")}, - {RecordType::CPTH, FourCC("CPTH")}, - {RecordType::CSTY, FourCC("CSTY")}, - {RecordType::DEBR, FourCC("DEBR")}, - {RecordType::DIAL, FourCC("DIAL")}, - {RecordType::DLBR, FourCC("DLBR")}, - {RecordType::DLVW, FourCC("DLVW")}, - {RecordType::DOBJ, FourCC("DOBJ")}, - {RecordType::DOOR, FourCC("DOOR")}, - {RecordType::DUAL, FourCC("DUAL")}, - {RecordType::ECZN, FourCC("ECZN")}, - {RecordType::EFSH, FourCC("EFSH")}, - {RecordType::ENCH, FourCC("ENCH")}, - {RecordType::EQUP, FourCC("EQUP")}, - {RecordType::EXPL, FourCC("EXPL")}, - {RecordType::EYES, FourCC("EYES")}, - {RecordType::FACT, FourCC("FACT")}, - {RecordType::FLOR, FourCC("FLOR")}, - {RecordType::FLST, FourCC("FLST")}, - {RecordType::FSTP, FourCC("FSTP")}, - {RecordType::FSTS, FourCC("FSTS")}, - {RecordType::FURN, FourCC("FURN")}, - {RecordType::GLOB, FourCC("GLOB")}, - {RecordType::GMST, FourCC("GMST")}, - {RecordType::GRAS, FourCC("GRAS")}, - {RecordType::GRUP, FourCC("GRUP")}, - {RecordType::HAIR, FourCC("HAIR")}, - {RecordType::HAZD, FourCC("HAZD")}, - {RecordType::HDPT, FourCC("HDPT")}, - {RecordType::IDLE, FourCC("IDLE")}, - {RecordType::IDLM, FourCC("IDLM")}, - {RecordType::IMAD, FourCC("IMAD")}, - {RecordType::IMGS, FourCC("IMGS")}, - {RecordType::INFO, FourCC("INFO")}, - {RecordType::INGR, FourCC("INGR")}, - {RecordType::IPCT, FourCC("IPCT")}, - {RecordType::IPDS, FourCC("IPDS")}, - {RecordType::KEYM, FourCC("KEYM")}, - {RecordType::KYWD, FourCC("KYWD")}, - {RecordType::LAND, FourCC("LAND")}, - {RecordType::LCRT, FourCC("LCRT")}, - {RecordType::LCTN, FourCC("LCTN")}, - {RecordType::LENS, FourCC("LENS")}, - {RecordType::LGTM, FourCC("LGTM")}, - {RecordType::LIGH, FourCC("LIGH")}, - {RecordType::LSCR, FourCC("LSCR")}, - {RecordType::LTEX, FourCC("LTEX")}, - {RecordType::LVLI, FourCC("LVLI")}, - {RecordType::LVLN, FourCC("LVLN")}, - {RecordType::LVSP, FourCC("LVSP")}, - {RecordType::MATO, FourCC("MATO")}, - {RecordType::MATT, FourCC("MATT")}, - {RecordType::MESG, FourCC("MESG")}, - {RecordType::MGEF, FourCC("MGEF")}, - {RecordType::MISC, FourCC("MISC")}, - {RecordType::MOVT, FourCC("MOVT")}, - {RecordType::MSTT, FourCC("MSTT")}, - {RecordType::MUSC, FourCC("MUSC")}, - {RecordType::MUST, FourCC("MUST")}, - {RecordType::NAVI, FourCC("NAVI")}, - {RecordType::NAVM, FourCC("NAVM")}, - {RecordType::NOTE, FourCC("NOTE")}, - {RecordType::NPC_, FourCC("NPC_")}, - {RecordType::OTFT, FourCC("OTFT")}, - {RecordType::PACK, FourCC("PACK")}, - {RecordType::PARW, FourCC("PARW")}, - {RecordType::PBAR, FourCC("PBAR")}, - {RecordType::PBEA, FourCC("PBEA")}, - {RecordType::PCON, FourCC("PCON")}, - {RecordType::PERK, FourCC("PERK")}, - {RecordType::PFLA, FourCC("PFLA")}, - {RecordType::PGRE, FourCC("PGRE")}, - {RecordType::PHZD, FourCC("PHZD")}, - {RecordType::PLYR, FourCC("PLYR")}, - {RecordType::PMIS, FourCC("PMIS")}, - {RecordType::PROJ, FourCC("PROJ")}, - {RecordType::PWAT, FourCC("PWAT")}, - {RecordType::QUST, FourCC("QUST")}, - {RecordType::RACE, FourCC("RACE")}, - {RecordType::REFR, FourCC("REFR")}, - {RecordType::REGN, FourCC("REGN")}, - {RecordType::RELA, FourCC("RELA")}, - {RecordType::REVB, FourCC("REVB")}, - {RecordType::RFCT, FourCC("RFCT")}, - {RecordType::RGDL, FourCC("RGDL")}, - {RecordType::SCEN, FourCC("SCEN")}, - {RecordType::SCOL, FourCC("SCOL")}, - {RecordType::SCOL, FourCC("SCOL")}, - {RecordType::SCPT, FourCC("SCPT")}, - {RecordType::SCRL, FourCC("SCRL")}, - {RecordType::SHOU, FourCC("SHOU")}, - {RecordType::SLGM, FourCC("SLGM")}, - {RecordType::SMBN, FourCC("SMBN")}, - {RecordType::SMEN, FourCC("SMEN")}, - {RecordType::SMQN, FourCC("SMQN")}, - {RecordType::SNCT, FourCC("SNCT")}, - {RecordType::SNDR, FourCC("SNDR")}, - {RecordType::SOPM, FourCC("SOPM")}, - {RecordType::SOUN, FourCC("SOUN")}, - {RecordType::SPEL, FourCC("SPEL")}, - {RecordType::SPGD, FourCC("SPGD")}, - {RecordType::STAT, FourCC("STAT")}, - {RecordType::TACT, FourCC("TACT")}, - {RecordType::TES4, FourCC("TES4")}, - {RecordType::TREE, FourCC("TREE")}, - {RecordType::TXST, FourCC("TXST")}, - {RecordType::VOLI, FourCC("VOLI")}, - {RecordType::VTYP, FourCC("VTYP")}, - {RecordType::WATR, FourCC("WATR")}, - {RecordType::WEAP, FourCC("WEAP")}, - {RecordType::WOOP, FourCC("WOOP")}, - {RecordType::WRLD, FourCC("WRLD")}, - {RecordType::WTHR, FourCC("WTHR")}, -}; - -static constexpr std::pair group_type_names_map[] = { +static constexpr std::pair group_type_name_map_builtin[] { {GroupType::Top , "Top Type" }, {GroupType::WorldChildren , "World Children" }, {GroupType::InteriorCellBlock , "Interior Cell Block" }, @@ -294,25 +14,601 @@ static constexpr std::pair group_type_names_map[] = {GroupType::CellChildren , "Cell Children" }, {GroupType::TopicChildren , "Topic Children" }, {GroupType::CellPersistentChildren, "Cell Persistent Children"}, - {GroupType::CellTemporaryChildren , "Cell Temporary Children" }, + {GroupType::CellTemporaryChildren , "Cell Temporary Children" }, }; +static constexpr auto group_type_name_map_std = utility::array_builtin_to_std(group_type_name_map_builtin); +static constexpr auto group_type_name_map = utility::map_to_soa(group_type_name_map_std); +[[nodiscard]] constexpr std::optional group_type_to_name(GroupType group_type) noexcept +{ + return utility::soa_first_to_second(group_type_name_map, group_type); +} -struct flag { - RecordType type; - unsigned bit; +static constexpr std::pair record_type_fourcc_map_builtin[] { + {RecordType::AACT, FourCC("AACT")}, {RecordType::ACHR, FourCC("ACHR")}, + {RecordType::ACTI, FourCC("ACTI")}, {RecordType::ADDN, FourCC("ADDN")}, + {RecordType::ALCH, FourCC("ALCH")}, {RecordType::AMMO, FourCC("AMMO")}, + {RecordType::ANIO, FourCC("ANIO")}, {RecordType::APPA, FourCC("APPA")}, + {RecordType::ARMA, FourCC("ARMA")}, {RecordType::ARMO, FourCC("ARMO")}, + {RecordType::ARTO, FourCC("ARTO")}, {RecordType::ASPC, FourCC("ASPC")}, + {RecordType::ASTP, FourCC("ASTP")}, {RecordType::AVIF, FourCC("AVIF")}, + {RecordType::BOOK, FourCC("BOOK")}, {RecordType::BPTD, FourCC("BPTD")}, + {RecordType::CAMS, FourCC("CAMS")}, {RecordType::CELL, FourCC("CELL")}, + {RecordType::CLAS, FourCC("CLAS")}, {RecordType::CLDC, FourCC("CLDC")}, + {RecordType::CLFM, FourCC("CLFM")}, {RecordType::CLMT, FourCC("CLMT")}, + {RecordType::COBJ, FourCC("COBJ")}, {RecordType::COLL, FourCC("COLL")}, + {RecordType::CONT, FourCC("CONT")}, {RecordType::CPTH, FourCC("CPTH")}, + {RecordType::CSTY, FourCC("CSTY")}, {RecordType::DEBR, FourCC("DEBR")}, + {RecordType::DIAL, FourCC("DIAL")}, {RecordType::DLBR, FourCC("DLBR")}, + {RecordType::DLVW, FourCC("DLVW")}, {RecordType::DOBJ, FourCC("DOBJ")}, + {RecordType::DOOR, FourCC("DOOR")}, {RecordType::DUAL, FourCC("DUAL")}, + {RecordType::ECZN, FourCC("ECZN")}, {RecordType::EFSH, FourCC("EFSH")}, + {RecordType::ENCH, FourCC("ENCH")}, {RecordType::EQUP, FourCC("EQUP")}, + {RecordType::EXPL, FourCC("EXPL")}, {RecordType::EYES, FourCC("EYES")}, + {RecordType::FACT, FourCC("FACT")}, {RecordType::FLOR, FourCC("FLOR")}, + {RecordType::FLST, FourCC("FLST")}, {RecordType::FSTP, FourCC("FSTP")}, + {RecordType::FSTS, FourCC("FSTS")}, {RecordType::FURN, FourCC("FURN")}, + {RecordType::GLOB, FourCC("GLOB")}, {RecordType::GMST, FourCC("GMST")}, + {RecordType::GRAS, FourCC("GRAS")}, {RecordType::GRUP, FourCC("GRUP")}, + {RecordType::HAIR, FourCC("HAIR")}, {RecordType::HAZD, FourCC("HAZD")}, + {RecordType::HDPT, FourCC("HDPT")}, {RecordType::IDLE, FourCC("IDLE")}, + {RecordType::IDLM, FourCC("IDLM")}, {RecordType::IMAD, FourCC("IMAD")}, + {RecordType::IMGS, FourCC("IMGS")}, {RecordType::INFO, FourCC("INFO")}, + {RecordType::INGR, FourCC("INGR")}, {RecordType::IPCT, FourCC("IPCT")}, + {RecordType::IPDS, FourCC("IPDS")}, {RecordType::KEYM, FourCC("KEYM")}, + {RecordType::KYWD, FourCC("KYWD")}, {RecordType::LAND, FourCC("LAND")}, + {RecordType::LCRT, FourCC("LCRT")}, {RecordType::LCTN, FourCC("LCTN")}, + {RecordType::LENS, FourCC("LENS")}, {RecordType::LGTM, FourCC("LGTM")}, + {RecordType::LIGH, FourCC("LIGH")}, {RecordType::LSCR, FourCC("LSCR")}, + {RecordType::LTEX, FourCC("LTEX")}, {RecordType::LVLI, FourCC("LVLI")}, + {RecordType::LVLN, FourCC("LVLN")}, {RecordType::LVSP, FourCC("LVSP")}, + {RecordType::MATO, FourCC("MATO")}, {RecordType::MATT, FourCC("MATT")}, + {RecordType::MESG, FourCC("MESG")}, {RecordType::MGEF, FourCC("MGEF")}, + {RecordType::MISC, FourCC("MISC")}, {RecordType::MOVT, FourCC("MOVT")}, + {RecordType::MSTT, FourCC("MSTT")}, {RecordType::MUSC, FourCC("MUSC")}, + {RecordType::MUST, FourCC("MUST")}, {RecordType::NAVI, FourCC("NAVI")}, + {RecordType::NAVM, FourCC("NAVM")}, {RecordType::NOTE, FourCC("NOTE")}, + {RecordType::NPC_, FourCC("NPC_")}, {RecordType::OTFT, FourCC("OTFT")}, + {RecordType::PACK, FourCC("PACK")}, {RecordType::PARW, FourCC("PARW")}, + {RecordType::PBAR, FourCC("PBAR")}, {RecordType::PBEA, FourCC("PBEA")}, + {RecordType::PCON, FourCC("PCON")}, {RecordType::PERK, FourCC("PERK")}, + {RecordType::PFLA, FourCC("PFLA")}, {RecordType::PGRE, FourCC("PGRE")}, + {RecordType::PHZD, FourCC("PHZD")}, {RecordType::PLYR, FourCC("PLYR")}, + {RecordType::PMIS, FourCC("PMIS")}, {RecordType::PROJ, FourCC("PROJ")}, + {RecordType::PWAT, FourCC("PWAT")}, {RecordType::QUST, FourCC("QUST")}, + {RecordType::RACE, FourCC("RACE")}, {RecordType::REFR, FourCC("REFR")}, + {RecordType::REGN, FourCC("REGN")}, {RecordType::RELA, FourCC("RELA")}, + {RecordType::REVB, FourCC("REVB")}, {RecordType::RFCT, FourCC("RFCT")}, + {RecordType::RGDL, FourCC("RGDL")}, {RecordType::SCEN, FourCC("SCEN")}, + {RecordType::SCOL, FourCC("SCOL")}, {RecordType::SCPT, FourCC("SCPT")}, + {RecordType::SCRL, FourCC("SCRL")}, {RecordType::SHOU, FourCC("SHOU")}, + {RecordType::SLGM, FourCC("SLGM")}, {RecordType::SMBN, FourCC("SMBN")}, + {RecordType::SMEN, FourCC("SMEN")}, {RecordType::SMQN, FourCC("SMQN")}, + {RecordType::SNCT, FourCC("SNCT")}, {RecordType::SNDR, FourCC("SNDR")}, + {RecordType::SOPM, FourCC("SOPM")}, {RecordType::SOUN, FourCC("SOUN")}, + {RecordType::SPEL, FourCC("SPEL")}, {RecordType::SPGD, FourCC("SPGD")}, + {RecordType::STAT, FourCC("STAT")}, {RecordType::TACT, FourCC("TACT")}, + {RecordType::TES4, FourCC("TES4")}, {RecordType::TREE, FourCC("TREE")}, + {RecordType::TXST, FourCC("TXST")}, {RecordType::VOLI, FourCC("VOLI")}, + {RecordType::VTYP, FourCC("VTYP")}, {RecordType::WATR, FourCC("WATR")}, + {RecordType::WEAP, FourCC("WEAP")}, {RecordType::WOOP, FourCC("WOOP")}, + {RecordType::WRLD, FourCC("WRLD")}, {RecordType::WTHR, FourCC("WTHR")}, }; +static constexpr auto record_type_fourcc_map_std = utility::array_builtin_to_std(record_type_fourcc_map_builtin); +static constexpr auto record_type_fourcc_map = utility::map_to_soa(record_type_fourcc_map_std); +[[nodiscard]] constexpr std::optional record_type_to_fourcc(RecordType record_type) noexcept +{ + return utility::soa_first_to_second(record_type_fourcc_map, record_type); +} +[[nodiscard]] constexpr std::optional fourcc_to_record_type(FourCC fourcc) noexcept +{ + return utility::soa_second_to_first(record_type_fourcc_map, fourcc); +} -static constexpr std::pair flag_strings_map[]{ - {{RecordType::ACHR, 9}, "Starts Dead"}, +static constexpr std::pair record_type_name_map_builtin[] { + {RecordType::AACT, "Action" }, + {RecordType::ACHR, "Placed NPC" }, + {RecordType::ACTI, "Activator" }, + {RecordType::ADDN, "Addon Node" }, + {RecordType::ALCH, "Ingestible" }, + {RecordType::AMMO, "Ammunition" }, + {RecordType::ANIO, "Animated Object" }, + {RecordType::APPA, "Alchemical Apparatus" }, + {RecordType::ARMA, "Armor Addon" }, + {RecordType::ARMO, "Armor" }, + {RecordType::ARTO, "Art Object" }, + {RecordType::ASPC, "Acoustic Space" }, + {RecordType::ASTP, "Association Type" }, + {RecordType::AVIF, "Actor Value Information" }, + {RecordType::BOOK, "Book" }, + {RecordType::BPTD, "Body Part Data" }, + {RecordType::CAMS, "Camera Shot" }, + {RecordType::CELL, "Cell" }, + {RecordType::CLAS, "Class" }, + {RecordType::CLDC, "CLDC" }, + {RecordType::CLFM, "Color" }, + {RecordType::CLMT, "Climate" }, + {RecordType::COBJ, "Constructible Object" }, + {RecordType::COLL, "Collision Layer" }, + {RecordType::CONT, "Container" }, + {RecordType::CPTH, "Camera Path" }, + {RecordType::CSTY, "Combat Style" }, + {RecordType::DEBR, "Debris" }, + {RecordType::DIAL, "Dialog Topic" }, + {RecordType::DLBR, "Dialog Branch" }, + {RecordType::DLVW, "Dialog View" }, + {RecordType::DOBJ, "Default Object Manager" }, + {RecordType::DOOR, "Door" }, + {RecordType::DUAL, "Dual Cast Data" }, + {RecordType::ECZN, "Encounter Zone" }, + {RecordType::EFSH, "Effect Shader" }, + {RecordType::ENCH, "Object Effect" }, + {RecordType::EQUP, "Equip Type" }, + {RecordType::EXPL, "Explosion" }, + {RecordType::EYES, "Eyes" }, + {RecordType::FACT, "Faction" }, + {RecordType::FLOR, "Flora" }, + {RecordType::FLST, "FormID List" }, + {RecordType::FSTP, "Footstep" }, + {RecordType::FSTS, "Footstep Set" }, + {RecordType::FURN, "Furniture" }, + {RecordType::GLOB, "Global" }, + {RecordType::GMST, "Game Setting" }, + {RecordType::GRAS, "Grass" }, + {RecordType::GRUP, "Group" }, + {RecordType::HAIR, "HAIR" }, + {RecordType::HAZD, "Hazard" }, + {RecordType::HDPT, "Head Part" }, + {RecordType::IDLE, "Idle Animation" }, + {RecordType::IDLM, "Idle Marker" }, + {RecordType::IMAD, "Image Space Adapter" }, + {RecordType::IMGS, "Image Space" }, + {RecordType::INFO, "Dialog response" }, + {RecordType::INGR, "Ingredient" }, + {RecordType::IPCT, "Impact" }, + {RecordType::IPDS, "Impact Data Set" }, + {RecordType::KEYM, "Key" }, + {RecordType::KYWD, "Keyword" }, + {RecordType::LAND, "Landscape" }, + {RecordType::LCRT, "Location Reference Type" }, + {RecordType::LCTN, "Location" }, + {RecordType::LENS, "Lens Flare" }, + {RecordType::LGTM, "Lighting Template" }, + {RecordType::LIGH, "Light" }, + {RecordType::LSCR, "Load Screen" }, + {RecordType::LTEX, "Landscape Texture" }, + {RecordType::LVLI, "Leveled Item" }, + {RecordType::LVLN, "Leveled NPC" }, + {RecordType::LVSP, "Leveled Spell" }, + {RecordType::MATO, "Material Object" }, + {RecordType::MATT, "Material Type" }, + {RecordType::MESG, "Message" }, + {RecordType::MGEF, "Magic Effect" }, + {RecordType::MISC, "Misc. Item" }, + {RecordType::MOVT, "Movement Type" }, + {RecordType::MSTT, "Moveable Static" }, + {RecordType::MUSC, "Music Type" }, + {RecordType::MUST, "Music Track" }, + {RecordType::NAVI, "Navigation Mesh Info Map" }, + {RecordType::NAVM, "Navigation Mesh" }, + {RecordType::NOTE, "Note" }, + {RecordType::NPC_, "Non-Player Character (Actor)"}, + {RecordType::OTFT, "Outfit" }, + {RecordType::PACK, "Package" }, + {RecordType::PARW, "Placed Arrow" }, + {RecordType::PBAR, "Placed Barrier" }, + {RecordType::PBEA, "Placed Beam" }, + {RecordType::PCON, "Placed Cone/Voice" }, + {RecordType::PERK, "Perk" }, + {RecordType::PFLA, "Placed Flame" }, + {RecordType::PGRE, "Placed Projectile" }, + {RecordType::PHZD, "Placed Hazard" }, + {RecordType::PLYR, "Player Reference" }, + {RecordType::PMIS, "Placed Missile" }, + {RecordType::PROJ, "Projectile" }, + {RecordType::PWAT, "PWAT" }, + {RecordType::QUST, "Quest" }, + {RecordType::RACE, "Race" }, + {RecordType::REFR, "Placed Object" }, + {RecordType::REGN, "Region" }, + {RecordType::RELA, "Relationship" }, + {RecordType::REVB, "Reverb Parameters" }, + {RecordType::RFCT, "Visual Effect" }, + {RecordType::RGDL, "RGDL" }, + {RecordType::SCEN, "Scene" }, + {RecordType::SCOL, "Static Collection" }, + {RecordType::SCPT, "SCPT" }, + {RecordType::SCRL, "Scroll" }, + {RecordType::SHOU, "Shout" }, + {RecordType::SLGM, "Soul Gem" }, + {RecordType::SMBN, "Story Manager Branch Node" }, + {RecordType::SMEN, "Story Manager Event Node" }, + {RecordType::SMQN, "Story Manager Quest Node" }, + {RecordType::SNCT, "Sound Category" }, + {RecordType::SNDR, "Sound Descriptor" }, + {RecordType::SOPM, "Sound Output Model" }, + {RecordType::SOUN, "Sound Marker" }, + {RecordType::SPEL, "Spell" }, + {RecordType::SPGD, "Shader Particle Geometry" }, + {RecordType::STAT, "Static" }, + {RecordType::TACT, "Talking Activator" }, + {RecordType::TES4, "Main File Header" }, + {RecordType::TREE, "Tree" }, + {RecordType::TXST, "Texture Set" }, + {RecordType::VOLI, "Volumetric Lighting" }, + {RecordType::VTYP, "Voice Type" }, + {RecordType::WATR, "Water" }, + {RecordType::WEAP, "Weapon" }, + {RecordType::WOOP, "Word of Power" }, + {RecordType::WRLD, "Worldspace" }, + {RecordType::WTHR, "Weather" }, }; +static constexpr auto record_type_name_map_std = utility::array_builtin_to_std(record_type_name_map_builtin); +static constexpr auto record_type_name_map = utility::map_to_soa(record_type_name_map_std); +[[nodiscard]] constexpr std::optional record_type_to_name(RecordType record_type) noexcept +{ + return utility::soa_first_to_second(record_type_name_map, record_type); +} -struct refr_flag { - RecordType refr_type; - unsigned bit; +static constexpr std::pair flag_description_map_builtin[] { + {{RecordType::ACHR, 9}, "Starts Dead" }, + {{RecordType::ACHR, 10}, "Persistent" }, + {{RecordType::ACHR, 11}, "Initially Disabled" }, + {{RecordType::ACHR, 25}, "No AI Acquire" }, + {{RecordType::ACHR, 29}, "Don't Havok Settle" }, + {{RecordType::ACTI, 6}, "Has Tree LOD" }, + {{RecordType::ACTI, 8}, "Must Update Anims" }, + {{RecordType::ACTI, 9}, "Hidden From Local Map" }, + {{RecordType::ACTI, 15}, "Has Distant LOD" }, + {{RecordType::ACTI, 16}, "Random Anim Start" }, + {{RecordType::ACTI, 17}, "Dangerous" }, + {{RecordType::ACTI, 20}, "Ignore Object Interaction" }, + {{RecordType::ACTI, 23}, "Is Marker" }, + {{RecordType::ACTI, 25}, "Obstacle" }, + {{RecordType::ACTI, 26}, "NavMesh Generation - Filter" }, + {{RecordType::ACTI, 27}, "NavMesh Generation - Bounding Box"}, + {{RecordType::ACTI, 29}, "Child Can Use" }, + {{RecordType::ACTI, 30}, "NavMesh Generation - Ground" }, + {{RecordType::ALCH, 29}, "Medicine" }, + {{RecordType::AMMO, 2}, "Non-Playable" }, + {{RecordType::ANIO, 9}, "Unknown 9" }, + {{RecordType::ARMO, 2}, "Non-Playable" }, + {{RecordType::ARMO, 6}, "Shield" }, + {{RecordType::ARMO, 10}, "Unknown 10" }, + {{RecordType::ARMO, 15}, "Unknown 15" }, + {{RecordType::CELL, 10}, "Persistent" }, + {{RecordType::CELL, 17}, "Off Limits" }, + {{RecordType::CELL, 18}, "Compressed" }, + {{RecordType::CELL, 19}, "Can't Wait" }, + {{RecordType::CLFM, 2}, "Non-Playable" }, + {{RecordType::CONT, 15}, "Has Distant LOD" }, + {{RecordType::CONT, 16}, "Random Anim Start" }, + {{RecordType::CONT, 25}, "Obstacle" }, + {{RecordType::CONT, 26}, "NavMesh Generation - Filter" }, + {{RecordType::CONT, 27}, "NavMesh Generation - Bounding Box"}, + {{RecordType::CONT, 30}, "NavMesh Generation - Ground" }, + {{RecordType::CSTY, 19}, "Allow Dual Wielding" }, + {{RecordType::DOOR, 15}, "Has Distant LOD" }, + {{RecordType::DOOR, 16}, "Random Anim Start" }, + {{RecordType::DOOR, 23}, "Is Marker" }, + {{RecordType::EYES, 2}, "Non-Playable" }, + {{RecordType::FURN, 7}, "Is Perch" }, + {{RecordType::FURN, 15}, "Has Distant LOD" }, + {{RecordType::FURN, 16}, "Random Anim Start" }, + {{RecordType::FURN, 23}, "Is Marker" }, + {{RecordType::FURN, 28}, "Must Exit To Talk" }, + {{RecordType::FURN, 29}, "Child Can Use" }, + {{RecordType::GLOB, 6}, "Constant" }, + {{RecordType::HDPT, 2}, "Non-Playable" }, + {{RecordType::IDLM, 29}, "Child Can Use" }, + {{RecordType::INFO, 13}, "Actor Changed" }, + {{RecordType::KEYM, 2}, "Non-Playable" }, + {{RecordType::LAND, 18}, "Compressed" }, + {{RecordType::LIGH, 16}, "Random Anim Start" }, + {{RecordType::LIGH, 17}, "Portal-strict" }, + {{RecordType::LIGH, 25}, "Obstacle" }, + {{RecordType::LSCR, 10}, "Displays In Main Menu" }, + {{RecordType::MISC, 2}, "Non-Playable" }, + {{RecordType::MSTT, 8}, "Must Update Anims" }, + {{RecordType::MSTT, 9}, "Hidden From Local Map" }, + {{RecordType::MSTT, 15}, "Has Distant LOD" }, + {{RecordType::MSTT, 16}, "Random Anim Start" }, + {{RecordType::MSTT, 19}, "Has Currents" }, + {{RecordType::MSTT, 25}, "Obstacle" }, + {{RecordType::MSTT, 26}, "NavMesh Generation - Filter" }, + {{RecordType::MSTT, 27}, "NavMesh Generation - Bounding Box"}, + {{RecordType::MSTT, 30}, "NavMesh Generation - Ground" }, + {{RecordType::NAVM, 18}, "Compressed" }, + {{RecordType::NAVM, 26}, "AutoGen" }, + {{RecordType::NAVM, 31}, "NavmeshGenCell" }, + {{RecordType::NPC_, 10}, "Unknown 10" }, + {{RecordType::NPC_, 18}, "Compressed" }, + {{RecordType::NPC_, 19}, "Unknown 19" }, + {{RecordType::NPC_, 29}, "Bleedout Override" }, + {{RecordType::PARW, 7}, "Turn Off Fire" }, + {{RecordType::PARW, 10}, "Persistent" }, + {{RecordType::PARW, 11}, "Initially Disabled" }, + {{RecordType::PARW, 28}, "Reflected By Auto Water" }, + {{RecordType::PARW, 29}, "Don't Havok Settle" }, + {{RecordType::PARW, 30}, "No Respawn" }, + {{RecordType::PBAR, 7}, "Turn Off Fire" }, + {{RecordType::PBAR, 10}, "Persistent" }, + {{RecordType::PBAR, 11}, "Initially Disabled" }, + {{RecordType::PBAR, 28}, "Reflected By Auto Water" }, + {{RecordType::PBAR, 29}, "Don't Havok Settle" }, + {{RecordType::PBAR, 30}, "No Respawn" }, + {{RecordType::PBEA, 7}, "Turn Off Fire" }, + {{RecordType::PBEA, 10}, "Persistent" }, + {{RecordType::PBEA, 11}, "Initially Disabled" }, + {{RecordType::PBEA, 28}, "Reflected By Auto Water" }, + {{RecordType::PBEA, 29}, "Don't Havok Settle" }, + {{RecordType::PBEA, 30}, "No Respawn" }, + {{RecordType::PCON, 7}, "Turn Off Fire" }, + {{RecordType::PCON, 10}, "Persistent" }, + {{RecordType::PCON, 11}, "Initially Disabled" }, + {{RecordType::PCON, 28}, "Reflected By Auto Water" }, + {{RecordType::PCON, 29}, "Don't Havok Settle" }, + {{RecordType::PCON, 30}, "No Respawn" }, + {{RecordType::PERK, 2}, "Non-Playable" }, + {{RecordType::PFLA, 7}, "Turn Off Fire" }, + {{RecordType::PFLA, 10}, "Persistent" }, + {{RecordType::PFLA, 11}, "Initially Disabled" }, + {{RecordType::PFLA, 28}, "Reflected By Auto Water" }, + {{RecordType::PFLA, 29}, "Don't Havok Settle" }, + {{RecordType::PFLA, 30}, "No Respawn" }, + {{RecordType::PGRE, 7}, "Turn Off Fire" }, + {{RecordType::PGRE, 10}, "Persistent" }, + {{RecordType::PGRE, 11}, "Initially Disabled" }, + {{RecordType::PGRE, 28}, "Reflected By Auto Water" }, + {{RecordType::PGRE, 29}, "Don't Havok Settle" }, + {{RecordType::PGRE, 30}, "No Respawn" }, + {{RecordType::PHZD, 7}, "Turn Off Fire" }, + {{RecordType::PHZD, 10}, "Persistent" }, + {{RecordType::PHZD, 11}, "Initially Disabled" }, + {{RecordType::PHZD, 28}, "Reflected By Auto Water" }, + {{RecordType::PHZD, 29}, "Don't Havok Settle" }, + {{RecordType::PHZD, 30}, "No Respawn" }, + {{RecordType::PMIS, 7}, "Turn Off Fire" }, + {{RecordType::PMIS, 10}, "Persistent" }, + {{RecordType::PMIS, 11}, "Initially Disabled" }, + {{RecordType::PMIS, 28}, "Reflected By Auto Water" }, + {{RecordType::PMIS, 29}, "Don't Havok Settle" }, + {{RecordType::PMIS, 30}, "No Respawn" }, + {{RecordType::RACE, 19}, "Critter?" }, + {{RecordType::REFR, 10}, "Persistent" }, + {{RecordType::REFR, 11}, "Initially Disabled" }, + {{RecordType::REFR, 16}, "Is Full LOD" }, + {{RecordType::REFR, 26}, "Filter (Collision Geometry)" }, + {{RecordType::REFR, 27}, "Bounding Box (Collision Geometry)"}, + {{RecordType::REFR, 28}, "Reflected By Auto Water" }, + {{RecordType::REFR, 30}, "Ground" }, + {{RecordType::REFR, 31}, "Multibound" }, + {{RecordType::REGN, 6}, "Border Region" }, + {{RecordType::RELA, 6}, "Secret" }, + {{RecordType::SHOU, 7}, "Treat spells as powers" }, + {{RecordType::SLGM, 17}, "Can Hold NPC Soul" }, + {{RecordType::STAT, 2}, "Never Fades" }, + {{RecordType::STAT, 5}, "Deleted" }, + {{RecordType::STAT, 6}, "Has Tree LOD" }, + {{RecordType::STAT, 7}, "Add-On LOD Object" }, + {{RecordType::STAT, 9}, "Hidden From Local Map" }, + {{RecordType::STAT, 11}, "Unknown 11" }, + {{RecordType::STAT, 15}, "Has Distant LOD" }, + {{RecordType::STAT, 16}, "Unknown 16" }, + {{RecordType::STAT, 17}, "Uses HD LOD Texture" }, + {{RecordType::STAT, 19}, "Has Currents" }, + {{RecordType::STAT, 23}, "Is Marker" }, + {{RecordType::STAT, 25}, "Obstacle" }, + {{RecordType::STAT, 26}, "NavMesh Generation - Filter" }, + {{RecordType::STAT, 27}, "NavMesh Generation - Bounding Box"}, + {{RecordType::STAT, 28}, "Show In World Map" }, + {{RecordType::STAT, 30}, "NavMesh Generation - Ground" }, + {{RecordType::TACT, 9}, "Hidden From Local Map" }, + {{RecordType::TACT, 16}, "Random Anim Start" }, + {{RecordType::TACT, 17}, "Radio Station" }, + {{RecordType::TES4, 0}, "ESM" }, + {{RecordType::TES4, 1}, "Altered" }, + {{RecordType::TES4, 2}, "Checked" }, + {{RecordType::TES4, 3}, "Active" }, + {{RecordType::TES4, 4}, "Optimized File" }, + {{RecordType::TES4, 5}, "Temp ID Owner" }, + {{RecordType::TES4, 7}, "Localized" }, + {{RecordType::TES4, 8}, "Precalc Data Only" }, + {{RecordType::TES4, 9}, "ESL" }, + {{RecordType::TREE, 15}, "Has Distant LOD" }, + {{RecordType::WEAP, 2}, "Non-Playable" }, + {{RecordType::WRLD, 19}, "Can't Wait" }, }; +static constexpr auto flag_description_map_std = utility::array_builtin_to_std(flag_description_map_builtin); +static constexpr auto flag_description_map = utility::map_to_soa(flag_description_map_std); +[[nodiscard]] constexpr std::optional flag_to_description(Flag flag) noexcept +{ + return utility::soa_first_to_second(flag_description_map, flag); +} -static constexpr std::pair refr_flag_strings_map[]{ - {{RecordType::ACHR, 9}, "Hidden From Local Map"}, +static constexpr std::pair refr_flag_description_map_builtin[] { + {{RecordType::ACTI, 9}, "Hidden From Local Map" }, + {{RecordType::ACTI, 10}, "Persistent" }, + {{RecordType::ACTI, 11}, "Initially Disabled" }, + {{RecordType::ACTI, 13}, "Sky Marker" }, + {{RecordType::ACTI, 15}, "Visible when distant" }, + {{RecordType::ACTI, 16}, "Is Full LOD" }, + {{RecordType::ACTI, 26}, "Filter (Collision Geometry)" }, + {{RecordType::ACTI, 27}, "Bounding Box (Collision Geometry)"}, + {{RecordType::ACTI, 28}, "Reflected By Auto Water" }, + {{RecordType::ACTI, 29}, "Don''t Havok Settle" }, + {{RecordType::ACTI, 30}, "No Respawn" }, + {{RecordType::ACTI, 31}, "Multibound" }, + {{RecordType::ADDN, 10}, "Persistent" }, + {{RecordType::ADDN, 11}, "Initially Disabled" }, + {{RecordType::ADDN, 16}, "Is Full LOD" }, + {{RecordType::ADDN, 28}, "Reflected By Auto Water" }, + {{RecordType::ADDN, 29}, "Don''t Havok Settle" }, + {{RecordType::ADDN, 30}, "No Respawn" }, + {{RecordType::ADDN, 31}, "Multibound" }, + {{RecordType::ALCH, 10}, "Persistent" }, + {{RecordType::ALCH, 11}, "Initially Disabled" }, + {{RecordType::ALCH, 16}, "Is Full LOD" }, + {{RecordType::ALCH, 25}, "No AI Acquire" }, + {{RecordType::ALCH, 28}, "Reflected By Auto Water" }, + {{RecordType::ALCH, 29}, "Don''t Havok Settle" }, + {{RecordType::ALCH, 30}, "No Respawn" }, + {{RecordType::ALCH, 31}, "Multibound" }, + {{RecordType::AMMO, 10}, "Persistent" }, + {{RecordType::AMMO, 11}, "Initially Disabled" }, + {{RecordType::AMMO, 16}, "Is Full LOD" }, + {{RecordType::AMMO, 25}, "No AI Acquire" }, + {{RecordType::AMMO, 28}, "Reflected By Auto Water" }, + {{RecordType::AMMO, 29}, "Don''t Havok Settle" }, + {{RecordType::AMMO, 30}, "No Respawn" }, + {{RecordType::AMMO, 31}, "Multibound" }, + {{RecordType::ARMO, 10}, "Persistent" }, + {{RecordType::ARMO, 11}, "Initially Disabled" }, + {{RecordType::ARMO, 16}, "Is Full LOD" }, + {{RecordType::ARMO, 25}, "No AI Acquire" }, + {{RecordType::ARMO, 28}, "Reflected By Auto Water" }, + {{RecordType::ARMO, 29}, "Don''t Havok Settle" }, + {{RecordType::ARMO, 30}, "No Respawn" }, + {{RecordType::ARMO, 31}, "Multibound" }, + {{RecordType::BOOK, 10}, "Persistent" }, + {{RecordType::BOOK, 11}, "Initially Disabled" }, + {{RecordType::BOOK, 16}, "Is Full LOD" }, + {{RecordType::BOOK, 25}, "No AI Acquire" }, + {{RecordType::BOOK, 28}, "Reflected By Auto Water" }, + {{RecordType::BOOK, 29}, "Don''t Havok Settle" }, + {{RecordType::BOOK, 30}, "No Respawn" }, + {{RecordType::BOOK, 31}, "Multibound" }, + {{RecordType::CONT, 10}, "Persistent" }, + {{RecordType::CONT, 11}, "Initially Disabled" }, + {{RecordType::CONT, 16}, "Is Full LOD" }, + {{RecordType::CONT, 25}, "No AI Acquire" }, + {{RecordType::CONT, 26}, "Filter (Collision Geometry)" }, + {{RecordType::CONT, 27}, "Bounding Box (Collision Geometry)"}, + {{RecordType::CONT, 28}, "Reflected By Auto Water" }, + {{RecordType::CONT, 29}, "Don''t Havok Settle" }, + {{RecordType::CONT, 30}, "Ground" }, + {{RecordType::CONT, 31}, "Multibound" }, + {{RecordType::DOOR, 6}, "Hidden From Local Map" }, + {{RecordType::DOOR, 8}, "Inaccessible" }, + {{RecordType::DOOR, 10}, "Persistent" }, + {{RecordType::DOOR, 11}, "Initially Disabled" }, + {{RecordType::DOOR, 16}, "Is Full LOD" }, + {{RecordType::DOOR, 26}, "Filter (Collision Geometry)" }, + {{RecordType::DOOR, 27}, "Bounding Box (Collision Geometry)"}, + {{RecordType::DOOR, 28}, "Reflected By Auto Water" }, + {{RecordType::DOOR, 29}, "Don''t Havok Settle" }, + {{RecordType::DOOR, 30}, "No Respawn" }, + {{RecordType::DOOR, 31}, "Multibound" }, + {{RecordType::FLOR, 9}, "Hidden From Local Map" }, + {{RecordType::FLOR, 10}, "Persistent" }, + {{RecordType::FLOR, 11}, "Initially Disabled" }, + {{RecordType::FLOR, 13}, "Sky Marker" }, + {{RecordType::FLOR, 15}, "Visible when distant" }, + {{RecordType::FLOR, 16}, "Is Full LOD" }, + {{RecordType::FLOR, 26}, "Filter (Collision Geometry)" }, + {{RecordType::FLOR, 27}, "Bounding Box (Collision Geometry)"}, + {{RecordType::FLOR, 28}, "Reflected By Auto Water" }, + {{RecordType::FLOR, 29}, "Don''t Havok Settle" }, + {{RecordType::FLOR, 30}, "No Respawn" }, + {{RecordType::FLOR, 31}, "Multibound" }, + {{RecordType::INGR, 10}, "Persistent" }, + {{RecordType::INGR, 11}, "Initially Disabled" }, + {{RecordType::INGR, 16}, "Is Full LOD" }, + {{RecordType::INGR, 25}, "No AI Acquire" }, + {{RecordType::INGR, 28}, "Reflected By Auto Water" }, + {{RecordType::INGR, 29}, "Don''t Havok Settle" }, + {{RecordType::INGR, 30}, "No Respawn" }, + {{RecordType::INGR, 31}, "Multibound" }, + {{RecordType::KEYM, 10}, "Persistent" }, + {{RecordType::KEYM, 11}, "Initially Disabled" }, + {{RecordType::KEYM, 16}, "Is Full LOD" }, + {{RecordType::KEYM, 25}, "No AI Acquire" }, + {{RecordType::KEYM, 28}, "Reflected By Auto Water" }, + {{RecordType::KEYM, 29}, "Don''t Havok Settle" }, + {{RecordType::KEYM, 30}, "No Respawn" }, + {{RecordType::KEYM, 31}, "Multibound" }, + {{RecordType::LIGH, 8}, "Doesn''t Light Water" }, + {{RecordType::LIGH, 9}, "Casts Shadows" }, + {{RecordType::LIGH, 10}, "Persistent" }, + {{RecordType::LIGH, 11}, "Initially Disabled" }, + {{RecordType::LIGH, 16}, "Never Fades" }, + {{RecordType::LIGH, 17}, "Doesn''t Light Landscape" }, + {{RecordType::LIGH, 25}, "No AI Acquire" }, + {{RecordType::LIGH, 28}, "Reflected By Auto Water" }, + {{RecordType::LIGH, 29}, "Don''t Havok Settle" }, + {{RecordType::LIGH, 30}, "No Respawn" }, + {{RecordType::LIGH, 31}, "Multibound" }, + {{RecordType::MISC, 10}, "Persistent" }, + {{RecordType::MISC, 11}, "Initially Disabled" }, + {{RecordType::MISC, 16}, "Is Full LOD" }, + {{RecordType::MISC, 25}, "No AI Acquire" }, + {{RecordType::MISC, 28}, "Reflected By Auto Water" }, + {{RecordType::MISC, 29}, "Don''t Havok Settle" }, + {{RecordType::MISC, 30}, "No Respawn" }, + {{RecordType::MISC, 31}, "Multibound" }, + {{RecordType::MSTT, 9}, "Motion Blur" }, + {{RecordType::MSTT, 10}, "Persistent" }, + {{RecordType::MSTT, 11}, "Initially Disabled" }, + {{RecordType::MSTT, 16}, "Is Full LOD" }, + {{RecordType::MSTT, 26}, "Filter (Collision Geometry)" }, + {{RecordType::MSTT, 27}, "Bounding Box (Collision Geometry)"}, + {{RecordType::MSTT, 28}, "Reflected By Auto Water" }, + {{RecordType::MSTT, 29}, "Don''t Havok Settle" }, + {{RecordType::MSTT, 30}, "No Respawn" }, + {{RecordType::MSTT, 31}, "Multibound" }, + {{RecordType::SCRL, 10}, "Persistent" }, + {{RecordType::SCRL, 11}, "Initially Disabled" }, + {{RecordType::SCRL, 16}, "Is Full LOD" }, + {{RecordType::SCRL, 25}, "No AI Acquire" }, + {{RecordType::SCRL, 28}, "Reflected By Auto Water" }, + {{RecordType::SCRL, 29}, "Don''t Havok Settle" }, + {{RecordType::SCRL, 30}, "No Respawn" }, + {{RecordType::SCRL, 31}, "Multibound" }, + {{RecordType::SLGM, 10}, "Persistent" }, + {{RecordType::SLGM, 11}, "Initially Disabled" }, + {{RecordType::SLGM, 16}, "Is Full LOD" }, + {{RecordType::SLGM, 25}, "No AI Acquire" }, + {{RecordType::SLGM, 28}, "Reflected By Auto Water" }, + {{RecordType::SLGM, 29}, "Don''t Havok Settle" }, + {{RecordType::SLGM, 30}, "No Respawn" }, + {{RecordType::SLGM, 31}, "Multibound" }, + {{RecordType::STAT, 9}, "Hidden From Local Map" }, + {{RecordType::STAT, 10}, "Persistent" }, + {{RecordType::STAT, 11}, "Initially Disabled" }, + {{RecordType::STAT, 13}, "Sky Marker" }, + {{RecordType::STAT, 15}, "Visible when distant" }, + {{RecordType::STAT, 16}, "Is Full LOD" }, + {{RecordType::STAT, 26}, "Filter (Collision Geometry)" }, + {{RecordType::STAT, 27}, "Bounding Box (Collision Geometry)"}, + {{RecordType::STAT, 28}, "Reflected By Auto Water" }, + {{RecordType::STAT, 29}, "Don''t Havok Settle" }, + {{RecordType::STAT, 30}, "No Respawn" }, + {{RecordType::STAT, 31}, "Multibound" }, + {{RecordType::TREE, 9}, "Hidden From Local Map" }, + {{RecordType::TREE, 10}, "Persistent" }, + {{RecordType::TREE, 11}, "Initially Disabled" }, + {{RecordType::TREE, 13}, "Sky Marker" }, + {{RecordType::TREE, 15}, "Visible when distant" }, + {{RecordType::TREE, 16}, "Is Full LOD" }, + {{RecordType::TREE, 26}, "Filter (Collision Geometry)" }, + {{RecordType::TREE, 27}, "Bounding Box (Collision Geometry)"}, + {{RecordType::TREE, 28}, "Reflected By Auto Water" }, + {{RecordType::TREE, 29}, "Don''t Havok Settle" }, + {{RecordType::TREE, 30}, "No Respawn" }, + {{RecordType::TREE, 31}, "Multibound" }, + {{RecordType::WEAP, 10}, "Persistent" }, + {{RecordType::WEAP, 11}, "Initially Disabled" }, + {{RecordType::WEAP, 16}, "Is Full LOD" }, + {{RecordType::WEAP, 25}, "No AI Acquire" }, + {{RecordType::WEAP, 28}, "Reflected By Auto Water" }, + {{RecordType::WEAP, 29}, "Don''t Havok Settle" }, + {{RecordType::WEAP, 30}, "No Respawn" }, + {{RecordType::WEAP, 31}, "Multibound" }, }; +static constexpr auto refr_flag_description_map_std = utility::array_builtin_to_std(refr_flag_description_map_builtin); +static constexpr auto refr_flag_description_map = utility::map_to_soa(refr_flag_description_map_std); +[[nodiscard]] constexpr std::optional refr_flag_to_description(RefrFlag refr_flag) noexcept +{ + return utility::soa_first_to_second(refr_flag_description_map, refr_flag); +} } diff --git a/Navmesher/utility.hpp b/Navmesher/utility.hpp index 7125f10..6dc56cc 100644 --- a/Navmesher/utility.hpp +++ b/Navmesher/utility.hpp @@ -1,23 +1,67 @@ #pragma once #include +#include +#include namespace utility { -// Converts a string literal to a std::array, from https://stackoverflow.com/a/33484394 -template -constexpr std::array -literal_to_array(const char(&a)[N], std::index_sequence) +// This is a base class for a generic store for some value that can be represented by +// type T but should not be type checked as type T, but rather some more constrained class. +template +struct Store { + static_assert(std::is_trivial_v); + T value; + friend constexpr auto operator<=>(const Store &, const Store &) noexcept = default; +}; + +// Convert a fourcc literal (e.g. "LITR" to a uint32_t) +constexpr uint32_t fourcc_lit_to_val(const char(&a)[5]) noexcept { - return { {a[Is]...} }; + char temp[4] = { a[0], a[1], a[2], a[3] }; + return std::bit_cast(temp); } -template -constexpr std::array literal_to_array(const char(&a)[N]) +// Convert a builtin array to a std::array +template +constexpr std::array array_builtin_to_std(const T(&builtin)[N]) noexcept { - return literal_to_array(a, std::make_index_sequence()); + std::array array; + std::copy(std::cbegin(builtin), std::cend(builtin), array.begin()); + return array; } +template +constexpr std::pair, std::array> map_to_soa(std::array, N> map) noexcept +{ + std::array first; + std::array second; + for (std::size_t i = 0; i != N; ++i) { + first[i] = map[i].first; + second[i] = map[i].second; + } + return std::make_pair(first, second); +} + +template +constexpr std::optional soa_first_to_second(const std::pair, std::array> &soa, const First &first) noexcept +{ + auto lhs = std::find(soa.first.cbegin(), soa.first.cend(), first); + if (lhs == soa.first.cend()) + return {}; + auto index = std::distance(soa.first.cbegin(), lhs); + return { soa.second[index] }; +} + +template +constexpr std::optional soa_second_to_first(const std::pair, std::array> &soa, const Second &second) noexcept +{ + auto lhs = std::find(soa.second.cbegin(), soa.second.cend(), second); + if (lhs == soa.second.cend()) + return {}; + auto index = std::distance(soa.second.cbegin(), lhs); + return { soa.first[index] }; +} // Used to inspect type sizes and values at compile time. Example: // @@ -32,15 +76,5 @@ class TS; template class TD; - -// This is a base class for a generic store for some value that can be represented by -// type T but should not be type checked as type T, but rather some more constrained class. -template -struct Store { - static_assert(std::is_trivial_v); - T value; - friend constexpr auto operator<=>(const Store &, const Store &) noexcept = default; -}; - } diff --git a/reference/esx_reader.hpp.fragment b/reference/esx_reader.hpp.fragment new file mode 100644 index 0000000..418cb64 --- /dev/null +++ b/reference/esx_reader.hpp.fragment @@ -0,0 +1,19 @@ +enum class RecordType { + AACT, ACHR, ACTI, ADDN, ALCH, AMMO, ANIO, APPA, ARMA, ARMO, ARTO, ASPC, + ASTP, AVIF, BOOK, BPTD, CAMS, CELL, CLAS, CLDC, CLFM, CLMT, COBJ, COLL, + CONT, CPTH, CSTY, DEBR, DIAL, DLBR, DLVW, DOBJ, DOOR, DUAL, ECZN, EFSH, + ENCH, EQUP, EXPL, EYES, FACT, FLOR, FLST, FSTP, FSTS, FURN, GLOB, GMST, + GRAS, GRUP, HAIR, HAZD, HDPT, IDLE, IDLM, IMAD, IMGS, INFO, INGR, IPCT, + IPDS, KEYM, KYWD, LAND, LCRT, LCTN, LENS, LGTM, LIGH, LSCR, LTEX, LVLI, + LVLN, LVSP, MATO, MATT, MESG, MGEF, MISC, MOVT, MSTT, MUSC, MUST, NAVI, + NAVM, NOTE, NPC_, OTFT, PACK, PARW, PBAR, PBEA, PCON, PERK, PFLA, PGRE, + PHZD, PLYR, PMIS, PROJ, PWAT, QUST, RACE, REFR, REGN, RELA, REVB, RFCT, + RGDL, SCEN, SCOL, SCPT, SCRL, SHOU, SLGM, SMBN, SMEN, SMQN, SNCT, SNDR, + SOPM, SOUN, SPEL, SPGD, STAT, TACT, TES4, TREE, TXST, VOLI, VTYP, WATR, + WEAP, WOOP, WRLD, WTHR, }; +[[nodiscard]] constexpr std::optional group_type_to_name(GroupType group_type) noexcept; +[[nodiscard]] constexpr std::optional record_type_to_fourcc(RecordType record_type) noexcept; +[[nodiscard]] constexpr std::optional fourcc_to_record_type(FourCC fourcc) noexcept; +[[nodiscard]] constexpr std::optional record_type_to_name(RecordType record_type) noexcept; +[[nodiscard]] constexpr std::optional flag_to_description(Flag flag) noexcept; +[[nodiscard]] constexpr std::optional refr_flag_to_description(RefrFlag refr_flag) noexcept; \ No newline at end of file diff --git a/reference/esx_reader_lut.cpp b/reference/esx_reader_lut.cpp new file mode 100644 index 0000000..373ad7c --- /dev/null +++ b/reference/esx_reader_lut.cpp @@ -0,0 +1,614 @@ +#include "esx_reader.hpp" + +using namespace esxr; + +namespace esxr_lut { + +static constexpr std::pair group_type_name_map_builtin[] { + {GroupType::Top , "Top Type" }, + {GroupType::WorldChildren , "World Children" }, + {GroupType::InteriorCellBlock , "Interior Cell Block" }, + {GroupType::InteriorCellSubBlock , "Interior Cell Sub-Block" }, + {GroupType::ExteriorCellBlock , "Exterior Cell" }, + {GroupType::ExteriorCellSubBlock , "Exterior Cell Sub-Block" }, + {GroupType::CellChildren , "Cell Children" }, + {GroupType::TopicChildren , "Topic Children" }, + {GroupType::CellPersistentChildren, "Cell Persistent Children"}, + {GroupType::CellTemporaryChildren , "Cell Temporary Children" }, +}; +static constexpr auto group_type_name_map_std = utility::array_builtin_to_std(group_type_name_map_builtin); +static constexpr auto group_type_name_map = utility::map_to_soa(group_type_name_map_std); +[[nodiscard]] constexpr std::optional group_type_to_name(GroupType group_type) noexcept +{ + return utility::soa_first_to_second(group_type_name_map, group_type); +} + +static constexpr std::pair record_type_fourcc_map_builtin[] { + {RecordType::AACT, FourCC("AACT")}, {RecordType::ACHR, FourCC("ACHR")}, + {RecordType::ACTI, FourCC("ACTI")}, {RecordType::ADDN, FourCC("ADDN")}, + {RecordType::ALCH, FourCC("ALCH")}, {RecordType::AMMO, FourCC("AMMO")}, + {RecordType::ANIO, FourCC("ANIO")}, {RecordType::APPA, FourCC("APPA")}, + {RecordType::ARMA, FourCC("ARMA")}, {RecordType::ARMO, FourCC("ARMO")}, + {RecordType::ARTO, FourCC("ARTO")}, {RecordType::ASPC, FourCC("ASPC")}, + {RecordType::ASTP, FourCC("ASTP")}, {RecordType::AVIF, FourCC("AVIF")}, + {RecordType::BOOK, FourCC("BOOK")}, {RecordType::BPTD, FourCC("BPTD")}, + {RecordType::CAMS, FourCC("CAMS")}, {RecordType::CELL, FourCC("CELL")}, + {RecordType::CLAS, FourCC("CLAS")}, {RecordType::CLDC, FourCC("CLDC")}, + {RecordType::CLFM, FourCC("CLFM")}, {RecordType::CLMT, FourCC("CLMT")}, + {RecordType::COBJ, FourCC("COBJ")}, {RecordType::COLL, FourCC("COLL")}, + {RecordType::CONT, FourCC("CONT")}, {RecordType::CPTH, FourCC("CPTH")}, + {RecordType::CSTY, FourCC("CSTY")}, {RecordType::DEBR, FourCC("DEBR")}, + {RecordType::DIAL, FourCC("DIAL")}, {RecordType::DLBR, FourCC("DLBR")}, + {RecordType::DLVW, FourCC("DLVW")}, {RecordType::DOBJ, FourCC("DOBJ")}, + {RecordType::DOOR, FourCC("DOOR")}, {RecordType::DUAL, FourCC("DUAL")}, + {RecordType::ECZN, FourCC("ECZN")}, {RecordType::EFSH, FourCC("EFSH")}, + {RecordType::ENCH, FourCC("ENCH")}, {RecordType::EQUP, FourCC("EQUP")}, + {RecordType::EXPL, FourCC("EXPL")}, {RecordType::EYES, FourCC("EYES")}, + {RecordType::FACT, FourCC("FACT")}, {RecordType::FLOR, FourCC("FLOR")}, + {RecordType::FLST, FourCC("FLST")}, {RecordType::FSTP, FourCC("FSTP")}, + {RecordType::FSTS, FourCC("FSTS")}, {RecordType::FURN, FourCC("FURN")}, + {RecordType::GLOB, FourCC("GLOB")}, {RecordType::GMST, FourCC("GMST")}, + {RecordType::GRAS, FourCC("GRAS")}, {RecordType::GRUP, FourCC("GRUP")}, + {RecordType::HAIR, FourCC("HAIR")}, {RecordType::HAZD, FourCC("HAZD")}, + {RecordType::HDPT, FourCC("HDPT")}, {RecordType::IDLE, FourCC("IDLE")}, + {RecordType::IDLM, FourCC("IDLM")}, {RecordType::IMAD, FourCC("IMAD")}, + {RecordType::IMGS, FourCC("IMGS")}, {RecordType::INFO, FourCC("INFO")}, + {RecordType::INGR, FourCC("INGR")}, {RecordType::IPCT, FourCC("IPCT")}, + {RecordType::IPDS, FourCC("IPDS")}, {RecordType::KEYM, FourCC("KEYM")}, + {RecordType::KYWD, FourCC("KYWD")}, {RecordType::LAND, FourCC("LAND")}, + {RecordType::LCRT, FourCC("LCRT")}, {RecordType::LCTN, FourCC("LCTN")}, + {RecordType::LENS, FourCC("LENS")}, {RecordType::LGTM, FourCC("LGTM")}, + {RecordType::LIGH, FourCC("LIGH")}, {RecordType::LSCR, FourCC("LSCR")}, + {RecordType::LTEX, FourCC("LTEX")}, {RecordType::LVLI, FourCC("LVLI")}, + {RecordType::LVLN, FourCC("LVLN")}, {RecordType::LVSP, FourCC("LVSP")}, + {RecordType::MATO, FourCC("MATO")}, {RecordType::MATT, FourCC("MATT")}, + {RecordType::MESG, FourCC("MESG")}, {RecordType::MGEF, FourCC("MGEF")}, + {RecordType::MISC, FourCC("MISC")}, {RecordType::MOVT, FourCC("MOVT")}, + {RecordType::MSTT, FourCC("MSTT")}, {RecordType::MUSC, FourCC("MUSC")}, + {RecordType::MUST, FourCC("MUST")}, {RecordType::NAVI, FourCC("NAVI")}, + {RecordType::NAVM, FourCC("NAVM")}, {RecordType::NOTE, FourCC("NOTE")}, + {RecordType::NPC_, FourCC("NPC_")}, {RecordType::OTFT, FourCC("OTFT")}, + {RecordType::PACK, FourCC("PACK")}, {RecordType::PARW, FourCC("PARW")}, + {RecordType::PBAR, FourCC("PBAR")}, {RecordType::PBEA, FourCC("PBEA")}, + {RecordType::PCON, FourCC("PCON")}, {RecordType::PERK, FourCC("PERK")}, + {RecordType::PFLA, FourCC("PFLA")}, {RecordType::PGRE, FourCC("PGRE")}, + {RecordType::PHZD, FourCC("PHZD")}, {RecordType::PLYR, FourCC("PLYR")}, + {RecordType::PMIS, FourCC("PMIS")}, {RecordType::PROJ, FourCC("PROJ")}, + {RecordType::PWAT, FourCC("PWAT")}, {RecordType::QUST, FourCC("QUST")}, + {RecordType::RACE, FourCC("RACE")}, {RecordType::REFR, FourCC("REFR")}, + {RecordType::REGN, FourCC("REGN")}, {RecordType::RELA, FourCC("RELA")}, + {RecordType::REVB, FourCC("REVB")}, {RecordType::RFCT, FourCC("RFCT")}, + {RecordType::RGDL, FourCC("RGDL")}, {RecordType::SCEN, FourCC("SCEN")}, + {RecordType::SCOL, FourCC("SCOL")}, {RecordType::SCPT, FourCC("SCPT")}, + {RecordType::SCRL, FourCC("SCRL")}, {RecordType::SHOU, FourCC("SHOU")}, + {RecordType::SLGM, FourCC("SLGM")}, {RecordType::SMBN, FourCC("SMBN")}, + {RecordType::SMEN, FourCC("SMEN")}, {RecordType::SMQN, FourCC("SMQN")}, + {RecordType::SNCT, FourCC("SNCT")}, {RecordType::SNDR, FourCC("SNDR")}, + {RecordType::SOPM, FourCC("SOPM")}, {RecordType::SOUN, FourCC("SOUN")}, + {RecordType::SPEL, FourCC("SPEL")}, {RecordType::SPGD, FourCC("SPGD")}, + {RecordType::STAT, FourCC("STAT")}, {RecordType::TACT, FourCC("TACT")}, + {RecordType::TES4, FourCC("TES4")}, {RecordType::TREE, FourCC("TREE")}, + {RecordType::TXST, FourCC("TXST")}, {RecordType::VOLI, FourCC("VOLI")}, + {RecordType::VTYP, FourCC("VTYP")}, {RecordType::WATR, FourCC("WATR")}, + {RecordType::WEAP, FourCC("WEAP")}, {RecordType::WOOP, FourCC("WOOP")}, + {RecordType::WRLD, FourCC("WRLD")}, {RecordType::WTHR, FourCC("WTHR")}, +}; +static constexpr auto record_type_fourcc_map_std = utility::array_builtin_to_std(record_type_fourcc_map_builtin); +static constexpr auto record_type_fourcc_map = utility::map_to_soa(record_type_fourcc_map_std); +[[nodiscard]] constexpr std::optional record_type_to_fourcc(RecordType record_type) noexcept +{ + return utility::soa_first_to_second(record_type_fourcc_map, record_type); +} +[[nodiscard]] constexpr std::optional fourcc_to_record_type(FourCC fourcc) noexcept +{ + return utility::soa_second_to_first(record_type_fourcc_map, fourcc); +} + +static constexpr std::pair record_type_name_map_builtin[] { + {RecordType::AACT, "Action" }, + {RecordType::ACHR, "Placed NPC" }, + {RecordType::ACTI, "Activator" }, + {RecordType::ADDN, "Addon Node" }, + {RecordType::ALCH, "Ingestible" }, + {RecordType::AMMO, "Ammunition" }, + {RecordType::ANIO, "Animated Object" }, + {RecordType::APPA, "Alchemical Apparatus" }, + {RecordType::ARMA, "Armor Addon" }, + {RecordType::ARMO, "Armor" }, + {RecordType::ARTO, "Art Object" }, + {RecordType::ASPC, "Acoustic Space" }, + {RecordType::ASTP, "Association Type" }, + {RecordType::AVIF, "Actor Value Information" }, + {RecordType::BOOK, "Book" }, + {RecordType::BPTD, "Body Part Data" }, + {RecordType::CAMS, "Camera Shot" }, + {RecordType::CELL, "Cell" }, + {RecordType::CLAS, "Class" }, + {RecordType::CLDC, "CLDC" }, + {RecordType::CLFM, "Color" }, + {RecordType::CLMT, "Climate" }, + {RecordType::COBJ, "Constructible Object" }, + {RecordType::COLL, "Collision Layer" }, + {RecordType::CONT, "Container" }, + {RecordType::CPTH, "Camera Path" }, + {RecordType::CSTY, "Combat Style" }, + {RecordType::DEBR, "Debris" }, + {RecordType::DIAL, "Dialog Topic" }, + {RecordType::DLBR, "Dialog Branch" }, + {RecordType::DLVW, "Dialog View" }, + {RecordType::DOBJ, "Default Object Manager" }, + {RecordType::DOOR, "Door" }, + {RecordType::DUAL, "Dual Cast Data" }, + {RecordType::ECZN, "Encounter Zone" }, + {RecordType::EFSH, "Effect Shader" }, + {RecordType::ENCH, "Object Effect" }, + {RecordType::EQUP, "Equip Type" }, + {RecordType::EXPL, "Explosion" }, + {RecordType::EYES, "Eyes" }, + {RecordType::FACT, "Faction" }, + {RecordType::FLOR, "Flora" }, + {RecordType::FLST, "FormID List" }, + {RecordType::FSTP, "Footstep" }, + {RecordType::FSTS, "Footstep Set" }, + {RecordType::FURN, "Furniture" }, + {RecordType::GLOB, "Global" }, + {RecordType::GMST, "Game Setting" }, + {RecordType::GRAS, "Grass" }, + {RecordType::GRUP, "Group" }, + {RecordType::HAIR, "HAIR" }, + {RecordType::HAZD, "Hazard" }, + {RecordType::HDPT, "Head Part" }, + {RecordType::IDLE, "Idle Animation" }, + {RecordType::IDLM, "Idle Marker" }, + {RecordType::IMAD, "Image Space Adapter" }, + {RecordType::IMGS, "Image Space" }, + {RecordType::INFO, "Dialog response" }, + {RecordType::INGR, "Ingredient" }, + {RecordType::IPCT, "Impact" }, + {RecordType::IPDS, "Impact Data Set" }, + {RecordType::KEYM, "Key" }, + {RecordType::KYWD, "Keyword" }, + {RecordType::LAND, "Landscape" }, + {RecordType::LCRT, "Location Reference Type" }, + {RecordType::LCTN, "Location" }, + {RecordType::LENS, "Lens Flare" }, + {RecordType::LGTM, "Lighting Template" }, + {RecordType::LIGH, "Light" }, + {RecordType::LSCR, "Load Screen" }, + {RecordType::LTEX, "Landscape Texture" }, + {RecordType::LVLI, "Leveled Item" }, + {RecordType::LVLN, "Leveled NPC" }, + {RecordType::LVSP, "Leveled Spell" }, + {RecordType::MATO, "Material Object" }, + {RecordType::MATT, "Material Type" }, + {RecordType::MESG, "Message" }, + {RecordType::MGEF, "Magic Effect" }, + {RecordType::MISC, "Misc. Item" }, + {RecordType::MOVT, "Movement Type" }, + {RecordType::MSTT, "Moveable Static" }, + {RecordType::MUSC, "Music Type" }, + {RecordType::MUST, "Music Track" }, + {RecordType::NAVI, "Navigation Mesh Info Map" }, + {RecordType::NAVM, "Navigation Mesh" }, + {RecordType::NOTE, "Note" }, + {RecordType::NPC_, "Non-Player Character (Actor)"}, + {RecordType::OTFT, "Outfit" }, + {RecordType::PACK, "Package" }, + {RecordType::PARW, "Placed Arrow" }, + {RecordType::PBAR, "Placed Barrier" }, + {RecordType::PBEA, "Placed Beam" }, + {RecordType::PCON, "Placed Cone/Voice" }, + {RecordType::PERK, "Perk" }, + {RecordType::PFLA, "Placed Flame" }, + {RecordType::PGRE, "Placed Projectile" }, + {RecordType::PHZD, "Placed Hazard" }, + {RecordType::PLYR, "Player Reference" }, + {RecordType::PMIS, "Placed Missile" }, + {RecordType::PROJ, "Projectile" }, + {RecordType::PWAT, "PWAT" }, + {RecordType::QUST, "Quest" }, + {RecordType::RACE, "Race" }, + {RecordType::REFR, "Placed Object" }, + {RecordType::REGN, "Region" }, + {RecordType::RELA, "Relationship" }, + {RecordType::REVB, "Reverb Parameters" }, + {RecordType::RFCT, "Visual Effect" }, + {RecordType::RGDL, "RGDL" }, + {RecordType::SCEN, "Scene" }, + {RecordType::SCOL, "Static Collection" }, + {RecordType::SCPT, "SCPT" }, + {RecordType::SCRL, "Scroll" }, + {RecordType::SHOU, "Shout" }, + {RecordType::SLGM, "Soul Gem" }, + {RecordType::SMBN, "Story Manager Branch Node" }, + {RecordType::SMEN, "Story Manager Event Node" }, + {RecordType::SMQN, "Story Manager Quest Node" }, + {RecordType::SNCT, "Sound Category" }, + {RecordType::SNDR, "Sound Descriptor" }, + {RecordType::SOPM, "Sound Output Model" }, + {RecordType::SOUN, "Sound Marker" }, + {RecordType::SPEL, "Spell" }, + {RecordType::SPGD, "Shader Particle Geometry" }, + {RecordType::STAT, "Static" }, + {RecordType::TACT, "Talking Activator" }, + {RecordType::TES4, "Main File Header" }, + {RecordType::TREE, "Tree" }, + {RecordType::TXST, "Texture Set" }, + {RecordType::VOLI, "Volumetric Lighting" }, + {RecordType::VTYP, "Voice Type" }, + {RecordType::WATR, "Water" }, + {RecordType::WEAP, "Weapon" }, + {RecordType::WOOP, "Word of Power" }, + {RecordType::WRLD, "Worldspace" }, + {RecordType::WTHR, "Weather" }, +}; +static constexpr auto record_type_name_map_std = utility::array_builtin_to_std(record_type_name_map_builtin); +static constexpr auto record_type_name_map = utility::map_to_soa(record_type_name_map_std); +[[nodiscard]] constexpr std::optional record_type_to_name(RecordType record_type) noexcept +{ + return utility::soa_first_to_second(record_type_name_map, record_type); +} + +static constexpr std::pair flag_description_map_builtin[] { + {{RecordType::ACHR, 9}, "Starts Dead" }, + {{RecordType::ACHR, 10}, "Persistent" }, + {{RecordType::ACHR, 11}, "Initially Disabled" }, + {{RecordType::ACHR, 25}, "No AI Acquire" }, + {{RecordType::ACHR, 29}, "Don't Havok Settle" }, + {{RecordType::ACTI, 6}, "Has Tree LOD" }, + {{RecordType::ACTI, 8}, "Must Update Anims" }, + {{RecordType::ACTI, 9}, "Hidden From Local Map" }, + {{RecordType::ACTI, 15}, "Has Distant LOD" }, + {{RecordType::ACTI, 16}, "Random Anim Start" }, + {{RecordType::ACTI, 17}, "Dangerous" }, + {{RecordType::ACTI, 20}, "Ignore Object Interaction" }, + {{RecordType::ACTI, 23}, "Is Marker" }, + {{RecordType::ACTI, 25}, "Obstacle" }, + {{RecordType::ACTI, 26}, "NavMesh Generation - Filter" }, + {{RecordType::ACTI, 27}, "NavMesh Generation - Bounding Box"}, + {{RecordType::ACTI, 29}, "Child Can Use" }, + {{RecordType::ACTI, 30}, "NavMesh Generation - Ground" }, + {{RecordType::ALCH, 29}, "Medicine" }, + {{RecordType::AMMO, 2}, "Non-Playable" }, + {{RecordType::ANIO, 9}, "Unknown 9" }, + {{RecordType::ARMO, 2}, "Non-Playable" }, + {{RecordType::ARMO, 6}, "Shield" }, + {{RecordType::ARMO, 10}, "Unknown 10" }, + {{RecordType::ARMO, 15}, "Unknown 15" }, + {{RecordType::CELL, 10}, "Persistent" }, + {{RecordType::CELL, 17}, "Off Limits" }, + {{RecordType::CELL, 18}, "Compressed" }, + {{RecordType::CELL, 19}, "Can't Wait" }, + {{RecordType::CLFM, 2}, "Non-Playable" }, + {{RecordType::CONT, 15}, "Has Distant LOD" }, + {{RecordType::CONT, 16}, "Random Anim Start" }, + {{RecordType::CONT, 25}, "Obstacle" }, + {{RecordType::CONT, 26}, "NavMesh Generation - Filter" }, + {{RecordType::CONT, 27}, "NavMesh Generation - Bounding Box"}, + {{RecordType::CONT, 30}, "NavMesh Generation - Ground" }, + {{RecordType::CSTY, 19}, "Allow Dual Wielding" }, + {{RecordType::DOOR, 15}, "Has Distant LOD" }, + {{RecordType::DOOR, 16}, "Random Anim Start" }, + {{RecordType::DOOR, 23}, "Is Marker" }, + {{RecordType::EYES, 2}, "Non-Playable" }, + {{RecordType::FURN, 7}, "Is Perch" }, + {{RecordType::FURN, 15}, "Has Distant LOD" }, + {{RecordType::FURN, 16}, "Random Anim Start" }, + {{RecordType::FURN, 23}, "Is Marker" }, + {{RecordType::FURN, 28}, "Must Exit To Talk" }, + {{RecordType::FURN, 29}, "Child Can Use" }, + {{RecordType::GLOB, 6}, "Constant" }, + {{RecordType::HDPT, 2}, "Non-Playable" }, + {{RecordType::IDLM, 29}, "Child Can Use" }, + {{RecordType::INFO, 13}, "Actor Changed" }, + {{RecordType::KEYM, 2}, "Non-Playable" }, + {{RecordType::LAND, 18}, "Compressed" }, + {{RecordType::LIGH, 16}, "Random Anim Start" }, + {{RecordType::LIGH, 17}, "Portal-strict" }, + {{RecordType::LIGH, 25}, "Obstacle" }, + {{RecordType::LSCR, 10}, "Displays In Main Menu" }, + {{RecordType::MISC, 2}, "Non-Playable" }, + {{RecordType::MSTT, 8}, "Must Update Anims" }, + {{RecordType::MSTT, 9}, "Hidden From Local Map" }, + {{RecordType::MSTT, 15}, "Has Distant LOD" }, + {{RecordType::MSTT, 16}, "Random Anim Start" }, + {{RecordType::MSTT, 19}, "Has Currents" }, + {{RecordType::MSTT, 25}, "Obstacle" }, + {{RecordType::MSTT, 26}, "NavMesh Generation - Filter" }, + {{RecordType::MSTT, 27}, "NavMesh Generation - Bounding Box"}, + {{RecordType::MSTT, 30}, "NavMesh Generation - Ground" }, + {{RecordType::NAVM, 18}, "Compressed" }, + {{RecordType::NAVM, 26}, "AutoGen" }, + {{RecordType::NAVM, 31}, "NavmeshGenCell" }, + {{RecordType::NPC_, 10}, "Unknown 10" }, + {{RecordType::NPC_, 18}, "Compressed" }, + {{RecordType::NPC_, 19}, "Unknown 19" }, + {{RecordType::NPC_, 29}, "Bleedout Override" }, + {{RecordType::PARW, 7}, "Turn Off Fire" }, + {{RecordType::PARW, 10}, "Persistent" }, + {{RecordType::PARW, 11}, "Initially Disabled" }, + {{RecordType::PARW, 28}, "Reflected By Auto Water" }, + {{RecordType::PARW, 29}, "Don't Havok Settle" }, + {{RecordType::PARW, 30}, "No Respawn" }, + {{RecordType::PBAR, 7}, "Turn Off Fire" }, + {{RecordType::PBAR, 10}, "Persistent" }, + {{RecordType::PBAR, 11}, "Initially Disabled" }, + {{RecordType::PBAR, 28}, "Reflected By Auto Water" }, + {{RecordType::PBAR, 29}, "Don't Havok Settle" }, + {{RecordType::PBAR, 30}, "No Respawn" }, + {{RecordType::PBEA, 7}, "Turn Off Fire" }, + {{RecordType::PBEA, 10}, "Persistent" }, + {{RecordType::PBEA, 11}, "Initially Disabled" }, + {{RecordType::PBEA, 28}, "Reflected By Auto Water" }, + {{RecordType::PBEA, 29}, "Don't Havok Settle" }, + {{RecordType::PBEA, 30}, "No Respawn" }, + {{RecordType::PCON, 7}, "Turn Off Fire" }, + {{RecordType::PCON, 10}, "Persistent" }, + {{RecordType::PCON, 11}, "Initially Disabled" }, + {{RecordType::PCON, 28}, "Reflected By Auto Water" }, + {{RecordType::PCON, 29}, "Don't Havok Settle" }, + {{RecordType::PCON, 30}, "No Respawn" }, + {{RecordType::PERK, 2}, "Non-Playable" }, + {{RecordType::PFLA, 7}, "Turn Off Fire" }, + {{RecordType::PFLA, 10}, "Persistent" }, + {{RecordType::PFLA, 11}, "Initially Disabled" }, + {{RecordType::PFLA, 28}, "Reflected By Auto Water" }, + {{RecordType::PFLA, 29}, "Don't Havok Settle" }, + {{RecordType::PFLA, 30}, "No Respawn" }, + {{RecordType::PGRE, 7}, "Turn Off Fire" }, + {{RecordType::PGRE, 10}, "Persistent" }, + {{RecordType::PGRE, 11}, "Initially Disabled" }, + {{RecordType::PGRE, 28}, "Reflected By Auto Water" }, + {{RecordType::PGRE, 29}, "Don't Havok Settle" }, + {{RecordType::PGRE, 30}, "No Respawn" }, + {{RecordType::PHZD, 7}, "Turn Off Fire" }, + {{RecordType::PHZD, 10}, "Persistent" }, + {{RecordType::PHZD, 11}, "Initially Disabled" }, + {{RecordType::PHZD, 28}, "Reflected By Auto Water" }, + {{RecordType::PHZD, 29}, "Don't Havok Settle" }, + {{RecordType::PHZD, 30}, "No Respawn" }, + {{RecordType::PMIS, 7}, "Turn Off Fire" }, + {{RecordType::PMIS, 10}, "Persistent" }, + {{RecordType::PMIS, 11}, "Initially Disabled" }, + {{RecordType::PMIS, 28}, "Reflected By Auto Water" }, + {{RecordType::PMIS, 29}, "Don't Havok Settle" }, + {{RecordType::PMIS, 30}, "No Respawn" }, + {{RecordType::RACE, 19}, "Critter?" }, + {{RecordType::REFR, 10}, "Persistent" }, + {{RecordType::REFR, 11}, "Initially Disabled" }, + {{RecordType::REFR, 16}, "Is Full LOD" }, + {{RecordType::REFR, 26}, "Filter (Collision Geometry)" }, + {{RecordType::REFR, 27}, "Bounding Box (Collision Geometry)"}, + {{RecordType::REFR, 28}, "Reflected By Auto Water" }, + {{RecordType::REFR, 30}, "Ground" }, + {{RecordType::REFR, 31}, "Multibound" }, + {{RecordType::REGN, 6}, "Border Region" }, + {{RecordType::RELA, 6}, "Secret" }, + {{RecordType::SHOU, 7}, "Treat spells as powers" }, + {{RecordType::SLGM, 17}, "Can Hold NPC Soul" }, + {{RecordType::STAT, 2}, "Never Fades" }, + {{RecordType::STAT, 5}, "Deleted" }, + {{RecordType::STAT, 6}, "Has Tree LOD" }, + {{RecordType::STAT, 7}, "Add-On LOD Object" }, + {{RecordType::STAT, 9}, "Hidden From Local Map" }, + {{RecordType::STAT, 11}, "Unknown 11" }, + {{RecordType::STAT, 15}, "Has Distant LOD" }, + {{RecordType::STAT, 16}, "Unknown 16" }, + {{RecordType::STAT, 17}, "Uses HD LOD Texture" }, + {{RecordType::STAT, 19}, "Has Currents" }, + {{RecordType::STAT, 23}, "Is Marker" }, + {{RecordType::STAT, 25}, "Obstacle" }, + {{RecordType::STAT, 26}, "NavMesh Generation - Filter" }, + {{RecordType::STAT, 27}, "NavMesh Generation - Bounding Box"}, + {{RecordType::STAT, 28}, "Show In World Map" }, + {{RecordType::STAT, 30}, "NavMesh Generation - Ground" }, + {{RecordType::TACT, 9}, "Hidden From Local Map" }, + {{RecordType::TACT, 16}, "Random Anim Start" }, + {{RecordType::TACT, 17}, "Radio Station" }, + {{RecordType::TES4, 0}, "ESM" }, + {{RecordType::TES4, 1}, "Altered" }, + {{RecordType::TES4, 2}, "Checked" }, + {{RecordType::TES4, 3}, "Active" }, + {{RecordType::TES4, 4}, "Optimized File" }, + {{RecordType::TES4, 5}, "Temp ID Owner" }, + {{RecordType::TES4, 7}, "Localized" }, + {{RecordType::TES4, 8}, "Precalc Data Only" }, + {{RecordType::TES4, 9}, "ESL" }, + {{RecordType::TREE, 15}, "Has Distant LOD" }, + {{RecordType::WEAP, 2}, "Non-Playable" }, + {{RecordType::WRLD, 19}, "Can't Wait" }, +}; +static constexpr auto flag_description_map_std = utility::array_builtin_to_std(flag_description_map_builtin); +static constexpr auto flag_description_map = utility::map_to_soa(flag_description_map_std); +[[nodiscard]] constexpr std::optional flag_to_description(Flag flag) noexcept +{ + return utility::soa_first_to_second(flag_description_map, flag); +} + +static constexpr std::pair refr_flag_description_map_builtin[] { + {{RecordType::ACTI, 9}, "Hidden From Local Map" }, + {{RecordType::ACTI, 10}, "Persistent" }, + {{RecordType::ACTI, 11}, "Initially Disabled" }, + {{RecordType::ACTI, 13}, "Sky Marker" }, + {{RecordType::ACTI, 15}, "Visible when distant" }, + {{RecordType::ACTI, 16}, "Is Full LOD" }, + {{RecordType::ACTI, 26}, "Filter (Collision Geometry)" }, + {{RecordType::ACTI, 27}, "Bounding Box (Collision Geometry)"}, + {{RecordType::ACTI, 28}, "Reflected By Auto Water" }, + {{RecordType::ACTI, 29}, "Don''t Havok Settle" }, + {{RecordType::ACTI, 30}, "No Respawn" }, + {{RecordType::ACTI, 31}, "Multibound" }, + {{RecordType::ADDN, 10}, "Persistent" }, + {{RecordType::ADDN, 11}, "Initially Disabled" }, + {{RecordType::ADDN, 16}, "Is Full LOD" }, + {{RecordType::ADDN, 28}, "Reflected By Auto Water" }, + {{RecordType::ADDN, 29}, "Don''t Havok Settle" }, + {{RecordType::ADDN, 30}, "No Respawn" }, + {{RecordType::ADDN, 31}, "Multibound" }, + {{RecordType::ALCH, 10}, "Persistent" }, + {{RecordType::ALCH, 11}, "Initially Disabled" }, + {{RecordType::ALCH, 16}, "Is Full LOD" }, + {{RecordType::ALCH, 25}, "No AI Acquire" }, + {{RecordType::ALCH, 28}, "Reflected By Auto Water" }, + {{RecordType::ALCH, 29}, "Don''t Havok Settle" }, + {{RecordType::ALCH, 30}, "No Respawn" }, + {{RecordType::ALCH, 31}, "Multibound" }, + {{RecordType::AMMO, 10}, "Persistent" }, + {{RecordType::AMMO, 11}, "Initially Disabled" }, + {{RecordType::AMMO, 16}, "Is Full LOD" }, + {{RecordType::AMMO, 25}, "No AI Acquire" }, + {{RecordType::AMMO, 28}, "Reflected By Auto Water" }, + {{RecordType::AMMO, 29}, "Don''t Havok Settle" }, + {{RecordType::AMMO, 30}, "No Respawn" }, + {{RecordType::AMMO, 31}, "Multibound" }, + {{RecordType::ARMO, 10}, "Persistent" }, + {{RecordType::ARMO, 11}, "Initially Disabled" }, + {{RecordType::ARMO, 16}, "Is Full LOD" }, + {{RecordType::ARMO, 25}, "No AI Acquire" }, + {{RecordType::ARMO, 28}, "Reflected By Auto Water" }, + {{RecordType::ARMO, 29}, "Don''t Havok Settle" }, + {{RecordType::ARMO, 30}, "No Respawn" }, + {{RecordType::ARMO, 31}, "Multibound" }, + {{RecordType::BOOK, 10}, "Persistent" }, + {{RecordType::BOOK, 11}, "Initially Disabled" }, + {{RecordType::BOOK, 16}, "Is Full LOD" }, + {{RecordType::BOOK, 25}, "No AI Acquire" }, + {{RecordType::BOOK, 28}, "Reflected By Auto Water" }, + {{RecordType::BOOK, 29}, "Don''t Havok Settle" }, + {{RecordType::BOOK, 30}, "No Respawn" }, + {{RecordType::BOOK, 31}, "Multibound" }, + {{RecordType::CONT, 10}, "Persistent" }, + {{RecordType::CONT, 11}, "Initially Disabled" }, + {{RecordType::CONT, 16}, "Is Full LOD" }, + {{RecordType::CONT, 25}, "No AI Acquire" }, + {{RecordType::CONT, 26}, "Filter (Collision Geometry)" }, + {{RecordType::CONT, 27}, "Bounding Box (Collision Geometry)"}, + {{RecordType::CONT, 28}, "Reflected By Auto Water" }, + {{RecordType::CONT, 29}, "Don''t Havok Settle" }, + {{RecordType::CONT, 30}, "Ground" }, + {{RecordType::CONT, 31}, "Multibound" }, + {{RecordType::DOOR, 6}, "Hidden From Local Map" }, + {{RecordType::DOOR, 8}, "Inaccessible" }, + {{RecordType::DOOR, 10}, "Persistent" }, + {{RecordType::DOOR, 11}, "Initially Disabled" }, + {{RecordType::DOOR, 16}, "Is Full LOD" }, + {{RecordType::DOOR, 26}, "Filter (Collision Geometry)" }, + {{RecordType::DOOR, 27}, "Bounding Box (Collision Geometry)"}, + {{RecordType::DOOR, 28}, "Reflected By Auto Water" }, + {{RecordType::DOOR, 29}, "Don''t Havok Settle" }, + {{RecordType::DOOR, 30}, "No Respawn" }, + {{RecordType::DOOR, 31}, "Multibound" }, + {{RecordType::FLOR, 9}, "Hidden From Local Map" }, + {{RecordType::FLOR, 10}, "Persistent" }, + {{RecordType::FLOR, 11}, "Initially Disabled" }, + {{RecordType::FLOR, 13}, "Sky Marker" }, + {{RecordType::FLOR, 15}, "Visible when distant" }, + {{RecordType::FLOR, 16}, "Is Full LOD" }, + {{RecordType::FLOR, 26}, "Filter (Collision Geometry)" }, + {{RecordType::FLOR, 27}, "Bounding Box (Collision Geometry)"}, + {{RecordType::FLOR, 28}, "Reflected By Auto Water" }, + {{RecordType::FLOR, 29}, "Don''t Havok Settle" }, + {{RecordType::FLOR, 30}, "No Respawn" }, + {{RecordType::FLOR, 31}, "Multibound" }, + {{RecordType::INGR, 10}, "Persistent" }, + {{RecordType::INGR, 11}, "Initially Disabled" }, + {{RecordType::INGR, 16}, "Is Full LOD" }, + {{RecordType::INGR, 25}, "No AI Acquire" }, + {{RecordType::INGR, 28}, "Reflected By Auto Water" }, + {{RecordType::INGR, 29}, "Don''t Havok Settle" }, + {{RecordType::INGR, 30}, "No Respawn" }, + {{RecordType::INGR, 31}, "Multibound" }, + {{RecordType::KEYM, 10}, "Persistent" }, + {{RecordType::KEYM, 11}, "Initially Disabled" }, + {{RecordType::KEYM, 16}, "Is Full LOD" }, + {{RecordType::KEYM, 25}, "No AI Acquire" }, + {{RecordType::KEYM, 28}, "Reflected By Auto Water" }, + {{RecordType::KEYM, 29}, "Don''t Havok Settle" }, + {{RecordType::KEYM, 30}, "No Respawn" }, + {{RecordType::KEYM, 31}, "Multibound" }, + {{RecordType::LIGH, 8}, "Doesn''t Light Water" }, + {{RecordType::LIGH, 9}, "Casts Shadows" }, + {{RecordType::LIGH, 10}, "Persistent" }, + {{RecordType::LIGH, 11}, "Initially Disabled" }, + {{RecordType::LIGH, 16}, "Never Fades" }, + {{RecordType::LIGH, 17}, "Doesn''t Light Landscape" }, + {{RecordType::LIGH, 25}, "No AI Acquire" }, + {{RecordType::LIGH, 28}, "Reflected By Auto Water" }, + {{RecordType::LIGH, 29}, "Don''t Havok Settle" }, + {{RecordType::LIGH, 30}, "No Respawn" }, + {{RecordType::LIGH, 31}, "Multibound" }, + {{RecordType::MISC, 10}, "Persistent" }, + {{RecordType::MISC, 11}, "Initially Disabled" }, + {{RecordType::MISC, 16}, "Is Full LOD" }, + {{RecordType::MISC, 25}, "No AI Acquire" }, + {{RecordType::MISC, 28}, "Reflected By Auto Water" }, + {{RecordType::MISC, 29}, "Don''t Havok Settle" }, + {{RecordType::MISC, 30}, "No Respawn" }, + {{RecordType::MISC, 31}, "Multibound" }, + {{RecordType::MSTT, 9}, "Motion Blur" }, + {{RecordType::MSTT, 10}, "Persistent" }, + {{RecordType::MSTT, 11}, "Initially Disabled" }, + {{RecordType::MSTT, 16}, "Is Full LOD" }, + {{RecordType::MSTT, 26}, "Filter (Collision Geometry)" }, + {{RecordType::MSTT, 27}, "Bounding Box (Collision Geometry)"}, + {{RecordType::MSTT, 28}, "Reflected By Auto Water" }, + {{RecordType::MSTT, 29}, "Don''t Havok Settle" }, + {{RecordType::MSTT, 30}, "No Respawn" }, + {{RecordType::MSTT, 31}, "Multibound" }, + {{RecordType::SCRL, 10}, "Persistent" }, + {{RecordType::SCRL, 11}, "Initially Disabled" }, + {{RecordType::SCRL, 16}, "Is Full LOD" }, + {{RecordType::SCRL, 25}, "No AI Acquire" }, + {{RecordType::SCRL, 28}, "Reflected By Auto Water" }, + {{RecordType::SCRL, 29}, "Don''t Havok Settle" }, + {{RecordType::SCRL, 30}, "No Respawn" }, + {{RecordType::SCRL, 31}, "Multibound" }, + {{RecordType::SLGM, 10}, "Persistent" }, + {{RecordType::SLGM, 11}, "Initially Disabled" }, + {{RecordType::SLGM, 16}, "Is Full LOD" }, + {{RecordType::SLGM, 25}, "No AI Acquire" }, + {{RecordType::SLGM, 28}, "Reflected By Auto Water" }, + {{RecordType::SLGM, 29}, "Don''t Havok Settle" }, + {{RecordType::SLGM, 30}, "No Respawn" }, + {{RecordType::SLGM, 31}, "Multibound" }, + {{RecordType::STAT, 9}, "Hidden From Local Map" }, + {{RecordType::STAT, 10}, "Persistent" }, + {{RecordType::STAT, 11}, "Initially Disabled" }, + {{RecordType::STAT, 13}, "Sky Marker" }, + {{RecordType::STAT, 15}, "Visible when distant" }, + {{RecordType::STAT, 16}, "Is Full LOD" }, + {{RecordType::STAT, 26}, "Filter (Collision Geometry)" }, + {{RecordType::STAT, 27}, "Bounding Box (Collision Geometry)"}, + {{RecordType::STAT, 28}, "Reflected By Auto Water" }, + {{RecordType::STAT, 29}, "Don''t Havok Settle" }, + {{RecordType::STAT, 30}, "No Respawn" }, + {{RecordType::STAT, 31}, "Multibound" }, + {{RecordType::TREE, 9}, "Hidden From Local Map" }, + {{RecordType::TREE, 10}, "Persistent" }, + {{RecordType::TREE, 11}, "Initially Disabled" }, + {{RecordType::TREE, 13}, "Sky Marker" }, + {{RecordType::TREE, 15}, "Visible when distant" }, + {{RecordType::TREE, 16}, "Is Full LOD" }, + {{RecordType::TREE, 26}, "Filter (Collision Geometry)" }, + {{RecordType::TREE, 27}, "Bounding Box (Collision Geometry)"}, + {{RecordType::TREE, 28}, "Reflected By Auto Water" }, + {{RecordType::TREE, 29}, "Don''t Havok Settle" }, + {{RecordType::TREE, 30}, "No Respawn" }, + {{RecordType::TREE, 31}, "Multibound" }, + {{RecordType::WEAP, 10}, "Persistent" }, + {{RecordType::WEAP, 11}, "Initially Disabled" }, + {{RecordType::WEAP, 16}, "Is Full LOD" }, + {{RecordType::WEAP, 25}, "No AI Acquire" }, + {{RecordType::WEAP, 28}, "Reflected By Auto Water" }, + {{RecordType::WEAP, 29}, "Don''t Havok Settle" }, + {{RecordType::WEAP, 30}, "No Respawn" }, + {{RecordType::WEAP, 31}, "Multibound" }, +}; +static constexpr auto refr_flag_description_map_std = utility::array_builtin_to_std(refr_flag_description_map_builtin); +static constexpr auto refr_flag_description_map = utility::map_to_soa(refr_flag_description_map_std); +[[nodiscard]] constexpr std::optional refr_flag_to_description(RefrFlag refr_flag) noexcept +{ + return utility::soa_first_to_second(refr_flag_description_map, refr_flag); +} + +} diff --git a/reference/group_type.json b/reference/group_type.json new file mode 100644 index 0000000..89cf0cf --- /dev/null +++ b/reference/group_type.json @@ -0,0 +1,42 @@ +[ + { + "type": "Top", + "name": "Top Type" + }, + { + "type": "WorldChildren", + "name": "World Children" + }, + { + "type": "InteriorCellBlock", + "name": "Interior Cell Block" + }, + { + "type": "InteriorCellSubBlock", + "name": "Interior Cell Sub-Block" + }, + { + "type": "ExteriorCellBlock", + "name": "Exterior Cell" + }, + { + "type": "ExteriorCellSubBlock", + "name": "Exterior Cell Sub-Block" + }, + { + "type": "CellChildren", + "name": "Cell Children" + }, + { + "type": "TopicChildren", + "name": "Topic Children" + }, + { + "type": "CellPersistentChildren", + "name": "Cell Persistent Children" + }, + { + "type": "CellTemporaryChildren", + "name": "Cell Temporary Children" + } +] diff --git a/reference/record_codegen.py b/reference/record_codegen.py new file mode 100644 index 0000000..bb3c377 --- /dev/null +++ b/reference/record_codegen.py @@ -0,0 +1,179 @@ +import json +import os +from dataclasses import dataclass + + +INDENT = 8 +WIDTH = 80 +LAST = "};" +SV = "std::string_view" + +PREAMBLE = """#include "esx_reader.hpp" + +using namespace esxr; + +namespace esxr_lut {""" +POSTAMBLE = "}\n" + + +def transpose(seq): + return list(zip(*seq)) + +def clean(seq): + return [x for x in seq if x is not None] + +def indented_block(items): + lines = [] + line = "" + for item in items: + if len(line) + len(item) + 1 > WIDTH: + lines += [line[:-1]] + line = "" + if not line: + line = " " * INDENT + line += item + ", " + if line.strip(): + lines += [line] + return "\n".join(lines) + +def indented_list(items): + return ",\n".join([" " * INDENT + x for x in items]) + +def max_length(list): + return max(map(lambda x: len(x), list)) + +def wrap_bracket(list): + return ["{" + string + "}" for string in list] + +def padded_join(lists): + maximums = [max_length(x) for x in lists] + padded = [] + for max, l in zip(maximums, lists): + padded += [[x + " " * (max - len(x)) for x in l]] + padded_transposed = transpose(padded) + return ["".join(x) for x in padded_transposed] + +@dataclass +class Map: + first_type: str + second_type: str + first_name: str + second_name: str + formats: list[str] + + F_DECL = "static constexpr std::pair<{0}, {1}> {2}_builtin[] {{" + F_SOA = """static constexpr auto {0}_std = utility::array_builtin_to_std({0}_builtin); +static constexpr auto {0} = utility::map_to_soa({0}_std);""" + F_FUNC_DECL = "[[nodiscard]] constexpr std::optional<{0}> {1}_to_{2}({3} {1}) noexcept" + F_FUNC_BODY_FORWARD = " return utility::soa_first_to_second({0}, {1});" + F_FUNC_BODY_REVERSE = " return utility::soa_second_to_first({0}, {1});" + + @property + def name(self): + return self.first_name + "_" + self.second_name + "_map" + + @property + def decl(self): + return Map.F_DECL.format(self.first_type, self.second_type, self.name) + + @property + def to_soa(self): + return Map.F_SOA.format(self.name) + + @property + def forward_decl(self): + return Map.F_FUNC_DECL.format(self.second_type, self.first_name, self.second_name, self.first_type) + + @property + def reverse_decl(self): + return Map.F_FUNC_DECL.format(self.first_type, self.second_name, self.first_name, self.second_type) + + @property + def forward_func(self): + return self.forward_decl + "\n{\n" + Map.F_FUNC_BODY_FORWARD.format(self.name, self.first_name) + "\n}" + + @property + def reverse_func(self): + return self.reverse_decl + "\n{\n" + Map.F_FUNC_BODY_REVERSE.format(self.name, self.second_name) + "\n}" + + def data_to_list(self, data): + parts = [] + for format in self.formats: + parts += [[format.format(*x) for x in data]] + return indented_block(wrap_bracket(padded_join(parts))) + + def code(self, data, reverse = False): + parts = [self.decl, self.data_to_list(data), LAST, self.to_soa, self.forward_func] + decls = [self.forward_decl] + if reverse: + parts += [self.reverse_func] + decls += [self.reverse_decl] + return ["\n".join(parts), "\n".join([x + ';' for x in decls])] + + +def add_extra(data): + grup = {"fourcc": "GRUP", "name": "Group", "flags": []} + note = {"fourcc": "NOTE", "name": "Note", "flags": []} + data += [grup, note] + data.sort(key=lambda x: x["fourcc"]) + +def gen_enum(data): + # generate sorted list of signatures + sigs = [r["fourcc"] for r in data] + string = "enum class RecordType {\n" + indented_block(sigs) + LAST + return [None, string] + +def gen_group_type(data): + map = Map("GroupType", SV, "group_type", "name", ["GroupType::{0}", ", \"{1}\""]) + data = [(x['type'], x['name']) for x in data] + return map.code(data) + +def gen_names(data): + map = Map("RecordType", SV, "record_type", "name", ["RecordType::{0}", ", \"{1}\""]) + data = [(x['fourcc'], x['name']) for x in data] + return map.code(data) + +def gen_fourcc(data): + map = Map("RecordType", "FourCC", "record_type", "fourcc", ["RecordType::{0}", ", FourCC(\"{0}\")"]) + data = [(x['fourcc'], ) for x in data] + return map.code(data, reverse = True) + +def gen_flags(data): + map = Map("Flag", SV, "flag", "description", ["{{RecordType::{0}, {1:>2}}}", ", \"{2}\""]) + data = [(x['fourcc'], y['bit'], y['description']) for x in data for y in x['flags']] + return map.code(data) + +def gen_refr_flags(data): + map = Map("RefrFlag", SV, "refr_flag", "description", ["{{RecordType::{0}, {1:>2}}}", ", \"{2}\""]) + data = [(x['fourcc'], y['bit'], y['description']) for x in data for y in x['flags']] + return map.code(data) + +def main(): + fdir = os.path.dirname(__file__) + with open(os.path.join(fdir, "records.json"), "r") as f: + data = json.load(f) + with open(os.path.join(fdir, "refr_flags.json"), "r") as f: + refr_data = json.load(f) + with open(os.path.join(fdir, "group_type.json"), "r") as f: + gt_data = json.load(f) + add_extra(data) + code = [] + code += [gen_enum(data)] + code += [gen_group_type(gt_data)] + code += [gen_fourcc(data)] + code += [gen_names(data)] + code += [gen_flags(data)] + code += [gen_refr_flags(refr_data)] + code = transpose(code) + lut = [PREAMBLE] + clean(code[0]) + [POSTAMBLE] + lut = "\n\n".join(lut) + header = clean(code[1]) + header = "\n".join(header) + with open(os.path.join(fdir, "esx_reader_lut.cpp"), "w") as f: + f.write(lut) + with open(os.path.join(fdir, "esx_reader.hpp.fragment"), "w") as f: + f.write(header) + + +if __name__ == "__main__": + main() diff --git a/reference/record_filter.py b/reference/record_filter.py index cf403e6..7c8ce51 100644 --- a/reference/record_filter.py +++ b/reference/record_filter.py @@ -63,7 +63,7 @@ for string in all: bit, desc = re_flag_line.match(line).groups() # fix '' pascal escape and ESL special case desc = desc.replace("''", "'").replace("', '", "") - flags += [Flag(bit, desc)] + flags += [Flag(int(bit), desc)] # handle STAT special case elif sig == "STAT": flags_string = re.match(".*?\n.*?wbFlags\(.*?\n(?:.*?\n){32}.*?\]", string).group(0) @@ -78,9 +78,6 @@ for string in all: rdict = {r.fourcc: r for r in records} records = list(rdict.values()) -# add in the apparently supported NOTE -records += [Record("NOTE", "Note", [])] - # sort the records by signature records = sorted(records, key=lambda x: x.fourcc) @@ -92,6 +89,6 @@ class Encoder(json.JSONEncoder): else: return json.JSONEncoder.default(self, obj) -with open(os.path.join(fdir, "flags.json"), "w") as f: +with open(os.path.join(fdir, "records.json"), "w") as f: json.dump(records, f, cls=Encoder, indent=4) \ No newline at end of file diff --git a/reference/flags.json b/reference/records.json similarity index 85% rename from reference/flags.json rename to reference/records.json index a95c9d1..c2a8cab 100644 --- a/reference/flags.json +++ b/reference/records.json @@ -9,23 +9,23 @@ "name": "Placed NPC", "flags": [ { - "bit": "9", + "bit": 9, "description": "Starts Dead" }, { - "bit": "10", + "bit": 10, "description": "Persistent" }, { - "bit": "11", + "bit": 11, "description": "Initially Disabled" }, { - "bit": "25", + "bit": 25, "description": "No AI Acquire" }, { - "bit": "29", + "bit": 29, "description": "Don't Havok Settle" } ] @@ -35,55 +35,55 @@ "name": "Activator", "flags": [ { - "bit": "6", + "bit": 6, "description": "Has Tree LOD" }, { - "bit": "8", + "bit": 8, "description": "Must Update Anims" }, { - "bit": "9", + "bit": 9, "description": "Hidden From Local Map" }, { - "bit": "15", + "bit": 15, "description": "Has Distant LOD" }, { - "bit": "16", + "bit": 16, "description": "Random Anim Start" }, { - "bit": "17", + "bit": 17, "description": "Dangerous" }, { - "bit": "20", + "bit": 20, "description": "Ignore Object Interaction" }, { - "bit": "23", + "bit": 23, "description": "Is Marker" }, { - "bit": "25", + "bit": 25, "description": "Obstacle" }, { - "bit": "26", + "bit": 26, "description": "NavMesh Generation - Filter" }, { - "bit": "27", + "bit": 27, "description": "NavMesh Generation - Bounding Box" }, { - "bit": "29", + "bit": 29, "description": "Child Can Use" }, { - "bit": "30", + "bit": 30, "description": "NavMesh Generation - Ground" } ] @@ -98,7 +98,7 @@ "name": "Ingestible", "flags": [ { - "bit": "29", + "bit": 29, "description": "Medicine" } ] @@ -108,7 +108,7 @@ "name": "Ammunition", "flags": [ { - "bit": "2", + "bit": 2, "description": "Non-Playable" } ] @@ -118,7 +118,7 @@ "name": "Animated Object", "flags": [ { - "bit": "9", + "bit": 9, "description": "Unknown 9" } ] @@ -138,19 +138,19 @@ "name": "Armor", "flags": [ { - "bit": "2", + "bit": 2, "description": "Non-Playable" }, { - "bit": "6", + "bit": 6, "description": "Shield" }, { - "bit": "10", + "bit": 10, "description": "Unknown 10" }, { - "bit": "15", + "bit": 15, "description": "Unknown 15" } ] @@ -195,19 +195,19 @@ "name": "Cell", "flags": [ { - "bit": "10", + "bit": 10, "description": "Persistent" }, { - "bit": "17", + "bit": 17, "description": "Off Limits" }, { - "bit": "18", + "bit": 18, "description": "Compressed" }, { - "bit": "19", + "bit": 19, "description": "Can't Wait" } ] @@ -227,7 +227,7 @@ "name": "Color", "flags": [ { - "bit": "2", + "bit": 2, "description": "Non-Playable" } ] @@ -252,27 +252,27 @@ "name": "Container", "flags": [ { - "bit": "15", + "bit": 15, "description": "Has Distant LOD" }, { - "bit": "16", + "bit": 16, "description": "Random Anim Start" }, { - "bit": "25", + "bit": 25, "description": "Obstacle" }, { - "bit": "26", + "bit": 26, "description": "NavMesh Generation - Filter" }, { - "bit": "27", + "bit": 27, "description": "NavMesh Generation - Bounding Box" }, { - "bit": "30", + "bit": 30, "description": "NavMesh Generation - Ground" } ] @@ -287,7 +287,7 @@ "name": "Combat Style", "flags": [ { - "bit": "19", + "bit": 19, "description": "Allow Dual Wielding" } ] @@ -322,15 +322,15 @@ "name": "Door", "flags": [ { - "bit": "15", + "bit": 15, "description": "Has Distant LOD" }, { - "bit": "16", + "bit": 16, "description": "Random Anim Start" }, { - "bit": "23", + "bit": 23, "description": "Is Marker" } ] @@ -370,7 +370,7 @@ "name": "Eyes", "flags": [ { - "bit": "2", + "bit": 2, "description": "Non-Playable" } ] @@ -405,27 +405,27 @@ "name": "Furniture", "flags": [ { - "bit": "7", + "bit": 7, "description": "Is Perch" }, { - "bit": "15", + "bit": 15, "description": "Has Distant LOD" }, { - "bit": "16", + "bit": 16, "description": "Random Anim Start" }, { - "bit": "23", + "bit": 23, "description": "Is Marker" }, { - "bit": "28", + "bit": 28, "description": "Must Exit To Talk" }, { - "bit": "29", + "bit": 29, "description": "Child Can Use" } ] @@ -435,7 +435,7 @@ "name": "Global", "flags": [ { - "bit": "6", + "bit": 6, "description": "Constant" } ] @@ -465,7 +465,7 @@ "name": "Head Part", "flags": [ { - "bit": "2", + "bit": 2, "description": "Non-Playable" } ] @@ -480,7 +480,7 @@ "name": "Idle Marker", "flags": [ { - "bit": "29", + "bit": 29, "description": "Child Can Use" } ] @@ -500,7 +500,7 @@ "name": "Dialog response", "flags": [ { - "bit": "13", + "bit": 13, "description": "Actor Changed" } ] @@ -525,7 +525,7 @@ "name": "Key", "flags": [ { - "bit": "2", + "bit": 2, "description": "Non-Playable" } ] @@ -540,7 +540,7 @@ "name": "Landscape", "flags": [ { - "bit": "18", + "bit": 18, "description": "Compressed" } ] @@ -570,15 +570,15 @@ "name": "Light", "flags": [ { - "bit": "16", + "bit": 16, "description": "Random Anim Start" }, { - "bit": "17", + "bit": 17, "description": "Portal-strict" }, { - "bit": "25", + "bit": 25, "description": "Obstacle" } ] @@ -588,7 +588,7 @@ "name": "Load Screen", "flags": [ { - "bit": "10", + "bit": 10, "description": "Displays In Main Menu" } ] @@ -638,7 +638,7 @@ "name": "Misc. Item", "flags": [ { - "bit": "2", + "bit": 2, "description": "Non-Playable" } ] @@ -653,39 +653,39 @@ "name": "Moveable Static", "flags": [ { - "bit": "8", + "bit": 8, "description": "Must Update Anims" }, { - "bit": "9", + "bit": 9, "description": "Hidden From Local Map" }, { - "bit": "15", + "bit": 15, "description": "Has Distant LOD" }, { - "bit": "16", + "bit": 16, "description": "Random Anim Start" }, { - "bit": "19", + "bit": 19, "description": "Has Currents" }, { - "bit": "25", + "bit": 25, "description": "Obstacle" }, { - "bit": "26", + "bit": 26, "description": "NavMesh Generation - Filter" }, { - "bit": "27", + "bit": 27, "description": "NavMesh Generation - Bounding Box" }, { - "bit": "30", + "bit": 30, "description": "NavMesh Generation - Ground" } ] @@ -710,42 +710,37 @@ "name": "Navigation Mesh", "flags": [ { - "bit": "18", + "bit": 18, "description": "Compressed" }, { - "bit": "26", + "bit": 26, "description": "AutoGen" }, { - "bit": "31", + "bit": 31, "description": "NavmeshGenCell" } ] }, - { - "fourcc": "NOTE", - "name": "Note", - "flags": [] - }, { "fourcc": "NPC_", "name": "Non-Player Character (Actor)", "flags": [ { - "bit": "10", + "bit": 10, "description": "Unknown 10" }, { - "bit": "18", + "bit": 18, "description": "Compressed" }, { - "bit": "19", + "bit": 19, "description": "Unknown 19" }, { - "bit": "29", + "bit": 29, "description": "Bleedout Override" } ] @@ -765,27 +760,27 @@ "name": "Placed Arrow", "flags": [ { - "bit": "7", + "bit": 7, "description": "Turn Off Fire" }, { - "bit": "10", + "bit": 10, "description": "Persistent" }, { - "bit": "11", + "bit": 11, "description": "Initially Disabled" }, { - "bit": "28", + "bit": 28, "description": "Reflected By Auto Water" }, { - "bit": "29", + "bit": 29, "description": "Don't Havok Settle" }, { - "bit": "30", + "bit": 30, "description": "No Respawn" } ] @@ -795,27 +790,27 @@ "name": "Placed Barrier", "flags": [ { - "bit": "7", + "bit": 7, "description": "Turn Off Fire" }, { - "bit": "10", + "bit": 10, "description": "Persistent" }, { - "bit": "11", + "bit": 11, "description": "Initially Disabled" }, { - "bit": "28", + "bit": 28, "description": "Reflected By Auto Water" }, { - "bit": "29", + "bit": 29, "description": "Don't Havok Settle" }, { - "bit": "30", + "bit": 30, "description": "No Respawn" } ] @@ -825,27 +820,27 @@ "name": "Placed Beam", "flags": [ { - "bit": "7", + "bit": 7, "description": "Turn Off Fire" }, { - "bit": "10", + "bit": 10, "description": "Persistent" }, { - "bit": "11", + "bit": 11, "description": "Initially Disabled" }, { - "bit": "28", + "bit": 28, "description": "Reflected By Auto Water" }, { - "bit": "29", + "bit": 29, "description": "Don't Havok Settle" }, { - "bit": "30", + "bit": 30, "description": "No Respawn" } ] @@ -855,27 +850,27 @@ "name": "Placed Cone/Voice", "flags": [ { - "bit": "7", + "bit": 7, "description": "Turn Off Fire" }, { - "bit": "10", + "bit": 10, "description": "Persistent" }, { - "bit": "11", + "bit": 11, "description": "Initially Disabled" }, { - "bit": "28", + "bit": 28, "description": "Reflected By Auto Water" }, { - "bit": "29", + "bit": 29, "description": "Don't Havok Settle" }, { - "bit": "30", + "bit": 30, "description": "No Respawn" } ] @@ -885,7 +880,7 @@ "name": "Perk", "flags": [ { - "bit": "2", + "bit": 2, "description": "Non-Playable" } ] @@ -895,27 +890,27 @@ "name": "Placed Flame", "flags": [ { - "bit": "7", + "bit": 7, "description": "Turn Off Fire" }, { - "bit": "10", + "bit": 10, "description": "Persistent" }, { - "bit": "11", + "bit": 11, "description": "Initially Disabled" }, { - "bit": "28", + "bit": 28, "description": "Reflected By Auto Water" }, { - "bit": "29", + "bit": 29, "description": "Don't Havok Settle" }, { - "bit": "30", + "bit": 30, "description": "No Respawn" } ] @@ -925,27 +920,27 @@ "name": "Placed Projectile", "flags": [ { - "bit": "7", + "bit": 7, "description": "Turn Off Fire" }, { - "bit": "10", + "bit": 10, "description": "Persistent" }, { - "bit": "11", + "bit": 11, "description": "Initially Disabled" }, { - "bit": "28", + "bit": 28, "description": "Reflected By Auto Water" }, { - "bit": "29", + "bit": 29, "description": "Don't Havok Settle" }, { - "bit": "30", + "bit": 30, "description": "No Respawn" } ] @@ -955,27 +950,27 @@ "name": "Placed Hazard", "flags": [ { - "bit": "7", + "bit": 7, "description": "Turn Off Fire" }, { - "bit": "10", + "bit": 10, "description": "Persistent" }, { - "bit": "11", + "bit": 11, "description": "Initially Disabled" }, { - "bit": "28", + "bit": 28, "description": "Reflected By Auto Water" }, { - "bit": "29", + "bit": 29, "description": "Don't Havok Settle" }, { - "bit": "30", + "bit": 30, "description": "No Respawn" } ] @@ -990,27 +985,27 @@ "name": "Placed Missile", "flags": [ { - "bit": "7", + "bit": 7, "description": "Turn Off Fire" }, { - "bit": "10", + "bit": 10, "description": "Persistent" }, { - "bit": "11", + "bit": 11, "description": "Initially Disabled" }, { - "bit": "28", + "bit": 28, "description": "Reflected By Auto Water" }, { - "bit": "29", + "bit": 29, "description": "Don't Havok Settle" }, { - "bit": "30", + "bit": 30, "description": "No Respawn" } ] @@ -1035,7 +1030,7 @@ "name": "Race", "flags": [ { - "bit": "19", + "bit": 19, "description": "Critter?" } ] @@ -1045,35 +1040,35 @@ "name": "Placed Object", "flags": [ { - "bit": "10", + "bit": 10, "description": "Persistent" }, { - "bit": "11", + "bit": 11, "description": "Initially Disabled" }, { - "bit": "16", + "bit": 16, "description": "Is Full LOD" }, { - "bit": "26", + "bit": 26, "description": "Filter (Collision Geometry)" }, { - "bit": "27", + "bit": 27, "description": "Bounding Box (Collision Geometry)" }, { - "bit": "28", + "bit": 28, "description": "Reflected By Auto Water" }, { - "bit": "30", + "bit": 30, "description": "Ground" }, { - "bit": "31", + "bit": 31, "description": "Multibound" } ] @@ -1083,7 +1078,7 @@ "name": "Region", "flags": [ { - "bit": "6", + "bit": 6, "description": "Border Region" } ] @@ -1093,7 +1088,7 @@ "name": "Relationship", "flags": [ { - "bit": "6", + "bit": 6, "description": "Secret" } ] @@ -1138,7 +1133,7 @@ "name": "Shout", "flags": [ { - "bit": "7", + "bit": 7, "description": "Treat spells as powers" } ] @@ -1148,7 +1143,7 @@ "name": "Soul Gem", "flags": [ { - "bit": "17", + "bit": 17, "description": "Can Hold NPC Soul" } ] @@ -1273,15 +1268,15 @@ "name": "Talking Activator", "flags": [ { - "bit": "9", + "bit": 9, "description": "Hidden From Local Map" }, { - "bit": "16", + "bit": 16, "description": "Random Anim Start" }, { - "bit": "17", + "bit": 17, "description": "Radio Station" } ] @@ -1291,39 +1286,39 @@ "name": "Main File Header", "flags": [ { - "bit": "0", + "bit": 0, "description": "ESM" }, { - "bit": "1", + "bit": 1, "description": "Altered" }, { - "bit": "2", + "bit": 2, "description": "Checked" }, { - "bit": "3", + "bit": 3, "description": "Active" }, { - "bit": "4", + "bit": 4, "description": "Optimized File" }, { - "bit": "5", + "bit": 5, "description": "Temp ID Owner" }, { - "bit": "7", + "bit": 7, "description": "Localized" }, { - "bit": "8", + "bit": 8, "description": "Precalc Data Only" }, { - "bit": "9", + "bit": 9, "description": "ESL" } ] @@ -1333,7 +1328,7 @@ "name": "Tree", "flags": [ { - "bit": "15", + "bit": 15, "description": "Has Distant LOD" } ] @@ -1363,7 +1358,7 @@ "name": "Weapon", "flags": [ { - "bit": "2", + "bit": 2, "description": "Non-Playable" } ] @@ -1378,7 +1373,7 @@ "name": "Worldspace", "flags": [ { - "bit": "19", + "bit": 19, "description": "Can't Wait" } ] diff --git a/reference/refr_flag_filter.py b/reference/refr_flag_filter.py new file mode 100644 index 0000000..06ca86d --- /dev/null +++ b/reference/refr_flag_filter.py @@ -0,0 +1,90 @@ +import os +import re +import json +from dataclasses import dataclass + + +# helper used when dumping the records to JSON +class Jsonify: + def encode(self, value=None): + if not value: + value = self.__dict__ + return value + +# Record model +@dataclass +class Flag(Jsonify): + bit: int + description: str + +@dataclass +class Record(Jsonify): + fourcc: str + flags: list[Flag] + + +# open and read the records from xEdit source +fdir = os.path.dirname(__file__) +with open(os.path.join(fdir, "TES5Edit/Core/wbDefinitionsTES5.pas"), "r") as f: + inp = f.read() + +# find the REFR flags decider +decider = re.findall("function wbREFRRecordFlagsDecider.*?\n(?:.*?\n)+?end;", inp) +assert len(decider) == 1, "Could not uniquely match wbREFRRecordFlagsDecider." +decider = decider[0] + +# get decider sections +sections = re.findall("if\s*?[\\(]?MainRecord.Signature.*?then\s*?Result.*?\n", decider, flags = re.DOTALL) + +# for each section get signatures and index +sig_to_index = {} +index_re = re.compile("Result := (\d.*?)") +sig_re = re.compile("MainRecord.Signature = (\w{4})") +for s in sections: + index = index_re.findall(s) + assert len(index) == 1, "Could not parse REFR decider index" + index = int(index[0]) - 1 + sigs = sig_re.findall(s) + for sig in sigs: + sig_to_index[sig] = index + + +# get the REFR record +refr = re.findall("wbRefRecord\((REFR.*?\n(?:.*?\n)*?.*?)\);", inp) +assert len(refr) == 1, "Could not find REFR record" +refr = refr[0] + +# get all of the flag lists +flag_lists = re.findall("wbFlagsList\\(\\[.*?\n((?:.*?\n)*?).*?\\]", refr)[1:] +assert len(flag_lists) - 1 == max(sig_to_index.values()), "Could not match decider indices with flag lists." + +# process flag lists into flags +index_to_flag_list = {} +re_flag_line = re.compile(".*?(\d+?),.*?'(.*)'") +for index, flist in enumerate(flag_lists): + flags = [] + for line in flist.strip().split('\n'): + match = re_flag_line.match(line).groups() + assert len(match) == 2, "Could not parse flag line." + flags += [Flag(int(match[0]), match[1])] + index_to_flag_list[index] = flags + +# create list of records +records = [] +for sig, index in sig_to_index.items(): + records += [Record(sig, index_to_flag_list[index])] + +# sort the records by signature +records = sorted(records, key=lambda x: x.fourcc) + +# write the records out to a JSON file +class Encoder(json.JSONEncoder): + def default(self, obj): + if isinstance(obj, Jsonify): + return obj.encode() + else: + return json.JSONEncoder.default(self, obj) + +with open(os.path.join(fdir, "refr_flags.json"), "w") as f: + json.dump(records, f, cls=Encoder, indent=4) + \ No newline at end of file diff --git a/reference/refr_flags.json b/reference/refr_flags.json new file mode 100644 index 0000000..38856b9 --- /dev/null +++ b/reference/refr_flags.json @@ -0,0 +1,805 @@ +[ + { + "fourcc": "ACTI", + "flags": [ + { + "bit": 9, + "description": "Hidden From Local Map" + }, + { + "bit": 10, + "description": "Persistent" + }, + { + "bit": 11, + "description": "Initially Disabled" + }, + { + "bit": 13, + "description": "Sky Marker" + }, + { + "bit": 15, + "description": "Visible when distant" + }, + { + "bit": 16, + "description": "Is Full LOD" + }, + { + "bit": 26, + "description": "Filter (Collision Geometry)" + }, + { + "bit": 27, + "description": "Bounding Box (Collision Geometry)" + }, + { + "bit": 28, + "description": "Reflected By Auto Water" + }, + { + "bit": 29, + "description": "Don''t Havok Settle" + }, + { + "bit": 30, + "description": "No Respawn" + }, + { + "bit": 31, + "description": "Multibound" + } + ] + }, + { + "fourcc": "ADDN", + "flags": [ + { + "bit": 10, + "description": "Persistent" + }, + { + "bit": 11, + "description": "Initially Disabled" + }, + { + "bit": 16, + "description": "Is Full LOD" + }, + { + "bit": 28, + "description": "Reflected By Auto Water" + }, + { + "bit": 29, + "description": "Don''t Havok Settle" + }, + { + "bit": 30, + "description": "No Respawn" + }, + { + "bit": 31, + "description": "Multibound" + } + ] + }, + { + "fourcc": "ALCH", + "flags": [ + { + "bit": 10, + "description": "Persistent" + }, + { + "bit": 11, + "description": "Initially Disabled" + }, + { + "bit": 16, + "description": "Is Full LOD" + }, + { + "bit": 25, + "description": "No AI Acquire" + }, + { + "bit": 28, + "description": "Reflected By Auto Water" + }, + { + "bit": 29, + "description": "Don''t Havok Settle" + }, + { + "bit": 30, + "description": "No Respawn" + }, + { + "bit": 31, + "description": "Multibound" + } + ] + }, + { + "fourcc": "AMMO", + "flags": [ + { + "bit": 10, + "description": "Persistent" + }, + { + "bit": 11, + "description": "Initially Disabled" + }, + { + "bit": 16, + "description": "Is Full LOD" + }, + { + "bit": 25, + "description": "No AI Acquire" + }, + { + "bit": 28, + "description": "Reflected By Auto Water" + }, + { + "bit": 29, + "description": "Don''t Havok Settle" + }, + { + "bit": 30, + "description": "No Respawn" + }, + { + "bit": 31, + "description": "Multibound" + } + ] + }, + { + "fourcc": "ARMO", + "flags": [ + { + "bit": 10, + "description": "Persistent" + }, + { + "bit": 11, + "description": "Initially Disabled" + }, + { + "bit": 16, + "description": "Is Full LOD" + }, + { + "bit": 25, + "description": "No AI Acquire" + }, + { + "bit": 28, + "description": "Reflected By Auto Water" + }, + { + "bit": 29, + "description": "Don''t Havok Settle" + }, + { + "bit": 30, + "description": "No Respawn" + }, + { + "bit": 31, + "description": "Multibound" + } + ] + }, + { + "fourcc": "BOOK", + "flags": [ + { + "bit": 10, + "description": "Persistent" + }, + { + "bit": 11, + "description": "Initially Disabled" + }, + { + "bit": 16, + "description": "Is Full LOD" + }, + { + "bit": 25, + "description": "No AI Acquire" + }, + { + "bit": 28, + "description": "Reflected By Auto Water" + }, + { + "bit": 29, + "description": "Don''t Havok Settle" + }, + { + "bit": 30, + "description": "No Respawn" + }, + { + "bit": 31, + "description": "Multibound" + } + ] + }, + { + "fourcc": "CONT", + "flags": [ + { + "bit": 10, + "description": "Persistent" + }, + { + "bit": 11, + "description": "Initially Disabled" + }, + { + "bit": 16, + "description": "Is Full LOD" + }, + { + "bit": 25, + "description": "No AI Acquire" + }, + { + "bit": 26, + "description": "Filter (Collision Geometry)" + }, + { + "bit": 27, + "description": "Bounding Box (Collision Geometry)" + }, + { + "bit": 28, + "description": "Reflected By Auto Water" + }, + { + "bit": 29, + "description": "Don''t Havok Settle" + }, + { + "bit": 30, + "description": "Ground" + }, + { + "bit": 31, + "description": "Multibound" + } + ] + }, + { + "fourcc": "DOOR", + "flags": [ + { + "bit": 6, + "description": "Hidden From Local Map" + }, + { + "bit": 8, + "description": "Inaccessible" + }, + { + "bit": 10, + "description": "Persistent" + }, + { + "bit": 11, + "description": "Initially Disabled" + }, + { + "bit": 16, + "description": "Is Full LOD" + }, + { + "bit": 26, + "description": "Filter (Collision Geometry)" + }, + { + "bit": 27, + "description": "Bounding Box (Collision Geometry)" + }, + { + "bit": 28, + "description": "Reflected By Auto Water" + }, + { + "bit": 29, + "description": "Don''t Havok Settle" + }, + { + "bit": 30, + "description": "No Respawn" + }, + { + "bit": 31, + "description": "Multibound" + } + ] + }, + { + "fourcc": "FLOR", + "flags": [ + { + "bit": 9, + "description": "Hidden From Local Map" + }, + { + "bit": 10, + "description": "Persistent" + }, + { + "bit": 11, + "description": "Initially Disabled" + }, + { + "bit": 13, + "description": "Sky Marker" + }, + { + "bit": 15, + "description": "Visible when distant" + }, + { + "bit": 16, + "description": "Is Full LOD" + }, + { + "bit": 26, + "description": "Filter (Collision Geometry)" + }, + { + "bit": 27, + "description": "Bounding Box (Collision Geometry)" + }, + { + "bit": 28, + "description": "Reflected By Auto Water" + }, + { + "bit": 29, + "description": "Don''t Havok Settle" + }, + { + "bit": 30, + "description": "No Respawn" + }, + { + "bit": 31, + "description": "Multibound" + } + ] + }, + { + "fourcc": "INGR", + "flags": [ + { + "bit": 10, + "description": "Persistent" + }, + { + "bit": 11, + "description": "Initially Disabled" + }, + { + "bit": 16, + "description": "Is Full LOD" + }, + { + "bit": 25, + "description": "No AI Acquire" + }, + { + "bit": 28, + "description": "Reflected By Auto Water" + }, + { + "bit": 29, + "description": "Don''t Havok Settle" + }, + { + "bit": 30, + "description": "No Respawn" + }, + { + "bit": 31, + "description": "Multibound" + } + ] + }, + { + "fourcc": "KEYM", + "flags": [ + { + "bit": 10, + "description": "Persistent" + }, + { + "bit": 11, + "description": "Initially Disabled" + }, + { + "bit": 16, + "description": "Is Full LOD" + }, + { + "bit": 25, + "description": "No AI Acquire" + }, + { + "bit": 28, + "description": "Reflected By Auto Water" + }, + { + "bit": 29, + "description": "Don''t Havok Settle" + }, + { + "bit": 30, + "description": "No Respawn" + }, + { + "bit": 31, + "description": "Multibound" + } + ] + }, + { + "fourcc": "LIGH", + "flags": [ + { + "bit": 8, + "description": "Doesn''t Light Water" + }, + { + "bit": 9, + "description": "Casts Shadows" + }, + { + "bit": 10, + "description": "Persistent" + }, + { + "bit": 11, + "description": "Initially Disabled" + }, + { + "bit": 16, + "description": "Never Fades" + }, + { + "bit": 17, + "description": "Doesn''t Light Landscape" + }, + { + "bit": 25, + "description": "No AI Acquire" + }, + { + "bit": 28, + "description": "Reflected By Auto Water" + }, + { + "bit": 29, + "description": "Don''t Havok Settle" + }, + { + "bit": 30, + "description": "No Respawn" + }, + { + "bit": 31, + "description": "Multibound" + } + ] + }, + { + "fourcc": "MISC", + "flags": [ + { + "bit": 10, + "description": "Persistent" + }, + { + "bit": 11, + "description": "Initially Disabled" + }, + { + "bit": 16, + "description": "Is Full LOD" + }, + { + "bit": 25, + "description": "No AI Acquire" + }, + { + "bit": 28, + "description": "Reflected By Auto Water" + }, + { + "bit": 29, + "description": "Don''t Havok Settle" + }, + { + "bit": 30, + "description": "No Respawn" + }, + { + "bit": 31, + "description": "Multibound" + } + ] + }, + { + "fourcc": "MSTT", + "flags": [ + { + "bit": 9, + "description": "Motion Blur" + }, + { + "bit": 10, + "description": "Persistent" + }, + { + "bit": 11, + "description": "Initially Disabled" + }, + { + "bit": 16, + "description": "Is Full LOD" + }, + { + "bit": 26, + "description": "Filter (Collision Geometry)" + }, + { + "bit": 27, + "description": "Bounding Box (Collision Geometry)" + }, + { + "bit": 28, + "description": "Reflected By Auto Water" + }, + { + "bit": 29, + "description": "Don''t Havok Settle" + }, + { + "bit": 30, + "description": "No Respawn" + }, + { + "bit": 31, + "description": "Multibound" + } + ] + }, + { + "fourcc": "SCRL", + "flags": [ + { + "bit": 10, + "description": "Persistent" + }, + { + "bit": 11, + "description": "Initially Disabled" + }, + { + "bit": 16, + "description": "Is Full LOD" + }, + { + "bit": 25, + "description": "No AI Acquire" + }, + { + "bit": 28, + "description": "Reflected By Auto Water" + }, + { + "bit": 29, + "description": "Don''t Havok Settle" + }, + { + "bit": 30, + "description": "No Respawn" + }, + { + "bit": 31, + "description": "Multibound" + } + ] + }, + { + "fourcc": "SLGM", + "flags": [ + { + "bit": 10, + "description": "Persistent" + }, + { + "bit": 11, + "description": "Initially Disabled" + }, + { + "bit": 16, + "description": "Is Full LOD" + }, + { + "bit": 25, + "description": "No AI Acquire" + }, + { + "bit": 28, + "description": "Reflected By Auto Water" + }, + { + "bit": 29, + "description": "Don''t Havok Settle" + }, + { + "bit": 30, + "description": "No Respawn" + }, + { + "bit": 31, + "description": "Multibound" + } + ] + }, + { + "fourcc": "STAT", + "flags": [ + { + "bit": 9, + "description": "Hidden From Local Map" + }, + { + "bit": 10, + "description": "Persistent" + }, + { + "bit": 11, + "description": "Initially Disabled" + }, + { + "bit": 13, + "description": "Sky Marker" + }, + { + "bit": 15, + "description": "Visible when distant" + }, + { + "bit": 16, + "description": "Is Full LOD" + }, + { + "bit": 26, + "description": "Filter (Collision Geometry)" + }, + { + "bit": 27, + "description": "Bounding Box (Collision Geometry)" + }, + { + "bit": 28, + "description": "Reflected By Auto Water" + }, + { + "bit": 29, + "description": "Don''t Havok Settle" + }, + { + "bit": 30, + "description": "No Respawn" + }, + { + "bit": 31, + "description": "Multibound" + } + ] + }, + { + "fourcc": "TREE", + "flags": [ + { + "bit": 9, + "description": "Hidden From Local Map" + }, + { + "bit": 10, + "description": "Persistent" + }, + { + "bit": 11, + "description": "Initially Disabled" + }, + { + "bit": 13, + "description": "Sky Marker" + }, + { + "bit": 15, + "description": "Visible when distant" + }, + { + "bit": 16, + "description": "Is Full LOD" + }, + { + "bit": 26, + "description": "Filter (Collision Geometry)" + }, + { + "bit": 27, + "description": "Bounding Box (Collision Geometry)" + }, + { + "bit": 28, + "description": "Reflected By Auto Water" + }, + { + "bit": 29, + "description": "Don''t Havok Settle" + }, + { + "bit": 30, + "description": "No Respawn" + }, + { + "bit": 31, + "description": "Multibound" + } + ] + }, + { + "fourcc": "WEAP", + "flags": [ + { + "bit": 10, + "description": "Persistent" + }, + { + "bit": 11, + "description": "Initially Disabled" + }, + { + "bit": 16, + "description": "Is Full LOD" + }, + { + "bit": 25, + "description": "No AI Acquire" + }, + { + "bit": 28, + "description": "Reflected By Auto Water" + }, + { + "bit": 29, + "description": "Don''t Havok Settle" + }, + { + "bit": 30, + "description": "No Respawn" + }, + { + "bit": 31, + "description": "Multibound" + } + ] + } +] \ No newline at end of file