Skip to content

Commit b137a39

Browse files
committed
Cleanup, fix bugs, crashes and memory leaks
1 parent 7e38dc0 commit b137a39

8 files changed

+212
-119
lines changed

Client/game_sa/C2DEffectSA.cpp

+101
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,101 @@
1+
/*****************************************************************************
2+
*
3+
* PROJECT: Multi Theft Auto
4+
* LICENSE: See LICENSE in the top level directory
5+
* FILE: game_sa/C2DEffectSA.cpp
6+
* PURPOSE: 2DFX static class
7+
*
8+
* Multi Theft Auto is available from https://www.multitheftauto.com/
9+
*
10+
*****************************************************************************/
11+
12+
#include "StdInc.h"
13+
#include "gamesa_renderware.h"
14+
#include "C2DEffectSA.h"
15+
#include "C2DEffectSAInterface.h"
16+
17+
// C2DEffect::Shutdown causes random unknown crash in ntdll.dll so we need own function
18+
void C2DEffectSA::Shutdown(C2DEffectSAInterface* effect)
19+
{
20+
if (!effect)
21+
return;
22+
23+
if (effect->type == e2dEffectType::ROADSIGN)
24+
{
25+
t2dEffectRoadsign& roadsign = effect->effect.roadsign;
26+
27+
if (roadsign.text)
28+
{
29+
std::free(roadsign.text);
30+
roadsign.text = nullptr;
31+
}
32+
33+
if (roadsign.atomic)
34+
{
35+
RwFrame* frame = RpAtomicGetFrame(roadsign.atomic);
36+
if (frame)
37+
{
38+
RpAtomicSetFrame(roadsign.atomic, nullptr);
39+
RwFrameDestroy(frame);
40+
}
41+
42+
RpAtomicDestroy(roadsign.atomic);
43+
roadsign.atomic = nullptr;
44+
}
45+
}
46+
else if (effect->type == e2dEffectType::LIGHT)
47+
{
48+
t2dEffectLight& light = effect->effect.light;
49+
50+
if (light.coronaTex)
51+
{
52+
RwTextureDestroy(light.coronaTex);
53+
light.coronaTex = nullptr;
54+
}
55+
56+
if (light.shadowTex)
57+
{
58+
RwTextureDestroy(light.shadowTex);
59+
light.shadowTex = nullptr;
60+
}
61+
}
62+
}
63+
64+
void C2DEffectSA::SafeDelete2DFXEffect(C2DEffectSAInterface* effect)
65+
{
66+
if (!effect)
67+
return;
68+
69+
if (effect->type == e2dEffectType::ROADSIGN || effect->type == e2dEffectType::LIGHT)
70+
Shutdown(effect);
71+
72+
delete effect;
73+
effect = nullptr;
74+
}
75+
76+
void C2DEffectSA::PrepareTexturesForLightEffect(RwTexture*& coronaTex, RwTexture*& shadowTex, const char* coronaName, const char* shadowName, bool removeIfExist)
77+
{
78+
// Call CTxdStore::PushCurrentTxd
79+
((void(__cdecl*)())FUNC_PushCurrentTxd)();
80+
// Call CTxdStore::FindTxdSlot
81+
int slot = ((int(__cdecl*)(const char*))FUNC_FindTxdSlot)("particle");
82+
// Call CTxdStore::SetCurrentTxd
83+
((void(__cdecl*)(int))FUNC_SetCurrentTxd)(slot);
84+
85+
if (removeIfExist)
86+
{
87+
if (coronaTex && coronaName)
88+
RwTextureDestroy(coronaTex);
89+
if (shadowTex && shadowName)
90+
RwTextureDestroy(shadowTex);
91+
}
92+
93+
if (coronaName)
94+
coronaTex = RwReadTexture(coronaName, nullptr);
95+
96+
if (shadowName)
97+
shadowTex = RwReadTexture(shadowName, nullptr);
98+
99+
// Call CTxdStore::PopCurrentTxd
100+
((void(__cdecl*)())FUNC_PopCurrentTxd)();
101+
}

