Skip to content

Commit

Permalink
SIG/Network - an example of using Filtering feature (i.e. omitting so…
Browse files Browse the repository at this point in the history
…me entities on per connection basis)

See o3de/o3de#1700 for the related core interfaces changes
  • Loading branch information
SelfishOlex authored Jul 6, 2021
2 parents 86a4249 + 6a5f153 commit bc82160
Show file tree
Hide file tree
Showing 9 changed files with 3,758 additions and 31 deletions.
74 changes: 74 additions & 0 deletions Gem/Code/Source/Components/ExampleFilteredEntityComponent.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,74 @@
/*
* Copyright (c) Contributors to the Open 3D Engine Project
*
* SPDX-License-Identifier: Apache-2.0 OR MIT
*
*/

#include <AzCore/Serialization/EditContext.h>
#include <Components/ExampleFilteredEntityComponent.h>

AZ_CVAR(bool, mps_EnableFilteringEntities, true, nullptr, AZ::ConsoleFunctorFlags::Null, "If true, enables the example of filtering entities");

namespace MultiplayerSample
{
void ExampleFilteredEntityComponent::Reflect(AZ::ReflectContext* context)
{
AZ::SerializeContext* serializeContext = azrtti_cast<AZ::SerializeContext*>(context);
if (serializeContext)
{
serializeContext->Class<ExampleFilteredEntityComponent, AZ::Component>()
->Field( "Enabled", &ExampleFilteredEntityComponent::m_enabled )
->Field( "Filter Names for Even Connections", &ExampleFilteredEntityComponent::m_filterNamesForEvenConnectionIds )
->Field( "Filter Names for Odd Connections", &ExampleFilteredEntityComponent::m_filterNamesForOddConnectionIds )
->Version(1);

if (AZ::EditContext* editContext = serializeContext->GetEditContext())
{
using namespace AZ::Edit;
editContext->Class<ExampleFilteredEntityComponent>("ExampleFilteredEntityComponent", "An example of filtering entities out in network replication")
->ClassElement(ClassElements::EditorData, "")
->Attribute(AZ::Edit::Attributes::Category, "MultiplayerSample")
->Attribute(AZ::Edit::Attributes::AppearsInAddComponentMenu, AZ_CRC_CE("Level"))
->DataElement(nullptr, &ExampleFilteredEntityComponent::m_enabled, "Enabled", "enabled if checked")
->DataElement(nullptr, &ExampleFilteredEntityComponent::m_filterNamesForEvenConnectionIds, "Filter for Even",
"if an entity starts with this prefix, don't send them to even connections")
->DataElement(nullptr, &ExampleFilteredEntityComponent::m_filterNamesForOddConnectionIds, "Filter for Odd",
"if an entity starts with this prefix, don't send them to odd connections")
;
}
}
}

void ExampleFilteredEntityComponent::Activate()
{
Multiplayer::GetMultiplayer()->SetFilterEntityManager( this );
}

void ExampleFilteredEntityComponent::Deactivate()
{
Multiplayer::GetMultiplayer()->SetFilterEntityManager( nullptr );
}

bool ExampleFilteredEntityComponent::IsEntityFiltered(
[[maybe_unused]] AZ::Entity* entity,
[[maybe_unused]] Multiplayer::ConstNetworkEntityHandle controllerEntity,
[[maybe_unused]] AzNetworking::ConnectionId connectionId)
{
if (m_enabled && mps_EnableFilteringEntities)
{
// Note: @IsEntityFiltered is a hot code path, so do your best to optimize this method.
// This example just uses entity names for filtering, for the sake of simplicity.
// In practice, one might implement this lookup using a specialized structure such as AZStd::map<AZ::EntityId, bool>, etc.

const bool evenConnectionId = static_cast<uint32_t>(connectionId) % 2 == 0;

if (entity->GetName().starts_with( evenConnectionId ? m_filterNamesForEvenConnectionIds : m_filterNamesForOddConnectionIds ))
{
return true;
}
}

return false;
}
}
43 changes: 43 additions & 0 deletions Gem/Code/Source/Components/ExampleFilteredEntityComponent.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
/*
* Copyright (c) Contributors to the Open 3D Engine Project
*
* SPDX-License-Identifier: Apache-2.0 OR MIT
*
*/

#pragma once

#include <AzCore/Component/Component.h>
#include <Multiplayer/NetworkEntity/IFilterEntityManager.h>

