Skip to content

Commit 7e38dc0

Browse files
committed
Update & cleanup
1 parent ebb2b2a commit 7e38dc0

File tree

6 files changed

+174
-83
lines changed

6 files changed

+174
-83
lines changed

Client/game_sa/C2DEffectSAInterface.h

+1
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,7 @@
2929

3030
// fx stuff
3131
#define FUNC_Fx_c_DestroyEntityFx 0x4A1280
32+
#define FUNC_Fx_c_CreateEntityFx 0x4A11E0
3233
#define VAR_G_Fx 0xA9AE00
3334
#define OFFSET_FxSystem_Entities 0xC
3435
#define OFFSET_FxSystem_Link_Prev 0x4

Client/game_sa/CModelInfoSA.cpp

+135-78
Original file line numberDiff line numberDiff line change
@@ -45,6 +45,7 @@ static std::unordered_map<DWORD, std::uint8_t>
4545
static std::unordered_map<DWORD, std::vector<C2DEffectSAInterface*>> tempCopy2dfxEffects;
4646

4747
int C2DEffectSA::effect2dPluginOffset = *(int*)0xC3A1E0; // g2dEffectPluginOffset
48+
static auto* fx = reinterpret_cast<CFxSAInterface*>(VAR_G_Fx);
4849

4950
union tIdeFlags
5051
{
@@ -1196,7 +1197,7 @@ void CModelInfoSA::StaticReset2DFXEffects()
11961197
for (auto innerIter = iter->second.begin(); innerIter != iter->second.end();)
11971198
{
11981199
// Copy default effect
1199-
memcpy(innerIter->first, innerIter->second, sizeof(C2DEffectSAInterface));
1200+
MemCpy(innerIter->first, innerIter->second, sizeof(C2DEffectSAInterface));
12001201

12011202
// Increase the counter if this effect was removed
12021203
auto& removedEffect = std::find(removedDefault2dfxEffects.begin(), removedDefault2dfxEffects.end(), innerIter->first);
@@ -1218,12 +1219,18 @@ void CModelInfoSA::StaticReset2DFXEffects()
12181219
modelInfoInterface->ucNumOf2DEffects -= customEffectsCount;
12191220

12201221
MapSet(numCustom2dfxEffects, modelInfoInterface, 0);
1222+
1223+
// Destroy copies
1224+
auto& copies = MapGet(tempCopy2dfxEffects, iter->first);
1225+
for (auto copy : copies)
1226+
delete copy;
12211227
}
12221228

1223-
// Clear maps
1229+
// Clear maps & vectors
12241230
removedDefault2dfxEffects.clear();
12251231
ms_DefaultEffectsMap.clear();
12261232
d2fxEffects.clear();
1233+
tempCopy2dfxEffects.clear();
12271234
}
12281235

12291236
short CModelInfoSA::GetAvailableVehicleMod(unsigned short usUpgrade)
@@ -2115,6 +2122,55 @@ bool CModelInfoSA::ForceUnload()
21152122
return true;
21162123
}
21172124

