Skip to content

Commit

Permalink
Fix bugs after stream in
Browse files Browse the repository at this point in the history
  • Loading branch information
FileEX committed Sep 28, 2024
1 parent fdddb29 commit ebb2b2a
Show file tree
Hide file tree
Showing 4 changed files with 161 additions and 24 deletions.
79 changes: 74 additions & 5 deletions Client/game_sa/CEntitySA.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -66,11 +66,6 @@ CRect* CEntitySAInterface::GetBoundRect_(CRect* pRect)
return pRect;
}

void CEntitySAInterface::StaticSetHooks()
{
HookInstall(0x534120, &CEntitySAInterface::GetBoundRect_);
}

CEntitySA::CEntitySA()
{
// Set these variables to a constant state
Expand Down Expand Up @@ -715,3 +710,77 @@ bool CEntitySA::GetUnderwater()
{
return m_pInterface->bUnderwater;
}

//////////////////////////////////////////////////////////////////////////////////////////
//
// Hook for CEntity::CreateEffects & CEntity::DestroyEffects
//
// Handle modified 2dfx effects during streaming
// This is necessary because once the object is streamed in, the 2dfx effects are loaded from RwStream
// and the default effects are restored even though they have been modified.
//
//////////////////////////////////////////////////////////////////////////////////////////
static void Keep2DFXEffectsBeforeRemove(std::uint32_t modelID)
{
CModelInfo* modelInfo = pGame->GetModelInfo(modelID);
if (!modelInfo)
return;

modelInfo->CopyModified2DFXEffects();
}

#define HOOKPOS_CEntity_DestroyEffects 0x533C01
#define HOOKSIZE_CEntity_DestroyEffects 5
static constexpr DWORD CONTINUE_CEntity_DestroyEffects = 0x533C06;
static void _declspec(naked) HOOK_CEntity_DestroyEffects()
{
_asm
{
pushad
push eax
call Keep2DFXEffectsBeforeRemove
add esp, 4
popad

movzx eax, byte ptr [ecx+0Dh]
push ebp
jmp CONTINUE_CEntity_DestroyEffects
}
}

static void Restore2DFXEffects(std::uint32_t modelID)
{
CModelInfo* modelInfo = pGame->GetModelInfo(modelID);
if (!modelInfo)
return;

modelInfo->RestoreModified2DFXEffects();
}

#define HOOKPOS_CEntity_CreateEffects 0x533BAE
#define HOOKSIZE_CEntity_CreateEffects 9
static constexpr DWORD RETURN_CEntity_CreateEffects = 0x533BB7;
static void _declspec(naked) HOOK_CEntity_CreateEffects()
{
_asm
{
pushad
push [ebp+22h]
call Restore2DFXEffects
add esp, 4
popad

pop edi
pop ebp
pop ebx
add esp, 0C0h
jmp RETURN_CEntity_CreateEffects
}
}

void CEntitySAInterface::StaticSetHooks()
{
HookInstall(0x534120, &CEntitySAInterface::GetBoundRect_);
EZHookInstall(CEntity_DestroyEffects);
EZHookInstall(CEntity_CreateEffects);
}
99 changes: 81 additions & 18 deletions Client/game_sa/CModelInfoSA.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -37,10 +37,12 @@ std::unordered_map<DWORD, unsigned short> CModelInfo
std::unordered_map<DWORD, std::pair<float, float>> CModelInfoSA::ms_VehicleModelDefaultWheelSizes;
std::map<unsigned short, int> CModelInfoSA::ms_DefaultTxdIDMap;

std::unordered_map<DWORD, std::unordered_map<C2DEffectSAInterface*, C2DEffectSAInterface*>> CModelInfoSA::ms_DefaultEffectsMap;
static std::unordered_map<CBaseModelInfoSAInterface*, std::uint32_t> m_numCustom2dfxEffects;
static std::vector<C2DEffectSAInterface*> d2fxEffects;
static std::vector<C2DEffectSAInterface*> removedDefaultEffects;
static std::unordered_map<DWORD, std::unordered_map<C2DEffectSAInterface*, C2DEffectSAInterface*>> ms_DefaultEffectsMap;
static std::unordered_map<CBaseModelInfoSAInterface*, std::uint32_t> numCustom2dfxEffects;
static std::vector<C2DEffectSAInterface*> d2fxEffects;
static std::vector<C2DEffectSAInterface*> removedDefault2dfxEffects;
static std::unordered_map<DWORD, std::uint8_t> defaultNumOf2DFXEffects;
static std::unordered_map<DWORD, std::vector<C2DEffectSAInterface*>> tempCopy2dfxEffects;

int C2DEffectSA::effect2dPluginOffset = *(int*)0xC3A1E0; // g2dEffectPluginOffset

Expand Down Expand Up @@ -116,7 +118,7 @@ CBaseModelInfoSAInterface* CModelInfoSA::GetInterface()
void CModelInfoSA::SetModelID(DWORD dwModelID)
{
m_dwModelID = dwModelID;
MapSet(m_numCustom2dfxEffects, ppModelInfo[dwModelID], 0);
MapSet(numCustom2dfxEffects, ppModelInfo[dwModelID], 0);
}

bool CModelInfoSA::IsBoat()
Expand Down Expand Up @@ -1197,10 +1199,10 @@ void CModelInfoSA::StaticReset2DFXEffects()
memcpy(innerIter->first, innerIter->second, sizeof(C2DEffectSAInterface));

// Increase the counter if this effect was removed
auto& removedEffect = std::find(removedDefaultEffects.begin(), removedDefaultEffects.end(), innerIter->first);
if (removedEffect != removedDefaultEffects.end())
auto& removedEffect = std::find(removedDefault2dfxEffects.begin(), removedDefault2dfxEffects.end(), innerIter->first);
if (removedEffect != removedDefault2dfxEffects.end())
{
removedDefaultEffects.erase(removedEffect);
removedDefault2dfxEffects.erase(removedEffect);
modelInfoInterface->ucNumOf2DEffects++;
}

Expand All @@ -1211,15 +1213,15 @@ void CModelInfoSA::StaticReset2DFXEffects()
}