Client/game_sa/C2DEffectSA.h

+44
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,44 @@
1+
/*****************************************************************************
2+
*
3+
* PROJECT: Multi Theft Auto
4+
* LICENSE: See LICENSE in the top level directory
5+
* FILE: game_sa/C2DEffectSA.h
6+
* PURPOSE: Header file for 2dfx static class
7+
*
8+
* Multi Theft Auto is available from https://www.multitheftauto.com/
9+
*
10+
*****************************************************************************/
11+
12+
#pragma once
13+
14+
#define ARRAY_2DFXInfoStore 0xB4C2D8 // C2dfxInfoStore d2fxModels
15+
16+
#define FUNC_C2DEffect_Shutdown 0x4C57D0
17+
#define FUNC_PushCurrentTxd 0x7316A0
18+
#define FUNC_FindTxdSlot 0x731850
19+
#define FUNC_SetCurrentTxd 0x7319C0
20+
#define FUNC_PopCurrentTxd 0x7316B0
21+
22+
// Escalators stuff
23+
#define ARRAY_CEscalators 0xC6E9A8
24+
#define NUM_MAX_ESCALATORS 32
25+
#define FUNC_CEscalator_SwitchOff 0x717860
26+
27+
// fx stuff
28+
#define FUNC_Fx_c_DestroyEntityFx 0x4A1280
29+
#define FUNC_Fx_c_CreateEntityFx 0x4A11E0
30+
#define VAR_G_Fx 0xA9AE00
31+
#define OFFSET_FxSystem_Entities 0xC
32+
#define OFFSET_FxSystem_Link_Prev 0x4
33+
34+
class C2DEffectSAInterface;
35+
36+
class C2DEffectSA
37+
{
38+
public:
39+
static int effect2dPluginOffset;
40+
41+
static void Shutdown(C2DEffectSAInterface* effect);
42+
static void SafeDelete2DFXEffect(C2DEffectSAInterface* effect);
43+
static void PrepareTexturesForLightEffect(RwTexture*& coronaTex, RwTexture*& shadowTex, const char* coronaName, const char* shadowName, bool removeIfExist);
44+
};

Client/game_sa/C2DEffectSAInterface.h

+4-57
Original file line numberDiff line numberDiff line change
@@ -11,30 +11,9 @@
1111
#pragma once
1212

1313
#include "game/RenderWare.h"
14+
#include "game/CModelInfo.h"
1415
#include "CObjectSA.h"
15-
16-
#define ARRAY_2DFXInfoStore 0xB4C2D8 // C2dfxInfoStore d2fxModels
17-
18-
#define FUNC_C2DEffect_Shutdown 0x4C57D0
19-
#define FUNC_PushCurrentTxd 0x7316A0
20-
#define FUNC_FindTxdSlot 0x731850
21-
#define FUNC_SetCurrentTxd 0x7319C0
22-
#define FUNC_PopCurrentTxd 0x7316B0
23-
#define FUNC_RwReadTexture 0x7F3AC0
24-
25-
// Escalators stuff
26-
#define ARRAY_CEscalators 0xC6E9A8
27-
#define NUM_MAX_ESCALATORS 32
28-
#define FUNC_CEscalator_SwitchOff 0x717860
29-
30-
// fx stuff
31-
#define FUNC_Fx_c_DestroyEntityFx 0x4A1280
32-
#define FUNC_Fx_c_CreateEntityFx 0x4A11E0
33-
#define VAR_G_Fx 0xA9AE00
34-
#define OFFSET_FxSystem_Entities 0xC
35-
#define OFFSET_FxSystem_Link_Prev 0x4
36-
37-
#define FUNC_RwTextureDestroy 0x7F3820
16+
#include "C2DEffectSA.h"
3817

3918
struct t2dEffectLight
4019
{
@@ -270,39 +249,7 @@ class CEscalatorSAInterface
270249
CObjectSAInterface* objects[42];
271250
};
272251