2125+
auto CModelInfoSA::GetEntitiesFromFx(std::uint32_t modelID)
2126+
{
2127+
auto vec = std::vector<CEntitySAInterface*>();
2128+
void* lastParticle = fx->m_lastParticleEntity;
2129+
2130+
while (lastParticle)
2131+
{
2132+
auto** entity = reinterpret_cast<CEntitySAInterface**>(reinterpret_cast<std::uint8_t*>(lastParticle) + OFFSET_FxSystem_Entities);
2133+
auto* prevParticle = *reinterpret_cast<CFxSAInterface**>(reinterpret_cast<std::uint8_t*>(lastParticle) + OFFSET_FxSystem_Link_Prev);
2134+
2135+
if (entity && *entity && static_cast<DWORD>((*entity)->m_nModelIndex) == modelID)
2136+
vec.push_back(*entity);
2137+
2138+
lastParticle = prevParticle;
2139+
}
2140+
2141+
return vec;
2142+
}
2143+
2144+
void CModelInfoSA::Update2DFXEffect(C2DEffectSAInterface* effect)
2145+
{
2146+
if (!effect)
2147+
return;
2148+
2149+
// This function aims to keep 2dfx effects updated to avoid restreaming
2150+
switch (effect->type)
2151+
{
2152+
case e2dEffectType::PARTICLE:
2153+
{
2154+
auto entities = GetEntitiesFromFx(m_dwModelID);
2155+
for (auto entity : entities)
2156+
{
2157+
// Call Fx_c::DestroyEntityFx
2158+
((void(__thiscall*)(CFxSAInterface*, CEntitySAInterface*))FUNC_Fx_c_DestroyEntityFx)(fx, entity);
2159+
2160+
RwMatrix* matrixTransform = nullptr;
2161+
if (auto* object = reinterpret_cast<RwObject*>(entity->m_pRwObject))
2162+
{
2163+
if (auto* frame = static_cast<RwFrame*>(object->parent))
2164+
matrixTransform = &frame->modelling;
2165+
}
2166+
2167+
// Call Fx_c::CreateEntityFx
2168+
((void(__thiscall*)(CFxSAInterface*, CEntitySAInterface*, const char*, RwV3d*, RwMatrix*))FUNC_Fx_c_CreateEntityFx)(fx, entity, effect->effect.particle.szName, &effect->position, matrixTransform);
2169+
}
2170+
}
2171+
}
2172+
}
2173+
21182174
void CModelInfoSA::StoreDefault2DFXEffect(C2DEffectSAInterface* effect)
21192175
{
21202176
if (MapContains(ms_DefaultEffectsMap, m_dwModelID) && MapContains(MapGet(ms_DefaultEffectsMap, m_dwModelID), effect))
@@ -2125,7 +2181,7 @@ void CModelInfoSA::StoreDefault2DFXEffect(C2DEffectSAInterface* effect)
21252181

21262182
// Copy an existing default effect
21272183
C2DEffectSAInterface* copy = new C2DEffectSAInterface();
2128-
memcpy(copy, effect, sizeof(C2DEffectSAInterface));
2184+
MemCpyFast(copy, effect, sizeof(C2DEffectSAInterface));
21292185

21302186
// Create a copy of textures for the lights
21312187
// We must to do this, because C2DEffect::Shutdown removes them
@@ -2160,7 +2216,7 @@ bool CModelInfoSA::Reset2DFXEffects(bool removeCustomEffects)
21602216
for (auto& it = map.begin(); it != map.end();)
21612217
{
21622218
// Copy data from copied effect to the default
2163-
memcpy(it->first, it->second, sizeof(C2DEffectSAInterface));
2219+
MemCpyFast(it->first, it->second, sizeof(C2DEffectSAInterface));
21642220

21652221
// Increase the counter if this effect was removed
21662222
auto& removedEffect = std::find(removedDefault2dfxEffects.begin(), removedDefault2dfxEffects.end(), it->first);
@@ -2170,15 +2226,23 @@ bool CModelInfoSA::Reset2DFXEffects(bool removeCustomEffects)
21702226
m_pInterface->ucNumOf2DEffects++;
21712227
}
21722228

2229+
Update2DFXEffect(it->first);
2230+
21732231
// We no longer need a copy
21742232
// So delete it
21752233
delete it->second;
21762234
it = map.erase(it);
21772235
}
21782236

2237+
// Delete temp copies
2238+
auto& copies = MapGet(tempCopy2dfxEffects, m_dwModelID);
2239+
for (auto* copy : copies)
2240+
delete copy;
2241+
21792242
// Clear maps
21802243
map.clear();
21812244
ms_DefaultEffectsMap.erase(m_dwModelID);
2245+
tempCopy2dfxEffects.erase(m_dwModelID);
21822246

