@@ -45,6 +45,7 @@ static std::unordered_map<DWORD, std::uint8_t>
45
45
static std::unordered_map<DWORD, std::vector<C2DEffectSAInterface*>> tempCopy2dfxEffects;
46
46
47
47
int C2DEffectSA::effect2dPluginOffset = *(int *)0xC3A1E0 ; // g2dEffectPluginOffset
48
+ static auto * fx = reinterpret_cast <CFxSAInterface*>(VAR_G_Fx);
48
49
49
50
union tIdeFlags
50
51
{
@@ -1196,7 +1197,7 @@ void CModelInfoSA::StaticReset2DFXEffects()
1196
1197
for (auto innerIter = iter->second .begin (); innerIter != iter->second .end ();)
1197
1198
{
1198
1199
// Copy default effect
1199
- memcpy (innerIter->first , innerIter->second , sizeof (C2DEffectSAInterface));
1200
+ MemCpy (innerIter->first , innerIter->second , sizeof (C2DEffectSAInterface));
1200
1201
1201
1202
// Increase the counter if this effect was removed
1202
1203
auto & removedEffect = std::find (removedDefault2dfxEffects.begin (), removedDefault2dfxEffects.end (), innerIter->first );
@@ -1218,12 +1219,18 @@ void CModelInfoSA::StaticReset2DFXEffects()
1218
1219
modelInfoInterface->ucNumOf2DEffects -= customEffectsCount;
1219
1220
1220
1221
MapSet (numCustom2dfxEffects, modelInfoInterface, 0 );
1222
+
1223
+ // Destroy copies
1224
+ auto & copies = MapGet (tempCopy2dfxEffects, iter->first );
1225
+ for (auto copy : copies)
1226
+ delete copy;
1221
1227
}
1222
1228
1223
- // Clear maps
1229
+ // Clear maps & vectors
1224
1230
removedDefault2dfxEffects.clear ();
1225
1231
ms_DefaultEffectsMap.clear ();
1226
1232
d2fxEffects.clear ();
1233
+ tempCopy2dfxEffects.clear ();
1227
1234
}
1228
1235
1229
1236
short CModelInfoSA::GetAvailableVehicleMod (unsigned short usUpgrade)
@@ -2115,6 +2122,55 @@ bool CModelInfoSA::ForceUnload()
2115
2122
return true ;
2116
2123
}
2117
2124
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
+
2118
2174
void CModelInfoSA::StoreDefault2DFXEffect (C2DEffectSAInterface* effect)
2119
2175
{
2120
2176
if (MapContains (ms_DefaultEffectsMap, m_dwModelID) && MapContains (MapGet (ms_DefaultEffectsMap, m_dwModelID), effect))
@@ -2125,7 +2181,7 @@ void CModelInfoSA::StoreDefault2DFXEffect(C2DEffectSAInterface* effect)
2125
2181
2126
2182
// Copy an existing default effect
2127
2183
C2DEffectSAInterface* copy = new C2DEffectSAInterface ();
2128
- memcpy (copy, effect, sizeof (C2DEffectSAInterface));
2184
+ MemCpyFast (copy, effect, sizeof (C2DEffectSAInterface));
2129
2185
2130
2186
// Create a copy of textures for the lights
2131
2187
// We must to do this, because C2DEffect::Shutdown removes them
@@ -2160,7 +2216,7 @@ bool CModelInfoSA::Reset2DFXEffects(bool removeCustomEffects)
2160
2216
for (auto & it = map.begin (); it != map.end ();)
2161
2217
{
2162
2218
// Copy data from copied effect to the default
2163
- memcpy (it->first , it->second , sizeof (C2DEffectSAInterface));
2219
+ MemCpyFast (it->first , it->second , sizeof (C2DEffectSAInterface));
2164
2220
2165
2221
// Increase the counter if this effect was removed
2166
2222
auto & removedEffect = std::find (removedDefault2dfxEffects.begin (), removedDefault2dfxEffects.end (), it->first );
@@ -2170,15 +2226,23 @@ bool CModelInfoSA::Reset2DFXEffects(bool removeCustomEffects)
2170
2226
m_pInterface->ucNumOf2DEffects ++;
2171
2227
}
2172
2228
2229
+ Update2DFXEffect (it->first );
2230
+
2173
2231
// We no longer need a copy
2174
2232
// So delete it
2175
2233
delete it->second ;
2176
2234
it = map.erase (it);
2177
2235
}
2178
2236
2237
+ // Delete temp copies
2238
+ auto & copies = MapGet (tempCopy2dfxEffects, m_dwModelID);
2239
+ for (auto * copy : copies)
2240
+ delete copy;
2241
+
2179
2242
// Clear maps
2180
2243
map.clear ();
2181
2244
ms_DefaultEffectsMap.erase (m_dwModelID);
2245
+ tempCopy2dfxEffects.erase (m_dwModelID);
2182
2246
2183
2247
// Remove all custom effects
2184
2248
if (removeCustomEffects)
@@ -2256,26 +2320,17 @@ bool CModelInfoSA::Remove2DFX(C2DEffectSAInterface* effect, bool includeDefault)
2256
2320
}
2257
2321
case e2dEffectType::PARTICLE:
2258
2322
{
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)
2263
2325
{
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);
2271
2328
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;
2277
2331
}
2278
2332
2333
+ entities.clear ();
2279
2334
break ;
2280
2335
}
2281
2336
case e2dEffectType::ESCALATOR:
@@ -2358,6 +2413,66 @@ C2DEffectSAInterface* CModelInfoSA::Get2DFXFromIndex(std::uint32_t index)
2358
2413
return ((C2DEffectSAInterface * (__thiscall*)(CBaseModelInfoSAInterface*, std::uint32_t index ))FUNC_CBaseModelInfo_Get2dEffect)(m_pInterface, index );
2359
2414
}
2360
2415
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
+
2361
2476
// ////////////////////////////////////////////////////////////////////////////////////////
2362
2477
//
2363
2478
// Hook for NodeNameStreamRead
@@ -2452,64 +2567,6 @@ static void _declspec(naked) HOOK_Get2dEffect()
2452
2567
}
2453
2568
}
2454
2569
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
-
2513
2570
// ////////////////////////////////////////////////////////////////////////////////////////
2514
2571
//
2515
2572
// Setup hooks
0 commit comments