Skip to content

Commit fcef9e4

Browse files
committed
Adds functions for adding new CJ clothes
- engineAddClotheModel - engineAddClotheTXD - addClotheModel - removeClotheModel
1 parent c7d40e8 commit fcef9e4

19 files changed

+507
-50
lines changed

Client/game_sa/CDirectorySA.cpp

Lines changed: 65 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,71 @@
1111
#include "StdInc.h"
1212
#include "CDirectorySA.h"
1313

14+
bool CDirectorySAInterface::AddEntry(DirectoryInfoSA& entry)
15+
{
16+
if (m_nNumEntries >= m_nCapacity)
17+
return false;
18+
19+
if (GetModelEntry(entry.m_szName))
20+
return false;
21+
22+
entry.m_nOffset = 0;
23+
24+
if (m_nNumEntries > 0)
25+
{
26+
DirectoryInfoSA* lastEntry = m_pEntries + m_nNumEntries - 1;
27+
entry.m_nOffset = lastEntry->m_nOffset + lastEntry->m_nStreamingSize;
28+
29+
if (entry.m_nOffset % 2048)
30+
entry.m_nOffset += 2048 - (entry.m_nOffset % 2048);
31+
}
32+
33+
m_pEntries[m_nNumEntries] = entry;
34+
m_nNumEntries++;
35+
36+
return true;
37+
}
38+
39+
bool CDirectorySAInterface::RemoveEntry(const char* pFileName)
40+
{
41+
if (m_nNumEntries <= 0)
42+
return false;
43+
44+
DirectoryInfoSA* entry = GetModelEntry(pFileName);
45+
46+
if (!entry)
47+
return false;
48+
49+
std::uint32_t index = entry - m_pEntries;
50+
51+
if (index < m_nNumEntries - 1)
52+
{
53+
DirectoryInfoSA* lastEntry = m_pEntries + m_nNumEntries - 1;
54+
entry->m_nOffset = lastEntry->m_nOffset + lastEntry->m_nSizeInArchive;
55+
}
56+
57+
m_nNumEntries--;
58+
59+
if (index < m_nNumEntries)
60+
memmove(entry, entry + 1, (m_nNumEntries - index) * sizeof(DirectoryInfoSA));
61+
62+
return true;
63+
}
64+
65+
DirectoryInfoSA* CDirectorySAInterface::GetModelEntry(const char* pFileName)
66+
{
67+
if (m_nNumEntries <= 0)
68+
return nullptr;
69+
70+
for (DirectoryInfoSA* it = m_pEntries; it != m_pEntries + m_nNumEntries; it++)
71+
{
72+
if (strcmp(it->m_szName, pFileName) == 0)
73+
return it;
74+
}
75+
76+
return nullptr;
77+
}
78+
1479
DirectoryInfoSA* CDirectorySAInterface::GetModelEntry(std::uint16_t modelId)
1580
{
1681
if (m_nNumEntries <= 0)

Client/game_sa/CDirectorySA.h

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,10 @@ struct DirectoryInfoSA
2121
class CDirectorySAInterface
2222
{
2323
public:
24+
bool AddEntry(DirectoryInfoSA& entry);
25+
bool RemoveEntry(const char* pFileName);
26+
27+
DirectoryInfoSA* GetModelEntry(const char* pFileName);
2428
DirectoryInfoSA* GetModelEntry(std::uint16_t modelId);
2529
bool SetModelStreamingSize(std::uint16_t modelId, std::uint16_t size);
2630
std::uint16_t GetModelStreamingSize(std::uint16_t modelId);

Client/game_sa/CRenderWareSA.ClothesReplacing.cpp

Lines changed: 100 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,7 @@ namespace
3131

3232
std::unordered_map<ushort, char*> ms_ReplacementClothesFileDataMap;
3333
std::unordered_map<ushort, std::uint16_t> ms_OriginalStreamingSizesMap;
34+
std::unordered_map<std::string, char*> ms_ClothesFileDataMap;
3435

3536
bool bClothesReplacementChanged = false;
3637

@@ -128,6 +129,83 @@ bool CRenderWareSA::HasClothesReplacementChanged()
128129
return bResult;
129130
}
130131

132+
////////////////////////////////////////////////////////////////
133+
//
134+
// CRenderWareSA::ClothesAddFile
135+
//
136+
// Add a file to the clothes directory
137+
//
138+
////////////////////////////////////////////////////////////////
139+
bool CRenderWareSA::ClothesAddFile(const char* pFileData, size_t fileSize, const char* pFileName)
140+
{
141+
if (!pFileData || !pFileName)
142+
return false;
143+
144+
if (MapFind(ms_ClothesFileDataMap, pFileName))
145+
return false;
146+
147+
DirectoryInfoSA entry{};
148+
entry.m_nStreamingSize = GetSizeInBlocks(fileSize);
149+
strncpy(entry.m_szName, pFileName, sizeof(entry.m_szName));
150+
151+
if (!g_clothesDirectory->AddEntry(entry))
152+
return false;
153+
154+
MapSet(ms_ClothesFileDataMap, pFileName, (char*)pFileData);
155+
bClothesReplacementChanged = true;
156+
157+
return true;
158+
}
159+
160+
////////////////////////////////////////////////////////////////
161+
//
162+
// CRenderWareSA::ClothesRemoveFile
163+
//
164+
// Remove a file from the clothes directory
165+
//
166+
////////////////////////////////////////////////////////////////
167+
bool CRenderWareSA::ClothesRemoveFile(char* pFileData)
168+
{
169+
if (!pFileData)
170+
return false;
171+
172+
for (auto iter = ms_ClothesFileDataMap.begin(); iter != ms_ClothesFileDataMap.end();)
173+
{
174+
if (iter->second == pFileData)
175+
{
176+
if (!g_clothesDirectory->RemoveEntry(iter->first.c_str()))
177+
return false;
178+
179+
iter = ms_ClothesFileDataMap.erase(iter);
180+
bClothesReplacementChanged = true;
181+
}
182+
else
183+
++iter;
184+
}
185+
}
186+
187+
////////////////////////////////////////////////////////////////
188+
//
189+
// CRenderWareSA::HasClothesFile
190+
//
191+
// Check if clothe file exits
192+
//
193+
////////////////////////////////////////////////////////////////
194+
bool CRenderWareSA::HasClothesFile(const char* pFileName)
195+
{
196+
if (!pFileName)
197+
{
198+
return false;
199+
}
200+
201+
if (!MapFind(ms_ClothesFileDataMap, pFileName))
202+
{
203+
return false;
204+
}
205+
206+
return true;
207+
}
208+
131209
////////////////////////////////////////////////////////////////
132210
//
133211
// CStreaming_RequestModel_Mid
@@ -143,34 +221,47 @@ __declspec(noinline) bool _cdecl OnCStreaming_RequestModel_Mid(int flags, SImgGT
143221
return false;
144222

145223
// Early out if no clothes textures to replace with
146-
if (ms_ReplacementClothesFileDataMap.empty())
224+
if (ms_ReplacementClothesFileDataMap.empty() && ms_ClothesFileDataMap.empty())
147225
return false;
148226

149227
// Initialze lookup map if needed
150228
static std::map<uint, int> blockOffsetToFileIdMap;
229+
static std::map<uint, std::string> blockOffsetToFileNameMap;
151230
if (blockOffsetToFileIdMap.empty())
152231
{
153232
// Check is player.img dir has been loaded by GTA
154233
SPlayerImgItemArray* pItemArray = (SPlayerImgItemArray*)0x00BC12C0;
155-
if (!pItemArray->pItems || pItemArray->uiArraySize != 542)
234+
std::uint32_t maxArraySize = 542 + ms_ClothesFileDataMap.size();
235+
236+
if (!pItemArray->pItems || pItemArray->uiArraySize != maxArraySize)
156237
return false;
157238

158239
for (uint i = 0; i < pItemArray->uiArraySize; i++)
159240
{
160241
SPlayerImgItem* pImgItem = &pItemArray->pItems[i];
161242
MapSet(blockOffsetToFileIdMap, pImgItem->uiBlockOffset, i);
243+
MapSet(blockOffsetToFileNameMap, pImgItem->uiBlockOffset, pImgItem->szName);
162244
}
163245
}
164246

165-
// Get player.img fileId by comparing the supplied BlockOffset with entries in the player.img dir
166-
int* piPlayerImgFileId = MapFind(blockOffsetToFileIdMap, pImgGTAInfo->iBlockOffset);
167-
if (!piPlayerImgFileId)
168-
return false;
247+
char* pReplacementFileData = nullptr;
248+
int* piPlayerImgFileId = MapFind(blockOffsetToFileIdMap, pImgGTAInfo->iBlockOffset);
249+
250+
if (piPlayerImgFileId)
251+
{
252+
pReplacementFileData = MapFindRef(ms_ReplacementClothesFileDataMap, *piPlayerImgFileId);
253+
}
254+
255+
if (!pReplacementFileData)
256+
{
257+
std::string* pFileName = MapFind(blockOffsetToFileNameMap, pImgGTAInfo->iBlockOffset);
169258

170-
int iPlayerImgFileId = *piPlayerImgFileId;
259+
if (pFileName)
260+
{
261+
pReplacementFileData = MapFindRef(ms_ClothesFileDataMap, *pFileName);
262+
}
263+
}
171264

172-
// Do we have a replacement for this clothes texture?
173-
char* pReplacementFileData = MapFindRef(ms_ReplacementClothesFileDataMap, iPlayerImgFileId);
174265
if (!pReplacementFileData)
175266
return false;
176267

Client/game_sa/CRenderWareSA.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,9 @@ class CRenderWareSA : public CRenderWare
3535
void ClothesAddReplacement(char* pFileData, size_t fileSize, ushort usFileId);
3636
void ClothesRemoveReplacement(char* pFileData);
3737
bool HasClothesReplacementChanged();
38+
bool ClothesAddFile(const char* pFileData, size_t fileSize, const char* pFileName);
39+
bool ClothesRemoveFile(char* pFileData);
40+
bool HasClothesFile(const char* pFileName);
3841

3942
// Reads and parses a TXD file specified by a path (szTXD)
4043
RwTexDictionary* ReadTXD(const SString& strFilename, const SString& buffer);

Client/mods/deathmatch/logic/CClientDFF.cpp

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -99,6 +99,23 @@ void CClientDFF::UnloadDFF()
9999
m_LoadedClumpInfoMap.clear();
100100
}
101101

102+
bool CClientDFF::AddClotheModel(std::string strModelName)
103+
{
104+
if (strModelName.empty())
105+
return false;
106+
107+
if (m_RawDataBuffer.empty() && m_bIsRawData)
108+
return false;
109+
110+
if (m_RawDataBuffer.empty())
111+
{
112+
if (!FileLoad(std::nothrow, m_strDffFilename, m_RawDataBuffer))
113+
return false;
114+
}
115+
116+
return g_pGame->GetRenderWare()->ClothesAddFile(m_RawDataBuffer.data(), m_RawDataBuffer.size(), strModelName.c_str());
117+
}
118+
102119
bool CClientDFF::ReplaceModel(unsigned short usModel, bool bAlphaTransparency)
103120
{
104121
// Record attempt in case it all goes wrong
@@ -232,6 +249,9 @@ void CClientDFF::RestoreModels()
232249
InternalRestoreModel(*iter);
233250
}
234251

252+
// Remove all clothes models
253+
g_pGame->GetRenderWare()->ClothesRemoveFile(m_RawDataBuffer.data());
254+
235255
// Clear the list
236256
m_Replaced.clear();
237257
}

Client/mods/deathmatch/logic/CClientDFF.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,7 @@ class CClientDFF final : public CClientEntity
3737

3838
bool Load(bool isRaw, SString input);
3939

40+
bool AddClotheModel(std::string strModelName);
4041
bool ReplaceModel(unsigned short usModel, bool bAlphaTransparency);
4142

4243
bool HasReplaced(unsigned short usModel);

Client/mods/deathmatch/logic/CClientPed.cpp

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4057,6 +4057,7 @@ void CClientPed::RebuildModel(bool bDelayChange)
40574057
if (m_ulModel == 0)
40584058
{
40594059
// Adds only the neccesary textures
4060+
m_pClothes->RefreshClothes();
40604061
m_pClothes->AddAllToModel();
40614062

40624063
m_bPendingRebuildPlayer = true;

0 commit comments

Comments
 (0)