From 93606b51ab683b74f06514b7503ab4353920cc55 Mon Sep 17 00:00:00 2001 From: Walace Date: Sat, 18 Jan 2025 18:29:19 -0300 Subject: [PATCH 1/7] Adds replacement CJ clothing models --- .../game_sa/CRenderWareSA.ClothesReplacing.cpp | 14 +++++++------- Client/game_sa/CRenderWareSA.h | 4 ++-- Client/mods/deathmatch/logic/CClientDFF.cpp | 16 ++++++++++++++++ Client/mods/deathmatch/logic/CClientTXD.cpp | 6 +++--- Client/sdk/game/CRenderWare.h | 4 ++-- 5 files changed, 30 insertions(+), 14 deletions(-) diff --git a/Client/game_sa/CRenderWareSA.ClothesReplacing.cpp b/Client/game_sa/CRenderWareSA.ClothesReplacing.cpp index dc51a90777..dbaef2371f 100644 --- a/Client/game_sa/CRenderWareSA.ClothesReplacing.cpp +++ b/Client/game_sa/CRenderWareSA.ClothesReplacing.cpp @@ -52,12 +52,12 @@ namespace //////////////////////////////////////////////////////////////// // -// CRenderWareSA::ClothesAddReplacementTxd +// CRenderWareSA::ClothesAddReplacement // -// Add replacement txd for a clothing component +// Add replacement txd/dff for a clothing component // //////////////////////////////////////////////////////////////// -void CRenderWareSA::ClothesAddReplacementTxd(char* pFileData, ushort usFileId) +void CRenderWareSA::ClothesAddReplacement(char* pFileData, ushort usFileId) { if (!pFileData) return; @@ -70,12 +70,12 @@ void CRenderWareSA::ClothesAddReplacementTxd(char* pFileData, ushort usFileId) //////////////////////////////////////////////////////////////// // -// CRenderWareSA::ClothesRemoveReplacementTxd +// CRenderWareSA::ClothesRemoveReplacement // -// Remove replacement txd for a clothing component +// Remove replacement txd/dff for a clothing component // //////////////////////////////////////////////////////////////// -void CRenderWareSA::ClothesRemoveReplacementTxd(char* pFileData) +void CRenderWareSA::ClothesRemoveReplacement(char* pFileData) { if (!pFileData) return; @@ -110,7 +110,7 @@ bool CRenderWareSA::HasClothesReplacementChanged() // CStreaming_RequestModel_Mid // // If request is for a file inside player.img (imgId 5) -// then maybe switch to replacement txd file data +// then maybe switch to replacement txd/dff file data // //////////////////////////////////////////////////////////////// __declspec(noinline) bool _cdecl OnCStreaming_RequestModel_Mid(int flags, SImgGTAItemInfo* pImgGTAInfo) diff --git a/Client/game_sa/CRenderWareSA.h b/Client/game_sa/CRenderWareSA.h index 6a0e64ea50..e7d15ba87b 100644 --- a/Client/game_sa/CRenderWareSA.h +++ b/Client/game_sa/CRenderWareSA.h @@ -32,8 +32,8 @@ class CRenderWareSA : public CRenderWare bool ModelInfoTXDLoadTextures(SReplacementTextures* pReplacementTextures, const SString& strFilename, const SString& buffer, bool bFilteringEnabled); bool ModelInfoTXDAddTextures(SReplacementTextures* pReplacementTextures, ushort usModelId); void ModelInfoTXDRemoveTextures(SReplacementTextures* pReplacementTextures); - void ClothesAddReplacementTxd(char* pFileData, ushort usFileId); - void ClothesRemoveReplacementTxd(char* pFileData); + void ClothesAddReplacement(char* pFileData, ushort usFileId); + void ClothesRemoveReplacement(char* pFileData); bool HasClothesReplacementChanged(); // Reads and parses a TXD file specified by a path (szTXD) diff --git a/Client/mods/deathmatch/logic/CClientDFF.cpp b/Client/mods/deathmatch/logic/CClientDFF.cpp index 7eb2a40a70..48e657c4ff 100644 --- a/Client/mods/deathmatch/logic/CClientDFF.cpp +++ b/Client/mods/deathmatch/logic/CClientDFF.cpp @@ -101,6 +101,21 @@ void CClientDFF::UnloadDFF() bool CClientDFF::ReplaceModel(unsigned short usModel, bool bAlphaTransparency) { + if (usModel >= CLOTHES_MODEL_ID_FIRST && usModel <= CLOTHES_MODEL_ID_LAST) + { + if (m_RawDataBuffer.empty() && m_bIsRawData) + return false; + + if (m_RawDataBuffer.empty()) + { + if (!FileLoad(std::nothrow, m_strDffFilename, m_RawDataBuffer)) + return false; + } + + g_pGame->GetRenderWare()->ClothesAddReplacement(m_RawDataBuffer.data(), usModel - CLOTHES_MODEL_ID_FIRST); + return true; + } + // Record attempt in case it all goes wrong CArgMap argMap; argMap.Set("id", usModel); @@ -231,6 +246,7 @@ void CClientDFF::RestoreModels() // Clear the list m_Replaced.clear(); + g_pGame->GetRenderWare()->ClothesRemoveReplacement(m_RawDataBuffer.data()); } void CClientDFF::InternalRestoreModel(unsigned short usModel) diff --git a/Client/mods/deathmatch/logic/CClientTXD.cpp b/Client/mods/deathmatch/logic/CClientTXD.cpp index 761784e056..c9061a5b5b 100644 --- a/Client/mods/deathmatch/logic/CClientTXD.cpp +++ b/Client/mods/deathmatch/logic/CClientTXD.cpp @@ -29,7 +29,7 @@ CClientTXD::~CClientTXD() } // Remove us from all the clothes replacement doo dah - g_pGame->GetRenderWare()->ClothesRemoveReplacementTxd(m_FileData.data()); + g_pGame->GetRenderWare()->ClothesRemoveReplacement(m_FileData.data()); } bool CClientTXD::Load(bool isRaw, SString input, bool enableFiltering) @@ -75,8 +75,8 @@ bool CClientTXD::Import(unsigned short usModelID) return false; } m_bUsingFileDataForClothes = true; - // Note: ClothesAddReplacementTxd uses the pointer from m_FileData, so don't touch m_FileData until matching ClothesRemove call - g_pGame->GetRenderWare()->ClothesAddReplacementTxd(m_FileData.data(), usModelID - CLOTHES_MODEL_ID_FIRST); + // Note: ClothesAddReplacement uses the pointer from m_FileData, so don't touch m_FileData until matching ClothesRemove call + g_pGame->GetRenderWare()->ClothesAddReplacement(m_FileData.data(), usModelID - CLOTHES_MODEL_ID_FIRST); return true; } else diff --git a/Client/sdk/game/CRenderWare.h b/Client/sdk/game/CRenderWare.h index bef9d8f79e..f1d7498cc1 100644 --- a/Client/sdk/game/CRenderWare.h +++ b/Client/sdk/game/CRenderWare.h @@ -76,8 +76,8 @@ class CRenderWare bool bFilteringEnabled) = 0; virtual bool ModelInfoTXDAddTextures(SReplacementTextures* pReplacementTextures, ushort usModelId) = 0; virtual void ModelInfoTXDRemoveTextures(SReplacementTextures* pReplacementTextures) = 0; - virtual void ClothesAddReplacementTxd(char* pFileData, ushort usFileId) = 0; - virtual void ClothesRemoveReplacementTxd(char* pFileData) = 0; + virtual void ClothesAddReplacement(char* pFileData, ushort usFileId) = 0; + virtual void ClothesRemoveReplacement(char* pFileData) = 0; 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; From 0b8106c2651f73513373bf4dc2254e5b9a261bde Mon Sep 17 00:00:00 2001 From: Walace Date: Sat, 25 Jan 2025 10:30:17 -0300 Subject: [PATCH 2/7] Update due to code revision --- Client/mods/deathmatch/logic/CClientDFF.cpp | 41 +++++++++++-------- Client/mods/deathmatch/logic/CClientDFF.h | 1 + .../deathmatch/logic/CClientDFFManager.cpp | 3 +- .../deathmatch/logic/CClientPlayerClothes.cpp | 5 +++ .../deathmatch/logic/CClientPlayerClothes.h | 2 +- 5 files changed, 34 insertions(+), 18 deletions(-) diff --git a/Client/mods/deathmatch/logic/CClientDFF.cpp b/Client/mods/deathmatch/logic/CClientDFF.cpp index 48e657c4ff..1f06b67756 100644 --- a/Client/mods/deathmatch/logic/CClientDFF.cpp +++ b/Client/mods/deathmatch/logic/CClientDFF.cpp @@ -101,21 +101,6 @@ void CClientDFF::UnloadDFF() bool CClientDFF::ReplaceModel(unsigned short usModel, bool bAlphaTransparency) { - if (usModel >= CLOTHES_MODEL_ID_FIRST && usModel <= CLOTHES_MODEL_ID_LAST) - { - if (m_RawDataBuffer.empty() && m_bIsRawData) - return false; - - if (m_RawDataBuffer.empty()) - { - if (!FileLoad(std::nothrow, m_strDffFilename, m_RawDataBuffer)) - return false; - } - - g_pGame->GetRenderWare()->ClothesAddReplacement(m_RawDataBuffer.data(), usModel - CLOTHES_MODEL_ID_FIRST); - return true; - } - // Record attempt in case it all goes wrong CArgMap argMap; argMap.Set("id", usModel); @@ -154,6 +139,9 @@ bool CClientDFF::DoReplaceModel(unsigned short usModel, bool bAlphaTransparency) if (!CClientDFFManager::IsReplacableModel(usModel)) return false; + if (CClientPlayerClothes::IsValidModel(usModel)) + return ReplaceClothes(usModel); + // Get clump loaded for this model id RpClump* pClump = GetLoadedClump(usModel); @@ -246,7 +234,6 @@ void CClientDFF::RestoreModels() // Clear the list m_Replaced.clear(); - g_pGame->GetRenderWare()->ClothesRemoveReplacement(m_RawDataBuffer.data()); } void CClientDFF::InternalRestoreModel(unsigned short usModel) @@ -284,6 +271,12 @@ void CClientDFF::InternalRestoreModel(unsigned short usModel) m_pManager->GetObjectManager()->RestreamObjects(usModel); g_pGame->GetModelInfo(usModel)->RestreamIPL(); } + // Is This a clothe ID? + else if (CClientPlayerClothes::IsValidModel(usModel)) + { + g_pGame->GetRenderWare()->ClothesRemoveReplacement(m_RawDataBuffer.data()); + return; + } else return; @@ -312,6 +305,22 @@ void CClientDFF::InternalRestoreModel(unsigned short usModel) } } +bool CClientDFF::ReplaceClothes(ushort usModel) +{ + if (m_RawDataBuffer.empty() && m_bIsRawData) + return false; + + if (m_RawDataBuffer.empty()) + { + if (!FileLoad(std::nothrow, m_strDffFilename, m_RawDataBuffer)) + return false; + } + + m_Replaced.push_back(usModel); + g_pGame->GetRenderWare()->ClothesAddReplacement(m_RawDataBuffer.data(), usModel - CLOTHES_MODEL_ID_FIRST); + return true; +} + bool CClientDFF::ReplaceObjectModel(RpClump* pClump, ushort usModel, bool bAlphaTransparency) { // Stream out all the object models with matching ID. diff --git a/Client/mods/deathmatch/logic/CClientDFF.h b/Client/mods/deathmatch/logic/CClientDFF.h index 3b6392c561..0a4db23894 100644 --- a/Client/mods/deathmatch/logic/CClientDFF.h +++ b/Client/mods/deathmatch/logic/CClientDFF.h @@ -59,6 +59,7 @@ class CClientDFF final : public CClientEntity void UnloadDFF(); void InternalRestoreModel(unsigned short usModel); + bool ReplaceClothes(ushort usModel); bool ReplaceObjectModel(RpClump* pClump, ushort usModel, bool bAlphaTransparency); bool ReplaceVehicleModel(RpClump* pClump, ushort usModel, bool bAlphaTransparency); bool ReplaceWeaponModel(RpClump* pClump, ushort usModel, bool bAlphaTransparency); diff --git a/Client/mods/deathmatch/logic/CClientDFFManager.cpp b/Client/mods/deathmatch/logic/CClientDFFManager.cpp index ab93a65ff2..f466dd8407 100644 --- a/Client/mods/deathmatch/logic/CClientDFFManager.cpp +++ b/Client/mods/deathmatch/logic/CClientDFFManager.cpp @@ -79,7 +79,8 @@ CClientDFF* CClientDFFManager::GetElementThatReplaced(unsigned short usModel, CC bool CClientDFFManager::IsReplacableModel(unsigned short usModel) { // Either a vehicle model or an object model - return CClientObjectManager::IsValidModel(usModel) || CClientVehicleManager::IsValidModel(usModel) || CClientPlayerManager::IsValidModel(usModel); + return CClientObjectManager::IsValidModel(usModel) || CClientVehicleManager::IsValidModel(usModel) || CClientPlayerManager::IsValidModel(usModel) || + CClientPlayerClothes::IsValidModel(usModel); } bool CClientDFFManager::RestoreModel(unsigned short usModel) diff --git a/Client/mods/deathmatch/logic/CClientPlayerClothes.cpp b/Client/mods/deathmatch/logic/CClientPlayerClothes.cpp index 50af2ea544..7a3ed663a4 100644 --- a/Client/mods/deathmatch/logic/CClientPlayerClothes.cpp +++ b/Client/mods/deathmatch/logic/CClientPlayerClothes.cpp @@ -577,3 +577,8 @@ const int CClientPlayerClothes::GetClothingGroupMax(unsigned char ucType) return 0; } + +bool CClientPlayerClothes::IsValidModel(unsigned short usModel) +{ + return usModel >= CLOTHES_MODEL_ID_FIRST && usModel <= CLOTHES_MODEL_ID_LAST; +} diff --git a/Client/mods/deathmatch/logic/CClientPlayerClothes.h b/Client/mods/deathmatch/logic/CClientPlayerClothes.h index 420856377d..eeb3e25f8f 100644 --- a/Client/mods/deathmatch/logic/CClientPlayerClothes.h +++ b/Client/mods/deathmatch/logic/CClientPlayerClothes.h @@ -67,7 +67,7 @@ class CClientPlayerClothes static const SPlayerClothing* GetClothingGroup(unsigned char ucType); static const int GetClothingGroupMax(unsigned char ucType); - + static bool IsValidModel(unsigned short usModel); private: static const SPlayerClothing* GetClothing(const char* szTexture, const char* szModel, unsigned char ucType); From 363363d58c12f6d4050f10517f37a833618087b1 Mon Sep 17 00:00:00 2001 From: Walace Date: Sat, 25 Jan 2025 10:33:30 -0300 Subject: [PATCH 3/7] Fixes clothing size crash --- .../CRenderWareSA.ClothesReplacing.cpp | 90 +++++++++++++++++-- Client/game_sa/CRenderWareSA.h | 2 +- Client/mods/deathmatch/logic/CClientDFF.cpp | 2 +- Client/mods/deathmatch/logic/CClientTXD.cpp | 2 +- Client/sdk/game/CRenderWare.h | 2 +- 5 files changed, 88 insertions(+), 10 deletions(-) diff --git a/Client/game_sa/CRenderWareSA.ClothesReplacing.cpp b/Client/game_sa/CRenderWareSA.ClothesReplacing.cpp index dbaef2371f..e3e61900e2 100644 --- a/Client/game_sa/CRenderWareSA.ClothesReplacing.cpp +++ b/Client/game_sa/CRenderWareSA.ClothesReplacing.cpp @@ -28,8 +28,10 @@ namespace uint uiLoadflag; // 0-not loaded 2-requested 3-loaded 1-processed }; - std::map ms_ReplacementClothesFileDataMap; - bool bClothesReplacementChanged = false; + std::map ms_ReplacementClothesFileDataMap; + std::map ms_OriginalStreamingSizesMap; + + bool bClothesReplacementChanged = false; struct SPlayerImgItem { @@ -45,9 +47,68 @@ namespace uint uiArraySize; }; - DWORD FUNC_CStreamingConvertBufferToObject = 0x40C6B0; - int iReturnFileId; - char* pReturnBuffer; + struct DirectoryInfo + { + uint32 m_nOffset; + uint16 m_nStreamingSize; + uint16 m_nSizeInArchive; + char m_szName[24]; + }; + + struct CDirectorySA + { + DirectoryInfo* m_pEntries{}; + uint32 m_nCapacity{}; + uint32 m_nNumEntries{}; + bool m_bOwnsEntries{}; + }; + + DWORD FUNC_CStreamingConvertBufferToObject = 0x40C6B0; + constexpr uintptr_t CLOTHES_DIRECTORY_ADDRESS = 0x5A419B; + int iReturnFileId; + char* pReturnBuffer; + + CDirectorySA* GetClothesDirectory() + { + CDirectorySA* directory = *reinterpret_cast(CLOTHES_DIRECTORY_ADDRESS); + + if (!directory) + return nullptr; + + return directory; + } + + DirectoryInfo* GetClothesEntry(ushort usFileId) + { + SPlayerImgItemArray* pItemArray = (SPlayerImgItemArray*)0x00BC12C0; + SPlayerImgItem* pImgItem = &pItemArray->pItems[usFileId]; + + if (!pImgItem) + return nullptr; + + CDirectorySA* directory = GetClothesDirectory(); + + if (!directory) + return nullptr; + + DirectoryInfo* entry = ((DirectoryInfo * (__thiscall*)(CDirectorySA*, const char*))0x532450)(directory, pImgItem->szName); + + if (!entry) + return nullptr; + + return entry; + } + + uint32_t GetSizeInBlocks(uint32_t size) + { + auto div = std::div(size, 2048); + return (div.quot + (div.rem ? 1 : 0)); + } + + uint32_t GetSizeInBlocks(uint64_t size) + { + return GetSizeInBlocks((uint32_t)size); + } } // namespace //////////////////////////////////////////////////////////////// @@ -57,13 +118,23 @@ namespace // Add replacement txd/dff for a clothing component // //////////////////////////////////////////////////////////////// -void CRenderWareSA::ClothesAddReplacement(char* pFileData, ushort usFileId) +void CRenderWareSA::ClothesAddReplacement(char* pFileData, size_t fileSize, ushort usFileId) { if (!pFileData) return; + if (pFileData != MapFindRef(ms_ReplacementClothesFileDataMap, usFileId)) { + DirectoryInfo* entry = GetClothesEntry(usFileId); + + if (!entry) + return; + MapSet(ms_ReplacementClothesFileDataMap, usFileId, pFileData); + MapSet(ms_OriginalStreamingSizesMap, usFileId, entry->m_nStreamingSize); + + entry->m_nStreamingSize = GetSizeInBlocks(fileSize); + bClothesReplacementChanged = true; } } @@ -79,10 +150,17 @@ void CRenderWareSA::ClothesRemoveReplacement(char* pFileData) { if (!pFileData) return; + for (std::map::iterator iter = ms_ReplacementClothesFileDataMap.begin(); iter != ms_ReplacementClothesFileDataMap.end();) { if (iter->second == pFileData) { + DirectoryInfo* entry = GetClothesEntry(iter->first); + uint16 originalStreamingSize = MapFindRef(ms_OriginalStreamingSizesMap, iter->first); + + if (entry && originalStreamingSize) + entry->m_nStreamingSize = originalStreamingSize; + ms_ReplacementClothesFileDataMap.erase(iter++); bClothesReplacementChanged = true; } diff --git a/Client/game_sa/CRenderWareSA.h b/Client/game_sa/CRenderWareSA.h index e7d15ba87b..d79d930720 100644 --- a/Client/game_sa/CRenderWareSA.h +++ b/Client/game_sa/CRenderWareSA.h @@ -32,7 +32,7 @@ class CRenderWareSA : public CRenderWare bool ModelInfoTXDLoadTextures(SReplacementTextures* pReplacementTextures, const SString& strFilename, const SString& buffer, bool bFilteringEnabled); bool ModelInfoTXDAddTextures(SReplacementTextures* pReplacementTextures, ushort usModelId); void ModelInfoTXDRemoveTextures(SReplacementTextures* pReplacementTextures); - void ClothesAddReplacement(char* pFileData, ushort usFileId); + void ClothesAddReplacement(char* pFileData, size_t fileSize, ushort usFileId); void ClothesRemoveReplacement(char* pFileData); bool HasClothesReplacementChanged(); diff --git a/Client/mods/deathmatch/logic/CClientDFF.cpp b/Client/mods/deathmatch/logic/CClientDFF.cpp index 1f06b67756..07e718a8b9 100644 --- a/Client/mods/deathmatch/logic/CClientDFF.cpp +++ b/Client/mods/deathmatch/logic/CClientDFF.cpp @@ -317,7 +317,7 @@ bool CClientDFF::ReplaceClothes(ushort usModel) } m_Replaced.push_back(usModel); - g_pGame->GetRenderWare()->ClothesAddReplacement(m_RawDataBuffer.data(), usModel - CLOTHES_MODEL_ID_FIRST); + g_pGame->GetRenderWare()->ClothesAddReplacement(m_RawDataBuffer.data(), m_RawDataBuffer.size(), usModel - CLOTHES_MODEL_ID_FIRST); return true; } diff --git a/Client/mods/deathmatch/logic/CClientTXD.cpp b/Client/mods/deathmatch/logic/CClientTXD.cpp index c9061a5b5b..8a37f87157 100644 --- a/Client/mods/deathmatch/logic/CClientTXD.cpp +++ b/Client/mods/deathmatch/logic/CClientTXD.cpp @@ -76,7 +76,7 @@ bool CClientTXD::Import(unsigned short usModelID) } m_bUsingFileDataForClothes = true; // Note: ClothesAddReplacement uses the pointer from m_FileData, so don't touch m_FileData until matching ClothesRemove call - g_pGame->GetRenderWare()->ClothesAddReplacement(m_FileData.data(), usModelID - CLOTHES_MODEL_ID_FIRST); + g_pGame->GetRenderWare()->ClothesAddReplacement(m_FileData.data(), m_FileData.size(), usModelID - CLOTHES_MODEL_ID_FIRST); return true; } else diff --git a/Client/sdk/game/CRenderWare.h b/Client/sdk/game/CRenderWare.h index f1d7498cc1..92686978b1 100644 --- a/Client/sdk/game/CRenderWare.h +++ b/Client/sdk/game/CRenderWare.h @@ -76,7 +76,7 @@ class CRenderWare bool bFilteringEnabled) = 0; virtual bool ModelInfoTXDAddTextures(SReplacementTextures* pReplacementTextures, ushort usModelId) = 0; virtual void ModelInfoTXDRemoveTextures(SReplacementTextures* pReplacementTextures) = 0; - virtual void ClothesAddReplacement(char* pFileData, ushort usFileId) = 0; + virtual void ClothesAddReplacement(char* pFileData, size_t fileSize, ushort usFileId) = 0; virtual void ClothesRemoveReplacement(char* pFileData) = 0; virtual bool HasClothesReplacementChanged() = 0; virtual RwTexDictionary* ReadTXD(const SString& strFilename, const SString& buffer) = 0; From 3b6b736043f4040457f1a6c034d6cff107239996 Mon Sep 17 00:00:00 2001 From: Walace Date: Sun, 26 Jan 2025 10:38:44 -0300 Subject: [PATCH 4/7] Create CDirectorySA Class --- Client/game_sa/CDirectorySA.cpp | 40 +++++++++++++++++++++++++++++++++ Client/game_sa/CDirectorySA.h | 23 +++++++++++++++++++ 2 files changed, 63 insertions(+) create mode 100644 Client/game_sa/CDirectorySA.cpp create mode 100644 Client/game_sa/CDirectorySA.h diff --git a/Client/game_sa/CDirectorySA.cpp b/Client/game_sa/CDirectorySA.cpp new file mode 100644 index 0000000000..ade0e6cdeb --- /dev/null +++ b/Client/game_sa/CDirectorySA.cpp @@ -0,0 +1,40 @@ +#include "StdInc.h" +#include "CDirectorySA.h" + +DirectoryInfo* CDirectorySA::GetModelEntry(ushort modelId) +{ + if (m_nNumEntries <= 0) + return nullptr; + + DirectoryInfo* entry = m_pEntries + modelId; + + if (!entry) + return nullptr; + + return entry; +} + +bool CDirectorySA::SetModelStreamingSize(ushort modelId, uint16 size) +{ + DirectoryInfo* entry = GetModelEntry(modelId); + + if (!entry) + return false; + + if (entry->m_nStreamingSize == size) + return false; + + entry->m_nStreamingSize = size; + return true; +} + + +uint16 CDirectorySA::GetModelStreamingSize(ushort modelId) +{ + DirectoryInfo* entry = GetModelEntry(modelId); + + if (!entry) + return false; + + return entry->m_nStreamingSize; +} diff --git a/Client/game_sa/CDirectorySA.h b/Client/game_sa/CDirectorySA.h new file mode 100644 index 0000000000..487ce5f5b6 --- /dev/null +++ b/Client/game_sa/CDirectorySA.h @@ -0,0 +1,23 @@ +#include + +struct DirectoryInfo +{ + uint32 m_nOffset; + uint16 m_nStreamingSize; + uint16 m_nSizeInArchive; + char m_szName[24]; +}; + +class CDirectorySA +{ + public: + DirectoryInfo* GetModelEntry(ushort modelId); + bool SetModelStreamingSize(ushort modelId, uint16 size); + uint16 GetModelStreamingSize(ushort modelId); + + private: + DirectoryInfo* m_pEntries{}; + uint32 m_nCapacity{}; + uint32 m_nNumEntries{}; + bool m_bOwnsEntries{}; +}; From 5c5619fb724b27a7fd7a7b7827a0d51d3b328ea9 Mon Sep 17 00:00:00 2001 From: Walace Date: Sun, 26 Jan 2025 10:42:47 -0300 Subject: [PATCH 5/7] Replaces CDirectorySA structure for class in ClothesReplacing --- .../CRenderWareSA.ClothesReplacing.cpp | 66 ++----------------- 1 file changed, 7 insertions(+), 59 deletions(-) diff --git a/Client/game_sa/CRenderWareSA.ClothesReplacing.cpp b/Client/game_sa/CRenderWareSA.ClothesReplacing.cpp index e3e61900e2..fd0c80a259 100644 --- a/Client/game_sa/CRenderWareSA.ClothesReplacing.cpp +++ b/Client/game_sa/CRenderWareSA.ClothesReplacing.cpp @@ -8,6 +8,7 @@ #include "StdInc.h" #include "CGameSA.h" +#include "CDirectorySA.h" #include "gamesa_renderware.h" extern CGameSA* pGame; @@ -47,57 +48,11 @@ namespace uint uiArraySize; }; - struct DirectoryInfo - { - uint32 m_nOffset; - uint16 m_nStreamingSize; - uint16 m_nSizeInArchive; - char m_szName[24]; - }; - - struct CDirectorySA - { - DirectoryInfo* m_pEntries{}; - uint32 m_nCapacity{}; - uint32 m_nNumEntries{}; - bool m_bOwnsEntries{}; - }; - DWORD FUNC_CStreamingConvertBufferToObject = 0x40C6B0; - constexpr uintptr_t CLOTHES_DIRECTORY_ADDRESS = 0x5A419B; + CDirectorySA* CLOTHES_DIRECTORY = *reinterpret_cast(0x5A419B); int iReturnFileId; char* pReturnBuffer; - CDirectorySA* GetClothesDirectory() - { - CDirectorySA* directory = *reinterpret_cast(CLOTHES_DIRECTORY_ADDRESS); - - if (!directory) - return nullptr; - - return directory; - } - - DirectoryInfo* GetClothesEntry(ushort usFileId) - { - SPlayerImgItemArray* pItemArray = (SPlayerImgItemArray*)0x00BC12C0; - SPlayerImgItem* pImgItem = &pItemArray->pItems[usFileId]; - - if (!pImgItem) - return nullptr; - - CDirectorySA* directory = GetClothesDirectory(); - - if (!directory) - return nullptr; - - DirectoryInfo* entry = ((DirectoryInfo * (__thiscall*)(CDirectorySA*, const char*))0x532450)(directory, pImgItem->szName); - - if (!entry) - return nullptr; - - return entry; - } uint32_t GetSizeInBlocks(uint32_t size) { @@ -125,15 +80,9 @@ void CRenderWareSA::ClothesAddReplacement(char* pFileData, size_t fileSize, usho if (pFileData != MapFindRef(ms_ReplacementClothesFileDataMap, usFileId)) { - DirectoryInfo* entry = GetClothesEntry(usFileId); - - if (!entry) - return; - MapSet(ms_ReplacementClothesFileDataMap, usFileId, pFileData); - MapSet(ms_OriginalStreamingSizesMap, usFileId, entry->m_nStreamingSize); - - entry->m_nStreamingSize = GetSizeInBlocks(fileSize); + MapSet(ms_OriginalStreamingSizesMap, usFileId, CLOTHES_DIRECTORY->GetModelStreamingSize(usFileId)); + CLOTHES_DIRECTORY->SetModelStreamingSize(usFileId, GetSizeInBlocks(fileSize)); bClothesReplacementChanged = true; } @@ -155,11 +104,10 @@ void CRenderWareSA::ClothesRemoveReplacement(char* pFileData) { if (iter->second == pFileData) { - DirectoryInfo* entry = GetClothesEntry(iter->first); - uint16 originalStreamingSize = MapFindRef(ms_OriginalStreamingSizesMap, iter->first); + uint16 originalStreamingSize = MapFindRef(ms_OriginalStreamingSizesMap, iter->first); - if (entry && originalStreamingSize) - entry->m_nStreamingSize = originalStreamingSize; + if (originalStreamingSize) + CLOTHES_DIRECTORY->SetModelStreamingSize(iter->first, originalStreamingSize); ms_ReplacementClothesFileDataMap.erase(iter++); bClothesReplacementChanged = true; From 0f1ceebec9f17598555bf04e089407aeb967b8af Mon Sep 17 00:00:00 2001 From: Walace Date: Wed, 29 Jan 2025 18:07:32 -0300 Subject: [PATCH 6/7] Adds comments to the CDirectorySA.cpp and CDirectorySA.h files --- Client/game_sa/CDirectorySA.cpp | 8 ++++++++ Client/game_sa/CDirectorySA.h | 10 +++++++++- 2 files changed, 17 insertions(+), 1 deletion(-) diff --git a/Client/game_sa/CDirectorySA.cpp b/Client/game_sa/CDirectorySA.cpp index ade0e6cdeb..6074d13a46 100644 --- a/Client/game_sa/CDirectorySA.cpp +++ b/Client/game_sa/CDirectorySA.cpp @@ -1,3 +1,11 @@ +/***************************************************************************** + * + * PROJECT: Multi Theft Auto + * LICENSE: See LICENSE in the top level directory + * FILE: game_sa/CDirectorySA.cpp + * + *****************************************************************************/ + #include "StdInc.h" #include "CDirectorySA.h" diff --git a/Client/game_sa/CDirectorySA.h b/Client/game_sa/CDirectorySA.h index 487ce5f5b6..37e3dca7a5 100644 --- a/Client/game_sa/CDirectorySA.h +++ b/Client/game_sa/CDirectorySA.h @@ -1,4 +1,12 @@ -#include +/***************************************************************************** + * + * PROJECT: Multi Theft Auto + * LICENSE: See LICENSE in the top level directory + * FILE: game_sa/CDirectorySA.h + * + *****************************************************************************/ + +#pragma once struct DirectoryInfo { From fa148638801e90d58ce2ce4f1eb5dc673e50ac3c Mon Sep 17 00:00:00 2001 From: Walace Date: Wed, 5 Feb 2025 12:55:29 -0300 Subject: [PATCH 7/7] Update due to code revision --- Client/game_sa/CDirectorySA.cpp | 12 ++++---- Client/game_sa/CDirectorySA.h | 12 ++++---- .../CRenderWareSA.ClothesReplacing.cpp | 30 ++++++++----------- 3 files changed, 24 insertions(+), 30 deletions(-) diff --git a/Client/game_sa/CDirectorySA.cpp b/Client/game_sa/CDirectorySA.cpp index 6074d13a46..1bb6eb0337 100644 --- a/Client/game_sa/CDirectorySA.cpp +++ b/Client/game_sa/CDirectorySA.cpp @@ -9,12 +9,12 @@ #include "StdInc.h" #include "CDirectorySA.h" -DirectoryInfo* CDirectorySA::GetModelEntry(ushort modelId) +DirectoryInfoSA* CDirectorySAInterface::GetModelEntry(std::uint16_t modelId) { if (m_nNumEntries <= 0) return nullptr; - DirectoryInfo* entry = m_pEntries + modelId; + DirectoryInfoSA* entry = m_pEntries + modelId; if (!entry) return nullptr; @@ -22,9 +22,9 @@ DirectoryInfo* CDirectorySA::GetModelEntry(ushort modelId) return entry; } -bool CDirectorySA::SetModelStreamingSize(ushort modelId, uint16 size) +bool CDirectorySAInterface::SetModelStreamingSize(std::uint16_t modelId, uint16 size) { - DirectoryInfo* entry = GetModelEntry(modelId); + DirectoryInfoSA* entry = GetModelEntry(modelId); if (!entry) return false; @@ -37,9 +37,9 @@ bool CDirectorySA::SetModelStreamingSize(ushort modelId, uint16 size) } -uint16 CDirectorySA::GetModelStreamingSize(ushort modelId) +uint16 CDirectorySAInterface::GetModelStreamingSize(std::uint16_t modelId) { - DirectoryInfo* entry = GetModelEntry(modelId); + DirectoryInfoSA* entry = GetModelEntry(modelId); if (!entry) return false; diff --git a/Client/game_sa/CDirectorySA.h b/Client/game_sa/CDirectorySA.h index 37e3dca7a5..6dc81366a9 100644 --- a/Client/game_sa/CDirectorySA.h +++ b/Client/game_sa/CDirectorySA.h @@ -8,7 +8,7 @@ #pragma once -struct DirectoryInfo +struct DirectoryInfoSA { uint32 m_nOffset; uint16 m_nStreamingSize; @@ -16,15 +16,15 @@ struct DirectoryInfo char m_szName[24]; }; -class CDirectorySA +class CDirectorySAInterface { public: - DirectoryInfo* GetModelEntry(ushort modelId); - bool SetModelStreamingSize(ushort modelId, uint16 size); - uint16 GetModelStreamingSize(ushort modelId); + DirectoryInfoSA* GetModelEntry(std::uint16_t modelId); + bool SetModelStreamingSize(std::uint16_t modelId, uint16 size); + uint16 GetModelStreamingSize(std::uint16_t modelId); private: - DirectoryInfo* m_pEntries{}; + DirectoryInfoSA* m_pEntries{}; uint32 m_nCapacity{}; uint32 m_nNumEntries{}; bool m_bOwnsEntries{}; diff --git a/Client/game_sa/CRenderWareSA.ClothesReplacing.cpp b/Client/game_sa/CRenderWareSA.ClothesReplacing.cpp index fd0c80a259..5723b8dcd7 100644 --- a/Client/game_sa/CRenderWareSA.ClothesReplacing.cpp +++ b/Client/game_sa/CRenderWareSA.ClothesReplacing.cpp @@ -29,8 +29,8 @@ namespace uint uiLoadflag; // 0-not loaded 2-requested 3-loaded 1-processed }; - std::map ms_ReplacementClothesFileDataMap; - std::map ms_OriginalStreamingSizesMap; + std::unordered_map ms_ReplacementClothesFileDataMap; + std::unordered_map ms_OriginalStreamingSizesMap; bool bClothesReplacementChanged = false; @@ -48,22 +48,16 @@ namespace uint uiArraySize; }; - DWORD FUNC_CStreamingConvertBufferToObject = 0x40C6B0; - CDirectorySA* CLOTHES_DIRECTORY = *reinterpret_cast(0x5A419B); - int iReturnFileId; - char* pReturnBuffer; + DWORD FUNC_CStreamingConvertBufferToObject = 0x40C6B0; + CDirectorySAInterface* CLOTHES_DIRECTORY = *reinterpret_cast(0x5A419B); + int iReturnFileId; + char* pReturnBuffer; - - uint32_t GetSizeInBlocks(uint32_t size) + size_t GetSizeInBlocks(size_t size) { auto div = std::div(size, 2048); return (div.quot + (div.rem ? 1 : 0)); } - - uint32_t GetSizeInBlocks(uint64_t size) - { - return GetSizeInBlocks((uint32_t)size); - } } // namespace //////////////////////////////////////////////////////////////// @@ -100,16 +94,16 @@ void CRenderWareSA::ClothesRemoveReplacement(char* pFileData) if (!pFileData) return; - for (std::map::iterator iter = ms_ReplacementClothesFileDataMap.begin(); iter != ms_ReplacementClothesFileDataMap.end();) + for (auto iter = ms_ReplacementClothesFileDataMap.begin(); iter != ms_ReplacementClothesFileDataMap.end();) { if (iter->second == pFileData) { - uint16 originalStreamingSize = MapFindRef(ms_OriginalStreamingSizesMap, iter->first); + auto originalStreamingSizeIter = ms_OriginalStreamingSizesMap.find(iter->first); - if (originalStreamingSize) - CLOTHES_DIRECTORY->SetModelStreamingSize(iter->first, originalStreamingSize); + if (originalStreamingSizeIter != ms_OriginalStreamingSizesMap.end()) + CLOTHES_DIRECTORY->SetModelStreamingSize(iter->first, originalStreamingSizeIter->second); - ms_ReplacementClothesFileDataMap.erase(iter++); + ms_ReplacementClothesFileDataMap.erase(iter); bClothesReplacementChanged = true; } else