Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Adds replacement CJ clothing models #3967

Open
wants to merge 17 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
50 changes: 50 additions & 0 deletions Client/game_sa/CDirectorySA.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
/*****************************************************************************
*
* PROJECT: Multi Theft Auto
* LICENSE: See LICENSE in the top level directory
* FILE: game_sa/CDirectorySA.cpp
*
* Multi Theft Auto is available from https://www.multitheftauto.com/
*
*****************************************************************************/

#include "StdInc.h"
W3lac3 marked this conversation as resolved.
Show resolved Hide resolved
#include "CDirectorySA.h"

DirectoryInfoSA* CDirectorySAInterface::GetModelEntry(std::uint16_t modelId)
{
if (m_nNumEntries <= 0)
return nullptr;

DirectoryInfoSA* entry = m_pEntries + modelId;

if (!entry)
return nullptr;

return entry;
}

bool CDirectorySAInterface::SetModelStreamingSize(std::uint16_t modelId, std::uint16_t size)
{
DirectoryInfoSA* entry = GetModelEntry(modelId);

if (!entry)
return false;

if (entry->m_nStreamingSize == size)
return false;

entry->m_nStreamingSize = size;
return true;
}


std::uint16_t CDirectorySAInterface::GetModelStreamingSize(std::uint16_t modelId)
{
DirectoryInfoSA* entry = GetModelEntry(modelId);

if (!entry)
return false;

return entry->m_nStreamingSize;
}
33 changes: 33 additions & 0 deletions Client/game_sa/CDirectorySA.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
/*****************************************************************************
*
* PROJECT: Multi Theft Auto
* LICENSE: See LICENSE in the top level directory
* FILE: game_sa/CDirectorySA.h
*
* Multi Theft Auto is available from https://www.multitheftauto.com/
*
*****************************************************************************/

#pragma once

struct DirectoryInfoSA
{
std::uint32_t m_nOffset;
std::uint16_t m_nStreamingSize;
std::uint16_t m_nSizeInArchive;
char m_szName[24];
};

class CDirectorySAInterface
{
public:
DirectoryInfoSA* GetModelEntry(std::uint16_t modelId);
bool SetModelStreamingSize(std::uint16_t modelId, std::uint16_t size);
std::uint16_t GetModelStreamingSize(std::uint16_t modelId);

private:
DirectoryInfoSA* m_pEntries{};
std::uint32_t m_nCapacity{};
std::uint32_t m_nNumEntries{};
bool m_bOwnsEntries{};
};
45 changes: 34 additions & 11 deletions Client/game_sa/CRenderWareSA.ClothesReplacing.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@

#include "StdInc.h"
#include "CGameSA.h"
#include "CDirectorySA.h"
#include "gamesa_renderware.h"

extern CGameSA* pGame;
Expand All @@ -28,8 +29,10 @@ namespace
uint uiLoadflag; // 0-not loaded 2-requested 3-loaded 1-processed
};

std::map<ushort, char*> ms_ReplacementClothesFileDataMap;
bool bClothesReplacementChanged = false;
std::unordered_map<ushort, char*> ms_ReplacementClothesFileDataMap;
std::unordered_map<ushort, std::uint16_t> ms_OriginalStreamingSizesMap;

bool bClothesReplacementChanged = false;

struct SPlayerImgItem
{
Expand All @@ -46,44 +49,64 @@ namespace
};

DWORD FUNC_CStreamingConvertBufferToObject = 0x40C6B0;
auto g_clothesDirectory = reinterpret_cast<CDirectorySAInterface*>(0xBC12C0);
int iReturnFileId;
char* pReturnBuffer;

size_t GetSizeInBlocks(size_t size)
{
auto blockDiv = std::div(size, 2048);
return (blockDiv.quot + (blockDiv.rem ? 1 : 0));
}
} // 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, size_t fileSize, ushort usFileId)
{
if (!pFileData)
return;

if (pFileData != MapFindRef(ms_ReplacementClothesFileDataMap, usFileId))
{
MapSet(ms_ReplacementClothesFileDataMap, usFileId, pFileData);
MapSet(ms_OriginalStreamingSizesMap, usFileId, g_clothesDirectory->GetModelStreamingSize(usFileId));
g_clothesDirectory->SetModelStreamingSize(usFileId, GetSizeInBlocks(fileSize));

bClothesReplacementChanged = true;
}
}

////////////////////////////////////////////////////////////////
//
// 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;
for (std::map<ushort, char*>::iterator iter = ms_ReplacementClothesFileDataMap.begin(); iter != ms_ReplacementClothesFileDataMap.end();)

for (auto iter = ms_ReplacementClothesFileDataMap.begin(); iter != ms_ReplacementClothesFileDataMap.end();)
{
if (iter->second == pFileData)
{
ms_ReplacementClothesFileDataMap.erase(iter++);
auto it = ms_OriginalStreamingSizesMap.find(iter->first);

if (it != ms_OriginalStreamingSizesMap.end())
{
std::uint16_t originalStreamingSize = it->second;
g_clothesDirectory->SetModelStreamingSize(iter->first, originalStreamingSize);
}

iter = ms_ReplacementClothesFileDataMap.erase(iter);
bClothesReplacementChanged = true;
}
else
Expand All @@ -110,7 +133,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)
Expand Down
4 changes: 2 additions & 2 deletions Client/game_sa/CRenderWareSA.h
Original file line number Diff line number Diff line change
Expand Up @@ -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, size_t fileSize, ushort usFileId);
void ClothesRemoveReplacement(char* pFileData);
bool HasClothesReplacementChanged();

// Reads and parses a TXD file specified by a path (szTXD)
Expand Down
25 changes: 25 additions & 0 deletions Client/mods/deathmatch/logic/CClientDFF.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -139,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);

Expand Down Expand Up @@ -268,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;

Expand Down Expand Up @@ -296,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(), m_RawDataBuffer.size(), 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.
Expand Down
1 change: 1 addition & 0 deletions Client/mods/deathmatch/logic/CClientDFF.h
Original file line number Diff line number Diff line change
Expand Up @@ -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);
Expand Down
3 changes: 2 additions & 1 deletion Client/mods/deathmatch/logic/CClientDFFManager.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand Down
5 changes: 5 additions & 0 deletions Client/mods/deathmatch/logic/CClientPlayerClothes.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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;
}
2 changes: 1 addition & 1 deletion Client/mods/deathmatch/logic/CClientPlayerClothes.h
Original file line number Diff line number Diff line change
Expand Up @@ -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);

Expand Down
6 changes: 3 additions & 3 deletions Client/mods/deathmatch/logic/CClientTXD.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand Down Expand Up @@ -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(), m_FileData.size(), usModelID - CLOTHES_MODEL_ID_FIRST);
return true;
}
else
Expand Down
4 changes: 2 additions & 2 deletions Client/sdk/game/CRenderWare.h
Original file line number Diff line number Diff line change
Expand Up @@ -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, 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;
virtual RpClump* ReadDFF(const SString& strFilename, const SString& buffer, unsigned short usModelID, bool bLoadEmbeddedCollisions) = 0;
Expand Down
Loading