Skip to content

Commit c5798ec

Browse files
Synchronize changes from 1.6 master branch [ci skip]
8261950 Adds functions for adding new CJ clothing files (#4050)
2 parents 65035e2 + 8261950 commit c5798ec

20 files changed

+720
-487
lines changed

Client/game_sa/CDirectorySA.cpp

Lines changed: 66 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -11,12 +11,73 @@
1111
#include "StdInc.h"
1212
#include "CDirectorySA.h"
1313

14+
bool CDirectorySAInterface::AddEntry(DirectoryInfoSA& entry)
15+
{
16+
if (m_numEntries >= m_capacity || GetModelEntry(entry.m_name))
17+
return false;
18+
19+
entry.m_offset = 0;
20+
21+
if (m_numEntries > 0)
22+
{
23+
DirectoryInfoSA* lastEntry = m_entries + m_numEntries - 1;
24+
entry.m_offset = lastEntry->m_offset + lastEntry->m_streamingSize;
25+
26+
if (entry.m_offset % 2048)
27+
entry.m_offset += 2048 - (entry.m_offset % 2048);
28+
}
29+
30+
m_entries[m_numEntries++] = entry;
31+
32+
return true;
33+
}
34+
35+
bool CDirectorySAInterface::RemoveEntry(const char* fileName)
36+
{
37+
if (m_numEntries == 0)
38+
return false;
39+
40+
DirectoryInfoSA* entry = GetModelEntry(fileName);
41+
42+
if (!entry)
43+
return false;
44+
45+
std::ptrdiff_t index = entry - m_entries;
46+
47+
if (index < m_numEntries - 1)
48+
{
49+
DirectoryInfoSA* lastEntry = m_entries + m_numEntries - 1;
50+
entry->m_offset = lastEntry->m_offset + lastEntry->m_sizeInArchive;
51+
}
52+
53+
m_numEntries--;
54+
55+
if (index < m_numEntries)
56+
std::memmove(entry, entry + 1, (m_numEntries - index) * sizeof(DirectoryInfoSA));
57+
58+
return true;
59+
}
60+
61+
DirectoryInfoSA* CDirectorySAInterface::GetModelEntry(const char* fileName)
62+
{
63+
if (m_numEntries == 0)
64+
return nullptr;
65+
66+
for (DirectoryInfoSA* it = m_entries; it != m_entries + m_numEntries; it++)
67+
{
68+
if (std::strcmp(it->m_name, fileName) == 0)
69+
return it;
70+
}
71+
72+
return nullptr;
73+
}
74+
1475
DirectoryInfoSA* CDirectorySAInterface::GetModelEntry(std::uint16_t modelId)
1576
{
16-
if (m_nNumEntries <= 0)
77+
if (m_numEntries == 0)
1778
return nullptr;
1879

19-
DirectoryInfoSA* entry = m_pEntries + modelId;
80+
DirectoryInfoSA* entry = m_entries + modelId;
2081

2182
if (!entry)
2283
return nullptr;
@@ -28,13 +89,10 @@ bool CDirectorySAInterface::SetModelStreamingSize(std::uint16_t modelId, std::ui
2889
{
2990
DirectoryInfoSA* entry = GetModelEntry(modelId);
3091

31-
if (!entry)
32-
return false;
33-
34-
if (entry->m_nStreamingSize == size)
92+
if (!entry || entry->m_streamingSize == size)
3593
return false;
3694

37-
entry->m_nStreamingSize = size;
95+
entry->m_streamingSize = size;
3896
return true;
3997
}
4098

@@ -46,5 +104,5 @@ std::uint16_t CDirectorySAInterface::GetModelStreamingSize(std::uint16_t modelId
46104
if (!entry)
47105
return 0;
48106

49-
return entry->m_nStreamingSize;
107+
return entry->m_streamingSize;
50108
}

Client/game_sa/CDirectorySA.h

Lines changed: 12 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -12,22 +12,26 @@
1212

1313
struct DirectoryInfoSA
1414
{
15-
std::uint32_t m_nOffset;
16-
std::uint16_t m_nStreamingSize;
17-
std::uint16_t m_nSizeInArchive;
18-
char m_szName[24];
15+
std::uint32_t m_offset;
16+
std::uint16_t m_streamingSize;
17+
std::uint16_t m_sizeInArchive;
18+
char m_name[24];
1919
};
2020

2121
class CDirectorySAInterface
2222
{
2323
public:
24+
bool AddEntry(DirectoryInfoSA& entry);
25+
bool RemoveEntry(const char* fileName);
26+
27+
DirectoryInfoSA* GetModelEntry(const char* fileName);
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);
2731

2832
private:
29-
DirectoryInfoSA* m_pEntries{};
30-
std::uint32_t m_nCapacity{};
31-
std::uint32_t m_nNumEntries{};
32-
bool m_bOwnsEntries{};
33+
DirectoryInfoSA* m_entries{};
34+
std::uint32_t m_capacity{};
35+
std::uint32_t m_numEntries{};
36+
bool m_ownsEntries{};
3337
};

Client/game_sa/CRenderWareSA.ClothesReplacing.cpp

Lines changed: 98 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -31,8 +31,9 @@ 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

35-
bool bClothesReplacementChanged = false;
36+
bool clothesReplacementChanged = false;
3637

3738
struct SPlayerImgItem
3839
{
@@ -78,7 +79,7 @@ void CRenderWareSA::ClothesAddReplacement(char* pFileData, size_t fileSize, usho
7879
MapSet(ms_OriginalStreamingSizesMap, usFileId, g_clothesDirectory->GetModelStreamingSize(usFileId));
7980
g_clothesDirectory->SetModelStreamingSize(usFileId, GetSizeInBlocks(fileSize));
8081

81-
bClothesReplacementChanged = true;
82+
clothesReplacementChanged = true;
8283
}
8384
}
8485

@@ -107,7 +108,7 @@ void CRenderWareSA::ClothesRemoveReplacement(char* pFileData)
107108
}
108109

109110
iter = ms_ReplacementClothesFileDataMap.erase(iter);
110-
bClothesReplacementChanged = true;
111+
clothesReplacementChanged = true;
111112
}
112113
else
113114
++iter;
@@ -123,11 +124,81 @@ void CRenderWareSA::ClothesRemoveReplacement(char* pFileData)
123124
////////////////////////////////////////////////////////////////
124125
bool CRenderWareSA::HasClothesReplacementChanged()
125126
{
126-
bool bResult = bClothesReplacementChanged;
127-
bClothesReplacementChanged = false;
127+
bool bResult = clothesReplacementChanged;
128+
clothesReplacementChanged = false;
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* fileData, std::size_t fileSize, const char* fileName)
140+
{
141+
if (!fileData || !fileName)
142+
return false;
143+
144+
if (MapFind(ms_ClothesFileDataMap, fileName))
145+
return false;
146+
147+
DirectoryInfoSA entry{};
148+
entry.m_streamingSize = GetSizeInBlocks(fileSize);
149+
150+
std::size_t nameSize = sizeof(entry.m_name) - 1;
151+
std::strncpy(entry.m_name, fileName, nameSize);
152+
entry.m_name[nameSize] = '\0';
153+
154+
if (!g_clothesDirectory->AddEntry(entry))
155+
return false;
156+
157+
MapSet(ms_ClothesFileDataMap, fileName, const_cast<char*>(fileData));
158+
clothesReplacementChanged = true;
159+
160+
return true;
161+
}
162+
163+
////////////////////////////////////////////////////////////////
164+
//
165+
// CRenderWareSA::ClothesRemoveFile
166+
//
167+
// Remove a file from the clothes directory
168+
//
169+
////////////////////////////////////////////////////////////////
170+
bool CRenderWareSA::ClothesRemoveFile(char* fileData)
171+
{
172+
if (!fileData)
173+
return false;
174+
175+
for (auto iter = ms_ClothesFileDataMap.begin(); iter != ms_ClothesFileDataMap.end();)
176+
{
177+
if (iter->second == fileData)
178+
{
179+
if (!g_clothesDirectory->RemoveEntry(iter->first.c_str()))
180+
return false;
181+
182+
iter = ms_ClothesFileDataMap.erase(iter);
183+
clothesReplacementChanged = true;
184+
}
185+
else
186+
++iter;
187+
}
188+
}
189+
190+
////////////////////////////////////////////////////////////////
191+
//
192+
// CRenderWareSA::HasClothesFile
193+
//
194+
// Check if clothe file exits
195+
//
196+
////////////////////////////////////////////////////////////////
197+
bool CRenderWareSA::HasClothesFile(const char* fileName) const noexcept
198+
{
199+
return fileName && MapFind(ms_ClothesFileDataMap, fileName);
200+
}
201+
131202
////////////////////////////////////////////////////////////////
132203
//
133204
// CStreaming_RequestModel_Mid
@@ -143,35 +214,44 @@ __declspec(noinline) bool _cdecl OnCStreaming_RequestModel_Mid(int flags, SImgGT
143214
return false;
144215

145216
// Early out if no clothes textures to replace with
146-
if (ms_ReplacementClothesFileDataMap.empty())
217+
if (ms_ReplacementClothesFileDataMap.empty() && ms_ClothesFileDataMap.empty())
147218
return false;
148219

149220
// Initialze lookup map if needed
150-
static std::map<uint, int> blockOffsetToFileIdMap;
221+
static std::map<std::uint32_t, int> blockOffsetToFileIdMap;
222+
static std::map<std::uint32_t, std::string> blockOffsetToFileNameMap;
151223
if (blockOffsetToFileIdMap.empty())
152224
{
153225
// Check is player.img dir has been loaded by GTA
154226
SPlayerImgItemArray* pItemArray = (SPlayerImgItemArray*)0x00BC12C0;
155-
if (!pItemArray->pItems || pItemArray->uiArraySize != 542)
227+
std::uint32_t maxArraySize = 542 + ms_ClothesFileDataMap.size();
228+
229+
if (!pItemArray->pItems || pItemArray->uiArraySize != maxArraySize)
156230
return false;
157231

158-
for (uint i = 0; i < pItemArray->uiArraySize; i++)
232+
for (std::uint32_t i = 0; i < pItemArray->uiArraySize; i++)
159233
{
160234
SPlayerImgItem* pImgItem = &pItemArray->pItems[i];
161235
MapSet(blockOffsetToFileIdMap, pImgItem->uiBlockOffset, i);
236+
MapSet(blockOffsetToFileNameMap, pImgItem->uiBlockOffset, pImgItem->szName);
162237
}
163238
}
164239

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;
240+
char* replacementFileData = nullptr;
241+
int* playerImgFileId = MapFind(blockOffsetToFileIdMap, pImgGTAInfo->iBlockOffset);
242+
243+
if (playerImgFileId)
244+
replacementFileData = MapFindRef(ms_ReplacementClothesFileDataMap, *playerImgFileId);
169245

170-
int iPlayerImgFileId = *piPlayerImgFileId;
246+
if (!replacementFileData)
247+
{
248+
std::string* fileName = MapFind(blockOffsetToFileNameMap, pImgGTAInfo->iBlockOffset);
249+
250+
if (fileName)
251+
replacementFileData = MapFindRef(ms_ClothesFileDataMap, *fileName);
252+
}
171253

172-
// Do we have a replacement for this clothes texture?
173-
char* pReplacementFileData = MapFindRef(ms_ReplacementClothesFileDataMap, iPlayerImgFileId);
174-
if (!pReplacementFileData)
254+
if (!replacementFileData)
175255
return false;
176256

177257
// If bLoadingBigModel is set, try to get it unset
@@ -187,7 +267,7 @@ __declspec(noinline) bool _cdecl OnCStreaming_RequestModel_Mid(int flags, SImgGT
187267

188268
// Set results
189269
iReturnFileId = ((char*)pImgGTAInfo - (char*)CStreaming__ms_aInfoForModel) / 20;
190-
pReturnBuffer = pReplacementFileData;
270+
pReturnBuffer = replacementFileData;
191271

192272
// Update flags
193273
pImgGTAInfo->uiLoadflag = 3;

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* fileData, std::size_t fileSize, const char* fileName) override;
39+
bool ClothesRemoveFile(char* fileData) override;
40+
bool HasClothesFile(const char* fileName) const noexcept override;
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::AddClothingModel(const std::string& modelName)
103+
{
104+
if (modelName.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(), modelName.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 AddClothingModel(const std::string& modelName);
4041
bool ReplaceModel(unsigned short usModel, bool bAlphaTransparency);
4142

4243
bool HasReplaced(unsigned short usModel);

Client/mods/deathmatch/logic/CClientModelCacheManager.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -139,7 +139,7 @@ void CClientModelCacheManagerImpl::DoPulse()
139139
DoPulseVehicleModels();
140140

141141
// Handle regeneration of possibly replaced clothes textures
142-
if (g_pGame->GetRenderWare()->HasClothesReplacementChanged())
142+
if (g_pGame->GetRenderWare()->HasClothesReplacementChanged() || CClientPlayerClothes::HasClothesChanged())
143143
{
144144
g_pMultiplayer->FlushClothesCache();
145145

Client/mods/deathmatch/logic/CClientPed.cpp

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4063,6 +4063,7 @@ void CClientPed::RebuildModel(bool bDelayChange)
40634063
if (m_ulModel == 0)
40644064
{
40654065
// Adds only the neccesary textures
4066+
m_pClothes->RefreshClothes();
40664067
m_pClothes->AddAllToModel();
40674068

40684069
m_bPendingRebuildPlayer = true;

0 commit comments

Comments
 (0)