Skip to content

Commit 0d49449

Browse files
committed
Revert recent changes to CRenderWareSA.TextureReplacing.cpp (and related) once again after following 895be40 i tried to made less intrusive 'safe' changes again, but touching this stuff in any way just causes too many issues.
Crash fixes also only cause the crash to relocate. It all started with a desire to avert an old crash reported by Xenius (who was using txd's with invalid/null textures), but it only relocated it and caused new ones.
1 parent 1ea65c1 commit 0d49449

File tree

3 files changed

+71
-174
lines changed

3 files changed

+71
-174
lines changed

Client/game_sa/CRenderWareSA.TextureReplacing.cpp

Lines changed: 70 additions & 159 deletions
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,6 @@
1212
#include "gamesa_renderware.h"
1313

1414
#include <map>
15-
#include <sstream>
1615
#include <unordered_map>
1716
#include <unordered_set>
1817
#include <utility>
@@ -113,49 +112,50 @@ namespace
113112
////////////////////////////////////////////////////////////////
114113
CModelTexturesInfo* CRenderWareSA::GetModelTexturesInfo(ushort usModelId)
115114
{
116-
auto* pModelInfo = dynamic_cast<CModelInfoSA*>(pGame->GetModelInfo(usModelId));
115+
CModelInfoSA* pModelInfo = dynamic_cast<CModelInfoSA*>(pGame->GetModelInfo(usModelId));
117116
if (!pModelInfo)
118-
return nullptr;
117+
return NULL;
119118

120-
const ushort usTxdId = pModelInfo->GetTextureDictionaryID();
119+
ushort usTxdId = pModelInfo->GetTextureDictionaryID();
121120

122-
if (auto it = ms_ModelTexturesInfoMap.find(usTxdId); it != ms_ModelTexturesInfoMap.end())
123-
return &it->second;
124-
125-
// Get txd
126-
RwTexDictionary* pTxd = CTxdStore_GetTxd(usTxdId);
127-
128-
if (!pTxd)
129-
{
130-
pModelInfo->Request(BLOCKING, "CRenderWareSA::GetModelTexturesInfo");
131-
CTxdStore_AddRef(usTxdId);
132-
((void(__cdecl*)(unsigned short))FUNC_RemoveModel)(usModelId);
133-
pTxd = CTxdStore_GetTxd(usTxdId);
134-
}
135-
else
121+
CModelTexturesInfo* pInfo = MapFind(ms_ModelTexturesInfoMap, usTxdId);
122+
if (!pInfo)
136123
{
137-
CTxdStore_AddRef(usTxdId);
138-
if (pModelInfo->GetModelType() == eModelInfoType::PED)
124+
// Get txd
125+
RwTexDictionary* pTxd = CTxdStore_GetTxd(usTxdId);
126+
127+
if (!pTxd)
139128
{
140-
// Mystery fix for #9336: (MTA sometimes fails at loading custom textures)
141-
// Possibly forces the ped model to be reloaded in some way
129+
pModelInfo->Request(BLOCKING, "CRenderWareSA::GetModelTexturesInfo");
130+
CTxdStore_AddRef(usTxdId);
142131
((void(__cdecl*)(unsigned short))FUNC_RemoveModel)(usModelId);
132+
pTxd = CTxdStore_GetTxd(usTxdId);
133+
}
134+
else
135+
{
136+
CTxdStore_AddRef(usTxdId);
137+
if (pModelInfo->GetModelType() == eModelInfoType::PED)
138+
{
139+
// Mystery fix for #9336: (MTA sometimes fails at loading custom textures)
140+
// Possibly forces the ped model to be reloaded in some way
141+
((void(__cdecl*)(unsigned short))FUNC_RemoveModel)(usModelId);
142+
}
143143
}
144-
}
145144

146-
if (!pTxd)
147-
return nullptr;
145+
if (!pTxd)
146+
return NULL;
148147

149-
// Add new info
150-
auto [it, inserted] = ms_ModelTexturesInfoMap.emplace(usTxdId, CModelTexturesInfo{});
151-
auto& newInfo = it->second;
152-
newInfo.usTxdId = usTxdId;
153-
newInfo.pTxd = pTxd;
148+
// Add new info
149+
MapSet(ms_ModelTexturesInfoMap, usTxdId, CModelTexturesInfo());
150+
pInfo = MapFind(ms_ModelTexturesInfoMap, usTxdId);
151+
pInfo->usTxdId = usTxdId;
152+
pInfo->pTxd = pTxd;
154153

155-
// Save original textures
156-
GetTxdTextures(newInfo.originalTextures, newInfo.pTxd);
157-
158-
return &newInfo;
154+
// Save original textures
155+
GetTxdTextures(pInfo->originalTextures, pInfo->pTxd);
156+
}
157+
158+
return pInfo;
159159
}
160160

