Skip to content

Commit

Permalink
Cleanup, fix bugs, crashes and memory leaks
Browse files Browse the repository at this point in the history
  • Loading branch information
FileEX committed Sep 29, 2024
1 parent 7e38dc0 commit b137a39
Show file tree
Hide file tree
Showing 8 changed files with 212 additions and 119 deletions.
101 changes: 101 additions & 0 deletions Client/game_sa/C2DEffectSA.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,101 @@
/*****************************************************************************
*
* PROJECT: Multi Theft Auto
* LICENSE: See LICENSE in the top level directory
* FILE: game_sa/C2DEffectSA.cpp
* PURPOSE: 2DFX static class
*
* Multi Theft Auto is available from https://www.multitheftauto.com/
*
*****************************************************************************/

#include "StdInc.h"
#include "gamesa_renderware.h"
#include "C2DEffectSA.h"
#include "C2DEffectSAInterface.h"

// C2DEffect::Shutdown causes random unknown crash in ntdll.dll so we need own function
void C2DEffectSA::Shutdown(C2DEffectSAInterface* effect)
{
if (!effect)
return;

if (effect->type == e2dEffectType::ROADSIGN)
{
t2dEffectRoadsign& roadsign = effect->effect.roadsign;

if (roadsign.text)
{
std::free(roadsign.text);
roadsign.text = nullptr;
}

if (roadsign.atomic)
{
RwFrame* frame = RpAtomicGetFrame(roadsign.atomic);
if (frame)
{
RpAtomicSetFrame(roadsign.atomic, nullptr);
RwFrameDestroy(frame);
}

RpAtomicDestroy(roadsign.atomic);
roadsign.atomic = nullptr;
}
}
else if (effect->type == e2dEffectType::LIGHT)
{
t2dEffectLight& light = effect->effect.light;

if (light.coronaTex)
{
RwTextureDestroy(light.coronaTex);
light.coronaTex = nullptr;
}

if (light.shadowTex)
{
RwTextureDestroy(light.shadowTex);
light.shadowTex = nullptr;
}
}
}

void C2DEffectSA::SafeDelete2DFXEffect(C2DEffectSAInterface* effect)
{
if (!effect)
return;

if (effect->type == e2dEffectType::ROADSIGN || effect->type == e2dEffectType::LIGHT)
Shutdown(effect);

delete effect;
effect = nullptr;
}

void C2DEffectSA::PrepareTexturesForLightEffect(RwTexture*& coronaTex, RwTexture*& shadowTex, const char* coronaName, const char* shadowName, bool removeIfExist)
{
// Call CTxdStore::PushCurrentTxd
((void(__cdecl*)())FUNC_PushCurrentTxd)();
// Call CTxdStore::FindTxdSlot
int slot = ((int(__cdecl*)(const char*))FUNC_FindTxdSlot)("particle");
// Call CTxdStore::SetCurrentTxd
((void(__cdecl*)(int))FUNC_SetCurrentTxd)(slot);

if (removeIfExist)
{
if (coronaTex && coronaName)
RwTextureDestroy(coronaTex);
if (shadowTex && shadowName)
RwTextureDestroy(shadowTex);
}

if (coronaName)
coronaTex = RwReadTexture(coronaName, nullptr);

if (shadowName)
shadowTex = RwReadTexture(shadowName, nullptr);

// Call CTxdStore::PopCurrentTxd
((void(__cdecl*)())FUNC_PopCurrentTxd)();
}
44 changes: 44 additions & 0 deletions Client/game_sa/C2DEffectSA.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
/*****************************************************************************
*
* PROJECT: Multi Theft Auto
* LICENSE: See LICENSE in the top level directory
* FILE: game_sa/C2DEffectSA.h
* PURPOSE: Header file for 2dfx static class
*
* Multi Theft Auto is available from https://www.multitheftauto.com/
*
*****************************************************************************/

#pragma once

#define ARRAY_2DFXInfoStore 0xB4C2D8 // C2dfxInfoStore d2fxModels

#define FUNC_C2DEffect_Shutdown 0x4C57D0
#define FUNC_PushCurrentTxd 0x7316A0
#define FUNC_FindTxdSlot 0x731850
#define FUNC_SetCurrentTxd 0x7319C0
#define FUNC_PopCurrentTxd 0x7316B0

