@@ -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
0 commit comments