1
0
mirror of https://gitlab.com/OpenMW/openmw.git synced 2025-01-01 03:21:41 +00:00
OpenMW/components/esm3/cellref.cpp
florent.teppe 65cdd489fb create a specific esm reader function for RefID to avoid allocation for string and then again for RefId
Fixed some types

removed useless header

applied clang format

fixed compile tests

fixed clang tidy, and closer to logic before this MR

Removed hardcoded refids

unless there is a returned value we don't use static RefIds
can use == between RefId and hardcoded string

Fix clang format

Fixed a few instances where std::string was used, when only const std::string& was needed

removed unused variable
2022-12-27 19:15:57 +01:00

298 lines
9.3 KiB
C++

#include "cellref.hpp"
#include <algorithm>
#include <components/debug/debuglog.hpp>
#include "esmreader.hpp"
#include "esmwriter.hpp"
namespace ESM
{
namespace
{
template <bool load>
void loadIdImpl(ESMReader& esm, bool wideRefNum, CellRef& cellRef)
{
// According to Hrnchamd, this does not belong to the actual ref. Instead, it is a marker indicating that
// the following refs are part of a "temp refs" section. A temp ref is not being tracked by the moved
// references system. Its only purpose is a performance optimization for "immovable" things. We don't need
// this, and it's problematic anyway, because any item can theoretically be moved by a script.
if (esm.isNextSub("NAM0"))
esm.skipHSub();
if constexpr (load)
{
cellRef.blank();
cellRef.mRefNum.load(esm, wideRefNum);
cellRef.mRefID = esm.getHNORefId("NAME");
if (cellRef.mRefID.empty())
Log(Debug::Warning) << "Warning: got CellRef with empty RefId in " << esm.getName() << " 0x"
<< std::hex << esm.getFileOffset();
}
else
{
RefNum{}.load(esm, wideRefNum);
esm.skipHNOString("NAME");
}
}
template <bool load>
void loadDataImpl(ESMReader& esm, bool& isDeleted, CellRef& cellRef)
{
const auto getRefIdOrSkip = [&](ESM::RefId refId) {
if constexpr (load)
refId = esm.getRefId();
else
esm.skipHString();
};
const auto getHStringOrSkip = [&](std::string& value) {
if constexpr (load)
value = esm.getHString();
else
esm.skipHString();
};
const auto getHTOrSkip = [&](auto& value) {
if constexpr (load)
esm.getHT(value);
else
esm.skipHT<std::decay_t<decltype(value)>>();
};
if constexpr (load)
isDeleted = false;
bool isLoaded = false;
while (!isLoaded && esm.hasMoreSubs())
{
esm.getSubName();
switch (esm.retSubName().toInt())
{
case fourCC("UNAM"):
getHTOrSkip(cellRef.mReferenceBlocked);
break;
case fourCC("XSCL"):
getHTOrSkip(cellRef.mScale);
if constexpr (load)
cellRef.mScale = std::clamp(cellRef.mScale, 0.5f, 2.0f);
break;
case fourCC("ANAM"):
getRefIdOrSkip(cellRef.mOwner);
break;
case fourCC("BNAM"):
getHStringOrSkip(cellRef.mGlobalVariable);
break;
case fourCC("XSOL"):
getRefIdOrSkip(cellRef.mSoul);
break;
case fourCC("CNAM"):
getRefIdOrSkip(cellRef.mFaction);
break;
case fourCC("INDX"):
getHTOrSkip(cellRef.mFactionRank);
break;
case fourCC("XCHG"):
getHTOrSkip(cellRef.mEnchantmentCharge);
break;
case fourCC("INTV"):
getHTOrSkip(cellRef.mChargeInt);
break;
case fourCC("NAM9"):
getHTOrSkip(cellRef.mGoldValue);
break;
case fourCC("DODT"):
getHTOrSkip(cellRef.mDoorDest);
if constexpr (load)
cellRef.mTeleport = true;
break;
case fourCC("DNAM"):
getHStringOrSkip(cellRef.mDestCell);
break;
case fourCC("FLTV"):
getHTOrSkip(cellRef.mLockLevel);
break;
case fourCC("KNAM"):
getRefIdOrSkip(cellRef.mKey);
break;
case fourCC("TNAM"):
getRefIdOrSkip(cellRef.mTrap);
break;
case fourCC("DATA"):
if constexpr (load)
esm.getHTSized<24>(cellRef.mPos);
else
esm.skipHTSized<24, decltype(cellRef.mPos)>();
break;
case fourCC("NAM0"):
{
esm.skipHSub();
break;
}
case SREC_DELE:
esm.skipHSub();
if constexpr (load)
isDeleted = true;
break;
default:
esm.cacheSubName();
isLoaded = true;
break;
}
}
if constexpr (load)
{
if (cellRef.mLockLevel == 0 && !cellRef.mKey.empty())
{
cellRef.mLockLevel = UnbreakableLock;
cellRef.mTrap = ESM::RefId::sEmpty;
}
}
}
}
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())
Log(Debug::Error) << "Generated RefNum can not be saved in 32bit format";
int refNum = (mIndex & 0xffffff) | ((hasContentFile() ? mContentFile : 0xff) << 24);
esm.writeHNT(tag, refNum, 4);
}
}
void CellRef::load(ESMReader& esm, bool& isDeleted, bool wideRefNum)
{
loadId(esm, wideRefNum);
loadData(esm, isDeleted);
}
void CellRef::loadId(ESMReader& esm, bool wideRefNum)
{
loadIdImpl<true>(esm, wideRefNum, *this);
}
void CellRef::loadData(ESMReader& esm, bool& isDeleted)
{
loadDataImpl<true>(esm, isDeleted, *this);
}
void CellRef::save(ESMWriter& esm, bool wideRefNum, bool inInventory, bool isDeleted) const
{
mRefNum.save(esm, wideRefNum);
esm.writeHNCString("NAME", mRefID.getRefIdString());
if (isDeleted)
{
esm.writeHNString("DELE", "", 3);
return;
}
if (mScale != 1.0)
{
esm.writeHNT("XSCL", std::clamp(mScale, 0.5f, 2.0f));
}
if (!inInventory)
esm.writeHNOCString("ANAM", mOwner.getRefIdString());
esm.writeHNOCString("BNAM", mGlobalVariable);
esm.writeHNOCString("XSOL", mSoul.getRefIdString());
if (!inInventory)
{
esm.writeHNOCString("CNAM", mFaction.getRefIdString());
if (mFactionRank != -2)
{
esm.writeHNT("INDX", mFactionRank);
}
}
if (mEnchantmentCharge != -1)
esm.writeHNT("XCHG", mEnchantmentCharge);
if (mChargeInt != -1)
esm.writeHNT("INTV", mChargeInt);
if (mGoldValue > 1)
esm.writeHNT("NAM9", mGoldValue);
if (!inInventory && mTeleport)
{
esm.writeHNT("DODT", mDoorDest);
esm.writeHNOCString("DNAM", mDestCell);
}
if (!inInventory && mLockLevel != 0)
{
esm.writeHNT("FLTV", mLockLevel);
}
if (!inInventory)
{
esm.writeHNOCString("KNAM", mKey.getRefIdString());
esm.writeHNOCString("TNAM", mTrap.getRefIdString());
}
if (mReferenceBlocked != -1)
esm.writeHNT("UNAM", mReferenceBlocked);
if (!inInventory)
esm.writeHNT("DATA", mPos, 24);
}
void CellRef::blank()
{
mRefNum.unset();
mRefID = ESM::RefId::sEmpty;
mScale = 1;
mOwner = ESM::RefId::sEmpty;
mGlobalVariable.clear();
mSoul = ESM::RefId::sEmpty;
mFaction = ESM::RefId::sEmpty;
mFactionRank = -2;
mChargeInt = -1;
mChargeIntRemainder = 0.0f;
mEnchantmentCharge = -1;
mGoldValue = 1;
mDestCell.clear();
mLockLevel = 0;
mKey = ESM::RefId::sEmpty;
mTrap = ESM::RefId::sEmpty;
mReferenceBlocked = -1;
mTeleport = false;
for (int i = 0; i < 3; ++i)
{
mDoorDest.pos[i] = 0;
mDoorDest.rot[i] = 0;
mPos.pos[i] = 0;
mPos.rot[i] = 0;
}
}
void skipLoadCellRef(ESMReader& esm, bool wideRefNum)
{
CellRef cellRef;
loadIdImpl<false>(esm, wideRefNum, cellRef);
bool isDeleted;
loadDataImpl<false>(esm, isDeleted, cellRef);
}
}