Skip to content
Permalink
Browse files

Reduce allocations for DFF loading

  • Loading branch information...
botder committed Sep 29, 2019
1 parent ce14053 commit 830f01b64ad8b12961ca14f7e0cebaa0583aeb2a
@@ -239,7 +239,7 @@ RwTexDictionary* CRenderWareSA::ReadTXD(const SString& strFilename, const CBuffe
// Reads and parses a DFF file specified by a path (szDFF) into a CModelInfo identified by the object id (usModelID)
// bLoadEmbeddedCollisions should be true for vehicles
// Any custom TXD should be imported before this call
RpClump* CRenderWareSA::ReadDFF(const SString& strFilename, const CBuffer& fileData, unsigned short usModelID, bool bLoadEmbeddedCollisions)
RpClump* CRenderWareSA::ReadDFF(const SString& strFilename, const SString& buffer, unsigned short usModelID, bool bLoadEmbeddedCollisions)
{
// Set correct TXD as materials are processed at the same time
if (usModelID != 0)
@@ -250,12 +250,12 @@ RpClump* CRenderWareSA::ReadDFF(const SString& strFilename, const CBuffer& fileD

// open the stream
RwStream* streamModel;
RwBuffer buffer;
if (!fileData.IsEmpty())
RwBuffer streamBuffer;
if (!buffer.empty())
{
buffer.ptr = (void*)fileData.GetData();
buffer.size = fileData.GetSize();
streamModel = RwStreamOpen(STREAM_TYPE_BUFFER, STREAM_MODE_READ, &buffer);
streamBuffer.ptr = (void*)buffer.data();
streamBuffer.size = buffer.size();
streamModel = RwStreamOpen(STREAM_TYPE_BUFFER, STREAM_MODE_READ, &streamBuffer);
}
else
streamModel = RwStreamOpen(STREAM_TYPE_FILENAME, STREAM_MODE_READ, *strFilename);
@@ -42,7 +42,7 @@ class CRenderWareSA : public CRenderWare
RwTexDictionary* ReadTXD(const SString& strFilename, const CBuffer& fileData);

// Reads and parses a DFF file specified by a path (szDFF) into a CModelInfo identified by the object id (usModelID)
RpClump* ReadDFF(const SString& strFilename, const CBuffer& fileData, unsigned short usModelID, bool bLoadEmbeddedCollisions);
RpClump* ReadDFF(const SString& strFilename, const SString& buffer, unsigned short usModelID, bool bLoadEmbeddedCollisions);

// Destroys a DFF instance
void DestroyDFF(RpClump* pClump);
@@ -55,48 +55,36 @@ RpClump* CClientDFF::GetLoadedClump(ushort usModelId)
if (g_pCore->GetNetwork()->CheckFile("dff", m_strDffFilename))
{
g_pClientGame->GetResourceManager()->ValidateResourceFile(m_strDffFilename, CBuffer());
info.pClump = g_pGame->GetRenderWare()->ReadDFF(m_strDffFilename, CBuffer(), usModelId, CClientVehicleManager::IsValidModel(usModelId));
info.pClump = g_pGame->GetRenderWare()->ReadDFF(m_strDffFilename, SString(), usModelId, CClientVehicleManager::IsValidModel(usModelId));
}
}
else // We have raw data
{
info.pClump = g_pGame->GetRenderWare()->ReadDFF(NULL, m_RawDataBuffer, usModelId, CClientVehicleManager::IsValidModel(usModelId));

// Remove raw data from memory (can only do one replace when using raw data)
m_RawDataBuffer = CBuffer();
SString().swap(m_RawDataBuffer);
}
}

return info.pClump;
}

