1
0
Fork 0
mirror of https://github.com/OpenMW/openmw.git synced 2025-06-20 19:11:33 +00:00

Minor performance gains on loading cell references.

- Use integers where possible
- Unfortunately many functions are simply duplicated for now, but over time the deprecated ones will be removed
This commit is contained in:
cc9cii 2015-12-19 17:54:45 +11:00
parent 003b0d48be
commit abe6904a94
4 changed files with 110 additions and 7 deletions

View file

@ -6,9 +6,9 @@
void ESM::RefNum::load (ESMReader& esm, bool wide) void ESM::RefNum::load (ESMReader& esm, bool wide)
{ {
if (wide) if (wide)
esm.getHNT (*this, "FRMR", 8); esm.getHNT (*this, SREC_FRMR, 8);
else else
esm.getHNT (mIndex, "FRMR"); esm.getHNT (mIndex, SREC_FRMR);
} }
void ESM::RefNum::save (ESMWriter &esm, bool wide, const std::string& tag) const void ESM::RefNum::save (ESMWriter &esm, bool wide, const std::string& tag) const
@ -36,14 +36,14 @@ void ESM::CellRef::loadId (ESMReader& esm, bool wideRefNum)
// the following refs are part of a "temp refs" section. A temp ref is not being tracked by the moved references system. // 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, // 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. // because any item can theoretically be moved by a script.
if (esm.isNextSub ("NAM0")) if (esm.isNextSub (SREC_NAM0))
esm.skipHSub(); esm.skipHSub();
blank(); blank();
mRefNum.load (esm, wideRefNum); mRefNum.load (esm, wideRefNum);
mRefID = esm.getHNString ("NAME"); esm.getHNString (SREC_NAME, mRefID);
} }
void ESM::CellRef::loadData(ESMReader &esm, bool &isDeleted) void ESM::CellRef::loadData(ESMReader &esm, bool &isDeleted)
@ -180,7 +180,7 @@ void ESM::CellRef::save (ESMWriter &esm, bool wideRefNum, bool inInventory, bool
void ESM::CellRef::blank() void ESM::CellRef::blank()
{ {
mRefNum.unset(); mRefNum.unset();
mRefID.clear(); mRefID.clear();
mScale = 1; mScale = 1;
mOwner.clear(); mOwner.clear();
mGlobalVariable.clear(); mGlobalVariable.clear();
@ -196,7 +196,7 @@ void ESM::CellRef::blank()
mTrap.clear(); mTrap.clear();
mReferenceBlocked = -1; mReferenceBlocked = -1;
mTeleport = false; mTeleport = false;
for (int i=0; i<3; ++i) for (int i=0; i<3; ++i)
{ {
mDoorDest.pos[i] = 0; mDoorDest.pos[i] = 0;

View file

@ -128,7 +128,9 @@ enum RecNameInts
enum SubRecNameInts enum SubRecNameInts
{ {
SREC_DELE = ESM::FourCC<'D','E','L','E'>::value, SREC_DELE = ESM::FourCC<'D','E','L','E'>::value,
SREC_NAME = ESM::FourCC<'N','A','M','E'>::value SREC_NAME = ESM::FourCC<'N','A','M','E'>::value,
SREC_NAM0 = ESM::FourCC<'N','A','M','0'>::value,
SREC_FRMR = ESM::FourCC<'F','R','M','R'>::value
}; };
} }

View file

@ -109,6 +109,12 @@ std::string ESMReader::getHNString(const char* name)
return getHString(); return getHString();
} }
void ESMReader::getHNString(const int name, std::string& str)
{
getSubNameIs(name);
getHString(str);
}
std::string ESMReader::getHString() std::string ESMReader::getHString()
{ {
getSubHeader(); getSubHeader();
@ -130,6 +136,28 @@ std::string ESMReader::getHString()
return getString(mCtx.leftSub); return getString(mCtx.leftSub);
} }
void ESMReader::getHString(std::string& str)
{
getSubHeader();
// Hack to make MultiMark.esp load. Zero-length strings do not
// occur in any of the official mods, but MultiMark makes use of
// them. For some reason, they break the rules, and contain a byte
// (value 0) even if the header says there is no data. If
// Morrowind accepts it, so should we.
if (mCtx.leftSub == 0)
{
// Skip the following zero byte
mCtx.leftRec--;
char c;
getExact(&c, 1);
str = "";
return;
}
getString(str, mCtx.leftSub);
}
void ESMReader::getHExact(void*p, int size) void ESMReader::getHExact(void*p, int size)
{ {
getSubHeader(); getSubHeader();
@ -159,6 +187,24 @@ void ESMReader::getSubNameIs(const char* name)
+ mCtx.subName.toString()); + mCtx.subName.toString());
} }
void ESMReader::getSubNameIs(const int name)
{
getSubName();
if (mCtx.subName != name)
{
unsigned char typeName[4];
typeName[0] = name & 0xff;
typeName[1] = (name >> 8) & 0xff;
typeName[2] = (name >> 16) & 0xff;
typeName[3] = (name >> 24) & 0xff;
std::string subName = std::string((char*)typeName, 4);
fail("Expected subrecord " + subName + " but got "
+ mCtx.subName.toString());
}
}
bool ESMReader::isNextSub(const char* name) bool ESMReader::isNextSub(const char* name)
{ {
if (!mCtx.leftRec) if (!mCtx.leftRec)
@ -174,6 +220,21 @@ bool ESMReader::isNextSub(const char* name)
return !mCtx.subCached; return !mCtx.subCached;
} }
bool ESMReader::isNextSub(const int name)
{
if (!mCtx.leftRec)
return false;
getSubName();
// If the name didn't match, then mark the it as 'cached' so it's
// available for the next call to getSubName.
mCtx.subCached = (mCtx.subName != name);
// If subCached is false, then subName == name.
return !mCtx.subCached;
}
bool ESMReader::peekNextSub(const char *name) bool ESMReader::peekNextSub(const char *name)
{ {
if (!mCtx.leftRec) if (!mCtx.leftRec)
@ -347,6 +408,26 @@ std::string ESMReader::getString(int size)
return std::string (ptr, size); return std::string (ptr, size);
} }
void ESMReader::getString(std::string& str, int size)
{
size_t s = size;
if (mBuffer.size() <= s)
// Add some extra padding to reduce the chance of having to resize again later.
mBuffer.resize(3*s);
mBuffer[s] = 0; // And make sure the string is zero terminated
char *ptr = &mBuffer[0];
getExact(ptr, size); // read ESM data
size = static_cast<int>(strnlen(ptr, size));
if (mEncoder)
str = mEncoder->getUtf8(ptr, size); // Convert to UTF8 and return
else
str = std::string (ptr, size);
}
void ESMReader::fail(const std::string &msg) void ESMReader::fail(const std::string &msg)
{ {
using namespace std; using namespace std;

View file

@ -103,6 +103,13 @@ public:
getHT(x); getHT(x);
} }
template <typename X>
void getHNT(X &x, const int name)
{
getSubNameIs(name);
getHT(x);
}
// Optional version of getHNT // Optional version of getHNT
template <typename X> template <typename X>
void getHNOT(X &x, const char* name) void getHNOT(X &x, const char* name)
@ -121,6 +128,14 @@ public:
getHT(x); getHT(x);
} }
template <typename X>
void getHNT(X &x, const int name, int size)
{
assert(sizeof(X) == size);
getSubNameIs(name);
getHT(x);
}
template <typename X> template <typename X>
void getHNOT(X &x, const char* name, int size) void getHNOT(X &x, const char* name, int size)
{ {
@ -159,9 +174,11 @@ public:
// Read a string with the given sub-record name // Read a string with the given sub-record name
std::string getHNString(const char* name); std::string getHNString(const char* name);
void getHNString(const int name, std::string& str);
// Read a string, including the sub-record header (but not the name) // Read a string, including the sub-record header (but not the name)
std::string getHString(); std::string getHString();
void getHString(std::string& str);
// Read the given number of bytes from a subrecord // Read the given number of bytes from a subrecord
void getHExact(void*p, int size); void getHExact(void*p, int size);
@ -177,6 +194,7 @@ public:
// 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 getSubNameIs(const char* name); void getSubNameIs(const char* name);
void getSubNameIs(const int name);
/** Checks if the next sub record name matches the parameter. If it /** Checks if the next sub record name matches the parameter. If it
does, it is read into 'subName' just as if getSubName() was does, it is read into 'subName' just as if getSubName() was
@ -184,6 +202,7 @@ public:
calls to getSubName(), isNextSub() and getSubNameIs(). calls to getSubName(), isNextSub() and getSubNameIs().
*/ */
bool isNextSub(const char* name); bool isNextSub(const char* name);
bool isNextSub(const int name);
bool peekNextSub(const char* name); bool peekNextSub(const char* name);
@ -256,6 +275,7 @@ public:
// Read the next 'size' bytes and return them as a string. Converts // Read the next 'size' bytes and return them as a string. Converts
// them from native encoding to UTF8 in the process. // them from native encoding to UTF8 in the process.
std::string getString(int size); std::string getString(int size);
void getString(std::string& str, int size);
void skip(int bytes) { mEsm->seek(mEsm->tell()+bytes); } void skip(int bytes) { mEsm->seek(mEsm->tell()+bytes); }
uint64_t getOffset() { return mEsm->tell(); } uint64_t getOffset() { return mEsm->tell(); }