21832247
// Remove all custom effects
21842248
if (removeCustomEffects)
@@ -2256,26 +2320,17 @@ bool CModelInfoSA::Remove2DFX(C2DEffectSAInterface* effect, bool includeDefault)
22562320
}
22572321
case e2dEffectType::PARTICLE:
22582322
{
2259-
auto* fx = reinterpret_cast<CFxSAInterface*>(VAR_G_Fx);
2260-
void* lastParticle = fx->m_lastParticleEntity;
2261-
2262-
while (lastParticle)
2323+
auto entities = GetEntitiesFromFx(m_dwModelID);
2324+
for (auto* entity : entities)
22632325
{
2264-
auto** entity = reinterpret_cast<CEntitySAInterface**>(reinterpret_cast<std::uint8_t*>(lastParticle) + OFFSET_FxSystem_Entities);
2265-
auto* prevParticle = *reinterpret_cast<CFxSAInterface**>(reinterpret_cast<std::uint8_t*>(lastParticle) + OFFSET_FxSystem_Link_Prev);
2266-
2267-
if (entity && *entity && static_cast<DWORD>((*entity)->m_nModelIndex) == m_dwModelID)
2268-
{
2269-
// Call Fx_c::DestroyEntityFx
2270-
((void(__thiscall*)(CFxSAInterface*, CEntitySAInterface*))FUNC_Fx_c_DestroyEntityFx)(fx, *entity);
2326+
// Call Fx_c::DestroyEntityFx
2327+
((void(__thiscall*)(CFxSAInterface*, CEntitySAInterface*))FUNC_Fx_c_DestroyEntityFx)(fx, entity);
22712328

2272-
// Prevent creation when stream in but keep in memory so we can restore it later
2273-
effect->type = e2dEffectType::NONE;
2274-
}
2275-
2276-
lastParticle = prevParticle;
2329+
// Prevent creation when stream in but keep in memory so we can restore it later
2330+
effect->type = e2dEffectType::NONE;
22772331
}
22782332

2333+
entities.clear();
22792334
break;
22802335
}
22812336
case e2dEffectType::ESCALATOR:
@@ -2358,6 +2413,66 @@ C2DEffectSAInterface* CModelInfoSA::Get2DFXFromIndex(std::uint32_t index)
23582413
return ((C2DEffectSAInterface * (__thiscall*)(CBaseModelInfoSAInterface*, std::uint32_t index))FUNC_CBaseModelInfo_Get2dEffect)(m_pInterface, index);
23592414
}
23602415

2416+
void CModelInfoSA::CopyModified2DFXEffects()
2417+
{
2418+
CBaseModelInfoSAInterface* modelInfo = ppModelInfo[m_dwModelID];
2419+
if (!modelInfo || modelInfo->ucNumOf2DEffects == 0)
2420+
return;
2421+
2422+
// Has modified effects?
2423+
if (!MapContains(ms_DefaultEffectsMap, m_dwModelID))
2424+
return;
2425+
2426+
auto tempVec = std::vector<C2DEffectSAInterface*>();
2427+
std::uint32_t numEffects = MapGet(defaultNumOf2DFXEffects, m_dwModelID);
2428+
for (std::uint32_t i = 0; i < numEffects; i++)
2429+
{
2430+
auto effect = ((C2DEffectSAInterface * (__thiscall*)(CBaseModelInfoSAInterface*, std::uint32_t index)) FUNC_CBaseModelInfo_Get2dEffect)(modelInfo, i);
2431+
if (!effect)
2432+
continue;
2433+
2434+
// Copy effect
2435+
auto copy = new C2DEffectSAInterface();
2436+
MemCpyFast(copy, effect, sizeof(C2DEffectSAInterface));
2437+
tempVec.push_back(copy);
2438+
}
2439+
2440+
MapSet(tempCopy2dfxEffects, m_dwModelID, tempVec);
2441+
}
2442+
2443+
void CModelInfoSA::RestoreModified2DFXEffects()
2444+
{
2445+
if (!MapContains(tempCopy2dfxEffects, m_dwModelID))
2446+
return;
2447+
2448+
CBaseModelInfoSAInterface* modelInfo = ppModelInfo[m_dwModelID];
2449+
if (!modelInfo)
2450+
return;
2451+
2452+
std::uint32_t numEffects = MapGet(defaultNumOf2DFXEffects, m_dwModelID);
2453+
auto& tempVec = MapGet(tempCopy2dfxEffects, m_dwModelID);
2454+
if (tempVec.size() > 0)
2455+
{
2456+
for (std::uint32_t i = 0; i < numEffects; i++)
2457+
{
2458+
auto effect = ((C2DEffectSAInterface*(__thiscall*)(CBaseModelInfoSAInterface*, std::uint32_t index))FUNC_CBaseModelInfo_Get2dEffect)(modelInfo, i);
2459+
if (!effect)
2460+
continue;
2461+
2462+
if (tempVec[i])
2463+
{
2464+
MemCpyFast(effect, tempVec[i], sizeof(C2DEffectSAInterface));
2465+
delete tempVec[i];
2466+
}
2467+
2468+
Update2DFXEffect(effect);
2469+
}
2470+
}
2471+
2472+
tempVec.clear();
2473+
tempCopy2dfxEffects.erase(m_dwModelID);
2474+
}
2475+
23612476
//////////////////////////////////////////////////////////////////////////////////////////
23622477
//
23632478
// Hook for NodeNameStreamRead
@@ -2452,64 +2567,6 @@ static void _declspec(naked) HOOK_Get2dEffect()
24522567
}
24532568
}
24542569

