IFilterEntityManager work
Signed-off-by: AMZN-Olex <5432499+AMZN-Olex@users.noreply.github.com>
This commit is contained in:
@@ -10,6 +10,7 @@
|
|||||||
#include <AzCore/RTTI/RTTI.h>
|
#include <AzCore/RTTI/RTTI.h>
|
||||||
#include <AzNetworking/ConnectionLayer/IConnection.h>
|
#include <AzNetworking/ConnectionLayer/IConnection.h>
|
||||||
#include <AzNetworking/DataStructures/ByteBuffer.h>
|
#include <AzNetworking/DataStructures/ByteBuffer.h>
|
||||||
|
#include <Multiplayer/NetworkEntity/IFilterEntityManager.h>
|
||||||
#include <Multiplayer/Components/MultiplayerComponentRegistry.h>
|
#include <Multiplayer/Components/MultiplayerComponentRegistry.h>
|
||||||
#include <Multiplayer/NetworkEntity/INetworkEntityManager.h>
|
#include <Multiplayer/NetworkEntity/INetworkEntityManager.h>
|
||||||
#include <Multiplayer/NetworkTime/INetworkTime.h>
|
#include <Multiplayer/NetworkTime/INetworkTime.h>
|
||||||
@@ -128,6 +129,15 @@ namespace Multiplayer
|
|||||||
//! @return pointer to the network entity manager instance bound to this multiplayer instance
|
//! @return pointer to the network entity manager instance bound to this multiplayer instance
|
||||||
virtual INetworkEntityManager* GetNetworkEntityManager() = 0;
|
virtual INetworkEntityManager* GetNetworkEntityManager() = 0;
|
||||||
|
|
||||||
|
//! Sets user-defined filtering manager for entities.
|
||||||
|
//! This allows selectively choosing which entities to replicate on a per client connection.
|
||||||
|
//! See IFilterEntityManager for details.
|
||||||
|
//! @param entityFilter non-owning pointer, the caller is responsible for memory management.
|
||||||
|
virtual void SetFilterEntityManager(IFilterEntityManager* entityFilter) = 0;
|
||||||
|
|
||||||
|
//! @return pointer to the user-defined filtering manager of entities. By default, this isn't set and returns nullptr.
|
||||||
|
virtual IFilterEntityManager* GetFilterEntityManager() = 0;
|
||||||
|
|
||||||
//! Retrieve the stats object bound to this multiplayer instance.
|
//! Retrieve the stats object bound to this multiplayer instance.
|
||||||
//! @return the stats object bound to this multiplayer instance
|
//! @return the stats object bound to this multiplayer instance
|
||||||
MultiplayerStats& GetStats() { return m_stats; }
|
MultiplayerStats& GetStats() { return m_stats; }
|
||||||
|
|||||||
@@ -0,0 +1,48 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (c) Contributors to the Open 3D Engine Project
|
||||||
|
*
|
||||||
|
* SPDX-License-Identifier: Apache-2.0 OR MIT
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <AzNetworking/ConnectionLayer/IConnection.h>
|
||||||
|
#include <Multiplayer/NetworkEntity/NetworkEntityHandle.h>
|
||||||
|
|
||||||
|
namespace Multiplayer
|
||||||
|
{
|
||||||
|
//! @class IFilterEntityManager
|
||||||
|
//! @brief IFilterEntityManager provides an interface for filtering entities out from replication down to clients.
|
||||||
|
//!
|
||||||
|
//! By default, all entities with NetBindComponent on them are replicated to all clients.
|
||||||
|
//! (There is a built-in distance filtering, where only entities within vicinity of a player are sent to that player.
|
||||||
|
//! This is controlled by sv_ClientAwarenessRadius AZ_CVAR variable.)
|
||||||
|
//!
|
||||||
|
//! There are use cases where you want to limit the entities sent to a client, for example "fog of war" or
|
||||||
|
//! "out of line of sight" anti-cheating mechanic by omitting information clients should not have access to.
|
||||||
|
//!
|
||||||
|
//! By implementing IFilterEntityManager interface and setting it on GetMultiplayer()->SetFilterEntityManager()
|
||||||
|
//! entities can be filtered by IsEntityFiltered(...) returning true.
|
||||||
|
//!
|
||||||
|
//! Note: one cannot filter out entities in Level prefab (spawned by LoadLevel console command). Level prefabs are fully
|
||||||
|
//! spawned on each client. Filtering of entities is applied to dynamically spawned prefabs, and specifically
|
||||||
|
//! entities must have NetBindComponent on them.
|
||||||
|
class IFilterEntityManager
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
AZ_RTTI(IFilterEntityManager, "{91F879F2-3DAF-43B8-B474-B312D26C0F48}");
|
||||||
|
|
||||||
|
virtual ~IFilterEntityManager() = default;
|
||||||
|
|
||||||
|
//! Return true if a given entity should be filtered out, false otherwise.
|
||||||
|
//! Important: this method is a hot code path, it will be called over all entities around each player frequently.
|
||||||
|
//! Ideally, this method should be implemented as a quick look up.
|
||||||
|
//!
|
||||||
|
//! @param entity the entity to be considered for filtering
|
||||||
|
//! @param controllerEntity player's entity for the associated connection
|
||||||
|
//! @param connectionId the affected connection should the entity be filtered out.
|
||||||
|
//! @return if false the given entity will be not be replicated to the connection
|
||||||
|
virtual bool IsEntityFiltered(AZ::Entity* entity, ConstNetworkEntityHandle controllerEntity, AzNetworking::ConnectionId connectionId) = 0;
|
||||||
|
};
|
||||||
|
}
|
||||||
@@ -812,6 +812,16 @@ namespace Multiplayer
|
|||||||
return &m_networkEntityManager;
|
return &m_networkEntityManager;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void MultiplayerSystemComponent::SetFilterEntityManager(IFilterEntityManager* entityFilter)
|
||||||
|
{
|
||||||
|
m_filterEntityManager = entityFilter;
|
||||||
|
}
|
||||||
|
|
||||||
|
IFilterEntityManager* MultiplayerSystemComponent::GetFilterEntityManager()
|
||||||
|
{
|
||||||
|
return m_filterEntityManager;
|
||||||
|
}
|
||||||
|
|
||||||
void MultiplayerSystemComponent::DumpStats([[maybe_unused]] const AZ::ConsoleCommandContainer& arguments)
|
void MultiplayerSystemComponent::DumpStats([[maybe_unused]] const AZ::ConsoleCommandContainer& arguments)
|
||||||
{
|
{
|
||||||
const MultiplayerStats& stats = GetStats();
|
const MultiplayerStats& stats = GetStats();
|
||||||
|
|||||||
@@ -114,6 +114,8 @@ namespace Multiplayer
|
|||||||
AZ::TimeMs GetCurrentHostTimeMs() const override;
|
AZ::TimeMs GetCurrentHostTimeMs() const override;
|
||||||
INetworkTime* GetNetworkTime() override;
|
INetworkTime* GetNetworkTime() override;
|
||||||
INetworkEntityManager* GetNetworkEntityManager() override;
|
INetworkEntityManager* GetNetworkEntityManager() override;
|
||||||
|
void SetFilterEntityManager(IFilterEntityManager* entityFilter) override;
|
||||||
|
IFilterEntityManager* GetFilterEntityManager() override;
|
||||||
//! @}
|
//! @}
|
||||||
|
|
||||||
//! Console commands.
|
//! Console commands.
|
||||||
@@ -138,6 +140,8 @@ namespace Multiplayer
|
|||||||
NetworkEntityManager m_networkEntityManager;
|
NetworkEntityManager m_networkEntityManager;
|
||||||
NetworkTime m_networkTime;
|
NetworkTime m_networkTime;
|
||||||
MultiplayerAgentType m_agentType = MultiplayerAgentType::Uninitialized;
|
MultiplayerAgentType m_agentType = MultiplayerAgentType::Uninitialized;
|
||||||
|
|
||||||
|
IFilterEntityManager* m_filterEntityManager = nullptr; // non-owning pointer
|
||||||
|
|
||||||
SessionInitEvent m_initEvent;
|
SessionInitEvent m_initEvent;
|
||||||
SessionShutdownEvent m_shutdownEvent;
|
SessionShutdownEvent m_shutdownEvent;
|
||||||
|
|||||||
+18
-24
@@ -63,13 +63,6 @@ namespace Multiplayer
|
|||||||
m_controlledEntityTransform = entity ? entity->GetTransform() : nullptr;
|
m_controlledEntityTransform = entity ? entity->GetTransform() : nullptr;
|
||||||
AZ_Assert(m_controlledEntityTransform, "Controlled player entity must have a transform");
|
AZ_Assert(m_controlledEntityTransform, "Controlled player entity must have a transform");
|
||||||
|
|
||||||
//// this one is optional
|
|
||||||
//mp_ControlledFilteredEntityComponent = m_controlledEntity->FindController<FilteredEntityComponent::Authority>();
|
|
||||||
//if (mp_ControlledFilteredEntityComponent)
|
|
||||||
//{
|
|
||||||
// mp_ControlledFilteredEntityComponent->AddFilteredEntityEventHandle(m_FilteredEntityAddedEventHandle);
|
|
||||||
//}
|
|
||||||
|
|
||||||
m_updateWindowEvent.Enqueue(sv_ClientReplicationWindowUpdateMs, true);
|
m_updateWindowEvent.Enqueue(sv_ClientReplicationWindowUpdateMs, true);
|
||||||
|
|
||||||
AZ::Interface<AZ::ComponentApplicationRequests>::Get()->RegisterEntityActivatedEventHandler(m_entityActivatedEventHandler);
|
AZ::Interface<AZ::ComponentApplicationRequests>::Get()->RegisterEntityActivatedEventHandler(m_entityActivatedEventHandler);
|
||||||
@@ -145,21 +138,23 @@ namespace Multiplayer
|
|||||||
}
|
}
|
||||||
);
|
);
|
||||||
|
|
||||||
NetworkEntityTracker* networkEntityTracker = GetNetworkEntityTracker();
|
NetworkEntityTracker* networkEntityTracker = GetNetworkEntityTracker();
|
||||||
|
IFilterEntityManager* filterEntityManager = GetMultiplayer()->GetFilterEntityManager();
|
||||||
|
|
||||||
// Add all the neighbors
|
// Add all the neighbors
|
||||||
for (AzFramework::VisibilityEntry* visEntry : gatheredEntries)
|
for (AzFramework::VisibilityEntry* visEntry : gatheredEntries)
|
||||||
{
|
{
|
||||||
//if (mp_ControlledFilteredEntityComponent && mp_ControlledFilteredEntityComponent->IsEntityFiltered(iterator.Get()))
|
|
||||||
//{
|
|
||||||
// continue;
|
|
||||||
//}
|
|
||||||
|
|
||||||
// We want to find the closest extent to the player and prioritize using that distance
|
|
||||||
AZ::Entity* entity = static_cast<AZ::Entity*>(visEntry->m_userData);
|
AZ::Entity* entity = static_cast<AZ::Entity*>(visEntry->m_userData);
|
||||||
|
|
||||||
|
if (filterEntityManager && filterEntityManager->IsEntityFiltered(entity, m_controlledEntity, m_connection->GetConnectionId()))
|
||||||
|
{
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
NetBindComponent* entryNetBindComponent = entity->template FindComponent<NetBindComponent>();
|
NetBindComponent* entryNetBindComponent = entity->template FindComponent<NetBindComponent>();
|
||||||
if (entryNetBindComponent != nullptr)
|
if (entryNetBindComponent != nullptr)
|
||||||
{
|
{
|
||||||
|
// We want to find the closest extent to the player and prioritize using that distance
|
||||||
const AZ::Vector3 supportNormal = controlledEntityPosition - visEntry->m_boundingVolume.GetCenter();
|
const AZ::Vector3 supportNormal = controlledEntityPosition - visEntry->m_boundingVolume.GetCenter();
|
||||||
const AZ::Vector3 closestPosition = visEntry->m_boundingVolume.GetSupport(supportNormal);
|
const AZ::Vector3 closestPosition = visEntry->m_boundingVolume.GetSupport(supportNormal);
|
||||||
const float gatherDistanceSquared = controlledEntityPosition.GetDistanceSq(closestPosition);
|
const float gatherDistanceSquared = controlledEntityPosition.GetDistanceSq(closestPosition);
|
||||||
@@ -212,10 +207,13 @@ namespace Multiplayer
|
|||||||
{
|
{
|
||||||
if (netBindComponent->HasController())
|
if (netBindComponent->HasController())
|
||||||
{
|
{
|
||||||
//if (mp_ControlledFilteredEntityComponent && mp_ControlledFilteredEntityComponent->IsEntityFiltered(newEntity))
|
if (IFilterEntityManager* filter = GetMultiplayer()->GetFilterEntityManager())
|
||||||
//{
|
{
|
||||||
// return;
|
if (filter->IsEntityFiltered(entity, m_controlledEntity, m_connection->GetConnectionId()))
|
||||||
//}
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
AZ::TransformInterface* transformInterface = entity->GetTransform();
|
AZ::TransformInterface* transformInterface = entity->GetTransform();
|
||||||
if (transformInterface != nullptr)
|
if (transformInterface != nullptr)
|
||||||
@@ -274,6 +272,8 @@ namespace Multiplayer
|
|||||||
|
|
||||||
void ServerToClientReplicationWindow::AddEntityToReplicationSet(ConstNetworkEntityHandle& entityHandle, float priority, [[maybe_unused]] float distanceSquared)
|
void ServerToClientReplicationWindow::AddEntityToReplicationSet(ConstNetworkEntityHandle& entityHandle, float priority, [[maybe_unused]] float distanceSquared)
|
||||||
{
|
{
|
||||||
|
// Assumption: the entity has been checked for filtering prior to this call.
|
||||||
|
|
||||||
if (!sv_ReplicateServerProxies)
|
if (!sv_ReplicateServerProxies)
|
||||||
{
|
{
|
||||||
NetBindComponent* netBindComponent = entityHandle.GetNetBindComponent();
|
NetBindComponent* netBindComponent = entityHandle.GetNetBindComponent();
|
||||||
@@ -314,10 +314,4 @@ namespace Multiplayer
|
|||||||
// }
|
// }
|
||||||
// }
|
// }
|
||||||
//}
|
//}
|
||||||
|
|
||||||
//void ServerToClientReplicationWindow::OnAddFilteredEntity(NetEntityId filteredEntityId)
|
|
||||||
//{
|
|
||||||
// ConstEntityPtr filteredEntity = gNovaGame->GetEntityManager().GetEntity(filteredEntityId);
|
|
||||||
// m_replicationSet.erase(filteredEntityId);
|
|
||||||
//}
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -54,7 +54,6 @@ namespace Multiplayer
|
|||||||
void OnEntityDeactivated(AZ::Entity* entity);
|
void OnEntityDeactivated(AZ::Entity* entity);
|
||||||
|
|
||||||
//void CollectControlledEntitiesRecursive(ReplicationSet& replicationSet, EntityHierarchyComponent::Authority& hierarchyController);
|
//void CollectControlledEntitiesRecursive(ReplicationSet& replicationSet, EntityHierarchyComponent::Authority& hierarchyController);
|
||||||
//void OnAddFilteredEntity(NetEntityId filteredEntityId);
|
|
||||||
|
|
||||||
void EvaluateConnection();
|
void EvaluateConnection();
|
||||||
void AddEntityToReplicationSet(ConstNetworkEntityHandle& entityHandle, float priority, float distanceSquared);
|
void AddEntityToReplicationSet(ConstNetworkEntityHandle& entityHandle, float priority, float distanceSquared);
|
||||||
@@ -73,7 +72,6 @@ namespace Multiplayer
|
|||||||
AZ::EntityActivatedEvent::Handler m_entityActivatedEventHandler;
|
AZ::EntityActivatedEvent::Handler m_entityActivatedEventHandler;
|
||||||
AZ::EntityDeactivatedEvent::Handler m_entityDeactivatedEventHandler;
|
AZ::EntityDeactivatedEvent::Handler m_entityDeactivatedEventHandler;
|
||||||
|
|
||||||
//FilteredEntityComponent::Authority* m_controlledFilteredEntityComponent = nullptr;
|
|
||||||
//NetBindComponent* m_controlledNetBindComponent = nullptr;
|
//NetBindComponent* m_controlledNetBindComponent = nullptr;
|
||||||
|
|
||||||
const AzNetworking::IConnection* m_connection = nullptr;
|
const AzNetworking::IConnection* m_connection = nullptr;
|
||||||
|
|||||||
@@ -21,6 +21,7 @@ set(FILES
|
|||||||
Include/Multiplayer/EntityDomains/IEntityDomain.h
|
Include/Multiplayer/EntityDomains/IEntityDomain.h
|
||||||
Include/Multiplayer/NetworkEntity/INetworkEntityManager.h
|
Include/Multiplayer/NetworkEntity/INetworkEntityManager.h
|
||||||
Include/Multiplayer/INetworkSpawnableLibrary.h
|
Include/Multiplayer/INetworkSpawnableLibrary.h
|
||||||
|
Include/Multiplayer/NetworkEntity/IFilterEntityManager.h
|
||||||
Include/Multiplayer/NetworkEntity/NetworkEntityRpcMessage.h
|
Include/Multiplayer/NetworkEntity/NetworkEntityRpcMessage.h
|
||||||
Include/Multiplayer/NetworkEntity/NetworkEntityUpdateMessage.h
|
Include/Multiplayer/NetworkEntity/NetworkEntityUpdateMessage.h
|
||||||
Include/Multiplayer/NetworkEntity/NetworkEntityHandle.h
|
Include/Multiplayer/NetworkEntity/NetworkEntityHandle.h
|
||||||
|
|||||||
Reference in New Issue
Block a user