// Escalators stuff
#define ARRAY_CEscalators 0xC6E9A8
#define NUM_MAX_ESCALATORS 32
#define FUNC_CEscalator_SwitchOff 0x717860

// fx stuff
#define FUNC_Fx_c_DestroyEntityFx 0x4A1280
#define FUNC_Fx_c_CreateEntityFx 0x4A11E0
#define VAR_G_Fx 0xA9AE00
#define OFFSET_FxSystem_Entities 0xC
#define OFFSET_FxSystem_Link_Prev 0x4

class C2DEffectSAInterface;

class C2DEffectSA
{
public:
static int effect2dPluginOffset;

static void Shutdown(C2DEffectSAInterface* effect);
static void SafeDelete2DFXEffect(C2DEffectSAInterface* effect);
static void PrepareTexturesForLightEffect(RwTexture*& coronaTex, RwTexture*& shadowTex, const char* coronaName, const char* shadowName, bool removeIfExist);
};
61 changes: 4 additions & 57 deletions Client/game_sa/C2DEffectSAInterface.h
Original file line number Diff line number Diff line change
Expand Up @@ -11,30 +11,9 @@
#pragma once

#include "game/RenderWare.h"
#include "game/CModelInfo.h"
#include "CObjectSA.h"

#define ARRAY_2DFXInfoStore 0xB4C2D8 // C2dfxInfoStore d2fxModels

#define FUNC_C2DEffect_Shutdown 0x4C57D0
#define FUNC_PushCurrentTxd 0x7316A0
#define FUNC_FindTxdSlot 0x731850
#define FUNC_SetCurrentTxd 0x7319C0
#define FUNC_PopCurrentTxd 0x7316B0
#define FUNC_RwReadTexture 0x7F3AC0

// Escalators stuff
#define ARRAY_CEscalators 0xC6E9A8
#define NUM_MAX_ESCALATORS 32
#define FUNC_CEscalator_SwitchOff 0x717860

// fx stuff
#define FUNC_Fx_c_DestroyEntityFx 0x4A1280
#define FUNC_Fx_c_CreateEntityFx 0x4A11E0
#define VAR_G_Fx 0xA9AE00
#define OFFSET_FxSystem_Entities 0xC
#define OFFSET_FxSystem_Link_Prev 0x4

#define FUNC_RwTextureDestroy 0x7F3820
#include "C2DEffectSA.h"

struct t2dEffectLight
{
Expand Down Expand Up @@ -270,39 +249,7 @@ class CEscalatorSAInterface
CObjectSAInterface* objects[42];
};

class C2DEffectSA
static void StaticPrepareTexturesForLightEffect(RwTexture*& coronaTex, RwTexture*& shadowTex, const char* coronaName, const char* shadowName, bool removeIfExist)
{
public:
static int effect2dPluginOffset;
};

static void PrepareTexturesForLightEffect(RwTexture*& coronaTex, RwTexture*& shadowTex, const char* coronaName, const char* shadowName, bool removeIfExist)
{
// Call CTxdStore::PushCurrentTxd
((void(__cdecl*)())FUNC_PushCurrentTxd)();
// Call CTxdStore::FindTxdSlot
int slot = ((int(__cdecl*)(const char*))FUNC_FindTxdSlot)("particle");
// Call CTxdStore::SetCurrentTxd
((void(__cdecl*)(int))FUNC_SetCurrentTxd)(slot);

if (removeIfExist)
{
using RwTextureDestroy = void(__cdecl*)(RwTexture*);

if (coronaTex && coronaName)
((RwTextureDestroy)FUNC_RwTextureDestroy)(coronaTex);
if (shadowTex && shadowName)
((RwTextureDestroy)FUNC_RwTextureDestroy)(shadowTex);
}

// Call RwReadTexture
using RwReadTexture = RwTexture*(__cdecl*)(const char*, const char*);
if (coronaName)
coronaTex = ((RwReadTexture)FUNC_RwReadTexture)(coronaName, nullptr);

if (shadowName)
shadowTex = ((RwReadTexture)FUNC_RwReadTexture)(shadowName, nullptr);

// Call CTxdStore::PopCurrentTxd
((void(__cdecl*)())FUNC_PopCurrentTxd)();
C2DEffectSA::PrepareTexturesForLightEffect(coronaTex, shadowTex, coronaName, shadowName, removeIfExist);
}
49 changes: 28 additions & 21 deletions Client/game_sa/CModelInfoSA.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@
#include "CWorldSA.h"
#include "gamesa_renderware.h"
#include "CFxSA.h"
#include "C2DEffectSA.h"

