diff --git a/addons/core/scripts/Game/ACE_Core/Player/SCR_PlayerController.c b/addons/core/scripts/Game/ACE_Core/Player/SCR_PlayerController.c index 9983a06c3..b24198b98 100644 --- a/addons/core/scripts/Game/ACE_Core/Player/SCR_PlayerController.c +++ b/addons/core/scripts/Game/ACE_Core/Player/SCR_PlayerController.c @@ -1,6 +1,8 @@ //------------------------------------------------------------------------------------------------ modded class SCR_PlayerController : PlayerController { + protected static const float ACE_MAX_DELETED_DISTANCE_M = 5; // Maximum distance for deletion requests to be granted + //------------------------------------------------------------------------------------------------ //! Request deletion of unreplicated entity from all machines //! Called from local player @@ -16,6 +18,13 @@ modded class SCR_PlayerController : PlayerController [RplRpc(RplChannel.Reliable, RplRcver.Server)] protected void RpcAsk_ACE_DeleteEntityByID(EntityID entityID) { + IEntity entity = GetGame().GetWorld().FindEntityByID(entityID); + if (!entity) + return; + + if (!ACE_IsDeletionGrantedByServer(entity)) + return; + ACE_LoadtimeEntityManager manager = ACE_LoadtimeEntityManager.GetInstance(); if (!manager) return; @@ -39,6 +48,9 @@ modded class SCR_PlayerController : PlayerController if (!entity) return; + if (!ACE_IsDeletionGrantedByServer(entity)) + return; + float health = entity.GetCurrentHealth(); if (health > 0) entity.HandleDamage(EDamageType.TRUE, health, hitPosDirNorm); @@ -57,6 +69,22 @@ modded class SCR_PlayerController : PlayerController GetGame().GetCallqueue().CallLater(manager.DeleteEntitiesByIdGlobal, deletionDelayMS, false, {entity.GetID()}); } + //------------------------------------------------------------------------------------------------ + //! Check whether player is allowed deleting the entity + protected bool ACE_IsDeletionGrantedByServer(IEntity entityToDelete) + { + // Only physical loadtime entities can be deleted + if (!entityToDelete || !entityToDelete.IsLoaded() || !entityToDelete.GetVObject()) + return false; + + SCR_ChimeraCharacter playerChar = SCR_ChimeraCharacter.Cast(GetControlledEntity()); + if (!playerChar) + return false; + + // Can only delete nearby entities + return (vector.Distance(playerChar.GetOrigin(), entityToDelete.GetOrigin()) <= ACE_MAX_DELETED_DISTANCE_M); + } + //------------------------------------------------------------------------------------------------ void ACE_RequestAnimateWithHelperCompartment(ACE_EAnimationHelperID helperID) { @@ -74,4 +102,5 @@ modded class SCR_PlayerController : PlayerController ACE_AnimationTools.AnimateWithHelperCompartment(helperID, char); } + } diff --git a/addons/core/scripts/Game/ACE_Core/Systems/ACE_LoadtimeEntityManager.c b/addons/core/scripts/Game/ACE_Core/Systems/ACE_LoadtimeEntityManager.c index 4e87ce1cd..5a5b6e327 100644 --- a/addons/core/scripts/Game/ACE_Core/Systems/ACE_LoadtimeEntityManager.c +++ b/addons/core/scripts/Game/ACE_Core/Systems/ACE_LoadtimeEntityManager.c @@ -25,7 +25,7 @@ class ACE_LoadtimeEntityManager : GameSystem //------------------------------------------------------------------------------------------------ //! Ensures that already deleted unreplicated entities are deleted for JIPs - void DeleteInitialEntities() + protected void DeleteInitialEntities() { foreach (ACE_EntityIdWrapper idWrapper : m_aDeletedEntityIDs) { @@ -68,8 +68,9 @@ class ACE_LoadtimeEntityManager : GameSystem //! Deletes unreplicated entity by ID on a local machine void DeleteEntityByIdLocal(EntityID entityID) { + // Only physical loadtime entities can be deleted IEntity entity = GetGame().GetWorld().FindEntityByID(entityID); - if (entity) + if (entity && entity.IsLoaded() && entity.GetVObject()) delete entity; }