bool CClientDFF::LoadDFF(const SString& strFile, bool bIsRawData)
bool CClientDFF::Load(bool isRaw, SString input)
{
// Should only be called once, directly after construction
m_bIsRawData = bIsRawData;
if (!m_bIsRawData) // If we have actual file
{
assert(m_strDffFilename.empty());

m_strDffFilename = strFile;
if (m_strDffFilename.empty())
return false;
if (input.empty())
return false;

if (!FileExists(m_strDffFilename))
return false;
m_bIsRawData = isRaw;

if (!g_pCore->GetNetwork()->CheckFile("dff", m_strDffFilename))
return false;
if (isRaw)
{
return LoadFromBuffer(std::move(input));
}
else
{
m_RawDataBuffer = CBuffer(strFile, strFile.length());
if (!g_pCore->GetNetwork()->CheckFile("dff", "", m_RawDataBuffer.GetData(), m_RawDataBuffer.GetSize()))
return false;
return LoadFromFile(std::move(input));
}

// Do actual load later (in ReplaceModel)
return true;
}

void CClientDFF::UnloadDFF()
@@ -125,6 +113,27 @@ bool CClientDFF::ReplaceModel(unsigned short usModel, bool bAlphaTransparency)
return bResult;
}

bool CClientDFF::LoadFromFile(SString filePath)
{
if (!FileExists(filePath))
return false;

if (!g_pCore->GetNetwork()->CheckFile("dff", filePath))
return false;

m_strDffFilename = std::move(filePath);
return true;
}

bool CClientDFF::LoadFromBuffer(SString buffer)
{
if (!g_pCore->GetNetwork()->CheckFile("dff", "", buffer.data(), buffer.size()))
return false;

m_RawDataBuffer = std::move(buffer);
return true;
}