extern CCoreInterface* g_pCore;
extern CGameSA* pGame;
Expand Down Expand Up @@ -1208,8 +1209,7 @@ void CModelInfoSA::StaticReset2DFXEffects()
}

// Delete copy of the default effect
delete innerIter->second;
innerIter->second = nullptr;
C2DEffectSA::SafeDelete2DFXEffect(innerIter->second);
innerIter = iter->second.erase(innerIter);
}

Expand All @@ -1223,7 +1223,7 @@ void CModelInfoSA::StaticReset2DFXEffects()
// Destroy copies
auto& copies = MapGet(tempCopy2dfxEffects, iter->first);
for (auto copy : copies)
delete copy;
C2DEffectSA::SafeDelete2DFXEffect(copy);
}

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

void CModelInfoSA::StoreDefault2DFXEffect(C2DEffectSAInterface* effect)
{
// Is custom effect?
if (std::find(d2fxEffects.begin(), d2fxEffects.end(), effect) != d2fxEffects.end())
return;

if (MapContains(ms_DefaultEffectsMap, m_dwModelID) && MapContains(MapGet(ms_DefaultEffectsMap, m_dwModelID), effect))
return;

Expand All @@ -2188,13 +2192,19 @@ void CModelInfoSA::StoreDefault2DFXEffect(C2DEffectSAInterface* effect)
if (copy->type == e2dEffectType::LIGHT)
{
if (effect->effect.light.coronaTex && effect->effect.light.shadowTex)
PrepareTexturesForLightEffect(copy->effect.light.coronaTex, copy->effect.light.shadowTex, effect->effect.light.coronaTex->name, effect->effect.light.shadowTex->name, false);
C2DEffectSA::PrepareTexturesForLightEffect(copy->effect.light.coronaTex, copy->effect.light.shadowTex, effect->effect.light.coronaTex->name, effect->effect.light.shadowTex->name, false);
}
else if (copy->type == e2dEffectType::ROADSIGN)
{
// Create a copy of text and atomic for the roadsign
// We must to do this, because C2DEffect::Shutdown removes them
std::strncpy(copy->effect.roadsign.text, effect->effect.roadsign.text, 64);
copy->effect.roadsign.text = static_cast<char*>(std::malloc(64));
if (copy->effect.roadsign.text)
{
std::memset(copy->effect.roadsign.text, 0, 64);
std::strncpy(copy->effect.roadsign.text, effect->effect.roadsign.text, 64);
}

copy->effect.roadsign.atomic = RpAtomicClone(effect->effect.roadsign.atomic);
}

Expand Down Expand Up @@ -2230,14 +2240,14 @@ bool CModelInfoSA::Reset2DFXEffects(bool removeCustomEffects)

// We no longer need a copy
// So delete it
delete it->second;
C2DEffectSA::SafeDelete2DFXEffect(it->second);
it = map.erase(it);
}

// Delete temp copies
auto& copies = MapGet(tempCopy2dfxEffects, m_dwModelID);
for (auto* copy : copies)
delete copy;
C2DEffectSA::SafeDelete2DFXEffect(copy);

// Clear maps
map.clear();
Expand Down Expand Up @@ -2300,20 +2310,14 @@ bool CModelInfoSA::Remove2DFX(C2DEffectSAInterface* effect, bool includeDefault)
StoreDefault2DFXEffect(effect);

m_pInterface->ucNumOf2DEffects--;
if (isCustomEffect)
{
MapGet(numCustom2dfxEffects, m_pInterface)--;
d2fxEffects.erase(it);
}

