diff --git a/Client/game_sa/CBuildingsPoolSA.cpp b/Client/game_sa/CBuildingsPoolSA.cpp index 6f15dc87e1..b8363f6507 100644 --- a/Client/game_sa/CBuildingsPoolSA.cpp +++ b/Client/game_sa/CBuildingsPoolSA.cpp @@ -40,10 +40,10 @@ inline bool CBuildingsPoolSA::AddBuildingToPool(CClientBuilding* pClientBuilding if (dwElementIndexInPool == UINT_MAX) return false; - m_buildingPool.arrayOfClientEntities[dwElementIndexInPool] = {pBuilding, (CClientEntity*)pClientBuilding}; + m_buildingPool.entities[dwElementIndexInPool] = {pBuilding, (CClientEntity*)pClientBuilding}; // Increase the count of objects - ++m_buildingPool.ulCount; + ++m_buildingPool.count; return true; } @@ -108,8 +108,8 @@ void CBuildingsPoolSA::RemoveBuilding(CBuilding* pBuilding) modelInfo->RemoveColRef(); // Remove from BuildingSA pool - auto* pBuildingSA = m_buildingPool.arrayOfClientEntities[dwElementIndexInPool].pEntity; - m_buildingPool.arrayOfClientEntities[dwElementIndexInPool] = {nullptr, nullptr}; + auto* pBuildingSA = m_buildingPool.entities[dwElementIndexInPool].pEntity; + m_buildingPool.entities[dwElementIndexInPool] = {nullptr, nullptr}; // Delete it from memory delete pBuildingSA; @@ -118,7 +118,7 @@ void CBuildingsPoolSA::RemoveBuilding(CBuilding* pBuilding) (*m_ppBuildingPoolInterface)->Release(dwElementIndexInPool); // Decrease the count of elements in the pool - --m_buildingPool.ulCount; + --m_buildingPool.count; } void CBuildingsPoolSA::RemoveAllBuildings() @@ -191,7 +191,9 @@ void CBuildingsPoolSA::RemoveBuildingFromWorld(CBuildingSAInterface* pBuilding) bool CBuildingsPoolSA::Resize(int size) { auto* pool = (*m_ppBuildingPoolInterface); - const int curretnSize = pool->m_nSize; + const int currentSize = pool->m_nSize; + + m_buildingPool.entities.resize(size); void* oldPool = pool->m_pObjects; @@ -210,7 +212,7 @@ bool CBuildingsPoolSA::Resize(int size) CBuildingSAInterface* newObjects = MemSA::malloc_struct(size); if (newObjects == nullptr) { - Resize(curretnSize); + Resize(currentSize); return false; } @@ -218,7 +220,7 @@ bool CBuildingsPoolSA::Resize(int size) if (newBytemap == nullptr) { MemSA::free(newObjects); - Resize(curretnSize); + Resize(currentSize); return false; } @@ -322,6 +324,7 @@ void CBuildingsPoolSA::RemovePedsContactEnityLinks() CPedSAInterface* ped = pedLinks->pEntity->GetPedInterface(); ped->m_pCollidedEntity = nullptr; ped->pContactEntity = nullptr; + ped->pLastContactEntity = nullptr; ped->pLastContactedEntity[0] = nullptr; ped->pLastContactedEntity[1] = nullptr; ped->pLastContactedEntity[2] = nullptr; diff --git a/Client/game_sa/CBuildingsPoolSA.h b/Client/game_sa/CBuildingsPoolSA.h index 9f38202243..5ce719bd73 100644 --- a/Client/game_sa/CBuildingsPoolSA.h +++ b/Client/game_sa/CBuildingsPoolSA.h @@ -40,8 +40,8 @@ class CBuildingsPoolSA : public CBuildingsPool void RemovePedsContactEnityLinks(); private: - SPoolData m_buildingPool; - CPoolSAInterface** m_ppBuildingPoolInterface; + SVectorPoolData m_buildingPool{MAX_BUILDINGS}; + CPoolSAInterface** m_ppBuildingPoolInterface; std::unique_ptr, MAX_BUILDINGS>> m_pOriginalBuildingsBackup; }; diff --git a/Client/game_sa/CFxSA.cpp b/Client/game_sa/CFxSA.cpp index dca7844fdf..b063cb927d 100644 --- a/Client/game_sa/CFxSA.cpp +++ b/Client/game_sa/CFxSA.cpp @@ -239,3 +239,93 @@ void CFxSA::TriggerFootSplash(CVector& vecPosition) call dwFunc } } + +void CFxSA::AddParticle(eFxParticleSystems eFxParticle, const CVector& vecPosition, const CVector& vecDirection, float fR, float fG, float fB, float fA, bool bRandomizeColors, std::uint32_t iCount, float fBrightness, float fSize, bool bRandomizeSizes, float fLife) +{ + // Init our own FxPrtMult struct + FxPrtMult_c fxPrt{{fR,fG,fB,fA}, fSize, 0, fLife}; + CVector newDirection; + + FxSystem_c* fxParticleSystem; + + switch (eFxParticle) + { + case eFxParticleSystems::PRT_BLOOD: + fxParticleSystem = m_pInterface->m_fxSysBlood; + break; + case eFxParticleSystems::PRT_BOATSPLASH: + fxParticleSystem = m_pInterface->m_fxSysBoatSplash; + break; + case eFxParticleSystems::PRT_BUBBLE: + fxParticleSystem = m_pInterface->m_fxSysBubble; + break; + case eFxParticleSystems::PRT_DEBRIS: + fxParticleSystem = m_pInterface->m_fxSysDebris; + break; + case eFxParticleSystems::PRT_GUNSHELL: + fxParticleSystem = m_pInterface->m_fxSysGunshell; + break; + case eFxParticleSystems::PRT_SAND: + fxParticleSystem = m_pInterface->m_fxSysSand; + break; + case eFxParticleSystems::PRT_SAND2: + fxParticleSystem = m_pInterface->m_fxSysSand2; + break; + case eFxParticleSystems::PRT_SMOKE: + fxParticleSystem = m_pInterface->m_fxSysSmoke; + break; + case eFxParticleSystems::PRT_SMOKEHUGE: + fxParticleSystem = m_pInterface->m_fxSysSmokeHuge; + break; + case eFxParticleSystems::PRT_SMOKE2: + fxParticleSystem = m_pInterface->m_fxSysSmoke2; + break; + case eFxParticleSystems::PRT_SPARK: + fxParticleSystem = m_pInterface->m_fxSysSpark; + break; + case eFxParticleSystems::PRT_SPARK2: + fxParticleSystem = m_pInterface->m_fxSysSpark2; + break; + case eFxParticleSystems::PRT_SPLASH: + fxParticleSystem = m_pInterface->m_fxSysSplash; + break; + case eFxParticleSystems::PRT_WAKE: + fxParticleSystem = m_pInterface->m_fxSysWake; + break; + case eFxParticleSystems::PRT_WATERSPLASH: + fxParticleSystem = m_pInterface->m_fxSysWaterSplash; + break; + case eFxParticleSystems::PRT_WHEELDIRT: + fxParticleSystem = m_pInterface->m_fxSysWheelDirt; + break; + case eFxParticleSystems::PRT_GLASS: + fxParticleSystem = m_pInterface->m_fxSysGlass; + break; + default: + fxParticleSystem = m_pInterface->m_fxSysBlood; + } + + for (size_t i = 0; i < iCount; i++) + { + if (bRandomizeColors) + { + // 0x49EECB + fxPrt.m_color.red = (rand() % 10000) * 0.0001f * fR + 0.13f; + fxPrt.m_color.green = (rand() % 10000) * 0.0001f * fG + 0.12f; + fxPrt.m_color.blue = (rand() % 10000) * 0.0001f * fB + 0.04f; + } + + if (bRandomizeSizes) + // 0x49EF21 - Calculate random size for each particle + fxPrt.m_fSize = (rand() % 10000) * 0.0001f * fSize + 0.3f; + + // 0x49EF4C - Calculate random direction for each particle + newDirection = CVector(vecDirection.fX * 4, vecDirection.fY * 4, vecDirection.fZ * 4); + newDirection.fX = (rand() % 10000) * 0.0001f * 4 - 2 + newDirection.fX; + newDirection.fY = (rand() % 10000) * 0.0001f * 4 - 2 + newDirection.fY; + newDirection.fZ = (rand() % 10000) * 0.0001f * 4 - 2 + newDirection.fZ; + + // Call FxSystem_c::AddParticle + ((int(__thiscall*)(FxSystem_c*, const CVector*, const CVector*, float, FxPrtMult_c*, float, float, float, int))FUNC_FXSystem_c_AddParticle)(fxParticleSystem, &vecPosition, &newDirection, 0, &fxPrt, -1.0f, fBrightness, 0, 0); + } +} diff --git a/Client/game_sa/CFxSA.h b/Client/game_sa/CFxSA.h index 55b56b83f2..7d61c1759a 100644 --- a/Client/game_sa/CFxSA.h +++ b/Client/game_sa/CFxSA.h @@ -14,6 +14,7 @@ #include struct RwColor; +class FxSystem_c; #define FUNC_CFx_AddBlood 0x49eb00 #define FUNC_CFx_AddWood 0x49ee10 @@ -29,10 +30,30 @@ struct RwColor; #define FUNC_CFx_TriggerWaterSplash 0x4a1070 #define FUNC_CFx_TriggerBulletSplash 0x4a10e0 #define FUNC_CFx_TriggerFootSplash 0x4a1150 +#define FUNC_FXSystem_c_AddParticle 0x4AA440 class CFxSAInterface { public: + FxSystem_c* m_fxSysBlood; + FxSystem_c* m_fxSysBoatSplash; + FxSystem_c* m_fxSysBubble; + FxSystem_c* m_fxSysDebris; + FxSystem_c* m_fxSysSmoke; + FxSystem_c* m_fxSysGunshell; + FxSystem_c* m_fxSysSand; + FxSystem_c* m_fxSysSand2; + FxSystem_c* m_fxSysSmokeHuge; + FxSystem_c* m_fxSysSmoke2; + FxSystem_c* m_fxSysSpark; + FxSystem_c* m_fxSysSpark2; + FxSystem_c* m_fxSysSplash; + FxSystem_c* m_fxSysWake; + FxSystem_c* m_fxSysWaterSplash; + FxSystem_c* m_fxSysWheelDirt; + FxSystem_c* m_fxSysGlass; + +private: }; class CFxSA : public CFx @@ -55,7 +76,23 @@ class CFxSA : public CFx void TriggerWaterSplash(CVector& vecPosition); void TriggerBulletSplash(CVector& vecPosition); void TriggerFootSplash(CVector& vecPosition); + void AddParticle(eFxParticleSystems eFxParticle, const CVector& vecPosition, const CVector& vecDirection, float fR, float fG, float fB, float fA, bool bRandomizeColors, std::uint32_t iCount, float fBrightness, float fSize, bool bRandomizeSizes, float fLife); private: CFxSAInterface* m_pInterface; + + struct FxPrtMult_c + { + struct + { + float red; + float green; + float blue; + float alpha; + } m_color; + + float m_fSize; + float unk; + float m_fLife; + }; }; diff --git a/Client/game_sa/CModelInfoSA.cpp b/Client/game_sa/CModelInfoSA.cpp index da81fb4f23..5dc00712da 100644 --- a/Client/game_sa/CModelInfoSA.cpp +++ b/Client/game_sa/CModelInfoSA.cpp @@ -1992,11 +1992,7 @@ void CModelInfoSA::SetObjectPropertiesGroup(unsigned short usNewGroup) unsigned short CModelInfoSA::GetObjectPropertiesGroup() { - unsigned short usGroup = GetInterface()->usDynamicIndex; - if (usGroup == 0xFFFF) - usGroup = 0; - - return usGroup; + return GetInterface()->usDynamicIndex; } void CModelInfoSA::RestoreObjectPropertiesGroup() diff --git a/Client/game_sa/CPedSA.h b/Client/game_sa/CPedSA.h index 5082eca7f9..5d7c8044ed 100644 --- a/Client/game_sa/CPedSA.h +++ b/Client/game_sa/CPedSA.h @@ -242,11 +242,11 @@ class CPedSAInterface : public CPhysicalSAInterface // +1420 = curre float fTargetRotation; float fRotationSpeed; float fMoveAnim; - CPedSAInterface* unkPed; + CEntitySAInterface* pContactEntity; CVector unk_56C; CVector unk_578; - CEntitySAInterface* pContactEntity; + CEntitySAInterface* pLastContactEntity; CVehicleSAInterface* pLastVehicle; CVehicleSAInterface* pVehicle; diff --git a/Client/game_sa/CPoolSAInterface.h b/Client/game_sa/CPoolSAInterface.h index 8b653aefc1..9f48bc63d3 100644 --- a/Client/game_sa/CPoolSAInterface.h +++ b/Client/game_sa/CPoolSAInterface.h @@ -149,3 +149,16 @@ struct SPoolData } } }; + +template +struct SVectorPoolData +{ + std::vector> entities; + size_t count; + +public: + SVectorPoolData(size_t defaultSize) : count(0) + { + entities.resize(defaultSize, {nullptr, nullptr}); + } +}; diff --git a/Client/mods/deathmatch/logic/CClientBuildingManager.cpp b/Client/mods/deathmatch/logic/CClientBuildingManager.cpp index 5fe42baf23..198fd23ed2 100644 --- a/Client/mods/deathmatch/logic/CClientBuildingManager.cpp +++ b/Client/mods/deathmatch/logic/CClientBuildingManager.cpp @@ -11,6 +11,8 @@ #include "StdInc.h" constexpr float WORLD_DISTANCE_FROM_CENTER = 3000.0f; +constexpr size_t PRESERVED_POOL_SIZE = 2000; +constexpr size_t RESIZE_POOL_STEP = 5000; CClientBuildingManager::CClientBuildingManager(CClientManager* pManager) { @@ -99,12 +101,72 @@ void CClientBuildingManager::RestoreDestroyed() for (CClientBuilding* building : GetBuildings()) { building->Create(); + } +} + +void CClientBuildingManager::ResizePoolIfNeeds() +{ + const int currentUsed = g_pGame->GetPools()->GetNumberOfUsedSpaces(ePools::BUILDING_POOL); + const int currentCapacity = g_pGame->GetPools()->GetPoolCapacity(ePools::BUILDING_POOL); + + if (currentCapacity - currentUsed < PRESERVED_POOL_SIZE) + { + DoPoolResize(currentCapacity + RESIZE_POOL_STEP); + } +} + +bool CClientBuildingManager::SetPoolCapacity(size_t newCapacity) +{ + const int currentUsed = g_pGame->GetPools()->GetNumberOfUsedSpaces(ePools::BUILDING_POOL); + + if (newCapacity - currentUsed < PRESERVED_POOL_SIZE) + return false; + + return DoPoolResize(newCapacity); +} + +bool CClientBuildingManager::DoPoolResize(size_t newCapacity) +{ + DestroyAllForABit(); - if (!building->IsValid()) - { - // User creates too much buildings - // We can't restore them all - delete building; - } + bool success = g_pGame->SetBuildingPoolSize(newCapacity); + + RestoreDestroyed(); + + return success; +} + + +void CClientBuildingManager::RemoveAllGameBuildings() +{ + // We do not want to remove scripted buildings + // But we need remove them from the buildings pool for a bit... + DestroyAllForABit(); + + // This function makes buildings backup without scripted buildings + g_pGame->RemoveAllBuildings(); + + // ... And restore here + RestoreDestroyed(); +} + +void CClientBuildingManager::RestoreAllGameBuildings() +{ + // We want to restore the game buildings to the same positions as they were before the backup. + // Remove scripted buildings for a bit + DestroyAllForABit(); + + g_pGame->RestoreGameBuildings(); + + // Resize the building pool if we need + const int currentUsed = g_pGame->GetPools()->GetNumberOfUsedSpaces(ePools::BUILDING_POOL) + m_List.size(); + const int currentCapacity = g_pGame->GetPools()->GetPoolCapacity(ePools::BUILDING_POOL); + + if (currentCapacity - currentUsed < PRESERVED_POOL_SIZE) + { + DoPoolResize(currentUsed + PRESERVED_POOL_SIZE); } + + // Restore + RestoreDestroyed(); } diff --git a/Client/mods/deathmatch/logic/CClientBuildingManager.h b/Client/mods/deathmatch/logic/CClientBuildingManager.h index 9a649dd5dd..050cff9f96 100644 --- a/Client/mods/deathmatch/logic/CClientBuildingManager.h +++ b/Client/mods/deathmatch/logic/CClientBuildingManager.h @@ -31,10 +31,17 @@ class CClientBuildingManager static bool IsValidModel(uint16_t modelId); static bool IsValidPosition(const CVector& pos) noexcept; + void ResizePoolIfNeeds(); + bool SetPoolCapacity(size_t newCapacity); + + void RemoveAllGameBuildings(); + void RestoreAllGameBuildings(); + +private: void DestroyAllForABit(); void RestoreDestroyed(); -private: + bool DoPoolResize(size_t newCapacity); void AddToList(CClientBuilding* pBuilding) { m_List.push_back(pBuilding); } void RemoveFromList(CClientBuilding* pBuilding); diff --git a/Client/mods/deathmatch/logic/CClientSound.cpp b/Client/mods/deathmatch/logic/CClientSound.cpp index dc10132e4b..052071a97a 100644 --- a/Client/mods/deathmatch/logic/CClientSound.cpp +++ b/Client/mods/deathmatch/logic/CClientSound.cpp @@ -147,6 +147,10 @@ bool CClientSound::Create() m_pAudio->SetPanEnabled(m_bPan); m_pAudio->SetPan(m_fPan); + // Also check and transfer if paused + if (m_bPaused) + m_pAudio->SetPaused(m_bPaused); + // Transfer play position if it was being simulated EndSimulationOfPlayPositionAndApply(); diff --git a/Client/mods/deathmatch/logic/CStaticFunctionDefinitions.cpp b/Client/mods/deathmatch/logic/CStaticFunctionDefinitions.cpp index c42156883b..fd0a2dcd76 100644 --- a/Client/mods/deathmatch/logic/CStaticFunctionDefinitions.cpp +++ b/Client/mods/deathmatch/logic/CStaticFunctionDefinitions.cpp @@ -7926,6 +7926,12 @@ bool CStaticFunctionDefinitions::FxAddFootSplash(CVector& vecPosition) return true; } +bool CStaticFunctionDefinitions::FxCreateParticle(eFxParticleSystems eFxParticle, CVector& vecPosition, CVector& vecDirection, float fR, float fG, float fB, float fA, bool bRandomizeColors, std::uint32_t iCount, float fBrightness, float fSize, bool bRandomizeSizes, float fLife) +{ + g_pGame->GetFx()->AddParticle(eFxParticle, vecPosition, vecDirection, fR, fG, fB, fA, bRandomizeColors, iCount, fBrightness, fSize, bRandomizeSizes, fLife); + return true; +} + CClientEffect* CStaticFunctionDefinitions::CreateEffect(CResource& Resource, const SString& strFxName, const CVector& vecPosition, bool bSoundEnable) { CClientEffect* pFx = m_pManager->GetEffectManager()->Create(strFxName, vecPosition, INVALID_ELEMENT_ID, bSoundEnable); diff --git a/Client/mods/deathmatch/logic/CStaticFunctionDefinitions.h b/Client/mods/deathmatch/logic/CStaticFunctionDefinitions.h index 437e4503f6..2ffe1ff0a5 100644 --- a/Client/mods/deathmatch/logic/CStaticFunctionDefinitions.h +++ b/Client/mods/deathmatch/logic/CStaticFunctionDefinitions.h @@ -729,6 +729,7 @@ class CStaticFunctionDefinitions static bool FxAddWaterSplash(CVector& vecPosition); static bool FxAddBulletSplash(CVector& vecPosition); static bool FxAddFootSplash(CVector& vecPosition); + static bool FxCreateParticle(eFxParticleSystems eFxParticle, CVector& vecPosition, CVector& vecDirection, float fR, float fG, float fB, float fA, bool bRandomizeColors, std::uint32_t iCount, float fBrightness, float fSize, bool bRandomizeSizes, float fLife); static CClientEffect* CreateEffect(CResource& Resource, const SString& strFxName, const CVector& vecPosition, bool bSoundEnable); // Sound funcs diff --git a/Client/mods/deathmatch/logic/lua/CLuaFunctionParseHelpers.cpp b/Client/mods/deathmatch/logic/lua/CLuaFunctionParseHelpers.cpp index e037494a1b..2ff7d9bd7d 100644 --- a/Client/mods/deathmatch/logic/lua/CLuaFunctionParseHelpers.cpp +++ b/Client/mods/deathmatch/logic/lua/CLuaFunctionParseHelpers.cpp @@ -853,6 +853,26 @@ ADD_ENUM(ePools::ENV_MAP_ATOMIC_POOL, "env-map-atomic") ADD_ENUM(ePools::SPEC_MAP_MATERIAL_POOL, "spec-map-material") IMPLEMENT_ENUM_END("gta-pool") +IMPLEMENT_ENUM_CLASS_BEGIN(eFxParticleSystems) +ADD_ENUM(eFxParticleSystems::PRT_BLOOD, "blood") +ADD_ENUM(eFxParticleSystems::PRT_BOATSPLASH, "boat_splash") +ADD_ENUM(eFxParticleSystems::PRT_BUBBLE, "bubble") +ADD_ENUM(eFxParticleSystems::PRT_DEBRIS, "car_debris") +ADD_ENUM(eFxParticleSystems::PRT_SMOKE, "collision_smoke") +ADD_ENUM(eFxParticleSystems::PRT_GUNSHELL, "gunshell") +ADD_ENUM(eFxParticleSystems::PRT_SAND, "sand") +ADD_ENUM(eFxParticleSystems::PRT_SAND2, "sand2") +ADD_ENUM(eFxParticleSystems::PRT_SMOKEHUGE, "huge_smoke") +ADD_ENUM(eFxParticleSystems::PRT_SMOKE2, "smoke") +ADD_ENUM(eFxParticleSystems::PRT_SPARK, "spark") +ADD_ENUM(eFxParticleSystems::PRT_SPARK2, "spark2") +ADD_ENUM(eFxParticleSystems::PRT_SPLASH, "splash") +ADD_ENUM(eFxParticleSystems::PRT_WAKE, "wake") +ADD_ENUM(eFxParticleSystems::PRT_WATERSPLASH, "water_splash") +ADD_ENUM(eFxParticleSystems::PRT_WHEELDIRT, "wheel_dirt") +ADD_ENUM(eFxParticleSystems::PRT_GLASS, "glass") +IMPLEMENT_ENUM_CLASS_END("particle-system") + // // CResource from userdata // diff --git a/Client/mods/deathmatch/logic/lua/CLuaFunctionParseHelpers.h b/Client/mods/deathmatch/logic/lua/CLuaFunctionParseHelpers.h index 3c8af2144c..aae4e759e5 100644 --- a/Client/mods/deathmatch/logic/lua/CLuaFunctionParseHelpers.h +++ b/Client/mods/deathmatch/logic/lua/CLuaFunctionParseHelpers.h @@ -82,6 +82,7 @@ DECLARE_ENUM_CLASS(eSoundEffectParams::Reverb); DECLARE_ENUM_CLASS(eModelIdeFlag); DECLARE_ENUM_CLASS(_D3DFORMAT); DECLARE_ENUM_CLASS(eRenderStage); +DECLARE_ENUM_CLASS(eFxParticleSystems); DECLARE_ENUM(ePools); class CRemoteCall; diff --git a/Client/mods/deathmatch/logic/luadefs/CLuaBuildingDefs.cpp b/Client/mods/deathmatch/logic/luadefs/CLuaBuildingDefs.cpp index e48121b6ec..f45efbf09c 100644 --- a/Client/mods/deathmatch/logic/luadefs/CLuaBuildingDefs.cpp +++ b/Client/mods/deathmatch/logic/luadefs/CLuaBuildingDefs.cpp @@ -45,14 +45,13 @@ CClientBuilding* CLuaBuildingDefs::CreateBuilding(lua_State* const luaVM, uint16 if (!CClientBuildingManager::IsValidModel(modelId)) throw std::invalid_argument("Invalid building model id"); - if (!g_pGame->GetPools()->GetBuildingsPool().HasFreeBuildingSlot()) - throw std::invalid_argument("No free slot in buildings pool"); - if (!CClientBuildingManager::IsValidPosition(pos)) throw std::invalid_argument("Position is outside of game world"); ConvertDegreesToRadians(rot); + m_pBuildingManager->ResizePoolIfNeeds(); + CClientBuilding* pBuilding = new CClientBuilding(m_pManager, INVALID_ELEMENT_ID, modelId, pos, rot, interior.value_or(0)); CClientEntity* pRoot = pResource->GetResourceDynamicEntity(); @@ -63,25 +62,10 @@ CClientBuilding* CLuaBuildingDefs::CreateBuilding(lua_State* const luaVM, uint16 void CLuaBuildingDefs::RemoveAllGameBuildings() { - // We do not want to remove scripted buildings - // But we need remove them from the buildings pool for a bit... - m_pBuildingManager->DestroyAllForABit(); - - // This function makes buildings backup without scripted buildings - g_pGame->RemoveAllBuildings(); - - // ... And restore here - m_pBuildingManager->RestoreDestroyed(); + m_pBuildingManager->RemoveAllGameBuildings(); } void CLuaBuildingDefs::RestoreGameBuildings() { - // We want to restore the game buildings to the same positions as they were before the backup. - // Remove scripted buildings for a bit - m_pBuildingManager->DestroyAllForABit(); - - g_pGame->RestoreGameBuildings(); - - // Restore what we can - m_pBuildingManager->RestoreDestroyed(); + m_pBuildingManager->RestoreAllGameBuildings(); } diff --git a/Client/mods/deathmatch/logic/luadefs/CLuaEffectDefs.cpp b/Client/mods/deathmatch/logic/luadefs/CLuaEffectDefs.cpp index 5b9940a01a..fb1a5e3dfe 100644 --- a/Client/mods/deathmatch/logic/luadefs/CLuaEffectDefs.cpp +++ b/Client/mods/deathmatch/logic/luadefs/CLuaEffectDefs.cpp @@ -10,6 +10,7 @@ *****************************************************************************/ #include "StdInc.h" +#include "lua/CLuaFunctionParser.h" void CLuaEffectDefs::LoadFunctions() { @@ -33,6 +34,7 @@ void CLuaEffectDefs::LoadFunctions() {"getEffectSpeed", GetEffectSpeed}, {"setEffectDensity", SetEffectDensity}, {"getEffectDensity", GetEffectDensity}, + {"fxCreateParticle", ArgumentParser}, }; // Add functions @@ -59,6 +61,7 @@ void CLuaEffectDefs::AddClass(lua_State* luaVM) lua_classfunction(luaVM, "addWaterHydrant", "fxAddWaterHydrant"); lua_classfunction(luaVM, "addWaterSplash", "fxAddWaterSplash"); lua_classfunction(luaVM, "addWood", "fxAddWood"); + lua_classfunction(luaVM, "createParticle", "fxCreateParticle"); lua_classfunction(luaVM, "setDensity", "setEffectDensity"); lua_classfunction(luaVM, "setSpeed", "setEffectSpeed"); @@ -639,3 +642,8 @@ int CLuaEffectDefs::SetEffectDensity(lua_State* luaVM) lua_pushboolean(luaVM, false); return 1; } + +bool CLuaEffectDefs::FxCreateParticle(eFxParticleSystems eParticleSystem, CVector vecPosition, CVector vecDirection, float fR, float fG, float fB, float fA, std::optional bRandomizeColors, std::optional iCount, std::optional fBrightness, std::optional fSize, std::optional bRandomizeSizes, std::optional fLife) +{ + return CStaticFunctionDefinitions::FxCreateParticle(eParticleSystem, vecPosition, vecDirection, fR/255, fG/255, fB/255, fA/255, bRandomizeColors.value_or(false), iCount.value_or(1), fBrightness.value_or(1.0f), fSize.value_or(0.3f), bRandomizeSizes.value_or(false), fLife.value_or(1.0f)); +} diff --git a/Client/mods/deathmatch/logic/luadefs/CLuaEffectDefs.h b/Client/mods/deathmatch/logic/luadefs/CLuaEffectDefs.h index e2f4c07fe1..e8e00df41f 100644 --- a/Client/mods/deathmatch/logic/luadefs/CLuaEffectDefs.h +++ b/Client/mods/deathmatch/logic/luadefs/CLuaEffectDefs.h @@ -37,4 +37,6 @@ class CLuaEffectDefs : public CLuaDefs LUA_DECLARE(GetEffectSpeed); LUA_DECLARE(SetEffectDensity); LUA_DECLARE(GetEffectDensity); + + static bool FxCreateParticle(eFxParticleSystems eParticleSystem, CVector vecPosition, CVector vecDirection, float fR, float fG, float fB, float fA, std::optional bRandomizeColors, std::optional iCount, std::optional fBrightness, std::optional fSize, std::optional bRandomizeSizes, std::optional fLife); }; diff --git a/Client/mods/deathmatch/logic/luadefs/CLuaEngineDefs.cpp b/Client/mods/deathmatch/logic/luadefs/CLuaEngineDefs.cpp index 61ab0e30a6..415227890f 100644 --- a/Client/mods/deathmatch/logic/luadefs/CLuaEngineDefs.cpp +++ b/Client/mods/deathmatch/logic/luadefs/CLuaEngineDefs.cpp @@ -1947,7 +1947,8 @@ int CLuaEngineDefs::EngineGetModelPhysicalPropertiesGroup(lua_State* luaVM) auto pModelInfo = g_pGame->GetModelInfo(iModelID); if (pModelInfo) { - lua_pushnumber(luaVM, pModelInfo->GetObjectPropertiesGroup()); + uint16_t groupId = pModelInfo->GetObjectPropertiesGroup(); + lua_pushnumber(luaVM, groupId == 0xFFFF ? -1 : groupId); return 1; } argStream.SetCustomError("Expected valid model ID at argument 1"); @@ -2497,13 +2498,7 @@ bool CLuaEngineDefs::EngineSetPoolCapacity(lua_State* luaVM, ePools pool, size_t { case ePools::BUILDING_POOL: { - m_pBuildingManager->DestroyAllForABit(); - - bool success = g_pGame->SetBuildingPoolSize(newSize); - - m_pBuildingManager->RestoreDestroyed(); - - return success; + return m_pBuildingManager->SetPoolCapacity(newSize); } default: throw std::invalid_argument("Can not change this pool capacity"); diff --git a/Client/sdk/game/CFx.h b/Client/sdk/game/CFx.h index 8b4460357d..861cfa31e2 100644 --- a/Client/sdk/game/CFx.h +++ b/Client/sdk/game/CFx.h @@ -11,6 +11,8 @@ #pragma once +#include "Common.h" + class CEntity; class CVector; class CVehicle; @@ -34,4 +36,5 @@ class CFx virtual void TriggerWaterSplash(CVector& vecPosition) = 0; virtual void TriggerBulletSplash(CVector& vecPosition) = 0; virtual void TriggerFootSplash(CVector& vecPosition) = 0; + virtual void AddParticle(eFxParticleSystems eFxParticle, const CVector& vecPosition, const CVector& vecDirection, float fR, float fG, float fB, float fA, bool bRandomizeColors, std::uint32_t iCount, float fBrightness, float fSize, bool bRandomizeSizes, float fLife) = 0; }; diff --git a/Client/sdk/game/Common.h b/Client/sdk/game/Common.h index 14108f5210..d746ddb93e 100644 --- a/Client/sdk/game/Common.h +++ b/Client/sdk/game/Common.h @@ -1599,3 +1599,24 @@ namespace eSoundEffectParams HIGH_FREQ_RT_RATIO, }; } // namespace eSoundEffectParams + +enum class eFxParticleSystems +{ + PRT_BLOOD, + PRT_BOATSPLASH, + PRT_BUBBLE, + PRT_DEBRIS, + PRT_SMOKE, + PRT_GUNSHELL, + PRT_SAND, + PRT_SAND2, + PRT_SMOKEHUGE, + PRT_SMOKE2, + PRT_SPARK, + PRT_SPARK2, + PRT_SPLASH, + PRT_WAKE, + PRT_WATERSPLASH, + PRT_WHEELDIRT, + PRT_GLASS, +}; diff --git a/README.md b/README.md index 223624c1ce..3fa1d8db7a 100644 --- a/README.md +++ b/README.md @@ -1,4 +1,4 @@ -## Multi Theft Auto: San Andreas +## Multi Theft Auto: San Andreas [![Build Status](https://github.com/multitheftauto/mtasa-blue/workflows/Build/badge.svg?event=push&branch=master)](https://github.com/multitheftauto/mtasa-blue/actions?query=branch%3Amaster+event%3Apush) [![Unique servers online](https://img.shields.io/endpoint?url=https%3A%2F%2Fmultitheftauto.com%2Fapi%2Fservers-shields.io.json)](https://community.multitheftauto.com/index.php?p=servers) [![Unique players online](https://img.shields.io/endpoint?url=https%3A%2F%2Fmultitheftauto.com%2Fapi%2Fplayers-shields.io.json)](https://multitheftauto.com) [![Unique players last 24 hours](https://img.shields.io/endpoint?url=https%3A%2F%2Fmultitheftauto.com%2Fapi%2Funique-players-shields.io.json)](https://multitheftauto.com) [![Discord](https://img.shields.io/discord/278474088903606273?label=discord&logo=discord)](https://discord.com/invite/mtasa) [![Crowdin](https://badges.crowdin.net/e/f5dba7b9aa6594139af737c85d81d3aa/localized.svg)](https://multitheftauto.crowdin.com/multitheftauto) diff --git a/Server/mods/deathmatch/acl.xml b/Server/mods/deathmatch/acl.xml index a3ecc8f9a7..5e4d1292c3 100644 --- a/Server/mods/deathmatch/acl.xml +++ b/Server/mods/deathmatch/acl.xml @@ -21,6 +21,7 @@ + diff --git a/Server/mods/deathmatch/logic/CScriptDebugging.cpp b/Server/mods/deathmatch/logic/CScriptDebugging.cpp index 45a131374e..b00f961743 100644 --- a/Server/mods/deathmatch/logic/CScriptDebugging.cpp +++ b/Server/mods/deathmatch/logic/CScriptDebugging.cpp @@ -147,9 +147,10 @@ void CScriptDebugging::Broadcast(const CPacket& Packet, unsigned int uiMinimumDe { // Tell everyone we log to about it list::const_iterator iter = m_Players.begin(); + auto uiRequiredDebugLevel = std::min(uiMinimumDebugLevel, 3u); // Make sure it doesn't skip outputDebugString with level 4 for (; iter != m_Players.end(); iter++) { - if ((*iter)->m_uiScriptDebugLevel >= uiMinimumDebugLevel) + if ((*iter)->m_uiScriptDebugLevel >= uiRequiredDebugLevel) { (*iter)->Send(Packet); } diff --git a/utils/buildactions/install_cef.lua b/utils/buildactions/install_cef.lua index 7e947ab255..e3da15ddd7 100644 --- a/utils/buildactions/install_cef.lua +++ b/utils/buildactions/install_cef.lua @@ -9,8 +9,8 @@ local CEF_URL_PREFIX = "https://cef-builds.spotifycdn.com/cef_binary_" local CEF_URL_SUFFIX = "_windows32_minimal.tar.bz2" -- Change here to update CEF version -local CEF_VERSION = "125.0.21+gc8b1a8c+chromium-125.0.6422.142" -local CEF_HASH = "b1e872a2cc837b5b6e24b9ac4f0efd0639afb3bdaed3dd41d3ad7e18b763de45" +local CEF_VERSION = "125.0.22+gc410c95+chromium-125.0.6422.142" +local CEF_HASH = "5da394a136e69dbf1c52dad2dee715ac3e48802857ec64ab3853895ba1c7c4fa" function make_cef_download_url() return CEF_URL_PREFIX..http.escapeUrlParam(CEF_VERSION)..CEF_URL_SUFFIX