273-
class C2DEffectSA
252+
static void StaticPrepareTexturesForLightEffect(RwTexture*& coronaTex, RwTexture*& shadowTex, const char* coronaName, const char* shadowName, bool removeIfExist)
274253
{
275-
public:
276-
static int effect2dPluginOffset;
277-
};
278-
279-
static void PrepareTexturesForLightEffect(RwTexture*& coronaTex, RwTexture*& shadowTex, const char* coronaName, const char* shadowName, bool removeIfExist)
280-
{
281-
// Call CTxdStore::PushCurrentTxd
282-
((void(__cdecl*)())FUNC_PushCurrentTxd)();
283-
// Call CTxdStore::FindTxdSlot
284-
int slot = ((int(__cdecl*)(const char*))FUNC_FindTxdSlot)("particle");
285-
// Call CTxdStore::SetCurrentTxd
286-
((void(__cdecl*)(int))FUNC_SetCurrentTxd)(slot);
287-
288-
if (removeIfExist)
289-
{
290-
using RwTextureDestroy = void(__cdecl*)(RwTexture*);
291-
292-
if (coronaTex && coronaName)
293-
((RwTextureDestroy)FUNC_RwTextureDestroy)(coronaTex);
294-
if (shadowTex && shadowName)
295-
((RwTextureDestroy)FUNC_RwTextureDestroy)(shadowTex);
296-
}
297-
298-
// Call RwReadTexture
299-
using RwReadTexture = RwTexture*(__cdecl*)(const char*, const char*);
300-
if (coronaName)
301-
coronaTex = ((RwReadTexture)FUNC_RwReadTexture)(coronaName, nullptr);
302-
303-
if (shadowName)
304-
shadowTex = ((RwReadTexture)FUNC_RwReadTexture)(shadowName, nullptr);
305-
306-
// Call CTxdStore::PopCurrentTxd
307-
((void(__cdecl*)())FUNC_PopCurrentTxd)();
254+
C2DEffectSA::PrepareTexturesForLightEffect(coronaTex, shadowTex, coronaName, shadowName, removeIfExist);
308255
}

Client/game_sa/CModelInfoSA.cpp

+28-21
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@
2020
#include "CWorldSA.h"
2121
#include "gamesa_renderware.h"
2222
#include "CFxSA.h"
23+
#include "C2DEffectSA.h"
2324

2425
extern CCoreInterface* g_pCore;
2526
extern CGameSA* pGame;
@@ -1208,8 +1209,7 @@ void CModelInfoSA::StaticReset2DFXEffects()
12081209
}
12091210

12101211
// Delete copy of the default effect
1211-
delete innerIter->second;
1212-
innerIter->second = nullptr;
1212+
C2DEffectSA::SafeDelete2DFXEffect(innerIter->second);
12131213
innerIter = iter->second.erase(innerIter);
12141214
}
12151215

@@ -1223,7 +1223,7 @@ void CModelInfoSA::StaticReset2DFXEffects()
12231223
// Destroy copies
12241224
auto& copies = MapGet(tempCopy2dfxEffects, iter->first);
12251225
for (auto copy : copies)
1226-
delete copy;
1226+
C2DEffectSA::SafeDelete2DFXEffect(copy);
12271227
}
12281228

12291229
// Clear maps & vectors
@@ -2173,6 +2173,10 @@ void CModelInfoSA::Update2DFXEffect(C2DEffectSAInterface* effect)
21732173