// Decrement the counter by the number of custom effects
auto customEffectsCount = MapGet(m_numCustom2dfxEffects, modelInfoInterface);
auto customEffectsCount = MapGet(numCustom2dfxEffects, modelInfoInterface);
if (customEffectsCount && customEffectsCount > 0)
modelInfoInterface->ucNumOf2DEffects -= customEffectsCount;

MapSet(m_numCustom2dfxEffects, modelInfoInterface, 0);
MapSet(numCustom2dfxEffects, modelInfoInterface, 0);
}

// Clear maps
removedDefaultEffects.clear();
removedDefault2dfxEffects.clear();
ms_DefaultEffectsMap.clear();
d2fxEffects.clear();
}
Expand Down Expand Up @@ -2118,6 +2120,9 @@ void CModelInfoSA::StoreDefault2DFXEffect(C2DEffectSAInterface* effect)
if (MapContains(ms_DefaultEffectsMap, m_dwModelID) && MapContains(MapGet(ms_DefaultEffectsMap, m_dwModelID), effect))
return;

if (!MapContains(defaultNumOf2DFXEffects, m_dwModelID))
MapSet(defaultNumOf2DFXEffects, m_dwModelID, ppModelInfo[m_dwModelID]->ucNumOf2DEffects);

// Copy an existing default effect
C2DEffectSAInterface* copy = new C2DEffectSAInterface();
memcpy(copy, effect, sizeof(C2DEffectSAInterface));
Expand Down Expand Up @@ -2158,10 +2163,10 @@ bool CModelInfoSA::Reset2DFXEffects(bool removeCustomEffects)
memcpy(it->first, it->second, sizeof(C2DEffectSAInterface));

// Increase the counter if this effect was removed
auto& removedEffect = std::find(removedDefaultEffects.begin(), removedDefaultEffects.end(), it->first);
if (removedEffect != removedDefaultEffects.end())
auto& removedEffect = std::find(removedDefault2dfxEffects.begin(), removedDefault2dfxEffects.end(), it->first);
if (removedEffect != removedDefault2dfxEffects.end())
{
removedDefaultEffects.erase(removedEffect);
removedDefault2dfxEffects.erase(removedEffect);
m_pInterface->ucNumOf2DEffects++;
}

Expand Down Expand Up @@ -2205,7 +2210,7 @@ C2DEffectSAInterface* CModelInfoSA::Add2DFXEffect(const CVector& position, const

// Update counters
m_pInterface->ucNumOf2DEffects = m_pInterface->ucNumOf2DEffects ? m_pInterface->ucNumOf2DEffects + 1 : 1;
MapGet(m_numCustom2dfxEffects, m_pInterface)++;
MapGet(numCustom2dfxEffects, m_pInterface)++;

// Save our effect
d2fxEffects.push_back(effectInterface);
Expand Down Expand Up @@ -2233,7 +2238,7 @@ bool CModelInfoSA::Remove2DFX(C2DEffectSAInterface* effect, bool includeDefault)
m_pInterface->ucNumOf2DEffects--;
if (isCustomEffect)
{
MapGet(m_numCustom2dfxEffects, m_pInterface)--;
MapGet(numCustom2dfxEffects, m_pInterface)--;
d2fxEffects.erase(it);
}

Expand Down Expand Up @@ -2307,7 +2312,7 @@ bool CModelInfoSA::Remove2DFX(C2DEffectSAInterface* effect, bool includeDefault)
effect = nullptr;
}
else
removedDefaultEffects.push_back(effect);
removedDefault2dfxEffects.push_back(effect);
}