namespace MultiplayerSample
{
//! @class ExampleFilteredEntityComponent
//! @brief An example of using IFilterEntityManager to filter entities to clients.
class ExampleFilteredEntityComponent final
: public AZ::Component
, public Multiplayer::IFilterEntityManager
{
public:
AZ_COMPONENT(MultiplayerSample::ExampleFilteredEntityComponent, "{7BF3BF1D-383A-40E7-BCF2-1ED5B2D2A43C}");

static void Reflect(AZ::ReflectContext* context);

//! AZ::Component overrides.
//! @{
void Activate() override;
void Deactivate() override;
//! }@

//! IFilterEntityManager overrides.
//! @{
bool IsEntityFiltered(AZ::Entity* entity, Multiplayer::ConstNetworkEntityHandle controllerEntity, AzNetworking::ConnectionId connectionId) override;
//! }@

private:
bool m_enabled = true;

AZStd::string m_filterNamesForEvenConnectionIds{ "Filter Even" };
AZStd::string m_filterNamesForOddConnectionIds{ "Filter Odd" };
};
}
7 changes: 5 additions & 2 deletions Gem/Code/Source/Components/NetworkAnimationComponent.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -91,8 +91,11 @@ namespace MultiplayerSample
return;
}

constexpr bool isAuthoritative = true;
m_networkRequests->CreateSnapshot(isAuthoritative);
if (m_networkRequests->HasSnapshot() == false)
{
constexpr bool isAuthoritative = true;
m_networkRequests->CreateSnapshot(isAuthoritative);
}
m_networkRequests->UpdateActorExternal(deltaTime);

if (m_velocityParamId == InvalidParamIndex)
Expand Down
2 changes: 2 additions & 0 deletions Gem/Code/Source/MultiplayerSampleModule.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@

#include <AzCore/Memory/SystemAllocator.h>
#include <AzCore/Module/Module.h>
#include <Components/ExampleFilteredEntityComponent.h>
#include <Source/AutoGen/AutoComponentTypes.h>

#include "MultiplayerSampleSystemComponent.h"
Expand All @@ -26,6 +27,7 @@ namespace MultiplayerSample
// Push results of [MyComponent]::CreateDescriptor() into m_descriptors here.
m_descriptors.insert(m_descriptors.end(), {
MultiplayerSampleSystemComponent::CreateDescriptor(),
ExampleFilteredEntityComponent::CreateDescriptor(),
});