21742174
void CModelInfoSA::StoreDefault2DFXEffect(C2DEffectSAInterface* effect)
21752175
{
2176+
// Is custom effect?
2177+
if (std::find(d2fxEffects.begin(), d2fxEffects.end(), effect) != d2fxEffects.end())
2178+
return;
2179+
21762180
if (MapContains(ms_DefaultEffectsMap, m_dwModelID) && MapContains(MapGet(ms_DefaultEffectsMap, m_dwModelID), effect))
21772181
return;
21782182

@@ -2188,13 +2192,19 @@ void CModelInfoSA::StoreDefault2DFXEffect(C2DEffectSAInterface* effect)
21882192
if (copy->type == e2dEffectType::LIGHT)
21892193
{
21902194
if (effect->effect.light.coronaTex && effect->effect.light.shadowTex)
2191-
PrepareTexturesForLightEffect(copy->effect.light.coronaTex, copy->effect.light.shadowTex, effect->effect.light.coronaTex->name, effect->effect.light.shadowTex->name, false);
2195+
C2DEffectSA::PrepareTexturesForLightEffect(copy->effect.light.coronaTex, copy->effect.light.shadowTex, effect->effect.light.coronaTex->name, effect->effect.light.shadowTex->name, false);
21922196
}
21932197
else if (copy->type == e2dEffectType::ROADSIGN)
21942198
{
21952199
// Create a copy of text and atomic for the roadsign
21962200
// We must to do this, because C2DEffect::Shutdown removes them
2197-
std::strncpy(copy->effect.roadsign.text, effect->effect.roadsign.text, 64);
2201+
copy->effect.roadsign.text = static_cast<char*>(std::malloc(64));
2202+
if (copy->effect.roadsign.text)
2203+
{
2204+
std::memset(copy->effect.roadsign.text, 0, 64);
2205+
std::strncpy(copy->effect.roadsign.text, effect->effect.roadsign.text, 64);
2206+
}
2207+
21982208
copy->effect.roadsign.atomic = RpAtomicClone(effect->effect.roadsign.atomic);
21992209
}
22002210

@@ -2230,14 +2240,14 @@ bool CModelInfoSA::Reset2DFXEffects(bool removeCustomEffects)
22302240

22312241
// We no longer need a copy
22322242
// So delete it
2233-
delete it->second;
2243+
C2DEffectSA::SafeDelete2DFXEffect(it->second);
22342244
it = map.erase(it);
22352245
}
22362246

22372247
// Delete temp copies
22382248
auto& copies = MapGet(tempCopy2dfxEffects, m_dwModelID);
22392249
for (auto* copy : copies)
2240-
delete copy;
2250+
C2DEffectSA::SafeDelete2DFXEffect(copy);
22412251

22422252
// Clear maps
22432253
map.clear();
@@ -2300,20 +2310,14 @@ bool CModelInfoSA::Remove2DFX(C2DEffectSAInterface* effect, bool includeDefault)
23002310
StoreDefault2DFXEffect(effect);
23012311

23022312
m_pInterface->ucNumOf2DEffects--;
2303-
if (isCustomEffect)
2304-
{
2305-
MapGet(numCustom2dfxEffects, m_pInterface)--;
2306-
d2fxEffects.erase(it);
2307-
}
23082313

23092314
switch (effect->type)
23102315
{
23112316
case e2dEffectType::ROADSIGN:
23122317
case e2dEffectType::LIGHT:
23132318
{
2314-
// Call C2DEffect::Shutdown
2315-
((void(__thiscall*)(C2DEffectSAInterface*))FUNC_C2DEffect_Shutdown)(effect);
2316-
2319+
C2DEffectSA::Shutdown(effect);
2320+
23172321
// Prevent creation when stream in but keep in memory so we can restore it later
23182322
effect->type = e2dEffectType::NONE;
23192323
break;
@@ -2322,15 +2326,13 @@ bool CModelInfoSA::Remove2DFX(C2DEffectSAInterface* effect, bool includeDefault)
23222326
{
23232327
auto entities = GetEntitiesFromFx(m_dwModelID);
23242328
for (auto* entity : entities)
2325-
{
23262329
// Call Fx_c::DestroyEntityFx
23272330
((void(__thiscall*)(CFxSAInterface*, CEntitySAInterface*))FUNC_Fx_c_DestroyEntityFx)(fx, entity);
23282331

2329-
// Prevent creation when stream in but keep in memory so we can restore it later
2330-
effect->type = e2dEffectType::NONE;
2331-
}
2332-
23332332
entities.clear();
2333+
2334+
// Prevent creation when stream in but keep in memory so we can restore it later
2335+
effect->type = e2dEffectType::NONE;
23342336
break;
23352337
}
23362338
case e2dEffectType::ESCALATOR:
@@ -2358,11 +2360,16 @@ bool CModelInfoSA::Remove2DFX(C2DEffectSAInterface* effect, bool includeDefault)
23582360
effect->type = e2dEffectType::NONE;
23592361
break;
23602362
}
2363+
default:
2364+
return false;
23612365
}
23622366