161161
////////////////////////////////////////////////////////////////
@@ -173,29 +173,27 @@ bool CRenderWareSA::ModelInfoTXDLoadTextures(SReplacementTextures* pReplacementT
173173
return false;
174174

175175
// Try to load it
176-
if (auto* pTxd = ReadTXD(strFilename, buffer); pTxd)
176+
RwTexDictionary* pTxd = ReadTXD(strFilename, buffer);
177+
if (pTxd)
177178
{
178179
// Get the list of textures into our own list
179180
GetTxdTextures(pReplacementTextures->textures, pTxd);
180181

181-
for (RwTexture* pTexture : pReplacementTextures->textures)
182+
for (uint i = 0; i < pReplacementTextures->textures.size(); i++)
182183
{
183-
if (!pTexture)
184-
continue;
185-
186-
pTexture->txd = nullptr;
184+
pReplacementTextures->textures[i]->txd = NULL;
187185
if (bFilteringEnabled)
188-
pTexture->flags = 0x1102; // Enable filtering (otherwise textures are pixely)
186+
pReplacementTextures->textures[i]->flags = 0x1102; // Enable filtering (otherwise textures are pixely)
189187
}
190188

191189
// Make the txd forget it has any textures and destroy it
192190
pTxd->textures.root.next = &pTxd->textures.root;
193191
pTxd->textures.root.prev = &pTxd->textures.root;
194192
RwTexDictionaryDestroy(pTxd);
195-
pTxd = nullptr;
193+
pTxd = NULL;
196194

197195
// We succeeded if we got any textures
198-
return !pReplacementTextures->textures.empty();
196+
return pReplacementTextures->textures.size() > 0;
199197
}
200198

201199
return false;
@@ -230,14 +228,17 @@ bool CRenderWareSA::ModelInfoTXDAddTextures(SReplacementTextures* pReplacementTe
230228
//
231229
// Add section for this txd
232230
//
233-
auto& perTxdInfo = pReplacementTextures->perTxdList.emplace_back();
231+
pReplacementTextures->perTxdList.push_back(SReplacementTextures::SPerTxd());
232+
SReplacementTextures::SPerTxd& perTxdInfo = pReplacementTextures->perTxdList.back();
234233

235234
perTxdInfo.usTxdId = pInfo->usTxdId;
236-
perTxdInfo.bTexturesAreCopies = !pReplacementTextures->usedInTxdIds.empty();
235+
perTxdInfo.bTexturesAreCopies = (pReplacementTextures->usedInTxdIds.size() > 0);
237236

238237
// Copy / clone textures
239-
for (RwTexture* pNewTexture : pReplacementTextures->textures)
238+
for (std::vector<RwTexture*>::iterator iter = pReplacementTextures->textures.begin(); iter != pReplacementTextures->textures.end(); iter++)
240239
{
240+
RwTexture* pNewTexture = *iter;
241+
241242
// Use a copy if not first txd
242243
if (perTxdInfo.bTexturesAreCopies)
243244
{
@@ -257,8 +258,10 @@ bool CRenderWareSA::ModelInfoTXDAddTextures(SReplacementTextures* pReplacementTe
257258
//
258259
// Add each texture to the target txd
259260
//
260-
for (RwTexture* pNewTexture : perTxdInfo.usingTextures)
261+
for (std::vector<RwTexture*>::iterator iter = perTxdInfo.usingTextures.begin(); iter != perTxdInfo.usingTextures.end(); iter++)
261262
{
263+
RwTexture* pNewTexture = *iter;
264+
262265
// If there is a name clash with an existing texture, replace it
263266
RwTexture* pExistingTexture = RwTexDictionaryFindNamedTexture(pInfo->pTxd, pNewTexture->name);
264267
if (pExistingTexture)
@@ -290,8 +293,10 @@ bool CRenderWareSA::ModelInfoTXDAddTextures(SReplacementTextures* pReplacementTe
290293
void CRenderWareSA::ModelInfoTXDRemoveTextures(SReplacementTextures* pReplacementTextures)
291294
{
292295
// For each using txd
293-
for (auto& perTxdInfo : pReplacementTextures->perTxdList)
296+
for (uint i = 0; i < pReplacementTextures->perTxdList.size(); i++)
294297
{
298+
SReplacementTextures::SPerTxd& perTxdInfo = pReplacementTextures->perTxdList[i];
299+
295300
// Get textures info
296301
ushort usTxdId = perTxdInfo.usTxdId;
297302
CModelTexturesInfo* pInfo = MapFind(ms_ModelTexturesInfoMap, usTxdId);
@@ -303,21 +308,15 @@ void CRenderWareSA::ModelInfoTXDRemoveTextures(SReplacementTextures* pReplacemen
303308
TextureSwapMap swapMap;
304309
swapMap.reserve(perTxdInfo.usingTextures.size());
305310

306-
for (std::size_t idx = 0; idx < perTxdInfo.usingTextures.size(); ++idx)
311+
for (size_t idx = 0; idx < perTxdInfo.usingTextures.size(); ++idx)
307312
{
308313
RwTexture* pOldTexture = perTxdInfo.usingTextures[idx];
309314
if (!pOldTexture)
310315
continue;
311316

312317
RwTexture* pOriginalTexture = (idx < perTxdInfo.replacedOriginals.size()) ? perTxdInfo.replacedOriginals[idx] : nullptr;
313-
314-
if (pOriginalTexture && !SharedUtil::IsReadablePointer(pOriginalTexture, sizeof(RwTexture)))
315-
pOriginalTexture = nullptr;
316-
317318
swapMap[pOldTexture] = pOriginalTexture;
318319

319-
// Always restore original textures to prevent them from becoming orphaned and GC'd
320-
// This is crucial for proper cleanup even when multiple replacement sets use the same TXD
321320
if (pOriginalTexture && !RwTexDictionaryContainsTexture(pInfo->pTxd, pOriginalTexture))
322321
RwTexDictionaryAddTexture(pInfo->pTxd, pOriginalTexture);
323322
}
@@ -331,7 +330,7 @@ void CRenderWareSA::ModelInfoTXDRemoveTextures(SReplacementTextures* pReplacemen
331330

332331
for (ushort modelId : pReplacementTextures->usedInModelIds)
333332
{
334-
auto* pModelInfo = dynamic_cast<CModelInfoSA*>(pGame->GetModelInfo(modelId));
333+
CModelInfoSA* pModelInfo = dynamic_cast<CModelInfoSA*>(pGame->GetModelInfo(modelId));
335334
if (!pModelInfo)
336335
continue;
337336

@@ -349,14 +348,9 @@ void CRenderWareSA::ModelInfoTXDRemoveTextures(SReplacementTextures* pReplacemen
349348
}
350349

351350
// Remove replacement textures
352-
for (RwTexture* pOldTexture : perTxdInfo.usingTextures)
351+
for (uint i = 0; i < perTxdInfo.usingTextures.size(); i++)
353352
{
354-
if (!pOldTexture)
355-
continue;
356-
357-
if (!SharedUtil::IsReadablePointer(pOldTexture, sizeof(RwTexture)))
358-
continue;
359-
353+
RwTexture* pOldTexture = perTxdInfo.usingTextures[i];
360354
RwTexDictionaryRemoveTexture(pInfo->pTxd, pOldTexture);
361355
dassert(!RwTexDictionaryContainsTexture(pInfo->pTxd, pOldTexture));
362356
if (perTxdInfo.bTexturesAreCopies)
@@ -368,23 +362,12 @@ void CRenderWareSA::ModelInfoTXDRemoveTextures(SReplacementTextures* pReplacemen
368362
}
369363

370364
perTxdInfo.usingTextures.clear();
371-
372-
// Free replaced textures that aren't in originalTextures (prevents leak)
373-
for (RwTexture* pReplacedTexture : perTxdInfo.replacedOriginals)
374-
{
375-
if (pReplacedTexture && SharedUtil::IsReadablePointer(pReplacedTexture, sizeof(RwTexture)) && !ListContains(pInfo->originalTextures, pReplacedTexture))
376-
RwTextureDestroy(pReplacedTexture);
377-
}
378-
379365
perTxdInfo.replacedOriginals.clear();
380366

381367
// Ensure there are original named textures in the txd
382-
for (RwTexture* pOriginalTexture : pInfo->originalTextures)
368+
for (uint i = 0; i < pInfo->originalTextures.size(); i++)
383369
{
384-
// Skip null/invalid textures (can happen during shutdown)
385-
if (!pOriginalTexture)
386-
continue;
387-
370+
RwTexture* pOriginalTexture = pInfo->originalTextures[i];
388371
if (!RwTexDictionaryFindNamedTexture(pInfo->pTxd, pOriginalTexture->name))
389372
RwTexDictionaryAddTexture(pInfo->pTxd, pOriginalTexture);
390373
}
@@ -399,101 +382,29 @@ void CRenderWareSA::ModelInfoTXDRemoveTextures(SReplacementTextures* pReplacemen
399382
#ifdef MTA_DEBUG
400383
std::vector<RwTexture*> currentTextures;
401384
GetTxdTextures(currentTextures, pInfo->pTxd);
402-
403-
auto formatTextures = [](const std::vector<RwTexture*>& textures) -> std::string {
404-
std::ostringstream result;
405-
for (size_t i = 0; i < textures.size(); ++i)
406-
{
407-
const auto* pTex = textures[i];
408-
const bool isValid = pTex && SharedUtil::IsReadablePointer(pTex, sizeof(RwTexture));
409-
const bool isLast = (i == textures.size() - 1);
410-
411-
if (isValid)
412-
result << pTex->name << "[0x" << std::hex << pTex << std::dec << "]";
413-
else
414-
result << "INVALID[0x" << std::hex << pTex << std::dec << "]";
415-
416-
if (!isLast)
417-
result << ", ";
418-
}
419-
return result.str();
420-
};
421-
422-
// Allow size mismatch in case texture removal was skipped due to invalid pointers
423-
if (currentTextures.size() != pInfo->originalTextures.size())
385+
assert(currentTextures.size() == pInfo->originalTextures.size());
386+
for (uint i = 0; i < pInfo->originalTextures.size(); i++)
424387
{
425-
std::ostringstream debugMsg;
426-
debugMsg << "TXD " << pInfo->usTxdId << ": texture count mismatch (current="
427-
<< currentTextures.size() << ", expected=" << pInfo->originalTextures.size() << ")\n";
428-
debugMsg << " Current textures: " << formatTextures(currentTextures);
429-
debugMsg << "\n Expected textures: " << formatTextures(pInfo->originalTextures);
430-
debugMsg << "\n";
431-
OutputDebugString(debugMsg.str().c_str());
432-
}
433-
else
434-
{
435-
// First pass: validate all original textures are present
436-
for (const auto* pOriginalTexture : pInfo->originalTextures)
437-
{
438-
if (!pOriginalTexture)
439-
continue;
440-
if (!ListContains(currentTextures, pOriginalTexture))
441-
{
442-
const char* texName = SharedUtil::IsReadablePointer(pOriginalTexture, sizeof(RwTexture))
443-
? pOriginalTexture->name : "INVALID";
444-
std::ostringstream oss;
445-
oss << "Original texture not found in TXD " << pInfo->usTxdId
446-
<< " - texture '" << texName << "' [0x" << std::hex << pOriginalTexture << std::dec
447-
<< "] was removed or replaced unexpectedly";
448-
const std::string assertMsg = oss.str();
449-
assert(false && assertMsg.c_str());
450-
}
451-
}
452-
453-
// Second pass: remove original textures from current list to find extras
454-
for (auto* pOriginalTexture : pInfo->originalTextures)
455-
{
456-
if (pOriginalTexture)
457-
ListRemove(currentTextures, pOriginalTexture);
458-
}
459-
460-
// Check for leaked textures
461-
if (!currentTextures.empty())
462-
{
463-
std::ostringstream oss;
464-
oss << "Extra textures remain in TXD " << pInfo->usTxdId
465-
<< " after removing all originals - indicates texture leak. Remaining: "
466-
<< formatTextures(currentTextures);
467-
const std::string assertMsg = oss.str();
468-
assert(false && assertMsg.c_str());
469-
}
388+
RwTexture* pOriginalTexture = pInfo->originalTextures[i];
389+
assert(ListContains(currentTextures, pOriginalTexture));
390+
ListRemove(currentTextures, pOriginalTexture);
470391
}
392+
assert(currentTextures.empty());
471393

472-
const int32_t refsCount = CTxdStore_GetNumRefs(pInfo->usTxdId);
473-
if (refsCount <= 0)
474-
{
475-
std::ostringstream oss;
476-
oss << "TXD " << pInfo->usTxdId << " has invalid ref count "
477-
<< refsCount << " - should be > 0 before cleanup";
478-
const std::string assertMsg = oss.str();
479-
assert(false && assertMsg.c_str());
480-
}
394+
int32_t refsCount = CTxdStore_GetNumRefs(pInfo->usTxdId);
395+
assert(refsCount > 0 && "Should have at least one TXD reference here");
481396
#endif
482-
// Clear original textures to prevent dangling pointers after TXD ref removal
483-
// The textures themselves are owned by the TXD and will be cleaned up when ref count hits zero
484-
pInfo->originalTextures.clear();
485-
486397
// Remove info
487398
CTxdStore_RemoveRef(pInfo->usTxdId);
488399
MapRemove(ms_ModelTexturesInfoMap, usTxdId);
489400
}
490401
}
491402

492403
// Destroy replacement textures
493-
for (RwTexture* pTexture : pReplacementTextures->textures)
404+
for (uint i = 0; i < pReplacementTextures->textures.size(); i++)
494405
{
495-
if (pTexture)
496-
DestroyTexture(pTexture);
406+
RwTexture* pOldTexture = pReplacementTextures->textures[i];
407+
DestroyTexture(pOldTexture);
497408
}
498409
pReplacementTextures->textures.clear();
499410
}

Client/game_sa/CRenderWareSA.cpp

Lines changed: 0 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -737,9 +737,6 @@ void CRenderWareSA::DestroyTexture(RwTexture* pTex)
737737

738738
void CRenderWareSA::RwTexDictionaryRemoveTexture(RwTexDictionary* pTXD, RwTexture* pTex)
739739
{
740-
if (!pTex || !pTXD)
741-
return;
742-
743740
if (pTex->txd != pTXD)
744741
return;
745742

@@ -755,17 +752,6 @@ short CRenderWareSA::CTxdStore_GetTxdRefcount(unsigned short usTxdID)
755752

756753
bool CRenderWareSA::RwTexDictionaryContainsTexture(RwTexDictionary* pTXD, RwTexture* pTex)
757754
{
758-
// Avoid crashes with freed/invalid textures and TXDs
759-
if (!pTex || !pTXD)
760-
return false;
761-
762-
// Prevent crash when texture/TXD has been freed but pointer still exists
763-
if (!SharedUtil::IsReadablePointer(pTex, sizeof(RwTexture)))
764-
return false;
765-
766-
if (!SharedUtil::IsReadablePointer(pTXD, sizeof(RwTexDictionary)))
767-
return false;
768-
769755
return pTex->txd == pTXD;
770756
}
771757

Client/game_sa/CRenderWareSA.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@
1616
#include "CRenderWareSA.ShaderSupport.h"
1717

1818
class CMatchChannelManager;
19-
struct CModelTexturesInfo;
19+
class CModelTexturesInfo;
2020
struct RpAtomic;
2121
struct SShaderReplacementStats;
2222
struct STexInfo;

0 commit comments

Comments
 (0)