CreateComponentDescriptors(m_descriptors);
Expand Down
2 changes: 2 additions & 0 deletions Gem/Code/multiplayersample_files.cmake
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,8 @@ set(FILES
Source/Components/AnimatedHitVolumesComponent.h
Source/Components/CharacterComponent.cpp
Source/Components/CharacterComponent.h
Source/Components/ExampleFilteredEntityComponent.h
Source/Components/ExampleFilteredEntityComponent.cpp
Source/Components/NetworkAnimationComponent.cpp
Source/Components/NetworkAnimationComponent.h
Source/Components/NetworkPlayerSpawnerComponent.cpp
Expand Down
141 changes: 135 additions & 6 deletions Levels/SampleBase/SampleBase.prefab
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
{
"Source": "Levels/SampleBase/SampleBase.prefab",
"ContainerEntity": {
"Id": "Entity_[356758116574]",
"Name": "Level",
Expand Down Expand Up @@ -49,6 +48,13 @@
"Component_[8247764638131379605]": {
"$type": "EditorEntitySortComponent",
"Id": 8247764638131379605
},
"Component_[17738894840857488786]": {
"$type": "GenericComponentWrapper",
"Id": 17738894840857488786,
"m_template": {
"$type": "MultiplayerSample::ExampleFilteredEntityComponent"
}
}
},
"IsDependencyReady": true
Expand Down Expand Up @@ -195,6 +201,13 @@
"Controller": {
"Configuration": {
"diffuseImageAsset": {
"assetId": {
"guid": "{4CF4C63C-B317-5E0B-B523-44167A02F81E}",
"subId": 3000
},
"assetHint": "testdata/lightingpresets/beach_parking_1k_iblglobalcm_ibldiffuse.exr.streamingimage"
},
"specularImageAsset": {
"assetId": {
"guid": "{4CF4C63C-B317-5E0B-B523-44167A02F81E}",
"subId": 2000
Expand Down Expand Up @@ -231,7 +244,12 @@
0.0,
0.0,
-0.5
]
],
"MaterialSelection": {
"MaterialIds": [
{}
]
}
}
}
},
Expand Down Expand Up @@ -322,7 +340,7 @@
},
"Entity_[391688917776]": {
"Id": "Entity_[391688917776]",
"Name": "Entity1",
"Name": "Box1",
"Components": {
"Component_[11653223786701195962]": {
"$type": "SelectionComponent",
Expand Down Expand Up @@ -434,6 +452,13 @@
"Id": 11384954117619258935,
"ShapeConfiguration": {
"ShapeType": 1
},
"ColliderConfiguration": {
"MaterialSelection": {
"MaterialIds": [
{}
]
}
}
},
"Component_[8125251054274400256]": {
Expand Down Expand Up @@ -462,13 +487,20 @@
},
"Entity_[514163319219]": {
"Id": "Entity_[514163319219]",
"Name": "Entity1",
"Name": "Box2",
"Components": {
"Component_[11384954117619258935]": {
"$type": "EditorColliderComponent",
"Id": 11384954117619258935,
"ShapeConfiguration": {
"ShapeType": 1
},
"ColliderConfiguration": {
"MaterialSelection": {
"MaterialIds": [
{}
]
}
}
},
"Component_[11653223786701195962]": {
Expand Down Expand Up @@ -610,13 +642,20 @@
},
"Entity_[668782141875]": {
"Id": "Entity_[668782141875]",
"Name": "Entity1",
"Name": "Box4",
"Components": {
"Component_[11384954117619258935]": {
"$type": "EditorColliderComponent",
"Id": 11384954117619258935,
"ShapeConfiguration": {
"ShapeType": 1
},
"ColliderConfiguration": {
"MaterialSelection": {
"MaterialIds": [
{}
]
}
}
},
"Component_[11653223786701195962]": {
Expand Down Expand Up @@ -758,13 +797,20 @@
},
"Entity_[673077109171]": {
"Id": "Entity_[673077109171]",
"Name": "Entity1",
"Name": "Box3",
"Components": {
"Component_[11384954117619258935]": {
"$type": "EditorColliderComponent",
"Id": 11384954117619258935,
"ShapeConfiguration": {
"ShapeType": 1
},
"ColliderConfiguration": {
"MaterialSelection": {
"MaterialIds": [
{}
]
}
}
},
"Component_[11653223786701195962]": {
Expand Down Expand Up @@ -903,6 +949,89 @@
},
"IsDependencyReady": true,
"IsRuntimeActive": true
},
"Entity_[1863191303392]": {
"Id": "Entity_[1863191303392]",
"Name": "Spawn On Server",
"Components": {
"Component_[11694963092145732257]": {
"$type": "EditorPendingCompositionComponent",
"Id": 11694963092145732257
},
"Component_[12168972718315127051]": {
"$type": "EditorEntityIconComponent",
"Id": 12168972718315127051
},
"Component_[15194128185768259769]": {
"$type": "EditorLockComponent",
"Id": 15194128185768259769
},
"Component_[15807254068344673462]": {
"$type": "EditorVisibilityComponent",
"Id": 15807254068344673462
},
"Component_[16123618383967744353]": {
"$type": "EditorEntitySortComponent",
"Id": 16123618383967744353
},
"Component_[17552782890585275482]": {
"$type": "EditorInspectorComponent",
"Id": 17552782890585275482
},
"Component_[495949337740718080]": {
"$type": "{27F1E1A1-8D9D-4C3B-BD3A-AFB9762449C0} TransformComponent",
"Id": 495949337740718080,
"Parent Entity": "Entity_[356758116574]",
"Transform Data": {
"Translate": [
11.002283096313477,
6.703400611877441,
12.253546714782717
]
},
"Cached World Transform": {
"Translation": [
11.002283096313477,
6.703400611877441,
12.253546714782717
]
},
"Cached World Transform Parent": "Entity_[356758116574]"
},
"Component_[6471614284017878558]": {
"$type": "EditorOnlyEntityComponent",
"Id": 6471614284017878558
},
"Component_[8728229503371540755]": {
"$type": "SelectionComponent",
"Id": 8728229503371540755
},
"Component_[9871950863787101514]": {
"$type": "EditorDisabledCompositionComponent",
"Id": 9871950863787101514
},
"Component_[92855489511868459]": {
"$type": "GenericComponentWrapper",
"Id": 92855489511868459,
"m_template": {
"$type": "NetBindComponent"
}
},
"Component_[12802329719955739455]": {
"$type": "EditorScriptCanvasComponent",
"Id": 12802329719955739455,
"m_name": "SpawnIfAuthority",
"m_assetHolder": {
"m_asset": {
"assetId": {
"guid": "{B605AD71-0689-5650-B3F5-558D471B6351}"
},
"assetHint": "scriptcanvas/spawnifauthority.scriptcanvas"
}
}
}
},
"IsDependencyReady": true
}
}
}
Loading

0 comments on commit bc82160

Please sign in to comment.