Skip to content
Permalink
Browse files

Reduce allocations for COL loading

  • Loading branch information...
botder committed Oct 1, 2019
1 parent 438bac5 commit f10151e7c9f9b871146d5e2a90ca6818752f64c5
@@ -421,17 +421,17 @@ void CRenderWareSA::ReplacePedModel(RpClump* pNew, unsigned short usModelID)
}

// Reads and parses a COL3 file
CColModel* CRenderWareSA::ReadCOL(const CBuffer& fileData)
CColModel* CRenderWareSA::ReadCOL(const SString& buffer)
{
if (fileData.GetSize() < sizeof(ColModelFileHeader) + 16)
if (buffer.size() < sizeof(ColModelFileHeader) + 16)
return NULL;

const ColModelFileHeader& header = *(ColModelFileHeader*)fileData.GetData();
const ColModelFileHeader& header = *(ColModelFileHeader*)buffer.data();

// Load the col model
if (header.version[0] == 'C' && header.version[1] == 'O' && header.version[2] == 'L')
{
unsigned char* pModelData = (unsigned char*)fileData.GetData() + sizeof(ColModelFileHeader);
unsigned char* pModelData = (unsigned char*)buffer.data() + sizeof(ColModelFileHeader);

// Create a new CColModel
CColModelSA* pColModel = new CColModelSA();
@@ -54,7 +54,7 @@ class CRenderWareSA : public CRenderWare
void DestroyTexture(RwTexture* pTex);

// Reads and parses a COL3 file with an optional collision key name
CColModel* ReadCOL(const CBuffer& fileData);
CColModel* ReadCOL(const SString& buffer);

// Replaces a CColModel for a specific object identified by the object id (usModelID)
void ReplaceCollisions(CColModel* pColModel, unsigned short usModelID);
@@ -35,36 +35,46 @@ CClientColModel::~CClientColModel()
delete m_pColModel;
}

bool CClientColModel::LoadCol(const SString& strFile, bool bIsRawData)
bool CClientColModel::Load(bool isRaw, SString input)
{
// Not already got a col model?
if (!m_pColModel)
if (m_pColModel)
return false;

if (isRaw)
{
SString strFilename;
CBuffer buffer;
if (!bIsRawData)
{
strFilename = strFile;
buffer.LoadFromFile(strFilename);
g_pClientGame->GetResourceManager()->ValidateResourceFile(strFilename, buffer);
}
else
{
buffer = CBuffer(strFile, strFile.length());
}
return LoadFromBuffer(std::move(input));
}
else
{
return LoadFromFile(std::move(input));
}
}

if (!g_pCore->GetNetwork()->CheckFile("col", strFilename, buffer.GetData(), buffer.GetSize()))
return false;
bool CClientColModel::LoadFromFile(SString filePath)
{
SString buffer;

// Load the collision file
m_pColModel = g_pGame->GetRenderWare()->ReadCOL(buffer);
if (!FileLoad(std::nothrow, filePath, buffer))
return false;

// Success if the col model is != NULL
return (m_pColModel != NULL);
}
g_pClientGame->GetResourceManager()->ValidateResourceFile(filePath, buffer.data(), buffer.size());

// Failed. Already loaded
return false;
if (!g_pCore->GetNetwork()->CheckFile("col", filePath, buffer.data(), buffer.size()))
return false;

m_pColModel = g_pGame->GetRenderWare()->ReadCOL(std::move(buffer));

return m_pColModel != nullptr;
}

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

m_pColModel = g_pGame->GetRenderWare()->ReadCOL(std::move(buffer));

return m_pColModel != nullptr;
}

bool CClientColModel::Replace(unsigned short usModel)
@@ -23,6 +23,8 @@ class CClientColModel : public CClientEntity
eClientEntityType GetType() const { return CCLIENTCOL; }

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

bool IsLoaded() { return m_pColModel != NULL; };

bool Replace(unsigned short usModel);
@@ -38,6 +40,9 @@ class CClientColModel : public CClientEntity
void SetPosition(const CVector& vecPosition){};

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

void InternalRestore(unsigned short usModel);

