mirror of
				https://github.com/OpenMW/openmw.git
				synced 2025-10-31 20:26:43 +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:
		
							parent
							
								
									003b0d48be
								
							
						
					
					
						commit
						abe6904a94
					
				
					 4 changed files with 110 additions and 7 deletions
				
			
		|  | @ -6,9 +6,9 @@ | |||
| void ESM::RefNum::load (ESMReader& esm, bool wide) | ||||
| { | ||||
|     if (wide) | ||||
|         esm.getHNT (*this, "FRMR", 8); | ||||
|         esm.getHNT (*this, SREC_FRMR, 8); | ||||
|     else | ||||
|         esm.getHNT (mIndex, "FRMR"); | ||||
|         esm.getHNT (mIndex, SREC_FRMR); | ||||
| } | ||||
| 
 | ||||
| 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.
 | ||||
|     // 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")) | ||||
|     if (esm.isNextSub (SREC_NAM0)) | ||||
|         esm.skipHSub(); | ||||
| 
 | ||||
|     blank(); | ||||
| 
 | ||||
|     mRefNum.load (esm, wideRefNum); | ||||
| 
 | ||||
|     mRefID = esm.getHNString ("NAME"); | ||||
|     esm.getHNString (SREC_NAME, mRefID); | ||||
| } | ||||
| 
 | ||||
| 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() | ||||
| { | ||||
|     mRefNum.unset(); | ||||
|     mRefID.clear();     | ||||
|     mRefID.clear(); | ||||
|     mScale = 1; | ||||
|     mOwner.clear(); | ||||
|     mGlobalVariable.clear(); | ||||
|  | @ -196,7 +196,7 @@ void ESM::CellRef::blank() | |||
|     mTrap.clear(); | ||||
|     mReferenceBlocked = -1; | ||||
|     mTeleport = false; | ||||
|      | ||||
| 
 | ||||
|     for (int i=0; i<3; ++i) | ||||
|     { | ||||
|         mDoorDest.pos[i] = 0; | ||||
|  |  | |||
|  | @ -128,7 +128,9 @@ enum RecNameInts | |||
| enum SubRecNameInts | ||||
| { | ||||
|     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 | ||||
| }; | ||||
| 
 | ||||
| } | ||||
|  |  | |||
|  | @ -109,6 +109,12 @@ std::string ESMReader::getHNString(const char* name) | |||
|     return getHString(); | ||||
| } | ||||
| 
 | ||||
| void ESMReader::getHNString(const int name, std::string& str) | ||||
| { | ||||
|     getSubNameIs(name); | ||||
|     getHString(str); | ||||
| } | ||||
| 
 | ||||
| std::string ESMReader::getHString() | ||||
| { | ||||
|     getSubHeader(); | ||||
|  | @ -130,6 +136,28 @@ std::string ESMReader::getHString() | |||
|     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) | ||||
| { | ||||
|     getSubHeader(); | ||||
|  | @ -159,6 +187,24 @@ void ESMReader::getSubNameIs(const char* name) | |||
|                         + 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) | ||||
| { | ||||
|     if (!mCtx.leftRec) | ||||
|  | @ -174,6 +220,21 @@ bool ESMReader::isNextSub(const char* name) | |||
|     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) | ||||
| { | ||||
|     if (!mCtx.leftRec) | ||||
|  | @ -347,6 +408,26 @@ std::string ESMReader::getString(int 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) | ||||
| { | ||||
|     using namespace std; | ||||
|  |  | |||
|  | @ -103,6 +103,13 @@ public: | |||
|     getHT(x); | ||||
|   } | ||||
| 
 | ||||
|   template <typename X> | ||||
|   void getHNT(X &x, const int name) | ||||
|   { | ||||
|     getSubNameIs(name); | ||||
|     getHT(x); | ||||
|   } | ||||
| 
 | ||||
|   // Optional version of getHNT
 | ||||
|   template <typename X> | ||||
|   void getHNOT(X &x, const char* name) | ||||
|  | @ -121,6 +128,14 @@ public: | |||
|       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> | ||||
|   void getHNOT(X &x, const char* name, int size) | ||||
|   { | ||||
|  | @ -159,9 +174,11 @@ public: | |||
| 
 | ||||
|   // Read a string with the given sub-record 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)
 | ||||
|   std::string getHString(); | ||||
|   void getHString(std::string& str); | ||||
| 
 | ||||
|   // Read the given number of bytes from a subrecord
 | ||||
|   void getHExact(void*p, int size); | ||||
|  | @ -177,6 +194,7 @@ public: | |||
| 
 | ||||
|   // Get the next subrecord name and check if it matches the parameter
 | ||||
|   void getSubNameIs(const char* name); | ||||
|   void getSubNameIs(const int name); | ||||
| 
 | ||||
|   /** Checks if the next sub record name matches the parameter. If it
 | ||||
|       does, it is read into 'subName' just as if getSubName() was | ||||
|  | @ -184,6 +202,7 @@ public: | |||
|       calls to getSubName(), isNextSub() and getSubNameIs(). | ||||
|    */ | ||||
|   bool isNextSub(const char* name); | ||||
|   bool isNextSub(const int name); | ||||
| 
 | ||||
|   bool peekNextSub(const char* name); | ||||
| 
 | ||||
|  | @ -256,6 +275,7 @@ public: | |||
|   // Read the next 'size' bytes and return them as a string. Converts
 | ||||
|   // them from native encoding to UTF8 in the process.
 | ||||
|   std::string getString(int size); | ||||
|   void getString(std::string& str, int size); | ||||
| 
 | ||||
|   void skip(int bytes) { mEsm->seek(mEsm->tell()+bytes); } | ||||
|   uint64_t getOffset() { return mEsm->tell(); } | ||||
|  |  | |||
		Loading…
	
		Reference in a new issue