bool CModelInfoSA::Remove2DFXEffectAtIndex(std::uint32_t index, bool includeDefault)
Expand Down Expand Up @@ -2410,7 +2415,7 @@ static C2DEffectSAInterface* Get2dEffect(CBaseModelInfoSAInterface* modelInfo, R

static auto* storedEffects = reinterpret_cast<C2DEffectInfoStoreSAInterface*>(ARRAY_2DFXInfoStore);

std::uint32_t numCustomEffects = m_numCustom2dfxEffects[modelInfo];
std::uint32_t numCustomEffects = numCustom2dfxEffects[modelInfo];
std::uint32_t numStoredEffects = modelInfo->ucNumOf2DEffects - numPluginEffects - numCustomEffects;

if (index < numStoredEffects)
Expand Down Expand Up @@ -2447,6 +2452,64 @@ static void _declspec(naked) HOOK_Get2dEffect()
}
}

void CModelInfoSA::CopyModified2DFXEffects()
{
CBaseModelInfoSAInterface* modelInfo = ppModelInfo[m_dwModelID];
if (!modelInfo || modelInfo->ucNumOf2DEffects == 0)
return;

// Has modified effects?
if (!MapContains(ms_DefaultEffectsMap, m_dwModelID))
return;

auto tempVec = std::vector<C2DEffectSAInterface*>();
std::uint32_t numEffects = MapGet(defaultNumOf2DFXEffects, m_dwModelID);
for (std::uint32_t i = 0; i < numEffects; i++)
{
auto effect = ((C2DEffectSAInterface * (__thiscall*)(CBaseModelInfoSAInterface*, std::uint32_t index))FUNC_CBaseModelInfo_Get2dEffect)(modelInfo, i);
if (!effect)
continue;

// Copy effect
auto copy = new C2DEffectSAInterface();
memcpy(copy, effect, sizeof(C2DEffectSAInterface));
tempVec.push_back(copy);
}

MapSet(tempCopy2dfxEffects, m_dwModelID, tempVec);
}

void CModelInfoSA::RestoreModified2DFXEffects()
{
if (!MapContains(tempCopy2dfxEffects, m_dwModelID))
return;

CBaseModelInfoSAInterface* modelInfo = ppModelInfo[m_dwModelID];
if (!modelInfo)
return;

std::uint32_t numEffects = MapGet(defaultNumOf2DFXEffects, m_dwModelID);
auto& tempVec = MapGet(tempCopy2dfxEffects, m_dwModelID);
if (tempVec.size() > 0)
{
for (std::uint32_t i = 0; i < numEffects; i++)
{
auto effect = ((C2DEffectSAInterface * (__thiscall*)(CBaseModelInfoSAInterface*, std::uint32_t index))FUNC_CBaseModelInfo_Get2dEffect)(modelInfo, i);
if (!effect)
continue;

if (tempVec[i])
{
memcpy(effect, tempVec[i], sizeof(C2DEffectSAInterface));
delete tempVec[i];
}
}
}

tempVec.clear();
tempCopy2dfxEffects.erase(m_dwModelID);
}

//////////////////////////////////////////////////////////////////////////////////////////
//
// Setup hooks
Expand Down
4 changes: 3 additions & 1 deletion Client/game_sa/CModelInfoSA.h
Original file line number Diff line number Diff line change
Expand Up @@ -333,7 +333,6 @@ class CModelInfoSA : public CModelInfo
static std::unordered_map<DWORD, std::pair<float, float>> ms_VehicleModelDefaultWheelSizes;
static std::map<unsigned short, int> ms_DefaultTxdIDMap;
SVehicleSupportedUpgrades m_ModelSupportedUpgrades;
static std::unordered_map<DWORD, std::unordered_map<C2DEffectSAInterface*, C2DEffectSAInterface*>> CModelInfoSA::ms_DefaultEffectsMap;

public:
CModelInfoSA();
Expand Down Expand Up @@ -482,6 +481,9 @@ class CModelInfoSA : public CModelInfo
bool Reset2DFXEffects(bool removeCustomEffects = false);
static void StaticReset2DFXEffects();

void CopyModified2DFXEffects();
void RestoreModified2DFXEffects();

bool IsDynamic() { return m_pInterface ? m_pInterface->usDynamicIndex != 0xffff : false; };

private:
Expand Down
3 changes: 3 additions & 0 deletions Client/sdk/game/CModelInfo.h
Original file line number Diff line number Diff line change
Expand Up @@ -356,6 +356,9 @@ class CModelInfo
virtual void StoreDefault2DFXEffect(C2DEffectSAInterface* effect) = 0;
virtual bool Reset2DFXEffects(bool removeCustomEffects = false) = 0;

virtual void CopyModified2DFXEffects() = 0;
virtual void RestoreModified2DFXEffects() = 0;

virtual unsigned int GetParentID() = 0;
virtual bool IsDynamic() = 0;
};

0 comments on commit ebb2b2a

Please sign in to comment.