class CClientColModelManager* m_pColModelManager;
@@ -54,7 +54,7 @@ RpClump* CClientDFF::GetLoadedClump(ushort usModelId)
{
if (g_pCore->GetNetwork()->CheckFile("dff", m_strDffFilename))
{
g_pClientGame->GetResourceManager()->ValidateResourceFile(m_strDffFilename, CBuffer());
g_pClientGame->GetResourceManager()->ValidateResourceFile(m_strDffFilename, nullptr, 0);
info.pClump = g_pGame->GetRenderWare()->ReadDFF(m_strDffFilename, SString(), usModelId, CClientVehicleManager::IsValidModel(usModelId));
}
}
@@ -173,7 +173,7 @@ void CClientTXD::Restream(unsigned short usModelID)
// Return filename to use, or false if not valid
bool CClientTXD::GetFilenameToUse(SString& strOutFilename)
{
g_pClientGame->GetResourceManager()->ValidateResourceFile(m_strFilename, CBuffer());
g_pClientGame->GetResourceManager()->ValidateResourceFile(m_strFilename, nullptr, 0);
if (!g_pCore->GetNetwork()->CheckFile("txd", m_strFilename))
return false;

@@ -247,7 +247,7 @@ void CResourceManager::OnFileModifedByScript(const SString& strInFilename, const
}

// Check resource file data matches server checksum
void CResourceManager::ValidateResourceFile(const SString& strInFilename, const CBuffer& fileData)
void CResourceManager::ValidateResourceFile(const SString& strInFilename, const char* buffer, size_t bufferSize)
{
SString strFilename = PathConform(strInFilename).ToLower();
CDownloadableResource* pResourceFile = MapFindRef(m_ResourceFileMap, strFilename);
@@ -262,8 +262,8 @@ void CResourceManager::ValidateResourceFile(const SString& strInFilename, const
else
{
CChecksum checksum;
if (!fileData.IsEmpty())
checksum = CChecksum::GenerateChecksumFromBuffer(fileData.GetData(), fileData.GetSize());
if (buffer)
checksum = CChecksum::GenerateChecksumFromBuffer(buffer, bufferSize);
else
checksum = CChecksum::GenerateChecksumFromFile(strInFilename);
if (checksum != pResourceFile->GetServerChecksum())
@@ -51,7 +51,7 @@ class CResourceManager
void OnDownloadedResourceFile(const SString& strFilename);
bool IsResourceFile(const SString& strFilename);
void OnFileModifedByScript(const SString& strFilename, const SString& strReason);
void ValidateResourceFile(const SString& strFilename, const CBuffer& fileData);
void ValidateResourceFile(const SString& strFilename, const char* buffer, size_t bufferSize);
CDownloadableResource* GetDownloadableResourceFile(const SString& strFilename) { return MapFindRef(m_ResourceFileMap, strFilename); }

static bool ParseResourcePathInput(std::string strInput, CResource*& pResource, std::string* pStrPath, std::string* pStrMetaPath = nullptr);
@@ -207,7 +207,7 @@ void CScriptFile::DoResourceFileCheck()
m_pFile->FSeek(lCurrentPos, SEEK_SET);

// Check file content
g_pClientGame->GetResourceManager()->ValidateResourceFile(m_strFilename, buffer);
g_pClientGame->GetResourceManager()->ValidateResourceFile(m_strFilename, buffer.GetData(), buffer.GetSize());
}
}

@@ -127,10 +127,10 @@ void CLuaEngineDefs::AddEngineDffClass(lua_State* luaVM)

int CLuaEngineDefs::EngineLoadCOL(lua_State* luaVM)
{
SString strFile = "";
SString input;
CScriptArgReader argStream(luaVM);
// Grab the COL filename or data
argStream.ReadString(strFile);
argStream.ReadString(input);

if (!argStream.HasErrors())
{
@@ -142,10 +142,21 @@ int CLuaEngineDefs::EngineLoadCOL(lua_State* luaVM)
CResource* pResource = pLuaMain->GetResource();
if (pResource)
{
bool bIsRawData = CClientColModel::IsCOLData(strFile);
SString strPath;
bool bIsRawData = CClientColModel::IsCOLData(input);

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

SString filePath;

// Is this a legal filepath?
if (bIsRawData || CResourceManager::ParseResourcePathInput(strFile, pResource, &strPath))
if (bIsRawData || CResourceManager::ParseResourcePathInput(input, pResource, &filePath))
{
// Grab the resource root entity
CClientEntity* pRoot = pResource->GetResourceCOLModelRoot();
@@ -154,7 +165,7 @@ int CLuaEngineDefs::EngineLoadCOL(lua_State* luaVM)
CClientColModel* pCol = new CClientColModel(m_pManager, INVALID_ELEMENT_ID);

// Attempt loading the file
if (pCol->LoadCol(bIsRawData ? strFile : strPath, bIsRawData))
if (pCol->Load(bIsRawData, bIsRawData ? std::move(input) : std::move(filePath)))
{
// Success. Make it a child of the resource collision root
pCol->SetParent(pRoot);
@@ -167,18 +178,22 @@ int CLuaEngineDefs::EngineLoadCOL(lua_State* luaVM)
{
// Delete it again. We failed
delete pCol;
argStream.SetCustomError(bIsRawData ? "raw data" : strFile, "Error loading COL");
argStream.SetCustomError(bIsRawData ? "raw data" : input, "Error loading COL");
}
}
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 for some reason
lua_pushboolean(luaVM, false);
return 1;
}
@@ -71,7 +71,7 @@ class CRenderWare
virtual bool HasClothesReplacementChanged() = 0;
virtual RwTexDictionary* ReadTXD(const SString& strFilename, const SString& buffer) = 0;
virtual RpClump* ReadDFF(const SString& strFilename, const SString& buffer, unsigned short usModelID, bool bLoadEmbeddedCollisions) = 0;
virtual CColModel* ReadCOL(const CBuffer& fileData) = 0;
virtual CColModel* ReadCOL(const SString& buffer) = 0;
virtual void DestroyDFF(RpClump* pClump) = 0;
virtual void DestroyTXD(RwTexDictionary* pTXD) = 0;
virtual void DestroyTexture(RwTexture* pTex) = 0;

0 comments on commit f10151e

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