2455-
void CModelInfoSA::CopyModified2DFXEffects()
2456-
{
2457-
CBaseModelInfoSAInterface* modelInfo = ppModelInfo[m_dwModelID];
2458-
if (!modelInfo || modelInfo->ucNumOf2DEffects == 0)
2459-
return;
2460-
2461-
// Has modified effects?
2462-
if (!MapContains(ms_DefaultEffectsMap, m_dwModelID))
2463-
return;
2464-
2465-
auto tempVec = std::vector<C2DEffectSAInterface*>();
2466-
std::uint32_t numEffects = MapGet(defaultNumOf2DFXEffects, m_dwModelID);
2467-
for (std::uint32_t i = 0; i < numEffects; i++)
2468-
{
2469-
auto effect = ((C2DEffectSAInterface * (__thiscall*)(CBaseModelInfoSAInterface*, std::uint32_t index))FUNC_CBaseModelInfo_Get2dEffect)(modelInfo, i);
2470-
if (!effect)
2471-
continue;
2472-
2473-
// Copy effect
2474-
auto copy = new C2DEffectSAInterface();
2475-
memcpy(copy, effect, sizeof(C2DEffectSAInterface));
2476-
tempVec.push_back(copy);
2477-
}
2478-
2479-
MapSet(tempCopy2dfxEffects, m_dwModelID, tempVec);
2480-
}
2481-
2482-
void CModelInfoSA::RestoreModified2DFXEffects()
2483-
{
2484-
if (!MapContains(tempCopy2dfxEffects, m_dwModelID))
2485-
return;
2486-
2487-
CBaseModelInfoSAInterface* modelInfo = ppModelInfo[m_dwModelID];
2488-
if (!modelInfo)
2489-
return;
2490-
2491-
std::uint32_t numEffects = MapGet(defaultNumOf2DFXEffects, m_dwModelID);
2492-
auto& tempVec = MapGet(tempCopy2dfxEffects, m_dwModelID);
2493-
if (tempVec.size() > 0)
2494-
{
2495-
for (std::uint32_t i = 0; i < numEffects; i++)
2496-
{
2497-
auto effect = ((C2DEffectSAInterface * (__thiscall*)(CBaseModelInfoSAInterface*, std::uint32_t index))FUNC_CBaseModelInfo_Get2dEffect)(modelInfo, i);
2498-
if (!effect)
2499-
continue;
2500-
2501-
if (tempVec[i])
2502-
{
2503-
memcpy(effect, tempVec[i], sizeof(C2DEffectSAInterface));
2504-
delete tempVec[i];
2505-
}
2506-
}
2507-
}
2508-
2509-
tempVec.clear();
2510-
tempCopy2dfxEffects.erase(m_dwModelID);
2511-
}
2512-
25132570
//////////////////////////////////////////////////////////////////////////////////////////
25142571
//
25152572
// Setup hooks

Client/game_sa/CModelInfoSA.h

+3
Original file line numberDiff line numberDiff line change
@@ -476,6 +476,9 @@ class CModelInfoSA : public CModelInfo
476476
bool RemoveAll2DFXEffects(bool includeDefault);
477477
C2DEffectSAInterface* Get2DFXFromIndex(std::uint32_t index);
478478
std::uint32_t Get2DFXCount() const { return m_pInterface ? m_pInterface->ucNumOf2DEffects : 0; }
479+
void Update2DFXEffect(C2DEffectSAInterface* effect);
480+
481+
static auto GetEntitiesFromFx(std::uint32_t modelID);
479482

