1
0
mirror of https://gitlab.com/OpenMW/openmw.git synced 2025-03-28 19:21:04 +00:00

Merge ESM::RefNum and ESM4::FormId

This commit is contained in:
Petr Mikheev 2023-04-07 02:14:32 +02:00
parent 2365ba2ce0
commit f09a689a4f
127 changed files with 383 additions and 395 deletions

View File

@ -340,7 +340,7 @@ void CSMDoc::WriteCellCollectionStage::writeReferences(
char ignore; char ignore;
istream >> ignore >> moved.mTarget[0] >> moved.mTarget[1]; istream >> ignore >> moved.mTarget[0] >> moved.mTarget[1];
refRecord.mRefNum.save(writer, false, "MVRF"); writer.writeFormId(refRecord.mRefNum, false, "MVRF");
writer.writeHNT("CNDT", moved.mTarget); writer.writeHNT("CNDT", moved.mTarget);
} }

View File

@ -55,7 +55,7 @@ namespace MWLua
static void saveEvent(ESM::ESMWriter& esm, const ESM::RefNum& dest, const Event& event) static void saveEvent(ESM::ESMWriter& esm, const ESM::RefNum& dest, const Event& event)
{ {
esm.writeHNString("LUAE", event.mEventName); esm.writeHNString("LUAE", event.mEventName);
dest.save(esm, true); esm.writeFormId(dest, true);
if (!event.mEventData.empty()) if (!event.mEventData.empty())
saveLuaBinaryData(esm, event.mEventData); saveLuaBinaryData(esm, event.mEventData);
} }
@ -67,8 +67,7 @@ namespace MWLua
while (esm.isNextSub("LUAE")) while (esm.isNextSub("LUAE"))
{ {
std::string name = esm.getHString(); std::string name = esm.getHString();
ESM::RefNum dest; ESM::RefNum dest = esm.getFormId(true);
dest.load(esm, true);
std::string data = loadLuaBinaryData(esm); std::string data = loadLuaBinaryData(esm);
try try
{ {

View File

@ -82,15 +82,13 @@ namespace MWLua
void WorldView::load(ESM::ESMReader& esm) void WorldView::load(ESM::ESMReader& esm)
{ {
esm.getHNT(mSimulationTime, "LUAW"); esm.getHNT(mSimulationTime, "LUAW");
ObjectId lastAssignedId; MWBase::Environment::get().getWorldModel()->setLastGeneratedRefNum(esm.getFormId(true));
lastAssignedId.load(esm, true);
MWBase::Environment::get().getWorldModel()->setLastGeneratedRefNum(lastAssignedId);
} }
void WorldView::save(ESM::ESMWriter& esm) const void WorldView::save(ESM::ESMWriter& esm) const
{ {
esm.writeHNT("LUAW", mSimulationTime); esm.writeHNT("LUAW", mSimulationTime);
MWBase::Environment::get().getWorldModel()->getLastGeneratedRefNum().save(esm, true); esm.writeFormId(MWBase::Environment::get().getWorldModel()->getLastGeneratedRefNum(), true);
} }
void WorldView::ObjectGroup::updateList() void WorldView::ObjectGroup::updateList()

View File

@ -42,7 +42,8 @@ namespace osgViewer
namespace ESM namespace ESM
{ {
struct Cell; struct Cell;
struct RefNum; struct FormId;
using RefNum = FormId;
} }
namespace Terrain namespace Terrain

View File

@ -21,7 +21,8 @@ namespace ESM
{ {
class ESMWriter; class ESMWriter;
class ESMReader; class ESMReader;
struct RefNum; struct FormId;
using RefNum = FormId;
} }
namespace Loading namespace Loading

View File

@ -25,7 +25,7 @@ namespace MWWorld
const ESM::RefNum& CellRef::getRefNum() const const ESM::RefNum& CellRef::getRefNum() const
{ {
return std::visit(ESM::VisitOverload{ return std::visit(ESM::VisitOverload{
[&](const ESM4::Reference& /*ref*/) -> const ESM::RefNum& { return emptyRefNum; }, [&](const ESM4::Reference& ref) -> const ESM::RefNum& { return ref.mFormId; },
[&](const ESM::CellRef& ref) -> const ESM::RefNum& { return ref.mRefNum; }, [&](const ESM::CellRef& ref) -> const ESM::RefNum& { return ref.mRefNum; },
}, },
mCellRef.mVariant); mCellRef.mVariant);
@ -33,36 +33,33 @@ namespace MWWorld
const ESM::RefNum& CellRef::getOrAssignRefNum(ESM::RefNum& lastAssignedRefNum) const ESM::RefNum& CellRef::getOrAssignRefNum(ESM::RefNum& lastAssignedRefNum)
{ {
auto esm3Visit = [&](ESM::CellRef& ref) -> const ESM::RefNum& { ESM::RefNum& refNum = std::visit(ESM::VisitOverload{
if (!ref.mRefNum.isSet()) [&](ESM4::Reference& ref) -> ESM::RefNum& { return ref.mFormId; },
{ [&](ESM::CellRef& ref) -> ESM::RefNum& { return ref.mRefNum; },
// Generated RefNums have negative mContentFile },
assert(lastAssignedRefNum.mContentFile < 0);
lastAssignedRefNum.mIndex++;
if (lastAssignedRefNum.mIndex == 0) // mIndex overflow, so mContentFile should be changed
{
if (lastAssignedRefNum.mContentFile > std::numeric_limits<int32_t>::min())
lastAssignedRefNum.mContentFile--;
else
Log(Debug::Error) << "RefNum counter overflow in CellRef::getOrAssignRefNum";
}
ref.mRefNum = lastAssignedRefNum;
mChanged = true;
}
return ref.mRefNum;
};
return std::visit(
ESM::VisitOverload{
[&](ESM4::Reference& /*ref*/) -> const ESM::RefNum& { return emptyRefNum; },
esm3Visit,
},
mCellRef.mVariant); mCellRef.mVariant);
if (!refNum.isSet())
{
// Generated RefNums have negative mContentFile
assert(lastAssignedRefNum.mContentFile < 0);
lastAssignedRefNum.mIndex++;
if (lastAssignedRefNum.mIndex == 0) // mIndex overflow, so mContentFile should be changed
{
if (lastAssignedRefNum.mContentFile > std::numeric_limits<int32_t>::min())
lastAssignedRefNum.mContentFile--;
else
Log(Debug::Error) << "RefNum counter overflow in CellRef::getOrAssignRefNum";
}
refNum = lastAssignedRefNum;
mChanged = true;
}
return refNum;
} }
void CellRef::unsetRefNum() void CellRef::unsetRefNum()
{ {
std::visit(ESM::VisitOverload{ std::visit(ESM::VisitOverload{
[&](ESM4::Reference& /*ref*/) {}, [&](ESM4::Reference& ref) { ref.mFormId = emptyRefNum; },
[&](ESM::CellRef& ref) { ref.mRefNum = emptyRefNum; }, [&](ESM::CellRef& ref) { ref.mRefNum = emptyRefNum; },
}, },
mCellRef.mVariant); mCellRef.mVariant);

View File

@ -983,7 +983,7 @@ namespace MWWorld
ESM::RefNum refNum = base->mRef.getRefNum(); ESM::RefNum refNum = base->mRef.getRefNum();
ESM::RefId movedTo = store->getCell()->getId(); ESM::RefId movedTo = store->getCell()->getId();
refNum.save(writer, true, "MVRF"); writer.writeFormId(refNum, true, "MVRF");
writer.writeCellId(movedTo); writer.writeCellId(movedTo);
} }
} }
@ -1039,8 +1039,7 @@ namespace MWWorld
while (reader.isNextSub("MVRF")) while (reader.isNextSub("MVRF"))
{ {
reader.cacheSubName(); reader.cacheSubName();
ESM::RefNum refnum; ESM::RefNum refnum = reader.getFormId(true, "MVRF");
refnum.load(reader, true, "MVRF");
ESM::RefId movedToId = reader.getCellId(); ESM::RefId movedToId = reader.getCellId();
if (refnum.hasContentFile()) if (refnum.hasContentFile())
{ {

View File

@ -27,7 +27,8 @@ namespace ESM
class ReadersCache; class ReadersCache;
struct Cell; struct Cell;
struct CellState; struct CellState;
struct RefNum; struct FormId;
using RefNum = FormId;
struct Activator; struct Activator;
struct Potion; struct Potion;
struct Apparatus; struct Apparatus;

View File

@ -9,6 +9,7 @@
#include <components/esm4/reader.hpp> #include <components/esm4/reader.hpp>
#include <components/files/conversion.hpp> #include <components/files/conversion.hpp>
#include <components/files/openfile.hpp> #include <components/files/openfile.hpp>
#include <components/misc/strings/lower.hpp>
#include <components/resource/resourcesystem.hpp> #include <components/resource/resourcesystem.hpp>
#include "../mwbase/environment.hpp" #include "../mwbase/environment.hpp"
@ -66,10 +67,13 @@ namespace MWWorld
ESM4::Reader readerESM4( ESM4::Reader readerESM4(
std::move(stream), filepath, MWBase::Environment::get().getResourceSystem()->getVFS()); std::move(stream), filepath, MWBase::Environment::get().getResourceSystem()->getVFS());
readerESM4.setEncoder(mReaders.getStatelessEncoder()); readerESM4.setEncoder(mReaders.getStatelessEncoder());
readerESM4.setModIndex(index);
readerESM4.updateModIndices(mNameToIndex);
mStore.loadESM4(readerESM4); mStore.loadESM4(readerESM4);
break; break;
} }
} }
mNameToIndex[Misc::StringUtils::lowerCase(Files::pathToUnicodeString(filepath.filename()))] = index;
} }
} /* namespace MWWorld */ } /* namespace MWWorld */

View File

@ -1,6 +1,7 @@
#ifndef ESMLOADER_HPP #ifndef ESMLOADER_HPP
#define ESMLOADER_HPP #define ESMLOADER_HPP
#include <map>
#include <optional> #include <optional>
#include <vector> #include <vector>
@ -38,6 +39,7 @@ namespace MWWorld
ESM::Dialogue* mDialogue; ESM::Dialogue* mDialogue;
std::optional<int> mMasterFileFormat; std::optional<int> mMasterFileFormat;
std::vector<int>& mESMVersions; std::vector<int>& mESMVersions;
std::map<std::string, int> mNameToIndex;
}; };
} /* namespace MWWorld */ } /* namespace MWWorld */