switch (effect->type)
{
case e2dEffectType::ROADSIGN:
case e2dEffectType::LIGHT:
{
// Call C2DEffect::Shutdown
((void(__thiscall*)(C2DEffectSAInterface*))FUNC_C2DEffect_Shutdown)(effect);

C2DEffectSA::Shutdown(effect);

// Prevent creation when stream in but keep in memory so we can restore it later
effect->type = e2dEffectType::NONE;
break;
Expand All @@ -2322,15 +2326,13 @@ bool CModelInfoSA::Remove2DFX(C2DEffectSAInterface* effect, bool includeDefault)
{
auto entities = GetEntitiesFromFx(m_dwModelID);
for (auto* entity : entities)
{
// Call Fx_c::DestroyEntityFx
((void(__thiscall*)(CFxSAInterface*, CEntitySAInterface*))FUNC_Fx_c_DestroyEntityFx)(fx, entity);

// Prevent creation when stream in but keep in memory so we can restore it later
effect->type = e2dEffectType::NONE;
}

entities.clear();

// Prevent creation when stream in but keep in memory so we can restore it later
effect->type = e2dEffectType::NONE;
break;
}
case e2dEffectType::ESCALATOR:
Expand Down Expand Up @@ -2358,11 +2360,16 @@ bool CModelInfoSA::Remove2DFX(C2DEffectSAInterface* effect, bool includeDefault)
effect->type = e2dEffectType::NONE;
break;
}
default:
return false;
}

// If it's custom effect then delete it. If it's default effect then store it as removed
if (isCustomEffect)
{
MapGet(numCustom2dfxEffects, m_pInterface)--;
d2fxEffects.erase(it);

delete effect;
effect = nullptr;
}
Expand Down Expand Up @@ -2462,7 +2469,7 @@ void CModelInfoSA::RestoreModified2DFXEffects()
if (tempVec[i])
{
MemCpyFast(effect, tempVec[i], sizeof(C2DEffectSAInterface));
delete tempVec[i];
C2DEffectSA::SafeDelete2DFXEffect(tempVec[i]);
}

Update2DFXEffect(effect);
Expand Down
2 changes: 2 additions & 0 deletions Client/game_sa/gamesa_renderware.h
Original file line number Diff line number Diff line change
Expand Up @@ -105,6 +105,7 @@ typedef RpHAnimHierarchy*(__cdecl* GetAnimHierarchyFromSkinClump_t)(RpClump*);
typedef int(__cdecl* RpHAnimIDGetIndex_t)(RpHAnimHierarchy*, int);
typedef RwMatrix*(__cdecl* RpHAnimHierarchyGetMatrixArray_t)(RpHAnimHierarchy*);
typedef RtQuat*(__cdecl* RtQuatRotate_t)(RtQuat* quat, const RwV3d* axis, float angle, RwOpCombineType combineOp);
typedef RwTexture*(__cdecl* RwReadTexture_t)(const char* name, const char* mask);

/*****************************************************************************/
/** Renderware function mappings **/
Expand Down Expand Up @@ -195,6 +196,7 @@ RWFUNC(GetAnimHierarchyFromSkinClump_t GetAnimHierarchyFromSkinClump, (GetAnimHi
RWFUNC(RpHAnimIDGetIndex_t RpHAnimIDGetIndex, (RpHAnimIDGetIndex_t)0xDEAD)
RWFUNC(RpHAnimHierarchyGetMatrixArray_t RpHAnimHierarchyGetMatrixArray, (RpHAnimHierarchyGetMatrixArray_t)0xDEAD)
RWFUNC(RtQuatRotate_t RtQuatRotate, (RtQuatRotate_t)0xDEAD)
RWFUNC(RwReadTexture_t RwReadTexture, reinterpret_cast<RwReadTexture_t>(0xDEAD))

/*****************************************************************************/
/** GTA function definitions and mappings **/
Expand Down
3 changes: 2 additions & 1 deletion Client/game_sa/gamesa_renderware.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -89,7 +89,8 @@ void InitRwFunctions()
RpHAnimIDGetIndex = (RpHAnimIDGetIndex_t)0x7C51A0;
RpHAnimHierarchyGetMatrixArray = (RpHAnimHierarchyGetMatrixArray_t)0x7C5120;
RtQuatRotate = (RtQuatRotate_t)0x7EB7C0;

RwReadTexture = reinterpret_cast<RwReadTexture_t>(0x7F3AC0);

SetTextureDict = (SetTextureDict_t)0x007319C0;
LoadClumpFile = (LoadClumpFile_t)0x005371F0;
LoadModel = (LoadModel_t)0x0040C6B0;
Expand Down
Loading

0 comments on commit b137a39

Please sign in to comment.