23632367
// If it's custom effect then delete it. If it's default effect then store it as removed
23642368
if (isCustomEffect)
23652369
{
2370+
MapGet(numCustom2dfxEffects, m_pInterface)--;
2371+
d2fxEffects.erase(it);
2372+
23662373
delete effect;
23672374
effect = nullptr;
23682375
}
@@ -2462,7 +2469,7 @@ void CModelInfoSA::RestoreModified2DFXEffects()
24622469
if (tempVec[i])
24632470
{
24642471
MemCpyFast(effect, tempVec[i], sizeof(C2DEffectSAInterface));
2465-
delete tempVec[i];
2472+
C2DEffectSA::SafeDelete2DFXEffect(tempVec[i]);
24662473
}
24672474

24682475
Update2DFXEffect(effect);

Client/game_sa/gamesa_renderware.h

+2
Original file line numberDiff line numberDiff line change
@@ -105,6 +105,7 @@ typedef RpHAnimHierarchy*(__cdecl* GetAnimHierarchyFromSkinClump_t)(RpClump*);
105105
typedef int(__cdecl* RpHAnimIDGetIndex_t)(RpHAnimHierarchy*, int);
106106
typedef RwMatrix*(__cdecl* RpHAnimHierarchyGetMatrixArray_t)(RpHAnimHierarchy*);
107107
typedef RtQuat*(__cdecl* RtQuatRotate_t)(RtQuat* quat, const RwV3d* axis, float angle, RwOpCombineType combineOp);
108+
typedef RwTexture*(__cdecl* RwReadTexture_t)(const char* name, const char* mask);
108109

109110
/*****************************************************************************/
110111
/** Renderware function mappings **/
@@ -195,6 +196,7 @@ RWFUNC(GetAnimHierarchyFromSkinClump_t GetAnimHierarchyFromSkinClump, (GetAnimHi
195196
RWFUNC(RpHAnimIDGetIndex_t RpHAnimIDGetIndex, (RpHAnimIDGetIndex_t)0xDEAD)
196197
RWFUNC(RpHAnimHierarchyGetMatrixArray_t RpHAnimHierarchyGetMatrixArray, (RpHAnimHierarchyGetMatrixArray_t)0xDEAD)
197198
RWFUNC(RtQuatRotate_t RtQuatRotate, (RtQuatRotate_t)0xDEAD)
199+
RWFUNC(RwReadTexture_t RwReadTexture, reinterpret_cast<RwReadTexture_t>(0xDEAD))
198200

199201
/*****************************************************************************/
200202
/** GTA function definitions and mappings **/

Client/game_sa/gamesa_renderware.hpp

+2-1
Original file line numberDiff line numberDiff line change
@@ -89,7 +89,8 @@ void InitRwFunctions()
8989
RpHAnimIDGetIndex = (RpHAnimIDGetIndex_t)0x7C51A0;
9090
RpHAnimHierarchyGetMatrixArray = (RpHAnimHierarchyGetMatrixArray_t)0x7C5120;
9191
RtQuatRotate = (RtQuatRotate_t)0x7EB7C0;
92-
92+
RwReadTexture = reinterpret_cast<RwReadTexture_t>(0x7F3AC0);
93+
9394
SetTextureDict = (SetTextureDict_t)0x007319C0;
9495
LoadClumpFile = (LoadClumpFile_t)0x005371F0;
9596
LoadModel = (LoadModel_t)0x0040C6B0;

0 commit comments

Comments
 (0)