bool CClientDFF::DoReplaceModel(unsigned short usModel, bool bAlphaTransparency)
{
if (!CClientDFFManager::IsReplacableModel(usModel))
@@ -33,7 +33,7 @@ class CClientDFF : public CClientEntity

eClientEntityType GetType() const { return CCLIENTDFF; }

bool LoadDFF(const SString& strFile, bool bIsRawData);
bool Load(bool isRaw, SString input);

bool ReplaceModel(unsigned short usModel, bool bAlphaTransparency);

@@ -49,7 +49,10 @@ class CClientDFF : public CClientEntity
void GetPosition(CVector& vecPosition) const {};
void SetPosition(const CVector& vecPosition){};

protected:
private:
bool LoadFromFile(SString filePath);
bool LoadFromBuffer(SString buffer);

bool DoReplaceModel(unsigned short usModel, bool bAlphaTransparency);
void UnloadDFF();
void InternalRestoreModel(unsigned short usModel);
@@ -64,8 +67,8 @@ class CClientDFF : public CClientEntity
class CClientDFFManager* m_pDFFManager;

SString m_strDffFilename;
CBuffer m_RawDataBuffer;
bool m_bIsRawData;
SString m_RawDataBuffer;
bool m_bIsRawData = false;
std::map<ushort, SLoadedClumpInfo> m_LoadedClumpInfoMap;

std::list<unsigned short> m_Replaced;
@@ -185,10 +185,10 @@ int CLuaEngineDefs::EngineLoadCOL(lua_State* luaVM)

int CLuaEngineDefs::EngineLoadDFF(lua_State* luaVM)
{
SString strFile = "";
SString input = "";
CScriptArgReader argStream(luaVM);
// Grab the DFF filename or data (model ID ignored after 1.3.1)
argStream.ReadString(strFile);
argStream.ReadString(input);

if (!argStream.HasErrors())
{
@@ -200,10 +200,20 @@ int CLuaEngineDefs::EngineLoadDFF(lua_State* luaVM)
CResource* pResource = pLuaMain->GetResource();
if (pResource)
{
bool bIsRawData = CClientDFF::IsDFFData(strFile);
SString strPath;
// Is this a legal filepath?
if (bIsRawData || CResourceManager::ParseResourcePathInput(strFile, pResource, &strPath))
bool bIsRawData = CClientDFF::IsDFFData(input);

// Do not proceed if the file path length appears too long to be real
if (!bIsRawData && input.size() > 32767)
{
argStream.SetCustomError("Corrupt DFF file data or file path too long", "Error loading DFF");
m_pScriptDebugging->LogCustom(luaVM, argStream.GetFullErrorMessage());
lua_pushboolean(luaVM, false);
return 1;
}

SString filePath;

if (bIsRawData || CResourceManager::ParseResourcePathInput(input, pResource, &filePath))
{
// Grab the resource root entity
CClientEntity* pRoot = pResource->GetResourceDFFRoot();
@@ -212,7 +222,7 @@ int CLuaEngineDefs::EngineLoadDFF(lua_State* luaVM)
CClientDFF* pDFF = new CClientDFF(m_pManager, INVALID_ELEMENT_ID);

// Try to load the DFF file
if (pDFF->LoadDFF(bIsRawData ? strFile : strPath, bIsRawData))
if (pDFF->Load(bIsRawData, bIsRawData ? std::move(input) : std::move(filePath)))
{
// Success loading the file. Set parent to DFF root
pDFF->SetParent(pRoot);
@@ -225,18 +235,22 @@ int CLuaEngineDefs::EngineLoadDFF(lua_State* luaVM)
{
// Delete it again
delete pDFF;
argStream.SetCustomError(bIsRawData ? "raw data" : strFile, "Error loading DFF");
argStream.SetCustomError(bIsRawData ? "raw data" : input, "Error loading DFF");
}
}
else
argStream.SetCustomError(bIsRawData ? "raw data" : strFile, "Bad file path");
{
argStream.SetCustomError(bIsRawData ? "raw data" : input, "Bad file path");
}
}
}
}

if (argStream.HasErrors())
{
m_pScriptDebugging->LogCustom(luaVM, argStream.GetFullErrorMessage());
}

// We failed
lua_pushboolean(luaVM, false);
return 1;
}
@@ -70,7 +70,7 @@ class CRenderWare
virtual void ClothesRemoveReplacementTxd(char* pFileData) = 0;
virtual bool HasClothesReplacementChanged() = 0;
virtual RwTexDictionary* ReadTXD(const SString& strFilename, const CBuffer& fileData) = 0;
virtual RpClump* ReadDFF(const SString& strFilename, const CBuffer& fileData, unsigned short usModelID, bool bLoadEmbeddedCollisions) = 0;
virtual RpClump* ReadDFF(const SString& strFilename, const SString& buffer, unsigned short usModelID, bool bLoadEmbeddedCollisions) = 0;
virtual CColModel* ReadCOL(const CBuffer& fileData) = 0;
virtual void DestroyDFF(RpClump* pClump) = 0;
virtual void DestroyTXD(RwTexDictionary* pTXD) = 0;
@@ -540,18 +540,37 @@ class CScriptArgReader
void ReadString(SString& outValue, const char* defaultValue = NULL)
{
int iArgument = lua_type(m_luaVM, m_iIndex);

if (iArgument == LUA_TSTRING || iArgument == LUA_TNUMBER)
{
uint uiLength = lua_strlen(m_luaVM, m_iIndex);
outValue.assign(lua_tostring(m_luaVM, m_iIndex++), uiLength);
size_t length = lua_strlen(m_luaVM, m_iIndex);

try
{
outValue.assign(lua_tostring(m_luaVM, m_iIndex++), length);
}
catch (const std::bad_alloc&)
{
SetCustomError("out of memory", "Memory allocation");
}

return;
}
else if (iArgument == LUA_TNONE || iArgument == LUA_TNIL)
{
if (defaultValue)
{
outValue = defaultValue;
m_iIndex++;

try
{
outValue.assign(defaultValue);
}
catch (const std::bad_alloc&)
{
SetCustomError("out of memory", "Memory allocation");
}

return;
}
}

0 comments on commit 830f01b

Please sign in to comment.
You can’t perform that action at this time.