View File

@ -2848,8 +2848,9 @@ namespace MWWorld
{ {
foundCell = findInteriorPosition(cellName, pos); foundCell = findInteriorPosition(cellName, pos);
} }
catch (std::exception&) catch (std::exception& e)
{ {
Log(Debug::Error) << e.what();
} }
if (foundCell.empty()) if (foundCell.empty())
{ {

View File

@ -18,7 +18,6 @@ namespace ESM
class ESMWriter; class ESMWriter;
class ReadersCache; class ReadersCache;
struct Cell; struct Cell;
struct RefNum;
} }
namespace ESM4 namespace ESM4

View File

@ -26,7 +26,7 @@ namespace ESM
TEST(ESMRefIdTest, formIdRefIdIsNotEmpty) TEST(ESMRefIdTest, formIdRefIdIsNotEmpty)
{ {
const RefId refId = RefId::formIdRefId(42); const RefId refId = RefId::formIdRefId({ 42, 0 });
EXPECT_FALSE(refId.empty()); EXPECT_FALSE(refId.empty());
} }
@ -53,7 +53,7 @@ namespace ESM
TEST(ESMRefIdTest, defaultConstructedIsNotEqualToFormIdRefId) TEST(ESMRefIdTest, defaultConstructedIsNotEqualToFormIdRefId)
{ {
const RefId a; const RefId a;
const RefId b = RefId::formIdRefId(42); const RefId b = RefId::formIdRefId({ 42, 0 });
EXPECT_NE(a, b); EXPECT_NE(a, b);
} }
@ -98,8 +98,8 @@ namespace ESM
TEST(ESMRefIdTest, equalityIsDefinedForFormRefIdAndRefId) TEST(ESMRefIdTest, equalityIsDefinedForFormRefIdAndRefId)
{ {
const FormIdRefId formIdRefId(42); const FormIdRefId formIdRefId({ 42, 0 });
const RefId refId = RefId::formIdRefId(42); const RefId refId = RefId::formIdRefId({ 42, 0 });
EXPECT_EQ(formIdRefId, refId); EXPECT_EQ(formIdRefId, refId);
} }
@ -125,8 +125,8 @@ namespace ESM
TEST(ESMRefIdTest, lessThanIsDefinedForFormRefIdAndRefId) TEST(ESMRefIdTest, lessThanIsDefinedForFormRefIdAndRefId)
{ {
const FormIdRefId formIdRefId(13); const FormIdRefId formIdRefId({ 13, 0 });
const RefId refId = RefId::formIdRefId(42); const RefId refId = RefId::formIdRefId({ 42, 0 });
EXPECT_LT(formIdRefId, refId); EXPECT_LT(formIdRefId, refId);
} }
@ -164,14 +164,14 @@ namespace ESM
TEST(ESMRefIdTest, stringRefIdHasStrongOrderWithFormId) TEST(ESMRefIdTest, stringRefIdHasStrongOrderWithFormId)
{ {
const RefId stringRefId = RefId::stringRefId("a"); const RefId stringRefId = RefId::stringRefId("a");
const RefId formIdRefId = RefId::formIdRefId(42); const RefId formIdRefId = RefId::formIdRefId({ 42, 0 });
EXPECT_TRUE(stringRefId < formIdRefId); EXPECT_TRUE(stringRefId < formIdRefId);
EXPECT_FALSE(formIdRefId < stringRefId); EXPECT_FALSE(formIdRefId < stringRefId);
} }
TEST(ESMRefIdTest, formIdRefIdHasStrongOrderWithStringView) TEST(ESMRefIdTest, formIdRefIdHasStrongOrderWithStringView)
{ {
const RefId formIdRefId = RefId::formIdRefId(42); const RefId formIdRefId = RefId::formIdRefId({ 42, 0 });
const std::string_view stringView = "42"; const std::string_view stringView = "42";
EXPECT_TRUE(stringView < formIdRefId); EXPECT_TRUE(stringView < formIdRefId);
EXPECT_FALSE(formIdRefId < stringView); EXPECT_FALSE(formIdRefId < stringView);
@ -192,7 +192,7 @@ namespace ESM
TEST(ESMRefIdTest, stringRefIdIsNotEqualToFormId) TEST(ESMRefIdTest, stringRefIdIsNotEqualToFormId)
{ {
const RefId stringRefId = RefId::stringRefId("\0"); const RefId stringRefId = RefId::stringRefId("\0");
const RefId formIdRefId = RefId::formIdRefId(0); const RefId formIdRefId = RefId::formIdRefId({ 0, 0 });
EXPECT_NE(stringRefId, formIdRefId); EXPECT_NE(stringRefId, formIdRefId);
} }
@ -235,7 +235,7 @@ namespace ESM
{ RefId(), std::string() }, { RefId(), std::string() },
{ RefId::stringRefId("foo"), "foo" }, { RefId::stringRefId("foo"), "foo" },
{ RefId::stringRefId(std::string({ 'a', 0, -1, '\n', '\t' })), { 'a', 0, -1, '\n', '\t' } }, { RefId::stringRefId(std::string({ 'a', 0, -1, '\n', '\t' })), { 'a', 0, -1, '\n', '\t' } },
{ RefId::formIdRefId(42), "0x2a" }, { RefId::formIdRefId({ 42, 0 }), "0x2a" },
{ RefId::generated(42), "0x2a" }, { RefId::generated(42), "0x2a" },
{ RefId::index(REC_ARMO, 42), "ARMO:0x2a" }, { RefId::index(REC_ARMO, 42), "ARMO:0x2a" },
{ RefId::esm3ExteriorCell(-13, 42), "-13:42" }, { RefId::esm3ExteriorCell(-13, 42), "-13:42" },
@ -268,7 +268,7 @@ namespace ESM
{ RefId::stringRefId("foo"), "\"foo\"" }, { RefId::stringRefId("foo"), "\"foo\"" },
{ RefId::stringRefId("BAR"), "\"BAR\"" }, { RefId::stringRefId("BAR"), "\"BAR\"" },
{ RefId::stringRefId(std::string({ 'a', 0, -1, '\n', '\t' })), "\"a\\x0\\xFF\\xA\\x9\"" }, { RefId::stringRefId(std::string({ 'a', 0, -1, '\n', '\t' })), "\"a\\x0\\xFF\\xA\\x9\"" },
{ RefId::formIdRefId(42), "FormId:0x2a" }, { RefId::formIdRefId({ 42, 0 }), "FormId:0x2a" },
{ RefId::generated(42), "Generated:0x2a" }, { RefId::generated(42), "Generated:0x2a" },
{ RefId::index(REC_ARMO, 42), "Index:ARMO:0x2a" }, { RefId::index(REC_ARMO, 42), "Index:ARMO:0x2a" },
{ RefId::esm3ExteriorCell(-13, 42), "Esm3ExteriorCell:-13:42" }, { RefId::esm3ExteriorCell(-13, 42), "Esm3ExteriorCell:-13:42" },
@ -295,10 +295,11 @@ namespace ESM
{ RefId::stringRefId("foo"), "foo" }, { RefId::stringRefId("foo"), "foo" },
{ RefId::stringRefId("BAR"), "bar" }, { RefId::stringRefId("BAR"), "bar" },
{ RefId::stringRefId(std::string({ 'a', 0, -1, '\n', '\t' })), { 'a', 0, -1, '\n', '\t' } }, { RefId::stringRefId(std::string({ 'a', 0, -1, '\n', '\t' })), { 'a', 0, -1, '\n', '\t' } },
{ RefId::formIdRefId(0), "FormId:0x0" }, { RefId::formIdRefId({ 0, 0 }), "FormId:0x0" },
{ RefId::formIdRefId(1), "FormId:0x1" }, { RefId::formIdRefId({ 1, 0 }), "FormId:0x1" },
{ RefId::formIdRefId(0x1f), "FormId:0x1f" }, { RefId::formIdRefId({ 0x1f, 0 }), "FormId:0x1f" },
{ RefId::formIdRefId(std::numeric_limits<ESM4::FormId>::max()), "FormId:0xffffffff" }, { RefId::formIdRefId({ 0x1f, 2 }), "FormId:0x200001f" },
{ RefId::formIdRefId({ 0xffffff, 0x1abc }), "FormId:0x1abcffffff" },
{ RefId::generated(0), "Generated:0x0" }, { RefId::generated(0), "Generated:0x0" },
{ RefId::generated(1), "Generated:0x1" }, { RefId::generated(1), "Generated:0x1" },
{ RefId::generated(0x1f), "Generated:0x1f" }, { RefId::generated(0x1f), "Generated:0x1f" },
@ -344,7 +345,7 @@ namespace ESM
template <> template <>
struct GenerateRefId<FormIdRefId> struct GenerateRefId<FormIdRefId>
{ {
static RefId call() { return RefId::formIdRefId(42); } static RefId call() { return RefId::formIdRefId({ 42, 0 }); }
}; };
template <> template <>

View File

@ -76,7 +76,7 @@ namespace ESM
const std::vector<std::pair<RefId, std::size_t>> refIdSizes = { const std::vector<std::pair<RefId, std::size_t>> refIdSizes = {
{ RefId(), 57 }, { RefId(), 57 },
{ RefId::stringRefId(std::string(32, 'a')), 89 }, { RefId::stringRefId(std::string(32, 'a')), 89 },
{ RefId::formIdRefId(0x1f), 61 }, { RefId::formIdRefId({ 0x1f, 0 }), 65 },
{ RefId::generated(0x1f), 65 }, { RefId::generated(0x1f), 65 },
{ RefId::index(REC_INGR, 0x1f), 65 }, { RefId::index(REC_INGR, 0x1f), 65 },
{ RefId::esm3ExteriorCell(-42, 42), 65 }, { RefId::esm3ExteriorCell(-42, 42), 65 },

View File

@ -86,6 +86,7 @@ add_component_dir (to_utf8
) )
add_component_dir(esm attr common defs esmcommon records util luascripts format refid esmbridge add_component_dir(esm attr common defs esmcommon records util luascripts format refid esmbridge
formid
formidrefid formidrefid
stringrefid stringrefid
generatedrefid generatedrefid

15
components/esm/formid.cpp Normal file
View File

@ -0,0 +1,15 @@
#include "formid.hpp"
std::string ESM::FormId::toString() const
{
return std::to_string(mIndex) + "_" + std::to_string(mContentFile);
}
uint32_t ESM::FormId::toUint32() const
{
if (isSet() && !hasContentFile())
throw std::runtime_error("Generated FormId can not be converted to 32bit format");
if (mContentFile > 0xfe)
throw std::runtime_error("FormId with mContentFile > 0xFE can not be converted to 32bit format");
return (mIndex & 0xffffff) | ((hasContentFile() ? mContentFile : 0xff) << 24);
}

63
components/esm/formid.hpp Normal file
View File

@ -0,0 +1,63 @@
#ifndef COMPONENT_ESM_FORMID_H
#define COMPONENT_ESM_FORMID_H
#include <cstdint>
#include <cstring>
#include <ostream>
#include <string>
#include <tuple>
namespace ESM
{
using FormId32 = uint32_t;
struct FormId
{
uint32_t mIndex = 0;
int32_t mContentFile = -1;
bool hasContentFile() const { return mContentFile >= 0; }
bool isSet() const { return mIndex != 0 || mContentFile != -1; }
// Used in ESM4 as a null reference
bool isZero() const { return mIndex == 0 && mContentFile == 0; }
std::string toString() const;
FormId32 toUint32() const;
static FormId fromUint32(FormId32 v) { return { v & 0xffffff, static_cast<int32_t>(v >> 24) }; }
};
inline constexpr bool operator==(const FormId& left, const FormId& right)
{
return left.mIndex == right.mIndex && left.mContentFile == right.mContentFile;
}
inline constexpr bool operator<(const FormId& left, const FormId& right)
{
return std::tie(left.mIndex, left.mContentFile) < std::tie(right.mIndex, right.mContentFile);
}
inline std::ostream& operator<<(std::ostream& stream, const FormId& formId)
{
return stream << formId.toString();
}
}
namespace std
{
// Needed to use ESM::FormId as a key in std::unordered_map
template <>
struct hash<ESM::FormId>
{
size_t operator()(const ESM::FormId& formId) const
{
static_assert(sizeof(ESM::FormId) == sizeof(size_t));
size_t s;
memcpy(&s, &formId, sizeof(size_t));
return hash<size_t>()(s);
}
};
}
#endif // COMPONENT_ESM_FORMID_H

View File

@ -1,23 +1,28 @@
#include "formidrefid.hpp" #include "formidrefid.hpp"
#include "serializerefid.hpp" #include <cassert>
#include <ostream> #include <ostream>
#include "serializerefid.hpp"
namespace ESM namespace ESM
{ {
std::string FormIdRefId::toString() const std::string FormIdRefId::toString() const
{ {
std::string result; std::string result;
result.resize(getHexIntegralSize(mValue) + 2, '\0'); assert((mValue.mIndex & 0xff000000) == 0);
serializeHexIntegral(mValue, 0, result); size_t v = (static_cast<size_t>(mValue.mContentFile) << 24) | mValue.mIndex;
result.resize(getHexIntegralSize(v) + 2, '\0');
serializeHexIntegral(v, 0, result);
return result; return result;
} }
std::string FormIdRefId::toDebugString() const std::string FormIdRefId::toDebugString() const
{ {
std::string result; std::string result;
serializeRefIdValue(mValue, formIdRefIdPrefix, result); assert((mValue.mIndex & 0xff000000) == 0);
size_t v = (static_cast<size_t>(mValue.mContentFile) << 24) | mValue.mIndex;
serializeRefIdValue(v, formIdRefIdPrefix, result);
return result; return result;
} }

View File

@ -4,7 +4,7 @@
#include <functional> #include <functional>
#include <iosfwd> #include <iosfwd>
#include <components/esm4/formid.hpp> #include <components/esm/formid.hpp>
namespace ESM namespace ESM
{ {
@ -13,12 +13,12 @@ namespace ESM
public: public:
constexpr FormIdRefId() = default; constexpr FormIdRefId() = default;
constexpr explicit FormIdRefId(ESM4::FormId value) noexcept constexpr explicit FormIdRefId(ESM::FormId value) noexcept
: mValue(value) : mValue(value)
{ {
} }
ESM4::FormId getValue() const { return mValue; } ESM::FormId getValue() const { return mValue; }
std::string toString() const; std::string toString() const;
@ -33,7 +33,7 @@ namespace ESM
friend struct std::hash<FormIdRefId>; friend struct std::hash<FormIdRefId>;
private: private:
ESM4::FormId mValue = 0; ESM::FormId mValue;
}; };
} }
@ -42,10 +42,7 @@ namespace std
template <> template <>
struct hash<ESM::FormIdRefId> struct hash<ESM::FormIdRefId>
{ {
std::size_t operator()(ESM::FormIdRefId value) const noexcept std::size_t operator()(ESM::FormIdRefId value) const noexcept { return std::hash<ESM::FormId>{}(value.mValue); }
{
return std::hash<ESM4::FormId>{}(value.mValue);
}
}; };
} }

View File

@ -225,7 +225,12 @@ namespace ESM
return ESM::RefId(); return ESM::RefId();
if (value.starts_with(formIdRefIdPrefix)) if (value.starts_with(formIdRefIdPrefix))
return ESM::RefId::formIdRefId(deserializeHexIntegral<ESM4::FormId>(formIdRefIdPrefix.size(), value)); {
uint64_t v = deserializeHexIntegral<uint64_t>(formIdRefIdPrefix.size(), value);
uint32_t index = static_cast<uint32_t>(v) & 0xffffff;
int contentFile = static_cast<int>(v >> 24);
return ESM::RefId::formIdRefId({ index, contentFile });
}
if (value.starts_with(generatedRefIdPrefix)) if (value.starts_with(generatedRefIdPrefix))
return ESM::RefId::generated(deserializeHexIntegral<std::uint64_t>(generatedRefIdPrefix.size(), value)); return ESM::RefId::generated(deserializeHexIntegral<std::uint64_t>(generatedRefIdPrefix.size(), value));

View File

@ -62,8 +62,8 @@ namespace ESM
// Constructs RefId from a string using a pointer to a static set of strings. // Constructs RefId from a string using a pointer to a static set of strings.
static RefId stringRefId(std::string_view value); static RefId stringRefId(std::string_view value);
// Constructs RefId from ESM4 FormId storing the value in-place. // Constructs RefId from FormId storing the value in-place.
static RefId formIdRefId(ESM4::FormId value) noexcept { return RefId(FormIdRefId(value)); } static RefId formIdRefId(FormId value) noexcept { return RefId(FormIdRefId(value)); }
// Constructs RefId from uint64 storing the value in-place. Should be used for generated records where id is a // Constructs RefId from uint64 storing the value in-place. Should be used for generated records where id is a
// global counter. // global counter.

View File

@ -17,7 +17,7 @@ namespace ESM
esm.writeHNString("DISP", params.mDisplayName); esm.writeHNString("DISP", params.mDisplayName);
esm.writeHNT("TYPE", params.mType); esm.writeHNT("TYPE", params.mType);
if (params.mItem.isSet()) if (params.mItem.isSet())
params.mItem.save(esm, true, "ITEM"); esm.writeFormId(params.mItem, true, "ITEM");
if (params.mWorsenings >= 0) if (params.mWorsenings >= 0)
{ {
esm.writeHNT("WORS", params.mWorsenings); esm.writeHNT("WORS", params.mWorsenings);
@ -56,7 +56,7 @@ namespace ESM
{ {
esm.getHNT(params.mType, "TYPE"); esm.getHNT(params.mType, "TYPE");
if (esm.peekNextSub("ITEM")) if (esm.peekNextSub("ITEM"))
params.mItem.load(esm, true, "ITEM"); params.mItem = esm.getFormId(true, "ITEM");
} }
if (esm.isNextSub("WORS")) if (esm.isNextSub("WORS"))
{ {

View File

@ -24,7 +24,7 @@ namespace ESM
if constexpr (load) if constexpr (load)
{ {
cellRef.blank(); cellRef.blank();
cellRef.mRefNum.load(esm, wideRefNum); cellRef.mRefNum = esm.getFormId(wideRefNum);
cellRef.mRefID = esm.getHNORefId("NAME"); cellRef.mRefID = esm.getHNORefId("NAME");
if (cellRef.mRefID.empty()) if (cellRef.mRefID.empty())
@ -33,7 +33,7 @@ namespace ESM
} }
else else
{ {
RefNum{}.load(esm, wideRefNum); esm.getFormId(wideRefNum);
esm.skipHNORefId("NAME"); esm.skipHNORefId("NAME");
} }
} }
@ -154,32 +154,6 @@ namespace ESM
} }
} }
void RefNum::load(ESMReader& esm, bool wide, NAME tag)
{
if (wide)
esm.getHNTSized<8>(*this, tag);
else
esm.getHNT(mIndex, tag);
}
void RefNum::save(ESMWriter& esm, bool wide, NAME tag) const
{
if (wide)
esm.writeHNT(tag, *this, 8);
else
{
if (isSet() && !hasContentFile())
throw std::runtime_error("Generated RefNum can not be saved in 32bit format");
int refNum = (mIndex & 0xffffff) | ((hasContentFile() ? mContentFile : 0xff) << 24);
esm.writeHNT(tag, refNum, 4);
}
}
std::string RefNum::toString() const
{
return std::to_string(mIndex) + "_" + std::to_string(mContentFile);
}
void CellRef::load(ESMReader& esm, bool& isDeleted, bool wideRefNum) void CellRef::load(ESMReader& esm, bool& isDeleted, bool wideRefNum)
{ {
loadId(esm, wideRefNum); loadId(esm, wideRefNum);
@ -198,7 +172,7 @@ namespace ESM
void CellRef::save(ESMWriter& esm, bool wideRefNum, bool inInventory, bool isDeleted) const void CellRef::save(ESMWriter& esm, bool wideRefNum, bool inInventory, bool isDeleted) const
{ {
mRefNum.save(esm, wideRefNum); esm.writeFormId(mRefNum, wideRefNum);
esm.writeHNCRefId("NAME", mRefID); esm.writeHNCRefId("NAME", mRefID);

View File

@ -4,6 +4,7 @@
#include <limits> #include <limits>
#include <string> #include <string>
#include "components/esm/common.hpp"
#include "components/esm/defs.hpp" #include "components/esm/defs.hpp"
#include "components/esm/esmcommon.hpp" #include "components/esm/esmcommon.hpp"
#include "components/esm/refid.hpp" #include "components/esm/refid.hpp"
@ -15,21 +16,7 @@ namespace ESM
const int UnbreakableLock = std::numeric_limits<int>::max(); const int UnbreakableLock = std::numeric_limits<int>::max();
struct RefNum using RefNum = ESM::FormId;
{
unsigned int mIndex = 0;
int mContentFile = -1;
void load(ESMReader& esm, bool wide = false, NAME tag = "FRMR");
void save(ESMWriter& esm, bool wide = false, NAME tag = "FRMR") const;
inline bool hasContentFile() const { return mContentFile >= 0; }
inline bool isSet() const { return mIndex != 0 || mContentFile != -1; }
std::string toString() const;
};
/* Cell reference. This represents ONE object (of many) inside the /* Cell reference. This represents ONE object (of many) inside the
cell. The cell references are not loaded as part of the normal cell. The cell references are not loaded as part of the normal
@ -119,39 +106,6 @@ namespace ESM
}; };
void skipLoadCellRef(ESMReader& esm, bool wideRefNum = false); void skipLoadCellRef(ESMReader& esm, bool wideRefNum = false);
inline bool operator==(const RefNum& left, const RefNum& right)
{
return left.mIndex == right.mIndex && left.mContentFile == right.mContentFile;
}
inline bool operator<(const RefNum& left, const RefNum& right)
{
if (left.mIndex < right.mIndex)
return true;
if (left.mIndex > right.mIndex)
return false;
return left.mContentFile < right.mContentFile;
}
}
namespace std
{
// Needed to use ESM::RefNum as a key in std::unordered_map
template <>
struct hash<ESM::RefNum>
{
size_t operator()(const ESM::RefNum& refNum) const
{
assert(sizeof(ESM::RefNum) == sizeof(size_t));
size_t s;
memcpy(&s, &refNum, sizeof(size_t));
return hash<size_t>()(s);
}
};
} }
#endif #endif

View File

@ -248,6 +248,16 @@ namespace ESM
getHExact(p, size); getHExact(p, size);
} }
FormId ESMReader::getFormId(bool wide, NAME tag)
{
FormId res;
if (wide)
getHNTSized<8>(res, tag);
else
getHNT(res.mIndex, tag);
return res;
}
// Get the next subrecord name and check if it matches the parameter // Get the next subrecord name and check if it matches the parameter
void ESMReader::getSubNameIs(NAME name) void ESMReader::getSubNameIs(NAME name)
{ {
@ -473,7 +483,7 @@ namespace ESM
return RefId::stringRefId(getStringView(size - sizeof(refIdType))); return RefId::stringRefId(getStringView(size - sizeof(refIdType)));
case RefIdType::FormId: case RefIdType::FormId:
{ {
ESM4::FormId formId{}; FormId formId{};
getT(formId); getT(formId);
return RefId::formIdRefId(formId); return RefId::formIdRefId(formId);
} }

View File

@ -195,6 +195,8 @@ namespace ESM
// Read the given number of bytes from a named subrecord // Read the given number of bytes from a named subrecord
void getHNExact(void* p, int size, NAME name); void getHNExact(void* p, int size, NAME name);
ESM::FormId getFormId(bool wide = false, NAME tag = "FRMR");
/************************************************************************* /*************************************************************************
* *
* Low level sub-record methods * Low level sub-record methods

View File

@ -340,6 +340,14 @@ namespace ESM
mStream->write(data, size); mStream->write(data, size);
} }
void ESMWriter::writeFormId(const FormId& formId, bool wide, NAME tag)
{
if (wide)
writeHNT(tag, formId, 8);
else
writeHNT(tag, formId.toUint32(), 4);
}
void ESMWriter::setEncoder(ToUTF8::Utf8Encoder* encoder) void ESMWriter::setEncoder(ToUTF8::Utf8Encoder* encoder)
{ {
mEncoder = encoder; mEncoder = encoder;

View File

@ -179,6 +179,8 @@ namespace ESM
void write(const char* data, size_t size); void write(const char* data, size_t size);
void writeFormId(const ESM::FormId&, bool wide = false, NAME tag = "FRMR");
private: private:
std::list<RecordData> mRecords; std::list<RecordData> mRecords;
std::ostream* mStream; std::ostream* mStream;

View File

@ -18,7 +18,7 @@ namespace ESM
mTargetRef = RefNum{}; mTargetRef = RefNum{};
mTargetId = esm.getHNORefId("TARG"); mTargetId = esm.getHNORefId("TARG");
if (esm.peekNextSub("FRMR")) if (esm.peekNextSub("FRMR"))
mTargetRef.load(esm, true, "FRMR"); mTargetRef = esm.getFormId(true, "FRMR");
} }
void GlobalScript::save(ESMWriter& esm) const void GlobalScript::save(ESMWriter& esm) const
@ -34,7 +34,7 @@ namespace ESM
{ {
esm.writeHNORefId("TARG", mTargetId); esm.writeHNORefId("TARG", mTargetId);
if (mTargetRef.isSet()) if (mTargetRef.isSet())
mTargetRef.save(esm, true, "FRMR"); esm.writeFormId(mTargetRef, true, "FRMR");
} }
} }

View File

@ -109,7 +109,7 @@ namespace ESM4
struct ActorFaction struct ActorFaction
{ {
FormId faction; FormId32 faction;
std::int8_t rank; std::int8_t rank;
std::uint8_t unknown1; std::uint8_t unknown1;
std::uint8_t unknown2; std::uint8_t unknown2;

View File

@ -27,18 +27,14 @@
#ifndef OPENMW_COMPONENTS_ESM4_CELLGRID_H #ifndef OPENMW_COMPONENTS_ESM4_CELLGRID_H
#define OPENMW_COMPONENTS_ESM4_CELLGRID_H #define OPENMW_COMPONENTS_ESM4_CELLGRID_H
#include <cstdint> #include <variant>
#include "formid.hpp" #include "formid.hpp"
#include "grid.hpp" #include "grid.hpp"
namespace ESM4 namespace ESM4
{ {
union CellGrid using CellGrid = std::variant<ESM::FormId, Grid>;
{
FormId cellId;
Grid grid;
};
} }
#endif // OPENMW_COMPONENTS_ESM4_CELLGRID_H #endif // OPENMW_COMPONENTS_ESM4_CELLGRID_H

View File

@ -42,7 +42,7 @@ namespace ESM4
struct ScriptEffect struct ScriptEffect
{ {
FormId formId; // Script effect (Magic effect must be SEFF) FormId32 formId; // Script effect (Magic effect must be SEFF)
std::int32_t school; // Magic school. See Magic schools for more information. std::int32_t school; // Magic school. See Magic schools for more information.
EFI_Label visualEffect; // Visual effect name or 0x00000000 if None EFI_Label visualEffect; // Visual effect name or 0x00000000 if None
std::uint8_t flags; // 0x01 = Hostile std::uint8_t flags; // 0x01 = Hostile

View File

@ -22,56 +22,20 @@
*/ */
#include "formid.hpp" #include "formid.hpp"
#include <charconv>
#include <stdexcept> #include <stdexcept>
#include <string> #include <string>
#include <system_error>
namespace ESM4 namespace ESM4
{ {
void formIdToString(FormId formId, std::string& str) std::string formIdToString(const FormId& formId)
{ {
std::string str;
char buf[8 + 1]; char buf[8 + 1];
int res = snprintf(buf, 8 + 1, "%08X", formId); int res = snprintf(buf, 8 + 1, "%08X", formId.toUint32());
if (res > 0 && res < 8 + 1) if (res > 0 && res < 8 + 1)
str.assign(buf); str.assign(buf);
else else
throw std::runtime_error("Possible buffer overflow while converting formId"); throw std::runtime_error("Possible buffer overflow while converting formId");
}
std::string formIdToString(FormId formId)
{
std::string str;
formIdToString(formId, str);
return str; return str;
} }
bool isFormId(const std::string& str, FormId* id)
{
if (str.size() != 8)
return false;
unsigned long value = 0;
if (auto [_ptr, ec] = std::from_chars(str.data(), str.data() + str.size(), value, 16); ec != std::errc())
return false;
if (id != nullptr)
*id = static_cast<FormId>(value);
return true;
}
FormId stringToFormId(const std::string& str)
{
if (str.size() != 8)
throw std::out_of_range("StringToFormId: incorrect string size");
unsigned long value = 0;
if (auto [_ptr, ec] = std::from_chars(str.data(), str.data() + str.size(), value, 16); ec != std::errc())
throw std::invalid_argument("StringToFormId: string not a valid hexadecimal number");
return static_cast<FormId>(value);
}
} }

View File

@ -23,20 +23,15 @@
#ifndef ESM4_FORMID_H #ifndef ESM4_FORMID_H
#define ESM4_FORMID_H #define ESM4_FORMID_H
#include <cstdint>
#include <string> #include <string>
#include <components/esm/formid.hpp>
namespace ESM4 namespace ESM4
{ {
typedef std::uint32_t FormId; using FormId = ESM::FormId;
using FormId32 = uint32_t;
void formIdToString(FormId formId, std::string& str); std::string formIdToString(const FormId& formId);
std::string formIdToString(FormId formId);
bool isFormId(const std::string& str, FormId* id = nullptr);
FormId stringToFormId(const std::string& str);
} }
#endif // ESM4_FORMID_H #endif // ESM4_FORMID_H

View File

@ -39,14 +39,14 @@ namespace ESM4
{ {
std::int16_t level; std::int16_t level;
std::uint16_t unknown; // sometimes missing std::uint16_t unknown; // sometimes missing
FormId item; FormId32 item;
std::int16_t count; std::int16_t count;
std::uint16_t unknown2; // sometimes missing std::uint16_t unknown2; // sometimes missing
}; };
struct InventoryItem // NPC_, CREA, CONT struct InventoryItem // NPC_, CREA, CONT
{ {
FormId item; FormId32 item;
std::uint32_t count; std::uint32_t count;
}; };
#pragma pack(pop) #pragma pack(pop)

View File

@ -34,7 +34,7 @@
void ESM4::ActorCharacter::load(ESM4::Reader& reader) void ESM4::ActorCharacter::load(ESM4::Reader& reader)
{ {
mFormId = reader.hdr().record.id; mFormId = reader.hdr().record.getFormId();
reader.adjustFormId(mFormId); reader.adjustFormId(mFormId);
mFlags = reader.hdr().record.flags; mFlags = reader.hdr().record.flags;
mParent = reader.currCell(); // NOTE: only for persistent achr? (aren't they all persistent?) mParent = reader.currCell(); // NOTE: only for persistent achr? (aren't they all persistent?)
@ -64,8 +64,8 @@ void ESM4::ActorCharacter::load(ESM4::Reader& reader)
break; break;
case ESM4::SUB_XESP: case ESM4::SUB_XESP:
{ {
reader.get(mEsp); reader.getFormId(mEsp.parent);
reader.adjustFormId(mEsp.parent); reader.get(mEsp.flags);
break; break;
} }
case ESM4::SUB_XRGD: // ragdoll case ESM4::SUB_XRGD: // ragdoll

View File

@ -34,7 +34,7 @@
void ESM4::ActorCreature::load(ESM4::Reader& reader) void ESM4::ActorCreature::load(ESM4::Reader& reader)
{ {
mFormId = reader.hdr().record.id; mFormId = reader.hdr().record.getFormId();
reader.adjustFormId(mFormId); reader.adjustFormId(mFormId);
mFlags = reader.hdr().record.flags; mFlags = reader.hdr().record.flags;
@ -57,8 +57,8 @@ void ESM4::ActorCreature::load(ESM4::Reader& reader)
break; break;
case ESM4::SUB_XESP: case ESM4::SUB_XESP:
{ {
reader.get(mEsp); reader.getFormId(mEsp.parent);
reader.adjustFormId(mEsp.parent); reader.get(mEsp.flags);
break; break;
} }
case ESM4::SUB_XOWN: case ESM4::SUB_XOWN:

View File

@ -34,7 +34,7 @@
void ESM4::Activator::load(ESM4::Reader& reader) void ESM4::Activator::load(ESM4::Reader& reader)
{ {
mFormId = reader.hdr().record.id; mFormId = reader.hdr().record.getFormId();
reader.adjustFormId(mFormId); reader.adjustFormId(mFormId);
mFlags = reader.hdr().record.flags; mFlags = reader.hdr().record.flags;

View File

@ -35,7 +35,7 @@
void ESM4::Potion::load(ESM4::Reader& reader) void ESM4::Potion::load(ESM4::Reader& reader)
{ {
mFormId = reader.hdr().record.id; mFormId = reader.hdr().record.getFormId();
reader.adjustFormId(mFormId); reader.adjustFormId(mFormId);
mFlags = reader.hdr().record.flags; mFlags = reader.hdr().record.flags;

View File

@ -49,9 +49,9 @@ namespace ESM4
{ {
std::int32_t value; std::int32_t value;
std::uint32_t flags; std::uint32_t flags;
FormId withdrawl; FormId32 withdrawl;
float chanceAddition; float chanceAddition;
FormId sound; FormId32 sound;
}; };
#pragma pack(pop) #pragma pack(pop)

View File

@ -38,7 +38,7 @@
void ESM4::MediaLocationController::load(ESM4::Reader& reader) void ESM4::MediaLocationController::load(ESM4::Reader& reader)
{ {
mFormId = reader.hdr().record.id; mFormId = reader.hdr().record.getFormId();
reader.adjustFormId(mFormId); reader.adjustFormId(mFormId);
mFlags = reader.hdr().record.flags; mFlags = reader.hdr().record.flags;

View File

@ -33,7 +33,7 @@
void ESM4::Ammunition::load(ESM4::Reader& reader) void ESM4::Ammunition::load(ESM4::Reader& reader)
{ {
mFormId = reader.hdr().record.id; mFormId = reader.hdr().record.getFormId();
reader.adjustFormId(mFormId); reader.adjustFormId(mFormId);
mFlags = reader.hdr().record.flags; mFlags = reader.hdr().record.flags;

View File

@ -33,7 +33,7 @@
void ESM4::AnimObject::load(ESM4::Reader& reader) void ESM4::AnimObject::load(ESM4::Reader& reader)
{ {
mFormId = reader.hdr().record.id; mFormId = reader.hdr().record.getFormId();
reader.adjustFormId(mFormId); reader.adjustFormId(mFormId);
mFlags = reader.hdr().record.flags; mFlags = reader.hdr().record.flags;

View File

@ -33,7 +33,7 @@
void ESM4::Apparatus::load(ESM4::Reader& reader) void ESM4::Apparatus::load(ESM4::Reader& reader)
{ {
mFormId = reader.hdr().record.id; mFormId = reader.hdr().record.getFormId();
reader.adjustFormId(mFormId); reader.adjustFormId(mFormId);
mFlags = reader.hdr().record.flags; mFlags = reader.hdr().record.flags;

View File

@ -34,7 +34,7 @@
void ESM4::ArmorAddon::load(ESM4::Reader& reader) void ESM4::ArmorAddon::load(ESM4::Reader& reader)
{ {
mFormId = reader.hdr().record.id; mFormId = reader.hdr().record.getFormId();
reader.adjustFormId(mFormId); reader.adjustFormId(mFormId);
mFlags = reader.hdr().record.flags; mFlags = reader.hdr().record.flags;

View File

@ -34,7 +34,7 @@
void ESM4::Armor::load(ESM4::Reader& reader) void ESM4::Armor::load(ESM4::Reader& reader)
{ {
mFormId = reader.hdr().record.id; mFormId = reader.hdr().record.getFormId();
reader.adjustFormId(mFormId); reader.adjustFormId(mFormId);
mFlags = reader.hdr().record.flags; mFlags = reader.hdr().record.flags;
std::uint32_t esmVer = reader.esmVersion(); std::uint32_t esmVer = reader.esmVersion();

View File

@ -34,7 +34,7 @@
void ESM4::AcousticSpace::load(ESM4::Reader& reader) void ESM4::AcousticSpace::load(ESM4::Reader& reader)
{ {
mFormId = reader.hdr().record.id; mFormId = reader.hdr().record.getFormId();
reader.adjustFormId(mFormId); reader.adjustFormId(mFormId);
mFlags = reader.hdr().record.flags; mFlags = reader.hdr().record.flags;

View File

@ -33,7 +33,7 @@
void ESM4::Book::load(ESM4::Reader& reader) void ESM4::Book::load(ESM4::Reader& reader)
{ {
mFormId = reader.hdr().record.id; mFormId = reader.hdr().record.getFormId();
reader.adjustFormId(mFormId); reader.adjustFormId(mFormId);
mFlags = reader.hdr().record.flags; mFlags = reader.hdr().record.flags;
// std::uint32_t esmVer = reader.esmVersion(); // currently unused // std::uint32_t esmVer = reader.esmVersion(); // currently unused

View File

@ -46,7 +46,7 @@ void ESM4::BodyPartData::BodyPart::clear()
void ESM4::BodyPartData::load(ESM4::Reader& reader) void ESM4::BodyPartData::load(ESM4::Reader& reader)
{ {
mFormId = reader.hdr().record.id; mFormId = reader.hdr().record.getFormId();
reader.adjustFormId(mFormId); reader.adjustFormId(mFormId);
mFlags = reader.hdr().record.flags; mFlags = reader.hdr().record.flags;

View File

@ -66,14 +66,14 @@ namespace ESM4
std::uint8_t explExplosionChance; // % std::uint8_t explExplosionChance; // %
std::uint16_t explDebrisCount; std::uint16_t explDebrisCount;
FormId explDebris; FormId32 explDebris;
FormId explExplosion; FormId32 explExplosion;
float trackingMaxAngle; float trackingMaxAngle;
float explDebrisScale; float explDebrisScale;
std::int32_t sevDebrisCount; std::int32_t sevDebrisCount;
FormId sevDebris; FormId32 sevDebris;
FormId sevExplosion; FormId32 sevExplosion;
float sevDebrisScale; float sevDebrisScale;
// Struct - Gore Effects Positioning // Struct - Gore Effects Positioning
@ -84,8 +84,8 @@ namespace ESM4
float rotY; float rotY;
float rotZ; float rotZ;
FormId sevImpactDataSet; FormId32 sevImpactDataSet;
FormId explImpactDataSet; FormId32 explImpactDataSet;
uint8_t sevDecalCount; uint8_t sevDecalCount;
uint8_t explDecalCount; uint8_t explDecalCount;
uint16_t Unknown; uint16_t Unknown;

View File

@ -50,7 +50,7 @@
// longer/shorter/same as loading the subrecords. // longer/shorter/same as loading the subrecords.
void ESM4::Cell::load(ESM4::Reader& reader) void ESM4::Cell::load(ESM4::Reader& reader)
{ {
mFormId = reader.hdr().record.id; mFormId = reader.hdr().record.getFormId();
reader.adjustFormId(mFormId); reader.adjustFormId(mFormId);
mId = ESM::RefId::formIdRefId(mFormId); mId = ESM::RefId::formIdRefId(mFormId);
mFlags = reader.hdr().record.flags; mFlags = reader.hdr().record.flags;
@ -66,8 +66,7 @@ void ESM4::Cell::load(ESM4::Reader& reader)
&& reader.grp().label.grid[0] == 0) && reader.grp().label.grid[0] == 0)
{ {
ESM4::CellGrid currCellGrid; ESM4::CellGrid currCellGrid;
currCellGrid.grid.x = 0; currCellGrid = Grid{ 0, 0 };
currCellGrid.grid.y = 0;
reader.setCurrCellGrid(currCellGrid); // side effect: sets mCellGridValid true reader.setCurrCellGrid(currCellGrid); // side effect: sets mCellGridValid true
} }
@ -123,10 +122,7 @@ void ESM4::Cell::load(ESM4::Reader& reader)
// Remember cell grid for later (loading LAND, NAVM which should be CELL temporary children) // Remember cell grid for later (loading LAND, NAVM which should be CELL temporary children)
// Note that grids only apply for external cells. For interior cells use the cell's formid. // Note that grids only apply for external cells. For interior cells use the cell's formid.
ESM4::CellGrid currCell; reader.setCurrCellGrid(Grid{ static_cast<int16_t>(mX), static_cast<int16_t>(mY) });
currCell.grid.x = (int16_t)mX;
currCell.grid.y = (int16_t)mY;
reader.setCurrCellGrid(currCell);
break; break;
} }
@ -156,7 +152,7 @@ void ESM4::Cell::load(ESM4::Reader& reader)
} }
case ESM4::SUB_XCLR: // for exterior cells case ESM4::SUB_XCLR: // for exterior cells
{ {
mRegions.resize(subHdr.dataSize / sizeof(FormId)); mRegions.resize(subHdr.dataSize / sizeof(FormId32));
for (std::vector<FormId>::iterator it = mRegions.begin(); it != mRegions.end(); ++it) for (std::vector<FormId>::iterator it = mRegions.begin(); it != mRegions.end(); ++it)
{ {
reader.getFormId(*it); reader.getFormId(*it);

View File

@ -44,7 +44,6 @@ namespace ESM4
class Writer; class Writer;
struct ReaderContext; struct ReaderContext;
struct CellGroup; struct CellGroup;
typedef std::uint32_t FormId;
enum CellFlags // TES4 TES5 enum CellFlags // TES4 TES5
{ // ----------------------- ------------------------------------ { // ----------------------- ------------------------------------

View File

@ -39,7 +39,7 @@
void ESM4::Class::load(ESM4::Reader& reader) void ESM4::Class::load(ESM4::Reader& reader)
{ {
// mFormId = reader.adjustFormId(reader.hdr().record.id); // FIXME: use master adjusted? // mFormId = reader.adjustFormId(reader.hdr().record.id); // FIXME: use master adjusted?
mFormId = reader.hdr().record.id; mFormId = reader.hdr().record.getFormId();
mFlags = reader.hdr().record.flags; mFlags = reader.hdr().record.flags;
while (reader.getSubRecordHeader()) while (reader.getSubRecordHeader())

View File

@ -34,7 +34,7 @@
void ESM4::Colour::load(ESM4::Reader& reader) void ESM4::Colour::load(ESM4::Reader& reader)
{ {
mFormId = reader.hdr().record.id; mFormId = reader.hdr().record.getFormId();
reader.adjustFormId(mFormId); reader.adjustFormId(mFormId);
mFlags = reader.hdr().record.flags; mFlags = reader.hdr().record.flags;

View File

@ -34,7 +34,7 @@
void ESM4::Clothing::load(ESM4::Reader& reader) void ESM4::Clothing::load(ESM4::Reader& reader)
{ {
mFormId = reader.hdr().record.id; mFormId = reader.hdr().record.getFormId();
reader.adjustFormId(mFormId); reader.adjustFormId(mFormId);
mFlags = reader.hdr().record.flags; mFlags = reader.hdr().record.flags;

View File

@ -33,7 +33,7 @@
void ESM4::Container::load(ESM4::Reader& reader) void ESM4::Container::load(ESM4::Reader& reader)
{ {
mFormId = reader.hdr().record.id; mFormId = reader.hdr().record.getFormId();
reader.adjustFormId(mFormId); reader.adjustFormId(mFormId);
mFlags = reader.hdr().record.flags; mFlags = reader.hdr().record.flags;

View File

@ -42,7 +42,7 @@
void ESM4::Creature::load(ESM4::Reader& reader) void ESM4::Creature::load(ESM4::Reader& reader)
{ {
mFormId = reader.hdr().record.id; mFormId = reader.hdr().record.getFormId();
reader.adjustFormId(mFormId); reader.adjustFormId(mFormId);
mFlags = reader.hdr().record.flags; mFlags = reader.hdr().record.flags;

View File

@ -35,7 +35,7 @@
void ESM4::Dialogue::load(ESM4::Reader& reader) void ESM4::Dialogue::load(ESM4::Reader& reader)
{ {
mFormId = reader.hdr().record.id; mFormId = reader.hdr().record.getFormId();
reader.adjustFormId(mFormId); reader.adjustFormId(mFormId);
mFlags = reader.hdr().record.flags; mFlags = reader.hdr().record.flags;

View File

@ -39,7 +39,7 @@
void ESM4::DefaultObj::load(ESM4::Reader& reader) void ESM4::DefaultObj::load(ESM4::Reader& reader)
{ {
mFormId = reader.hdr().record.id; mFormId = reader.hdr().record.getFormId();
reader.adjustFormId(mFormId); reader.adjustFormId(mFormId);
mFlags = reader.hdr().record.flags; mFlags = reader.hdr().record.flags;

View File

@ -33,7 +33,7 @@
void ESM4::Door::load(ESM4::Reader& reader) void ESM4::Door::load(ESM4::Reader& reader)
{ {
mFormId = reader.hdr().record.id; mFormId = reader.hdr().record.getFormId();
reader.adjustFormId(mFormId); reader.adjustFormId(mFormId);
mFlags = reader.hdr().record.flags; mFlags = reader.hdr().record.flags;

View File

@ -33,7 +33,7 @@
void ESM4::Eyes::load(ESM4::Reader& reader) void ESM4::Eyes::load(ESM4::Reader& reader)
{ {
mFormId = reader.hdr().record.id; mFormId = reader.hdr().record.getFormId();
reader.adjustFormId(mFormId); reader.adjustFormId(mFormId);
mFlags = reader.hdr().record.flags; mFlags = reader.hdr().record.flags;

View File

@ -33,7 +33,7 @@
void ESM4::Flora::load(ESM4::Reader& reader) void ESM4::Flora::load(ESM4::Reader& reader)
{ {
mFormId = reader.hdr().record.id; mFormId = reader.hdr().record.getFormId();
reader.adjustFormId(mFormId); reader.adjustFormId(mFormId);
mFlags = reader.hdr().record.flags; mFlags = reader.hdr().record.flags;

View File

@ -34,7 +34,7 @@
void ESM4::FormIdList::load(ESM4::Reader& reader) void ESM4::FormIdList::load(ESM4::Reader& reader)
{ {
mFormId = reader.hdr().record.id; mFormId = reader.hdr().record.getFormId();
reader.adjustFormId(mFormId); reader.adjustFormId(mFormId);
mFlags = reader.hdr().record.flags; mFlags = reader.hdr().record.flags;

View File

@ -33,7 +33,7 @@
void ESM4::Furniture::load(ESM4::Reader& reader) void ESM4::Furniture::load(ESM4::Reader& reader)
{ {
mFormId = reader.hdr().record.id; mFormId = reader.hdr().record.getFormId();
reader.adjustFormId(mFormId); reader.adjustFormId(mFormId);
mFlags = reader.hdr().record.flags; mFlags = reader.hdr().record.flags;

View File

@ -34,7 +34,7 @@
void ESM4::GlobalVariable::load(ESM4::Reader& reader) void ESM4::GlobalVariable::load(ESM4::Reader& reader)
{ {
mFormId = reader.hdr().record.id; mFormId = reader.hdr().record.getFormId();
reader.adjustFormId(mFormId); reader.adjustFormId(mFormId);
mFlags = reader.hdr().record.flags; mFlags = reader.hdr().record.flags;

View File

@ -11,8 +11,7 @@ namespace ESM4
GameSetting::Data readData(FormId formId, std::string_view editorId, Reader& reader) GameSetting::Data readData(FormId formId, std::string_view editorId, Reader& reader)
{ {
if (editorId.empty()) if (editorId.empty())
throw std::runtime_error( throw std::runtime_error("Unknown ESM4 GMST (" + formId.toString() + ") data type: editor id is empty");
"Unknown ESM4 GMST (" + std::to_string(formId) + ") data type: editor id is empty");
const char type = editorId[0]; const char type = editorId[0];
switch (type) switch (type)
{ {
@ -36,14 +35,14 @@ namespace ESM4
} }
default: default:
throw std::runtime_error( throw std::runtime_error(
"Unsupported ESM4 GMST (" + std::to_string(formId) + ") data type: " + std::string(editorId)); "Unsupported ESM4 GMST (" + formId.toString() + ") data type: " + std::string(editorId));
} }
} }
} }
void GameSetting::load(Reader& reader) void GameSetting::load(Reader& reader)
{ {
mFormId = reader.hdr().record.id; mFormId = reader.hdr().record.getFormId();
reader.adjustFormId(mFormId); reader.adjustFormId(mFormId);
mFlags = reader.hdr().record.flags; mFlags = reader.hdr().record.flags;
@ -59,8 +58,8 @@ namespace ESM4
mData = readData(mFormId, mEditorId, reader); mData = readData(mFormId, mEditorId, reader);
break; break;
default: default:
throw std::runtime_error("Unknown ESM4 GMST (" + std::to_string(mFormId) + ") subrecord " throw std::runtime_error(
+ ESM::printName(subHdr.typeId)); "Unknown ESM4 GMST (" + mFormId.toString() + ") subrecord " + ESM::printName(subHdr.typeId));
} }
} }
} }

View File

@ -33,7 +33,7 @@
void ESM4::Grass::load(ESM4::Reader& reader) void ESM4::Grass::load(ESM4::Reader& reader)
{ {
mFormId = reader.hdr().record.id; mFormId = reader.hdr().record.getFormId();
reader.adjustFormId(mFormId); reader.adjustFormId(mFormId);
mFlags = reader.hdr().record.flags; mFlags = reader.hdr().record.flags;

View File

@ -34,7 +34,7 @@
void ESM4::Hair::load(ESM4::Reader& reader) void ESM4::Hair::load(ESM4::Reader& reader)
{ {
mFormId = reader.hdr().record.id; mFormId = reader.hdr().record.getFormId();
reader.adjustFormId(mFormId); reader.adjustFormId(mFormId);
mFlags = reader.hdr().record.flags; mFlags = reader.hdr().record.flags;

View File

@ -35,7 +35,7 @@
void ESM4::HeadPart::load(ESM4::Reader& reader) void ESM4::HeadPart::load(ESM4::Reader& reader)
{ {
mFormId = reader.hdr().record.id; mFormId = reader.hdr().record.getFormId();
reader.adjustFormId(mFormId); reader.adjustFormId(mFormId);
mFlags = reader.hdr().record.flags; mFlags = reader.hdr().record.flags;

View File

@ -33,7 +33,7 @@
void ESM4::IdleAnimation::load(ESM4::Reader& reader) void ESM4::IdleAnimation::load(ESM4::Reader& reader)
{ {
mFormId = reader.hdr().record.id; mFormId = reader.hdr().record.getFormId();
reader.adjustFormId(mFormId); reader.adjustFormId(mFormId);
mFlags = reader.hdr().record.flags; mFlags = reader.hdr().record.flags;

View File

@ -34,7 +34,7 @@
void ESM4::IdleMarker::load(ESM4::Reader& reader) void ESM4::IdleMarker::load(ESM4::Reader& reader)
{ {
mFormId = reader.hdr().record.id; mFormId = reader.hdr().record.getFormId();
reader.adjustFormId(mFormId); reader.adjustFormId(mFormId);
mFlags = reader.hdr().record.flags; mFlags = reader.hdr().record.flags;

View File

@ -36,7 +36,7 @@
void ESM4::ItemMod::load(ESM4::Reader& reader) void ESM4::ItemMod::load(ESM4::Reader& reader)
{ {
mFormId = reader.hdr().record.id; mFormId = reader.hdr().record.getFormId();
reader.adjustFormId(mFormId); reader.adjustFormId(mFormId);
mFlags = reader.hdr().record.flags; mFlags = reader.hdr().record.flags;

View File

@ -35,7 +35,7 @@
void ESM4::DialogInfo::load(ESM4::Reader& reader) void ESM4::DialogInfo::load(ESM4::Reader& reader)
{ {
mFormId = reader.hdr().record.id; mFormId = reader.hdr().record.getFormId();
reader.adjustFormId(mFormId); reader.adjustFormId(mFormId);
mFlags = reader.hdr().record.flags; mFlags = reader.hdr().record.flags;

View File

@ -34,7 +34,7 @@
void ESM4::Ingredient::load(ESM4::Reader& reader) void ESM4::Ingredient::load(ESM4::Reader& reader)
{ {
mFormId = reader.hdr().record.id; mFormId = reader.hdr().record.getFormId();
reader.adjustFormId(mFormId); reader.adjustFormId(mFormId);
mFlags = reader.hdr().record.flags; mFlags = reader.hdr().record.flags;

View File

@ -33,7 +33,7 @@
void ESM4::Key::load(ESM4::Reader& reader) void ESM4::Key::load(ESM4::Reader& reader)
{ {
mFormId = reader.hdr().record.id; mFormId = reader.hdr().record.getFormId();
reader.adjustFormId(mFormId); reader.adjustFormId(mFormId);
mFlags = reader.hdr().record.flags; mFlags = reader.hdr().record.flags;

View File

@ -55,7 +55,7 @@
// //
void ESM4::Land::load(ESM4::Reader& reader) void ESM4::Land::load(ESM4::Reader& reader)
{ {
mFormId = reader.hdr().record.id; mFormId = reader.hdr().record.getFormId();
reader.adjustFormId(mFormId); reader.adjustFormId(mFormId);
mFlags = reader.hdr().record.flags; mFlags = reader.hdr().record.flags;
mDataTypes = 0; mDataTypes = 0;
@ -181,8 +181,9 @@ void ESM4::Land::load(ESM4::Reader& reader)
} }
case ESM4::SUB_VTEX: // only in Oblivion? case ESM4::SUB_VTEX: // only in Oblivion?
{ {
int count = (int)reader.subRecordHeader().dataSize / sizeof(FormId); int count = (int)reader.subRecordHeader().dataSize / sizeof(FormId32);
assert((reader.subRecordHeader().dataSize % sizeof(FormId)) == 0 && "ESM4::LAND VTEX data size error"); assert(
(reader.subRecordHeader().dataSize % sizeof(FormId32)) == 0 && "ESM4::LAND VTEX data size error");
if (count) if (count)
{ {
@ -212,7 +213,7 @@ void ESM4::Land::load(ESM4::Reader& reader)
bool missing = false; bool missing = false;
for (int i = 0; i < 4; ++i) for (int i = 0; i < 4; ++i)
{ {
if (mTextures[i].base.formId == 0) if (mTextures[i].base.formId.isZero())
{ {
// std::cout << "ESM4::LAND " << ESM4::formIdToString(mFormId) << " missing base, quad " << i << std::endl; // std::cout << "ESM4::LAND " << ESM4::formIdToString(mFormId) << " missing base, quad " << i << std::endl;
// std::cout << "layers " << mTextures[i].layers.size() << std::endl; // std::cout << "layers " << mTextures[i].layers.size() << std::endl;

View File

@ -37,7 +37,7 @@
void ESM4::LightingTemplate::load(ESM4::Reader& reader) void ESM4::LightingTemplate::load(ESM4::Reader& reader)
{ {
mFormId = reader.hdr().record.id; mFormId = reader.hdr().record.getFormId();
reader.adjustFormId(mFormId); reader.adjustFormId(mFormId);
mFlags = reader.hdr().record.flags; mFlags = reader.hdr().record.flags;

View File

@ -39,7 +39,6 @@ namespace ESM4
{ {
class Reader; class Reader;
class Writer; class Writer;
typedef std::uint32_t FormId;
struct LightingTemplate struct LightingTemplate
{ {

View File

@ -33,7 +33,7 @@
void ESM4::Light::load(ESM4::Reader& reader) void ESM4::Light::load(ESM4::Reader& reader)
{ {
FormId formId = reader.hdr().record.id; FormId formId = reader.hdr().record.getFormId();
reader.adjustFormId(formId); reader.adjustFormId(formId);
mId = ESM::RefId::formIdRefId(formId); mId = ESM::RefId::formIdRefId(formId);
mFlags = reader.hdr().record.flags; mFlags = reader.hdr().record.flags;

View File

@ -39,7 +39,7 @@
void ESM4::LandTexture::load(ESM4::Reader& reader) void ESM4::LandTexture::load(ESM4::Reader& reader)
{ {
mFormId = reader.hdr().record.id; mFormId = reader.hdr().record.getFormId();
reader.adjustFormId(mFormId); reader.adjustFormId(mFormId);
mFlags = reader.hdr().record.flags; mFlags = reader.hdr().record.flags;
std::uint32_t esmVer = reader.esmVersion(); std::uint32_t esmVer = reader.esmVersion();

View File

@ -34,7 +34,7 @@
void ESM4::LevelledCreature::load(ESM4::Reader& reader) void ESM4::LevelledCreature::load(ESM4::Reader& reader)
{ {
mFormId = reader.hdr().record.id; mFormId = reader.hdr().record.getFormId();
reader.adjustFormId(mFormId); reader.adjustFormId(mFormId);
mFlags = reader.hdr().record.flags; mFlags = reader.hdr().record.flags;

View File

@ -34,7 +34,7 @@
void ESM4::LevelledItem::load(ESM4::Reader& reader) void ESM4::LevelledItem::load(ESM4::Reader& reader)
{ {
mFormId = reader.hdr().record.id; mFormId = reader.hdr().record.getFormId();
reader.adjustFormId(mFormId); reader.adjustFormId(mFormId);
mFlags = reader.hdr().record.flags; mFlags = reader.hdr().record.flags;

View File

@ -34,7 +34,7 @@
void ESM4::LevelledNpc::load(ESM4::Reader& reader) void ESM4::LevelledNpc::load(ESM4::Reader& reader)
{ {
mFormId = reader.hdr().record.id; mFormId = reader.hdr().record.getFormId();
reader.adjustFormId(mFormId); reader.adjustFormId(mFormId);
mFlags = reader.hdr().record.flags; mFlags = reader.hdr().record.flags;
// std::uint32_t esmVer = reader.esmVersion(); // currently unused // std::uint32_t esmVer = reader.esmVersion(); // currently unused

View File

@ -34,7 +34,7 @@
void ESM4::Material::load(ESM4::Reader& reader) void ESM4::Material::load(ESM4::Reader& reader)
{ {
// mFormId = reader.adjustFormId(reader.hdr().record.id); // FIXME: use master adjusted? // mFormId = reader.adjustFormId(reader.hdr().record.id); // FIXME: use master adjusted?
mFormId = reader.hdr().record.id; mFormId = reader.hdr().record.getFormId();
mFlags = reader.hdr().record.flags; mFlags = reader.hdr().record.flags;
while (reader.getSubRecordHeader()) while (reader.getSubRecordHeader())

View File

@ -33,7 +33,7 @@
void ESM4::MiscItem::load(ESM4::Reader& reader) void ESM4::MiscItem::load(ESM4::Reader& reader)
{ {
mFormId = reader.hdr().record.id; mFormId = reader.hdr().record.getFormId();
reader.adjustFormId(mFormId); reader.adjustFormId(mFormId);
mFlags = reader.hdr().record.flags; mFlags = reader.hdr().record.flags;

View File

@ -34,7 +34,7 @@
void ESM4::MediaSet::load(ESM4::Reader& reader) void ESM4::MediaSet::load(ESM4::Reader& reader)
{ {
mFormId = reader.hdr().record.id; mFormId = reader.hdr().record.getFormId();
reader.adjustFormId(mFormId); reader.adjustFormId(mFormId);
mFlags = reader.hdr().record.flags; mFlags = reader.hdr().record.flags;

View File

@ -34,7 +34,7 @@
void ESM4::MovableStatic::load(ESM4::Reader& reader) void ESM4::MovableStatic::load(ESM4::Reader& reader)
{ {
mFormId = reader.hdr().record.id; mFormId = reader.hdr().record.getFormId();
reader.adjustFormId(mFormId); reader.adjustFormId(mFormId);
mFlags = reader.hdr().record.flags; mFlags = reader.hdr().record.flags;

View File

@ -38,7 +38,7 @@
void ESM4::Music::load(ESM4::Reader& reader) void ESM4::Music::load(ESM4::Reader& reader)
{ {
mFormId = reader.hdr().record.id; mFormId = reader.hdr().record.getFormId();
reader.adjustFormId(mFormId); reader.adjustFormId(mFormId);
mFlags = reader.hdr().record.flags; mFlags = reader.hdr().record.flags;

View File

@ -151,10 +151,12 @@ void ESM4::Navigation::NavMeshInfo::load(ESM4::Reader& reader)
reader.get(worldSpaceId); reader.get(worldSpaceId);
// FLG_Tamriel = 0x0000003c, // grid info follows, possibly Tamriel? // FLG_Tamriel = 0x0000003c, // grid info follows, possibly Tamriel?
// FLG_Morrowind = 0x01380000, // grid info follows, probably Skywind // FLG_Morrowind = 0x01380000, // grid info follows, probably Skywind
if (worldSpaceId == 0x0000003c || worldSpaceId == 0x01380000) if (worldSpaceId == FormId{ 0x3c, 0 } || worldSpaceId == FormId{ 0x380000, 1 })
{ {
reader.get(cellGrid.grid.y); // NOTE: reverse order Grid grid;
reader.get(cellGrid.grid.x); reader.get(grid.y); // NOTE: reverse order
reader.get(grid.x);
cellGrid = grid;
// FIXME: debugging only // FIXME: debugging only
#if 0 #if 0
std::string padding; std::string padding;
@ -167,7 +169,9 @@ void ESM4::Navigation::NavMeshInfo::load(ESM4::Reader& reader)
} }
else else
{ {
reader.get(cellGrid.cellId); FormId cellId;
reader.get(cellId);
cellGrid = cellId;
#if 0 #if 0
if (worldSpaceId == 0) // interior if (worldSpaceId == 0) // interior
@ -237,7 +241,7 @@ void ESM4::Navigation::NavMeshInfo::load(ESM4::Reader& reader)
// //
void ESM4::Navigation::load(ESM4::Reader& reader) void ESM4::Navigation::load(ESM4::Reader& reader)
{ {
// mFormId = reader.hdr().record.id; // mFormId = reader.hdr().record.getFormId();
// mFlags = reader.hdr().record.flags; // mFlags = reader.hdr().record.flags;
std::uint32_t esmVer = reader.esmVersion(); std::uint32_t esmVer = reader.esmVersion();
bool isFONV = esmVer == ESM::VER_132 || esmVer == ESM::VER_133 || esmVer == ESM::VER_134; bool isFONV = esmVer == ESM::VER_132 || esmVer == ESM::VER_133 || esmVer == ESM::VER_134;
@ -312,8 +316,9 @@ void ESM4::Navigation::load(ESM4::Reader& reader)
std::cout << "node " << std::hex << node // FIXME: debugging only std::cout << "node " << std::hex << node // FIXME: debugging only
<< ", index " << index << ", i " << std::dec << total+i << std::endl; << ", index " << index << ", i " << std::dec << total+i << std::endl;
#endif #endif
FormId nodeFormId = FormId::fromUint32(node); // should we apply reader.adjustFormId?
// std::pair<std::map<FormId, std::uint32_t>::iterator, bool> res = // std::pair<std::map<FormId, std::uint32_t>::iterator, bool> res =
mPathIndexMap.insert(std::make_pair(node, index)); mPathIndexMap.emplace(nodeFormId, index);
// FIXME: this throws if more than one file is being loaded // FIXME: this throws if more than one file is being loaded
// if (!res.second) // if (!res.second)
// throw std::runtime_error ("node already exists in the preferred path index map"); // throw std::runtime_error ("node already exists in the preferred path index map");

View File

@ -45,7 +45,7 @@ namespace ESM4
struct DoorRef struct DoorRef
{ {
std::uint32_t unknown; std::uint32_t unknown;
FormId formId; FormId32 formId;
}; };
struct Triangle struct Triangle

View File

@ -47,7 +47,7 @@ void ESM4::NavMesh::NVNMstruct::load(ESM4::Reader& reader)
reader.get(worldSpaceId); reader.get(worldSpaceId);
// FLG_Tamriel = 0x0000003c, // grid info follows, possibly Tamriel? // FLG_Tamriel = 0x0000003c, // grid info follows, possibly Tamriel?
// FLG_Morrowind = 0x01380000, // grid info follows, probably Skywind // FLG_Morrowind = 0x01380000, // grid info follows, probably Skywind
if (worldSpaceId == 0x0000003c || worldSpaceId == 0x01380000) if (worldSpaceId == FormId{ 0x3c, 0 } || worldSpaceId == FormId{ 380000, 1 })
{ {
// ^ // ^
// Y | X Y Index // Y | X Y Index
@ -65,8 +65,10 @@ void ESM4::NavMesh::NVNMstruct::load(ESM4::Reader& reader)
// //
// Formula seems to be floor(Skywind coord / 2) <cmath> // Formula seems to be floor(Skywind coord / 2) <cmath>
// //
reader.get(cellGrid.grid.y); // NOTE: reverse order Grid grid;
reader.get(cellGrid.grid.x); reader.get(grid.y); // NOTE: reverse order
reader.get(grid.x);
cellGrid = grid;
// FIXME: debugging only // FIXME: debugging only
#if 0 #if 0
std::string padding; std::string padding;
@ -79,7 +81,9 @@ void ESM4::NavMesh::NVNMstruct::load(ESM4::Reader& reader)
} }
else else
{ {
reader.get(cellGrid.cellId); FormId cellId;
reader.get(cellId);
cellGrid = cellId;
#if 0 #if 0
std::string padding; // FIXME std::string padding; // FIXME
@ -186,7 +190,7 @@ void ESM4::NavMesh::NVNMstruct::load(ESM4::Reader& reader)
void ESM4::NavMesh::load(ESM4::Reader& reader) void ESM4::NavMesh::load(ESM4::Reader& reader)
{ {
mFormId = reader.hdr().record.id; mFormId = reader.hdr().record.getFormId();
mFlags = reader.hdr().record.flags; mFlags = reader.hdr().record.flags;
// std::cout << "NavMesh 0x" << std::hex << this << std::endl; // FIXME // std::cout << "NavMesh 0x" << std::hex << this << std::endl; // FIXME

View File

@ -56,7 +56,7 @@ namespace ESM4
struct ExtConnection struct ExtConnection
{ {
std::uint32_t unknown; std::uint32_t unknown;
FormId navMesh; FormId32 navMesh;
std::uint16_t triangleIndex; std::uint16_t triangleIndex;
}; };
@ -64,7 +64,7 @@ namespace ESM4
{ {
std::uint16_t triangleIndex; std::uint16_t triangleIndex;
std::uint32_t unknown; std::uint32_t unknown;
FormId doorRef; FormId32 doorRef;
}; };
#pragma pack(pop) #pragma pack(pop)

View File

@ -34,7 +34,7 @@
void ESM4::Note::load(ESM4::Reader& reader) void ESM4::Note::load(ESM4::Reader& reader)
{ {
mFormId = reader.hdr().record.id; mFormId = reader.hdr().record.getFormId();
reader.adjustFormId(mFormId); reader.adjustFormId(mFormId);
mFlags = reader.hdr().record.flags; mFlags = reader.hdr().record.flags;

View File

@ -42,7 +42,7 @@
void ESM4::Npc::load(ESM4::Reader& reader) void ESM4::Npc::load(ESM4::Reader& reader)
{ {
mFormId = reader.hdr().record.id; mFormId = reader.hdr().record.getFormId();
reader.adjustFormId(mFormId); reader.adjustFormId(mFormId);
mFlags = reader.hdr().record.flags; mFlags = reader.hdr().record.flags;

View File

@ -34,7 +34,7 @@
void ESM4::Outfit::load(ESM4::Reader& reader) void ESM4::Outfit::load(ESM4::Reader& reader)
{ {
mFormId = reader.hdr().record.id; mFormId = reader.hdr().record.getFormId();
reader.adjustFormId(mFormId); reader.adjustFormId(mFormId);
mFlags = reader.hdr().record.flags; mFlags = reader.hdr().record.flags;
@ -48,7 +48,7 @@ void ESM4::Outfit::load(ESM4::Reader& reader)
break; break;
case ESM4::SUB_INAM: case ESM4::SUB_INAM:
{ {
std::size_t numObj = subHdr.dataSize / sizeof(FormId); std::size_t numObj = subHdr.dataSize / sizeof(FormId32);
for (std::size_t i = 0; i < numObj; ++i) for (std::size_t i = 0; i < numObj; ++i)
{ {
FormId formId; FormId formId;

View File

@ -35,7 +35,7 @@
void ESM4::AIPackage::load(ESM4::Reader& reader) void ESM4::AIPackage::load(ESM4::Reader& reader)
{ {
mFormId = reader.hdr().record.id; mFormId = reader.hdr().record.getFormId();
reader.adjustFormId(mFormId); reader.adjustFormId(mFormId);
mFlags = reader.hdr().record.flags; mFlags = reader.hdr().record.flags;

View File

@ -60,14 +60,14 @@ namespace ESM4
{ {
std::int32_t type = 0xff; // 0 = near ref, 1 = in cell, 2 = current loc, 3 = editor loc, 4 = obj id, 5 = obj std::int32_t type = 0xff; // 0 = near ref, 1 = in cell, 2 = current loc, 3 = editor loc, 4 = obj id, 5 = obj
// type, 0xff = no location data // type, 0xff = no location data
FormId location; // uint32_t if type = 5 FormId32 location; // uint32_t if type = 5
std::int32_t radius; std::int32_t radius;
}; };
struct PTDT // target struct PTDT // target
{ {
std::int32_t type = 0xff; // 0 = specific ref, 1 = obj id, 2 = obj type, 0xff = no target data std::int32_t type = 0xff; // 0 = specific ref, 1 = obj id, 2 = obj type, 0xff = no target data
FormId target; // uint32_t if type = 2 FormId32 target; // uint32_t if type = 2
std::int32_t distance; std::int32_t distance;
}; };
@ -81,8 +81,8 @@ namespace ESM4
std::uint8_t unknown3; // probably padding std::uint8_t unknown3; // probably padding
float compValue; float compValue;
std::int32_t fnIndex; std::int32_t fnIndex;
FormId param1; FormId32 param1;
FormId param2; FormId32 param2;
std::uint32_t unknown4; // probably padding std::uint32_t unknown4; // probably padding
}; };
#pragma pack(pop) #pragma pack(pop)

View File

@ -36,7 +36,7 @@
void ESM4::Pathgrid::load(ESM4::Reader& reader) void ESM4::Pathgrid::load(ESM4::Reader& reader)
{ {
mFormId = reader.hdr().record.id; mFormId = reader.hdr().record.getFormId();
reader.adjustFormId(mFormId); reader.adjustFormId(mFormId);
mFlags = reader.hdr().record.flags; mFlags = reader.hdr().record.flags;

View File

@ -36,7 +36,7 @@
void ESM4::PlacedGrenade::load(ESM4::Reader& reader) void ESM4::PlacedGrenade::load(ESM4::Reader& reader)
{ {
mFormId = reader.hdr().record.id; mFormId = reader.hdr().record.getFormId();
reader.adjustFormId(mFormId); reader.adjustFormId(mFormId);
mFlags = reader.hdr().record.flags; mFlags = reader.hdr().record.flags;

View File

@ -36,7 +36,7 @@
void ESM4::PlaceableWater::load(ESM4::Reader& reader) void ESM4::PlaceableWater::load(ESM4::Reader& reader)
{ {
mFormId = reader.hdr().record.id; mFormId = reader.hdr().record.getFormId();
reader.adjustFormId(mFormId); reader.adjustFormId(mFormId);
mFlags = reader.hdr().record.flags; mFlags = reader.hdr().record.flags;

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