diff --git a/Client/mods/deathmatch/logic/CClientEntity.cpp b/Client/mods/deathmatch/logic/CClientEntity.cpp index b4054429d5a..524d7520e61 100644 --- a/Client/mods/deathmatch/logic/CClientEntity.cpp +++ b/Client/mods/deathmatch/logic/CClientEntity.cpp @@ -173,6 +173,12 @@ CClientEntity::~CClientEntity ( void ) SAFE_RELEASE( m_pChildrenListSnapshot ); g_pCore->GetGraphics ()->GetRenderItemManager ()->RemoveClientEntityRefs ( this ); g_pCore->UpdateDummyProgress(); + + // Remove from m_DisabledCollisions + CClientPlayer::m_DisabledCollisions.remove ( this ); + CClientPed::m_DisabledCollisions.remove ( this ); + CClientObject::m_DisabledCollisions.remove ( this ); + CClientVehicle::m_DisabledCollisions.remove ( this ); } @@ -1455,6 +1461,41 @@ void CClientEntity::RemoveEntityFromRoot ( unsigned int uiTypeHash, CClientEntit CClientEntity::RemoveEntityFromRoot ( (*iter)->GetTypeHash (), *iter ); } + +CFastList < CClientEntity* > CClientEntity::GetEntitiesFromRoot ( unsigned int uiTypeHash, bool bStreamedIn ) +{ + CFastList < CClientEntity* > entities; + + t_mapEntitiesFromRoot::iterator find = ms_mapEntitiesFromRoot.find ( uiTypeHash ); + if ( find != ms_mapEntitiesFromRoot.end () ) + { + CFromRootListType& listEntities = find->second; + CClientEntity* pEntity; + unsigned int uiIndex = 0; + + for ( CFromRootListType::reverse_iterator i = listEntities.rbegin (); + i != listEntities.rend (); + ++i ) + { + pEntity = *i; + + // Only streamed in elements? + if ( !bStreamedIn || !pEntity->IsStreamingCompatibleClass () || + reinterpret_cast < CClientStreamElement* > ( pEntity )->IsStreamedIn () ) + { + if ( !pEntity->IsBeingDeleted () ) + { + // Add it to the table + entities.push_back ( pEntity ); + } + } + } + } + + return entities; +} + + void CClientEntity::GetEntitiesFromRoot ( unsigned int uiTypeHash, lua_State* luaVM, bool bStreamedIn ) { #if CHECK_ENTITIES_FROM_ROOT diff --git a/Client/mods/deathmatch/logic/CClientEntity.h b/Client/mods/deathmatch/logic/CClientEntity.h index ba5a97454d9..4fded85c601 100644 --- a/Client/mods/deathmatch/logic/CClientEntity.h +++ b/Client/mods/deathmatch/logic/CClientEntity.h @@ -373,6 +373,7 @@ class CClientEntity : public CClientEntityBase public: // Optimization for getElementsByType starting at root static void StartupEntitiesFromRoot ( ); + static CFastList < CClientEntity* > GetEntitiesFromRoot ( unsigned int uiTypeHash, bool bStreamedIn ); private: static bool IsFromRoot ( CClientEntity* pEntity ); static void AddEntityFromRoot ( unsigned int uiTypeHash, CClientEntity* pEntity, bool bDebugCheck = true ); diff --git a/Client/mods/deathmatch/logic/CClientObject.cpp b/Client/mods/deathmatch/logic/CClientObject.cpp index 091a512b5c6..f0e4e3255d5 100644 --- a/Client/mods/deathmatch/logic/CClientObject.cpp +++ b/Client/mods/deathmatch/logic/CClientObject.cpp @@ -21,6 +21,8 @@ #define M_PI 3.14159265358979323846 #endif +std::list < CClientEntity* > CClientObject::m_DisabledCollisions; + CClientObject::CClientObject ( CClientManager* pManager, ElementID ID, unsigned short usModel, bool bLowLod ) : ClassInit ( this ) , CClientStreamElement ( bLowLod ? pManager->GetObjectLodStreamer () : pManager->GetObjectStreamer (), ID ) @@ -54,6 +56,12 @@ CClientObject::CClientObject ( CClientManager* pManager, ElementID ID, unsigned if ( m_bIsLowLod ) m_pManager->OnLowLODElementCreated (); + + // Check DisableCollisions // + for ( CClientEntity * entity : m_DisabledCollisions ) + { + SetCollidableWith ( entity, false ); + } } diff --git a/Client/mods/deathmatch/logic/CClientObject.h b/Client/mods/deathmatch/logic/CClientObject.h index 922d95c523a..2a37d4038a6 100644 --- a/Client/mods/deathmatch/logic/CClientObject.h +++ b/Client/mods/deathmatch/logic/CClientObject.h @@ -153,6 +153,7 @@ class CClientObject : public CClientStreamElement public: CObject* m_pObject; SLastSyncedObjectData m_LastSyncedData; + static std::list < CClientEntity * > m_DisabledCollisions; }; #endif diff --git a/Client/mods/deathmatch/logic/CClientPed.cpp b/Client/mods/deathmatch/logic/CClientPed.cpp index 3c8836bbae4..4b4ea895600 100644 --- a/Client/mods/deathmatch/logic/CClientPed.cpp +++ b/Client/mods/deathmatch/logic/CClientPed.cpp @@ -16,10 +16,11 @@ #include "StdInc.h" -using std::list; using std::vector; +using std::list; extern CClientGame* g_pClientGame; +list < CClientEntity* > CClientPed::m_DisabledCollisions; #ifndef M_PI #define M_PI 3.14159265358979323846 @@ -242,6 +243,12 @@ void CClientPed::Init ( CClientManager* pManager, unsigned long ulModelID, bool SetArmor ( 0.0f ); } + + // Check DisableCollisions // + for ( CClientEntity * entity : m_DisabledCollisions ) + { + SetCollidableWith ( entity, false ); + } } diff --git a/Client/mods/deathmatch/logic/CClientPed.h b/Client/mods/deathmatch/logic/CClientPed.h index 75bec4283ef..b97970704c2 100644 --- a/Client/mods/deathmatch/logic/CClientPed.h +++ b/Client/mods/deathmatch/logic/CClientPed.h @@ -646,6 +646,8 @@ class CClientPed : public CClientStreamElement, public CAntiCheatModule CVector m_vecPrevTargetPosition; uint m_uiForceLocalCounter; + + static std::list < CClientEntity * > m_DisabledCollisions; }; #endif diff --git a/Client/mods/deathmatch/logic/CClientPlayer.cpp b/Client/mods/deathmatch/logic/CClientPlayer.cpp index 23b3b5d2f10..bf524393233 100644 --- a/Client/mods/deathmatch/logic/CClientPlayer.cpp +++ b/Client/mods/deathmatch/logic/CClientPlayer.cpp @@ -16,9 +16,11 @@ *****************************************************************************/ #include + int g_iDamageEventLimit = -1; extern float g_fApplyDamageLastAmount; extern CClientPed* g_pApplyDamageLastDamagedPed; +std::list < CClientEntity* > CClientPlayer::m_DisabledCollisions; CClientPlayer::CClientPlayer ( CClientManager* pManager, ElementID ID, bool bIsLocalPlayer ) : ClassInit ( this ), CClientPed ( pManager, 0, ID, bIsLocalPlayer ) { @@ -88,6 +90,12 @@ CClientPlayer::CClientPlayer ( CClientManager* pManager, ElementID ID, bool bIsL // Add us to the player list m_pManager->GetPlayerManager ()->AddToList ( this ); + // Check DisableCollisions // + for ( CClientEntity * entity : m_DisabledCollisions ) + { + SetCollidableWith ( entity, false ); + } + #ifdef MTA_DEBUG m_bShowingWepdata = false; #endif diff --git a/Client/mods/deathmatch/logic/CClientPlayer.h b/Client/mods/deathmatch/logic/CClientPlayer.h index baea56691e2..cf8205e2f48 100644 --- a/Client/mods/deathmatch/logic/CClientPlayer.h +++ b/Client/mods/deathmatch/logic/CClientPlayer.h @@ -120,6 +120,7 @@ class CClientPlayer : public CClientPed CVector m_vecPrevBulletSyncStart; CVector m_vecPrevBulletSyncEnd; uchar m_ucPrevBulletSyncOrderCounter; + static std::list < CClientEntity * > m_DisabledCollisions; private: bool m_bIsLocalPlayer; SString m_strNick; diff --git a/Client/mods/deathmatch/logic/CClientVehicle.cpp b/Client/mods/deathmatch/logic/CClientVehicle.cpp index 07feaef35fb..228c35889c5 100644 --- a/Client/mods/deathmatch/logic/CClientVehicle.cpp +++ b/Client/mods/deathmatch/logic/CClientVehicle.cpp @@ -25,6 +25,7 @@ using std::list; extern CClientGame* g_pClientGame; std::set < const CClientEntity* > ms_AttachedVehiclesToIgnore; +list < CClientEntity* > CClientVehicle::m_DisabledCollisions; // To hide the ugly "pointer truncation from DWORD* to unsigned long warning #pragma warning(disable:4311) @@ -179,6 +180,12 @@ CClientVehicle::CClientVehicle ( CClientManager* pManager, ElementID ID, unsigne // We've not yet been streamed in m_bJustStreamedIn = false; + + // Check DisableCollisions // + for ( CClientEntity * entity : m_DisabledCollisions ) + { + SetCollidableWith ( entity, false ); + } } diff --git a/Client/mods/deathmatch/logic/CClientVehicle.h b/Client/mods/deathmatch/logic/CClientVehicle.h index 5dd98790618..5de17ea5649 100644 --- a/Client/mods/deathmatch/logic/CClientVehicle.h +++ b/Client/mods/deathmatch/logic/CClientVehicle.h @@ -686,6 +686,7 @@ class CClientVehicle : public CClientStreamElement SSirenInfo m_tSirenBeaconInfo; std::map m_ComponentData; bool m_bAsyncLoadingDisabled; + static std::list < CClientEntity * > m_DisabledCollisions; }; diff --git a/Client/mods/deathmatch/logic/CStaticFunctionDefinitions.cpp b/Client/mods/deathmatch/logic/CStaticFunctionDefinitions.cpp index 916be2528d5..0bd3c911f65 100644 --- a/Client/mods/deathmatch/logic/CStaticFunctionDefinitions.cpp +++ b/Client/mods/deathmatch/logic/CStaticFunctionDefinitions.cpp @@ -3603,6 +3603,76 @@ bool CStaticFunctionDefinitions::SetElementCollidableWith ( CClientEntity & Enti } +bool CStaticFunctionDefinitions::SetElementCollidableWithType ( CClientEntity & Entity, const char* szTypeName, bool bCanCollide, bool bOnlyWithCreated ) +{ + switch ( Entity.GetType () ) + { + case CCLIENTPLAYER: + case CCLIENTPED: + case CCLIENTOBJECT: + case CCLIENTVEHICLE: + break; + default: return false; + } + + unsigned int uiType = CClientEntity::GetTypeID ( szTypeName ); + + switch ( uiType ) + { + case CCLIENTPLAYER: + case CCLIENTPED: + case CCLIENTOBJECT: + case CCLIENTVEHICLE: + break; + default: return false; + } + + // Change CollidableWith for all elements of this type on the server + CFastList < CClientEntity* > entities = CClientEntity::GetEntitiesFromRoot ( HashString ( szTypeName ), false ); + + CChildListType::const_iterator iter = entities.begin (); + for ( ; iter != entities.end (); iter++ ) + { + CClientEntity* pEntity = *iter; + Entity.SetCollidableWith ( pEntity, bCanCollide ); + } + + // Save it so new created elements also have to consider CollidableWith + if ( !bOnlyWithCreated ) + { + switch ( uiType ) + { + case CCLIENTPLAYER: + if ( bCanCollide ) + CClientPlayer::m_DisabledCollisions.remove ( &Entity ); + else + CClientPlayer::m_DisabledCollisions.push_back ( &Entity ); + break; + case CCLIENTPED: + if ( bCanCollide ) + CClientPed::m_DisabledCollisions.remove ( &Entity ); + else + CClientPed::m_DisabledCollisions.push_back ( &Entity ); + break; + case CCLIENTOBJECT: + if ( bCanCollide ) + CClientObject::m_DisabledCollisions.remove ( &Entity ); + else + CClientObject::m_DisabledCollisions.push_back ( &Entity ); + break; + case CCLIENTVEHICLE: + if ( bCanCollide ) + CClientVehicle::m_DisabledCollisions.remove ( &Entity ); + else + CClientVehicle::m_DisabledCollisions.push_back ( &Entity ); + break; + } + } + + return true; +} + + bool CStaticFunctionDefinitions::SetElementFrozen ( CClientEntity& Entity, bool bFrozen ) { switch ( Entity.GetType () ) diff --git a/Client/mods/deathmatch/logic/CStaticFunctionDefinitions.h b/Client/mods/deathmatch/logic/CStaticFunctionDefinitions.h index 4756c722e10..e7becb47e04 100644 --- a/Client/mods/deathmatch/logic/CStaticFunctionDefinitions.h +++ b/Client/mods/deathmatch/logic/CStaticFunctionDefinitions.h @@ -108,6 +108,7 @@ class CStaticFunctionDefinitions static bool SetElementModel ( CClientEntity& Entity, unsigned short usModel ); static bool SetElementCollisionsEnabled ( CClientEntity& Entity, bool bEnabled ); static bool SetElementCollidableWith ( CClientEntity& Entity, CClientEntity& ThisEntity, bool bCanCollide ); + static bool SetElementCollidableWithType ( CClientEntity& Entity, const char* szTypeName, bool bCanCollide, bool bOnlyWithCreated ); static bool SetElementFrozen ( CClientEntity& Entity, bool bFrozen ); static bool SetLowLodElement ( CClientEntity& Entity, CClientEntity* pLowLodEntity ); static bool SetElementCallPropagationEnabled ( CClientEntity& Entity, bool bEnabled ); diff --git a/Client/mods/deathmatch/logic/luadefs/CLuaElementDefs.cpp b/Client/mods/deathmatch/logic/luadefs/CLuaElementDefs.cpp index c728e884677..6be7ef3cc84 100644 --- a/Client/mods/deathmatch/logic/luadefs/CLuaElementDefs.cpp +++ b/Client/mods/deathmatch/logic/luadefs/CLuaElementDefs.cpp @@ -85,6 +85,7 @@ void CLuaElementDefs::LoadFunctions ( void ) CLuaCFunctions::AddFunction ( "setElementStreamable", SetElementStreamable ); CLuaCFunctions::AddFunction ( "setElementCollisionsEnabled", SetElementCollisionsEnabled ); CLuaCFunctions::AddFunction ( "setElementCollidableWith", SetElementCollidableWith ); + CLuaCFunctions::AddFunction ( "setElementCollidableWithType", SetElementCollidableWithType ); CLuaCFunctions::AddFunction ( "setElementDoubleSided", SetElementDoubleSided ); CLuaCFunctions::AddFunction ( "setElementFrozen", SetElementFrozen ); CLuaCFunctions::AddFunction ( "setLowLODElement", SetLowLodElement ); @@ -167,6 +168,7 @@ void CLuaElementDefs::AddClass ( lua_State* luaVM ) lua_classfunction ( luaVM, "setModel", "setElementModel" ); lua_classfunction ( luaVM, "setCollisionsEnabled", "setElementCollisionsEnabled" ); lua_classfunction ( luaVM, "setCollidableWith", "setElementCollidableWith" ); + lua_classfunction ( luaVM, "setCollidableWithType", "setElementCollidableWithType" ); lua_classfunction ( luaVM, "setFrozen", "setElementFrozen" ); lua_classfunction ( luaVM, "setLowLOD", "setLowLODElement" ); lua_classfunction ( luaVM, "setCallPropagationEnabled", "setElementCallPropagationEnabled" ); @@ -2180,6 +2182,32 @@ int CLuaElementDefs::SetElementCollidableWith ( lua_State* luaVM ) } +int CLuaElementDefs::SetElementCollidableWithType ( lua_State* luaVM ) { + // bool setElementCollidableWithType ( element theElement, string withType, bool enabled[, bool onlyWithCreated = false] ) + CClientEntity* pEntity = nullptr; + SString strType; + bool bCanCollide = true; + bool bOnlyWithCreated = false; + CScriptArgReader argStream ( luaVM ); + argStream.ReadUserData ( pEntity ); + argStream.ReadString ( strType ); + argStream.ReadBool ( bCanCollide ); + argStream.ReadBool ( bOnlyWithCreated, false ); + + if ( !argStream.HasErrors () ) + { + if ( CStaticFunctionDefinitions::SetElementCollidableWithType ( *pEntity, strType.c_str (), bCanCollide, bOnlyWithCreated ) ) + { + lua_pushboolean ( luaVM, true ); + return 1; + } + } + else + m_pScriptDebugging->LogCustom ( luaVM, argStream.GetFullErrorMessage () ); + lua_pushboolean ( luaVM, false ); + return 1; +} + int CLuaElementDefs::SetElementDoubleSided ( lua_State* luaVM ) { CClientEntity* pEntity; diff --git a/Client/mods/deathmatch/logic/luadefs/CLuaElementDefs.h b/Client/mods/deathmatch/logic/luadefs/CLuaElementDefs.h index 9951d75b080..dacee692dc6 100644 --- a/Client/mods/deathmatch/logic/luadefs/CLuaElementDefs.h +++ b/Client/mods/deathmatch/logic/luadefs/CLuaElementDefs.h @@ -88,6 +88,7 @@ class CLuaElementDefs : public CLuaDefs LUA_DECLARE ( SetElementStreamable ); LUA_DECLARE ( SetElementModel ); LUA_DECLARE ( SetElementCollidableWith ); + LUA_DECLARE ( SetElementCollidableWithType ); LUA_DECLARE ( SetElementDoubleSided ); LUA_DECLARE ( SetElementFrozen ); LUA_DECLARE ( SetLowLodElement );