480483
void StoreDefault2DFXEffect(C2DEffectSAInterface* effect);
481484
bool Reset2DFXEffects(bool removeCustomEffects = false);

Client/mods/deathmatch/logic/CClient2DFX.h

+2-1
Original file line numberDiff line numberDiff line change
@@ -31,10 +31,11 @@ class CClient2DFX final : public CClientEntity
3131

3232
e2dEffectType Get2DFXType() const noexcept { return m_effectType; }
3333
C2DEffectSAInterface* Get2DFX() const noexcept { return m_effectInterface; }
34+
std::uint32_t GetModelID() const noexcept { return m_model; }
3435

3536
private:
3637
class CClient2DFXManager* m_2DFXManager;
3738
C2DEffectSAInterface* m_effectInterface;
3839
e2dEffectType m_effectType;
39-
DWORD m_model;
40+
std::uint32_t m_model;
4041
};

Client/mods/deathmatch/logic/luadefs/CLua2DFXDefs.cpp

+30-4
Original file line numberDiff line numberDiff line change
@@ -142,16 +142,29 @@ bool CLua2DFXDefs::SetModel2DFXProperties(std::uint32_t modelID, std::uint32_t i
142142
throw LuaFunctionError(error);
143143

144144
modelInfo->StoreDefault2DFXEffect(effect);
145-
return m_p2DFXManager->Set2DFXProperties(effect, effectData);
145+
146+
if (!m_p2DFXManager->Set2DFXProperties(effect, effectData))
147+
return false;
148+
149+
modelInfo->Update2DFXEffect(effect);
150+
return true;
146151
}
147152

148153
bool CLua2DFXDefs::Set2DFXProperties(CClient2DFX* effect, effectDataMap effectData)
149154
{
155+
CModelInfo* modelInfo = g_pGame->GetModelInfo(effect->GetModelID());
156+
if (!modelInfo)
157+
return false;
158+
150159
const char* error = CClient2DFXManager::IsValidEffectData(effect->Get2DFXType(), effectData);
151160
if (error)
152161
throw LuaFunctionError(error);
153162

154-
return m_p2DFXManager->Set2DFXProperties(effect->Get2DFX(), effectData);
163+
if (!m_p2DFXManager->Set2DFXProperties(effect->Get2DFX(), effectData))
164+
return false;
165+
166+
modelInfo->Update2DFXEffect(effect->Get2DFX());
167+
return true;
155168
}
156169

157170
bool CLua2DFXDefs::SetModel2DFXProperty(std::uint32_t modelID, std::uint32_t index, e2dEffectProperty property, std::variant<bool, float, std::string> propertyValue)
@@ -172,12 +185,25 @@ bool CLua2DFXDefs::SetModel2DFXProperty(std::uint32_t modelID, std::uint32_t ind
172185
return false;
173186

174187
modelInfo->StoreDefault2DFXEffect(effect);
175-
return m_p2DFXManager->Set2DFXProperty(effect, property, propertyValue);
188+
189+
if (!m_p2DFXManager->Set2DFXProperty(effect, property, propertyValue))
190+
return false;
191+
192+
modelInfo->Update2DFXEffect(effect);
193+
return true;
176194
}
177195

178196
bool CLua2DFXDefs::Set2DFXProperty(CClient2DFX* effect, e2dEffectProperty property, std::variant<bool, float, std::string> propertyValue)
179197
{
180-
return m_p2DFXManager->Set2DFXProperty(effect->Get2DFX(), property, propertyValue);
198+
CModelInfo* modelInfo = g_pGame->GetModelInfo(effect->GetModelID());
199+
if (!modelInfo)
200+
return false;
201+
202+
if (!m_p2DFXManager->Set2DFXProperty(effect->Get2DFX(), property, propertyValue))
203+
return false;
204+
205+
modelInfo->Update2DFXEffect(effect->Get2DFX());
206+
return true;
181207
}
182208

183209
bool CLua2DFXDefs::SetModel2DFXPosition(std::uint32_t modelID, std::uint32_t index, CVector position)

0 commit comments

Comments
 (0)