Files
UnrealEngine/Engine/Plugins/Runtime/ReplicationSystemTestPlugin/Source/Private/Tests/ReplicationSystem/TestDependentObjects.cpp
2025-05-18 13:04:45 +08:00

949 lines
42 KiB
C++

// Copyright Epic Games, Inc. All Rights Reserved.
#include "ReplicationSystemServerClientTestFixture.h"
#include "Iris/ReplicationSystem/ReplicationSystem.h"
#include "Iris/ReplicationSystem/Filtering/NetObjectFilterDefinitions.h"
#include "Tests/ReplicationSystem/Filtering/MockNetObjectFilter.h"
namespace UE::Net::Private
{
class FTestFilteredDependentObjectFixture : public FReplicationSystemServerClientTestFixture
{
protected:
virtual void SetUp() override
{
InitFilterDefinitions();
FReplicationSystemServerClientTestFixture::SetUp();
InitFilterHandles();
}
virtual void TearDown() override
{
FReplicationSystemServerClientTestFixture::TearDown();
RestoreFilterDefinitions();
}
void SetMockFilterStatus(UE::Net::ENetFilterStatus FilterStatus)
{
UMockNetObjectFilter::FFunctionCallSetup CallSetup;
CallSetup.AddObject.bReturnValue = true;
CallSetup.Filter.bFilterOutByDefault = FilterStatus == UE::Net::ENetFilterStatus::Disallow;
MockFilter->SetFunctionCallSetup(CallSetup);
}
FNetObjectFilterHandle NotRoutedFilterHandle = InvalidNetObjectFilterHandle;
FNetObjectFilterHandle MockFilterHandle = InvalidNetObjectFilterHandle;
TObjectPtr<UMockNetObjectFilter> MockFilter = nullptr;
private:
void InitFilterDefinitions()
{
const UClass* NetObjectFilterDefinitionsClass = UNetObjectFilterDefinitions::StaticClass();
const FProperty* DefinitionsProperty = NetObjectFilterDefinitionsClass->FindPropertyByName("NetObjectFilterDefinitions");
check(DefinitionsProperty != nullptr);
// Save CDO state.
UNetObjectFilterDefinitions* FilterDefinitions = GetMutableDefault<UNetObjectFilterDefinitions>();
DefinitionsProperty->CopyCompleteValue(&OriginalFilterDefinitions, (void*)(UPTRINT(FilterDefinitions) + DefinitionsProperty->GetOffset_ForInternal()));
// Modify definitions to only include our filters.
TArray<FNetObjectFilterDefinition> NewFilterDefinitions;
{
FNetObjectFilterDefinition& NotRoutedDefinition = NewFilterDefinitions.Emplace_GetRef();
NotRoutedDefinition.FilterName = "NotRouted";
NotRoutedDefinition.ClassName = "/Script/IrisCore.FilterOutNetObjectFilter";
NotRoutedDefinition.ConfigClassName = "/Script/IrisCore.NetObjectGridFilterConfig";
}
{
FNetObjectFilterDefinition& MockDefinition = NewFilterDefinitions.Emplace_GetRef();
MockDefinition.FilterName = "MockFilter";
MockDefinition.ClassName = "/Script/ReplicationSystemTestPlugin.MockNetObjectFilter";
MockDefinition.ConfigClassName = "/Script/ReplicationSystemTestPlugin.MockNetObjectFilterConfig";
}
DefinitionsProperty->CopyCompleteValue((void*)(UPTRINT(FilterDefinitions) + DefinitionsProperty->GetOffset_ForInternal()), &NewFilterDefinitions);
}
void RestoreFilterDefinitions()
{
// Restore CDO state from the saved state.
const UClass* NetObjectFilterDefinitionsClass = UNetObjectFilterDefinitions::StaticClass();
const FProperty* DefinitionsProperty = NetObjectFilterDefinitionsClass->FindPropertyByName("NetObjectFilterDefinitions");
UNetObjectFilterDefinitions* FilterDefinitions = GetMutableDefault<UNetObjectFilterDefinitions>();
DefinitionsProperty->CopyCompleteValue((void*)(UPTRINT(FilterDefinitions) + DefinitionsProperty->GetOffset_ForInternal()), &OriginalFilterDefinitions);
OriginalFilterDefinitions.Empty();
NotRoutedFilterHandle = InvalidNetObjectFilterHandle;
MockFilterHandle = InvalidNetObjectFilterHandle;
MockFilter = nullptr;
}
void InitFilterHandles()
{
NotRoutedFilterHandle = Server->GetReplicationSystem()->GetFilterHandle("NotRouted");
MockFilterHandle = Server->GetReplicationSystem()->GetFilterHandle("MockFilter");
MockFilter = Cast<UMockNetObjectFilter>(Server->GetReplicationSystem()->GetFilter("MockFilter"));
}
private:
TArray<FNetObjectFilterDefinition> OriginalFilterDefinitions;
};
UE_NET_TEST_FIXTURE(FReplicationSystemServerClientTestFixture, TestDependentObjectDroppedDataIsRetransmitted)
{
UReplicationSystem* ReplicationSystem = Server->ReplicationSystem;
// Add a client
FReplicationSystemTestClient* Client = CreateClient();
// Spawn object on server
UTestReplicatedIrisObject* ServerObject = Server->CreateObject(0, 0);
// Spawn second object on server add as a dependent object
UTestReplicatedIrisObject* ServerDependentObject = Server->CreateObject(0, 0);
UReplicatedTestObjectBridge* Bridge = Server->GetReplicationBridge();
// Trigger replication
ServerObject->IntA = 1;
// Send and deliver packet
Server->NetUpdate();
Server->SendAndDeliverTo(Client, true);
Server->PostSendUpdate();
Bridge->AddDependentObject(ServerObject->NetRefHandle, ServerDependentObject->NetRefHandle);
ServerDependentObject->IntA = 1;
// Send and deliver packet
Server->NetUpdate();
Server->SendAndDeliverTo(Client, true);
Server->PostSendUpdate();
// Store Pointer to objects
UTestReplicatedIrisObject* ClientObject = Cast<UTestReplicatedIrisObject>(Client->GetReplicationBridge()->GetReplicatedObject(ServerObject->NetRefHandle));
UTestReplicatedIrisObject* ClientDependentObject = Cast<UTestReplicatedIrisObject>(Client->GetReplicationBridge()->GetReplicatedObject(ServerDependentObject->NetRefHandle));
UE_NET_ASSERT_NE(ClientDependentObject, nullptr);
UE_NET_ASSERT_EQ(ServerDependentObject->IntA, ClientDependentObject->IntA);
// Modify the value of dependent object only
ServerDependentObject->IntA = 2;
// Send and do not deliver packet
Server->NetUpdate();
Server->SendAndDeliverTo(Client, false);
Server->PostSendUpdate();
// Verify that the final state was applied to dependent object
UE_NET_ASSERT_NE(ServerDependentObject->IntA, ClientDependentObject->IntA);
// Send and deliver packet
Server->NetUpdate();
Server->SendAndDeliverTo(Client, true);
Server->PostSendUpdate();
// Verify that the final state was applied to dependent object
UE_NET_ASSERT_EQ(ServerDependentObject->IntA, ClientDependentObject->IntA);
}
// Dependent objects
UE_NET_TEST_FIXTURE(FReplicationSystemServerClientTestFixture, TestDependentObjectWithZeroPrioOnlyReplicatesWithParent)
{
UReplicationSystem* ReplicationSystem = Server->ReplicationSystem;
UReplicatedTestObjectBridge* Bridge = Server->GetReplicationBridge();
// Add a client
FReplicationSystemTestClient* Client = CreateClient();
// Spawn object on server
UTestReplicatedIrisObject* ServerObject = Server->CreateObject(0, 0);
// Filter out Server object to start with
FNetObjectGroupHandle FilterGroup = ReplicationSystem->CreateGroup(NAME_None);
ReplicationSystem->AddExclusionFilterGroup(FilterGroup);
ReplicationSystem->AddToGroup(FilterGroup, ServerObject->NetRefHandle);
// Setup dependent object to only replicate with ServerObject
UTestReplicatedIrisObject* ServerDependentObject = Server->CreateObject(0, 0);
ReplicationSystem->SetStaticPriority(ServerDependentObject->NetRefHandle, 0.f);
Bridge->AddDependentObject(ServerObject->NetRefHandle, ServerDependentObject->NetRefHandle);
// Send and deliver packet
Server->NetUpdate();
Server->SendAndDeliverTo(Client, true);
Server->PostSendUpdate();
// Objects should not be created on client
UTestReplicatedIrisObject* ClientObject = Cast<UTestReplicatedIrisObject>(Client->GetReplicationBridge()->GetReplicatedObject(ServerObject->NetRefHandle));
UTestReplicatedIrisObject* ClientDependentObject = Cast<UTestReplicatedIrisObject>(Client->GetReplicationBridge()->GetReplicatedObject(ServerDependentObject->NetRefHandle));
UE_NET_ASSERT_EQ(ClientObject, nullptr);
UE_NET_ASSERT_EQ(ClientDependentObject, nullptr);
// Enable
ReplicationSystem->SetGroupFilterStatus(FilterGroup, ENetFilterStatus::Allow);
// Send and deliver packet
Server->NetUpdate();
Server->SendAndDeliverTo(Client, true);
Server->PostSendUpdate();
// Objects should now exist on client
ClientObject = Cast<UTestReplicatedIrisObject>(Client->GetReplicationBridge()->GetReplicatedObject(ServerObject->NetRefHandle));
ClientDependentObject = Cast<UTestReplicatedIrisObject>(Client->GetReplicationBridge()->GetReplicatedObject(ServerDependentObject->NetRefHandle));
UE_NET_ASSERT_NE(ClientObject, nullptr);
UE_NET_ASSERT_NE(ClientDependentObject, nullptr);
}
// Chained dependent objects
UE_NET_TEST_FIXTURE(FReplicationSystemServerClientTestFixture, TestChainedDependentObjectWithZeroPrio)
{
UReplicationSystem* ReplicationSystem = Server->ReplicationSystem;
UReplicatedTestObjectBridge* Bridge = Server->GetReplicationBridge();
// Add a client
FReplicationSystemTestClient* Client = CreateClient();
// Spawn object on server
UTestReplicatedIrisObject* ServerObject = Server->CreateObject(0, 0);
// Filter out Server object to start with
FNetObjectGroupHandle FilterGroup = ReplicationSystem->CreateGroup(NAME_None);
ReplicationSystem->AddExclusionFilterGroup(FilterGroup);
ReplicationSystem->AddToGroup(FilterGroup, ServerObject->NetRefHandle);
// Setup dependent object to only replicate with ServerObject
UTestReplicatedIrisObject* ServerDependentObject0 = Server->CreateObject(0, 0);
UTestReplicatedIrisObject* ServerDependentObject1 = Server->CreateObject(0, 0);
ReplicationSystem->SetStaticPriority(ServerDependentObject0->NetRefHandle, 0.f);
ReplicationSystem->SetStaticPriority(ServerDependentObject1->NetRefHandle, 0.f);
// Setup dependency chain
Bridge->AddDependentObject(ServerObject->NetRefHandle, ServerDependentObject0->NetRefHandle);
Bridge->AddDependentObject(ServerDependentObject0->NetRefHandle, ServerDependentObject1->NetRefHandle);
// Send and deliver packet
Server->NetUpdate();
Server->SendAndDeliverTo(Client, true);
Server->PostSendUpdate();
// Objects should not be created on client
UTestReplicatedIrisObject* ClientObject = Cast<UTestReplicatedIrisObject>(Client->GetReplicationBridge()->GetReplicatedObject(ServerObject->NetRefHandle));
UTestReplicatedIrisObject* ClientDependentObject0 = Cast<UTestReplicatedIrisObject>(Client->GetReplicationBridge()->GetReplicatedObject(ServerDependentObject0->NetRefHandle));
UTestReplicatedIrisObject* ClientDependentObject1 = Cast<UTestReplicatedIrisObject>(Client->GetReplicationBridge()->GetReplicatedObject(ServerDependentObject1->NetRefHandle));
UE_NET_ASSERT_EQ(ClientObject, nullptr);
UE_NET_ASSERT_EQ(ClientDependentObject0, nullptr);
UE_NET_ASSERT_EQ(ClientDependentObject1, nullptr);
// Enable the parent
ReplicationSystem->SetGroupFilterStatus(FilterGroup, ENetFilterStatus::Allow);
// Send and deliver packet
Server->NetUpdate();
Server->SendAndDeliverTo(Client, true);
Server->PostSendUpdate();
// Verify that dependent object now is created
ClientObject = Cast<UTestReplicatedIrisObject>(Client->GetReplicationBridge()->GetReplicatedObject(ServerObject->NetRefHandle));
ClientDependentObject0 = Cast<UTestReplicatedIrisObject>(Client->GetReplicationBridge()->GetReplicatedObject(ServerDependentObject0->NetRefHandle));
ClientDependentObject1 = Cast<UTestReplicatedIrisObject>(Client->GetReplicationBridge()->GetReplicatedObject(ServerDependentObject1->NetRefHandle));
UE_NET_ASSERT_NE(ClientObject, nullptr);
UE_NET_ASSERT_NE(ClientDependentObject0, nullptr);
UE_NET_ASSERT_NE(ClientDependentObject1, nullptr);
}
UE_NET_TEST_FIXTURE(FReplicationSystemServerClientTestFixture, TestDependentObjectPollFrequency)
{
UReplicationSystem* ReplicationSystem = Server->ReplicationSystem;
// Add a client
FReplicationSystemTestClient* Client = CreateClient();
// Spawn object on server
UTestReplicatedIrisObject* ServerObject = Server->CreateObject(0, 0);
// Spawn second object on server that later will be added as a dependent object
// With high PollFramePeriod so that it will not replicate in a while unless it is a dependent
UObjectReplicationBridge::FRootObjectReplicationParams Params;
Params.PollFrequency = Server->ConvertPollPeriodIntoFrequency(255U);
UTestReplicatedIrisObject* ServerDependentObject = Server->CreateObject(Params);
// Send and deliver packet
Server->NetUpdate();
Server->SendAndDeliverTo(Client, true);
Server->PostSendUpdate();
// Store Pointer to objects and verify state after initial replication
UTestReplicatedIrisObject* ClientObject = Cast<UTestReplicatedIrisObject>(Client->GetReplicationBridge()->GetReplicatedObject(ServerObject->NetRefHandle));
UTestReplicatedIrisObject* ClientDependentObject = Cast<UTestReplicatedIrisObject>(Client->GetReplicationBridge()->GetReplicatedObject(ServerDependentObject->NetRefHandle));
UE_NET_ASSERT_NE(ClientDependentObject, nullptr);
UE_NET_ASSERT_NE(ClientObject, nullptr);
UE_NET_ASSERT_EQ(ClientObject->IntA, ServerObject->IntA);
UE_NET_ASSERT_EQ(ClientDependentObject->IntA, ServerDependentObject->IntA);
// Trigger replication
constexpr uint32 MaxIterationCount = 256;
uint32 It = 0;
for (const uint32 EndIt = MaxIterationCount; It < EndIt; ++It)
{
ServerObject->IntA += 1;
ServerDependentObject->IntA += 1;
// Send and deliver packet
Server->NetUpdate();
Server->SendAndDeliverTo(Client, true);
Server->PostSendUpdate();
UE_NET_ASSERT_EQ(ServerObject->IntA, ClientObject->IntA);
// Verify that only the server object has been updated
if (ClientDependentObject->IntA != ServerDependentObject->IntA)
{
break;
}
}
// At some point the object is expected not to be polled
UE_NET_ASSERT_LT(It, MaxIterationCount);
// Add dependency
Server->ReplicationBridge->AddDependentObject(ServerObject->NetRefHandle, ServerDependentObject->NetRefHandle);
// Change a value on owner
ServerObject->IntA += 1;
// Send and deliver packet
Server->NetUpdate();
Server->SendAndDeliverTo(Client, true);
Server->PostSendUpdate();
// We now expect both objects to be in sync
UE_NET_ASSERT_EQ(ClientObject->IntA, ServerObject->IntA);
UE_NET_ASSERT_EQ(ClientDependentObject->IntA, ServerDependentObject->IntA);
}
UE_NET_TEST_FIXTURE(FReplicationSystemServerClientTestFixture, TestDependentObjectPollWithDirtyParent)
{
UReplicationSystem* ReplicationSystem = Server->ReplicationSystem;
// Add a client
FReplicationSystemTestClient* Client = CreateClient();
// Spawn object on server
UObjectReplicationBridge::FRootObjectReplicationParams Params;
// Setup different poll frequencies for the objects
Params.PollFrequency = Server->ConvertPollPeriodIntoFrequency(10U);
UTestReplicatedIrisObject* ServerObject0 = Server->CreateObject(Params);
Params.PollFrequency = Server->ConvertPollPeriodIntoFrequency(20U);
UTestReplicatedIrisObject* ServerObject1 = Server->CreateObject(Params);
// Spawn second object on server that later will be added as a dependent object
Params.PollFrequency = Server->ConvertPollPeriodIntoFrequency(40U);
UTestReplicatedIrisObject* ServerDependentObject = Server->CreateObject(Params);
// Add dependent object to both server objects
Server->ReplicationBridge->AddDependentObject(ServerObject0->NetRefHandle, ServerDependentObject->NetRefHandle);
Server->ReplicationBridge->AddDependentObject(ServerObject1->NetRefHandle, ServerDependentObject->NetRefHandle);
// Send and deliver packet, All objects are polled and replicated
Server->NetUpdate();
Server->SendAndDeliverTo(Client, true);
Server->PostSendUpdate();
// Verify state after initial replication
UTestReplicatedIrisObject* ClientDependentObject = Cast<UTestReplicatedIrisObject>(Client->GetReplicationBridge()->GetReplicatedObject(ServerDependentObject->NetRefHandle));
UTestReplicatedIrisObject* ClientObject0 = Cast<UTestReplicatedIrisObject>(Client->GetReplicationBridge()->GetReplicatedObject(ServerObject0->NetRefHandle));
UTestReplicatedIrisObject* ClientObject1 = Cast<UTestReplicatedIrisObject>(Client->GetReplicationBridge()->GetReplicatedObject(ServerObject1->NetRefHandle));
UE_NET_ASSERT_NE(ClientDependentObject, nullptr);
UE_NET_ASSERT_NE(ClientObject0, nullptr);
UE_NET_ASSERT_NE(ClientObject1, nullptr);
UE_NET_ASSERT_EQ(ClientDependentObject->IntA, 0);
const uint32 TickCount = 256;
int PrevRcvdValue = 0;
uint32 RepCount0 = 0U;
uint32 RepCount1 = 0U;
uint32 RepCountDependent = 0U;
for (uint32 CurrentFrame = 1U; CurrentFrame < TickCount; ++CurrentFrame)
{
ServerObject0->IntA = CurrentFrame;
ServerObject1->IntA = CurrentFrame;
ServerDependentObject->IntA = CurrentFrame;
// Send and deliver packet
Server->NetUpdate();
Server->SendAndDeliverTo(Client, true);
Server->PostSendUpdate();
const int RcvdValue = ClientDependentObject->IntA;
if (RcvdValue != PrevRcvdValue)
{
if (RcvdValue == ClientObject0->IntA)
{
++RepCount0;
}
if (RcvdValue == ClientObject1->IntA)
{
++RepCount1;
}
++RepCountDependent;
}
PrevRcvdValue = RcvdValue;
}
// We expect the dependent object to have replicated more often than the parents
UE_NET_ASSERT_GE(RepCountDependent, RepCount0);
UE_NET_ASSERT_GE(RepCountDependent, RepCount1);
}
UE_NET_TEST_FIXTURE(FReplicationSystemServerClientTestFixture, TestDependentObjectIsPolledIfParentIsMarkedDirty)
{
UReplicationSystem* ReplicationSystem = Server->ReplicationSystem;
// Add a client
FReplicationSystemTestClient* Client = CreateClient();
// Spawn object on server
UObjectReplicationBridge::FRootObjectReplicationParams Params;
Params.PollFrequency = Server->ConvertPollPeriodIntoFrequency(14U);
UTestReplicatedIrisObject* ServerObject = Server->CreateObject(Params);
// Spawn second object add it as a dependency and bump poll period
Params.PollFrequency = Server->ConvertPollPeriodIntoFrequency(30U);
UTestReplicatedIrisObject* ServerDependentObject = Server->CreateObject(Params);
Server->ReplicationBridge->AddDependentObject(ServerObject->NetRefHandle, ServerDependentObject->NetRefHandle);
// Send and deliver packet
Server->NetUpdate();
Server->SendAndDeliverTo(Client, true);
Server->PostSendUpdate();
// Store Pointer to objects and verify state after initial replication
UTestReplicatedIrisObject* ClientObject = Cast<UTestReplicatedIrisObject>(Client->GetReplicationBridge()->GetReplicatedObject(ServerObject->NetRefHandle));
UTestReplicatedIrisObject* ClientDependentObject = Cast<UTestReplicatedIrisObject>(Client->GetReplicationBridge()->GetReplicatedObject(ServerDependentObject->NetRefHandle));
// Modify data until none of the objects are replicated, due to the set polling frequencies.
constexpr uint32 MaxIterationCount = 32;
uint32 It = 0;
for (const uint32 EndIt = MaxIterationCount; It < EndIt; ++It)
{
ServerObject->IntA += 1;
ServerDependentObject->IntA += 1;
// Send and deliver packet
Server->NetUpdate();
Server->SendAndDeliverTo(Client, true);
Server->PostSendUpdate();
// Verify that nothing replicated
if (ClientObject->IntA != ServerObject->IntA && ClientDependentObject->IntA != ServerDependentObject->IntA)
{
break;
}
}
// If we hit this assert then it's likely the poll frequency limiter is broken.
UE_NET_ASSERT_LT(It, MaxIterationCount);
// Mark dependent dirty
ReplicationSystem->ForceNetUpdate(ServerDependentObject->NetRefHandle);
// Send and deliver packet, we expect dependent object to have replicated
Server->NetUpdate();
Server->SendAndDeliverTo(Client, true);
Server->PostSendUpdate();
UE_NET_EXPECT_NE(ClientObject->IntA, ServerObject->IntA);
// Verify that dependent object has replicated
UE_NET_ASSERT_EQ(ClientDependentObject->IntA, ServerDependentObject->IntA);
// Modify data
ServerObject->IntA += 2;
ServerDependentObject->IntA += 2;
// Mark parent dirty
ReplicationSystem->ForceNetUpdate(ServerObject->NetRefHandle);
// Send and deliver packet
Server->NetUpdate();
Server->SendAndDeliverTo(Client, true);
Server->PostSendUpdate();
// Verify that both objects have replicated
UE_NET_ASSERT_EQ(ClientObject->IntA, ServerObject->IntA);
UE_NET_ASSERT_EQ(ClientDependentObject->IntA, ServerDependentObject->IntA);
}
UE_NET_TEST_FIXTURE(FReplicationSystemServerClientTestFixture, TestDependentObjectScheduledAfterParent)
{
UReplicationSystem* ReplicationSystem = Server->ReplicationSystem;
UReplicatedTestObjectBridge* Bridge = Server->GetReplicationBridge();
// Add a client
FReplicationSystemTestClient* Client = CreateClient();
// Spawn object on server
UReplicatedSubObjectOrderObject* ServerObject = Server->CreateObject<UReplicatedSubObjectOrderObject>();
// Spawn dependent object
UReplicatedSubObjectOrderObject* ServerDependentObject = Server->CreateObject<UReplicatedSubObjectOrderObject>();
Bridge->AddDependentObject(ServerObject->NetRefHandle, ServerDependentObject->NetRefHandle);
// Set prio to only replicate with parent
ReplicationSystem->SetStaticPriority(ServerDependentObject->NetRefHandle, 0.f);
// Reset RepOrderCounter
UReplicatedSubObjectOrderObject::RepOrderCounter = 0U;
// Send and deliver packet
Server->NetUpdate();
Server->SendAndDeliverTo(Client, true);
Server->PostSendUpdate();
// Verify that objects have replicated
UReplicatedSubObjectOrderObject* ClientObject = Cast<UReplicatedSubObjectOrderObject>(Client->GetReplicationBridge()->GetReplicatedObject(ServerObject->NetRefHandle));
UReplicatedSubObjectOrderObject* ClientDependentObject = Cast<UReplicatedSubObjectOrderObject>(Client->GetReplicationBridge()->GetReplicatedObject(ServerDependentObject->NetRefHandle));
UE_NET_ASSERT_NE(ClientObject, nullptr);
UE_NET_ASSERT_NE(ClientDependentObject, nullptr);
// Verify that they have replicated in expected order for initial objects
UE_NET_ASSERT_GT(ClientDependentObject->LastRepOrderCounter, ClientObject->LastRepOrderCounter);
// Modify both parent and dependent
ServerObject->IntA = 1;
ServerDependentObject->IntA = 1;
// Send and deliver packet
Server->NetUpdate();
Server->SendAndDeliverTo(Client, true);
Server->PostSendUpdate();
// Verify that they have replicated in expected order
UE_NET_ASSERT_GT(ClientDependentObject->LastRepOrderCounter, ClientObject->LastRepOrderCounter);
}
UE_NET_TEST_FIXTURE(FReplicationSystemServerClientTestFixture, TestDependentObjectScheduledBeforeParent)
{
UReplicationSystem* ReplicationSystem = Server->ReplicationSystem;
UReplicatedTestObjectBridge* Bridge = Server->GetReplicationBridge();
// Add a client
FReplicationSystemTestClient* Client = CreateClient();
// Spawn object on server
UReplicatedSubObjectOrderObject* ServerObject = Server->CreateObject<UReplicatedSubObjectOrderObject>();
// Spawn dependent object
UReplicatedSubObjectOrderObject* ServerDependentObject = Server->CreateObject<UReplicatedSubObjectOrderObject>();
Bridge->AddDependentObject(ServerObject->NetRefHandle, ServerDependentObject->NetRefHandle, EDependentObjectSchedulingHint::ScheduleBeforeParent);
// Set prio to only replicate with parent
ReplicationSystem->SetStaticPriority(ServerDependentObject->NetRefHandle, 0.f);
// Reset RepOrderCounter
UReplicatedSubObjectOrderObject::RepOrderCounter = 0U;
// Send and deliver packet
Server->NetUpdate();
Server->SendAndDeliverTo(Client, true);
Server->PostSendUpdate();
// Verify that objects have replicated
UReplicatedSubObjectOrderObject* ClientObject = Cast<UReplicatedSubObjectOrderObject>(Client->GetReplicationBridge()->GetReplicatedObject(ServerObject->NetRefHandle));
UReplicatedSubObjectOrderObject* ClientDependentObject = Cast<UReplicatedSubObjectOrderObject>(Client->GetReplicationBridge()->GetReplicatedObject(ServerDependentObject->NetRefHandle));
UE_NET_ASSERT_NE(ClientObject, nullptr);
UE_NET_ASSERT_NE(ClientDependentObject, nullptr);
// Verify that they have replicated in expected order for initial objects
UE_NET_ASSERT_LT(ClientDependentObject->LastRepOrderCounter, ClientObject->LastRepOrderCounter);
// Modify both parent and dependent
ServerObject->IntA = 1;
ServerDependentObject->IntA = 1;
// Send and deliver packet
Server->NetUpdate();
Server->SendAndDeliverTo(Client, true);
Server->PostSendUpdate();
// Verify that they have replicated in expected order
UE_NET_ASSERT_LT(ClientDependentObject->LastRepOrderCounter, ClientObject->LastRepOrderCounter);
}
UE_NET_TEST_FIXTURE(FReplicationSystemServerClientTestFixture, TestDependentObjectScheduledBeforeParentIfInitialState)
{
UReplicationSystem* ReplicationSystem = Server->ReplicationSystem;
UReplicatedTestObjectBridge* Bridge = Server->GetReplicationBridge();
// Add a client
FReplicationSystemTestClient* Client = CreateClient();
// Spawn object on server
UReplicatedSubObjectOrderObject* ServerObject = Server->CreateObject<UReplicatedSubObjectOrderObject>();
// Spawn dependent object
UReplicatedSubObjectOrderObject* ServerDependentObject = Server->CreateObject<UReplicatedSubObjectOrderObject>();
Bridge->AddDependentObject(ServerObject->NetRefHandle, ServerDependentObject->NetRefHandle, EDependentObjectSchedulingHint::ScheduleBeforeParentIfInitialState);
// Set prio to only replicate with parent
ReplicationSystem->SetStaticPriority(ServerDependentObject->NetRefHandle, 0.f);
// Reset RepOrderCounter
UReplicatedSubObjectOrderObject::RepOrderCounter = 0U;
// Send and deliver packet
Server->NetUpdate();
Server->SendAndDeliverTo(Client, true);
Server->PostSendUpdate();
// Verify that objects have replicated
UReplicatedSubObjectOrderObject* ClientObject = Cast<UReplicatedSubObjectOrderObject>(Client->GetReplicationBridge()->GetReplicatedObject(ServerObject->NetRefHandle));
UReplicatedSubObjectOrderObject* ClientDependentObject = Cast<UReplicatedSubObjectOrderObject>(Client->GetReplicationBridge()->GetReplicatedObject(ServerDependentObject->NetRefHandle));
UE_NET_ASSERT_NE(ClientObject, nullptr);
UE_NET_ASSERT_NE(ClientDependentObject, nullptr);
// Verify that they have replicated in expected order for initial objects
UE_NET_ASSERT_LT(ClientDependentObject->LastRepOrderCounter, ClientObject->LastRepOrderCounter);
// Modify both parent and dependent
ServerObject->IntA = 1;
ServerDependentObject->IntA = 1;
// Send and deliver packet
Server->NetUpdate();
Server->SendAndDeliverTo(Client, true);
Server->PostSendUpdate();
// Verify that they have replicated in expected order
UE_NET_ASSERT_GT(ClientDependentObject->LastRepOrderCounter, ClientObject->LastRepOrderCounter);
}
UE_NET_TEST_FIXTURE(FReplicationSystemServerClientTestFixture, TestNestedDependentObjectScheduledBeforeParent)
{
UReplicationSystem* ReplicationSystem = Server->ReplicationSystem;
UReplicatedTestObjectBridge* Bridge = Server->GetReplicationBridge();
// Add a client
FReplicationSystemTestClient* Client = CreateClient();
// Spawn objects on server, abusing some assumptions about scheduling order based on assigned internal indices to try out ordering of dependent objects
UReplicatedSubObjectOrderObject* ServerNestedDependentObject = Server->CreateObject<UReplicatedSubObjectOrderObject>();
UReplicatedSubObjectOrderObject* ServerDependentObject = Server->CreateObject<UReplicatedSubObjectOrderObject>();
UReplicatedSubObjectOrderObject* ServerObject = Server->CreateObject<UReplicatedSubObjectOrderObject>();
// Setup dependent object and nested dependent object to both replicate before the parent
Bridge->AddDependentObject(ServerObject->NetRefHandle, ServerDependentObject->NetRefHandle, EDependentObjectSchedulingHint::ScheduleBeforeParent);
Bridge->AddDependentObject(ServerDependentObject->NetRefHandle, ServerNestedDependentObject->NetRefHandle, EDependentObjectSchedulingHint::ScheduleBeforeParent);
// Set static prio to only replicate with parent
ReplicationSystem->SetStaticPriority(ServerDependentObject->NetRefHandle, 0.f);
ReplicationSystem->SetStaticPriority(ServerNestedDependentObject->NetRefHandle, 0.f);
// Reset RepOrderCounter
UReplicatedSubObjectOrderObject::RepOrderCounter = 0U;
// Send and deliver packet
Server->NetUpdate();
Server->SendAndDeliverTo(Client, true);
Server->PostSendUpdate();
// Verify that objects have replicated
UReplicatedSubObjectOrderObject* ClientObject = Cast<UReplicatedSubObjectOrderObject>(Client->GetReplicationBridge()->GetReplicatedObject(ServerObject->NetRefHandle));
UReplicatedSubObjectOrderObject* ClientDependentObject = Cast<UReplicatedSubObjectOrderObject>(Client->GetReplicationBridge()->GetReplicatedObject(ServerDependentObject->NetRefHandle));
UReplicatedSubObjectOrderObject* ClientNestedDependentObject = Cast<UReplicatedSubObjectOrderObject>(Client->GetReplicationBridge()->GetReplicatedObject(ServerNestedDependentObject->NetRefHandle));
UE_NET_ASSERT_NE(ClientObject, nullptr);
UE_NET_ASSERT_NE(ClientDependentObject, nullptr);
UE_NET_ASSERT_NE(ClientNestedDependentObject, nullptr);
// Verify that they have replicated in expected order for initial objects
UE_NET_ASSERT_LT(ClientNestedDependentObject->LastRepOrderCounter, ClientDependentObject->LastRepOrderCounter);
UE_NET_ASSERT_LT(ClientDependentObject->LastRepOrderCounter, ClientObject->LastRepOrderCounter);
// Modify both parent and dependent
ServerObject->IntA = 1;
ServerDependentObject->IntA = 1;
ServerNestedDependentObject->IntA = 1;
// Send and deliver packet
Server->NetUpdate();
Server->SendAndDeliverTo(Client, true);
Server->PostSendUpdate();
// Verify that they have replicated in expected order
UE_NET_ASSERT_LT(ClientNestedDependentObject->LastRepOrderCounter, ClientDependentObject->LastRepOrderCounter);
UE_NET_ASSERT_LT(ClientDependentObject->LastRepOrderCounter, ClientObject->LastRepOrderCounter);
}
UE_NET_TEST_FIXTURE(FReplicationSystemServerClientTestFixture, TestNestedDependentObjectScheduledBeforeParents)
{
UReplicationSystem* ReplicationSystem = Server->ReplicationSystem;
UReplicatedTestObjectBridge* Bridge = Server->GetReplicationBridge();
// Add a client
FReplicationSystemTestClient* Client = CreateClient();
// Spawn objects on server, abusing some assumptions about scheduling order based on assigned internal indices to try out ordering of dependent objects
UReplicatedSubObjectOrderObject* ServerNestedDependentObject = Server->CreateObject<UReplicatedSubObjectOrderObject>();
UReplicatedSubObjectOrderObject* ServerDependentObject = Server->CreateObject<UReplicatedSubObjectOrderObject>();
UReplicatedSubObjectOrderObject* ServerObject = Server->CreateObject<UReplicatedSubObjectOrderObject>();
// Setup dependent object with a nested dependent object that is replicating before its parent
Bridge->AddDependentObject(ServerObject->NetRefHandle, ServerDependentObject->NetRefHandle);
Bridge->AddDependentObject(ServerDependentObject->NetRefHandle, ServerNestedDependentObject->NetRefHandle, EDependentObjectSchedulingHint::ScheduleBeforeParent);
// Set static prio to only replicate with parent
ReplicationSystem->SetStaticPriority(ServerDependentObject->NetRefHandle, 0.f);
ReplicationSystem->SetStaticPriority(ServerNestedDependentObject->NetRefHandle, 0.f);
// Reset RepOrderCounter
UReplicatedSubObjectOrderObject::RepOrderCounter = 0U;
// Send and deliver packet
Server->NetUpdate();
Server->SendAndDeliverTo(Client, true);
Server->PostSendUpdate();
// Verify that objects have replicated
UReplicatedSubObjectOrderObject* ClientObject = Cast<UReplicatedSubObjectOrderObject>(Client->GetReplicationBridge()->GetReplicatedObject(ServerObject->NetRefHandle));
UReplicatedSubObjectOrderObject* ClientDependentObject = Cast<UReplicatedSubObjectOrderObject>(Client->GetReplicationBridge()->GetReplicatedObject(ServerDependentObject->NetRefHandle));
UReplicatedSubObjectOrderObject* ClientNestedDependentObject = Cast<UReplicatedSubObjectOrderObject>(Client->GetReplicationBridge()->GetReplicatedObject(ServerNestedDependentObject->NetRefHandle));
UE_NET_ASSERT_NE(ClientObject, nullptr);
UE_NET_ASSERT_NE(ClientDependentObject, nullptr);
UE_NET_ASSERT_NE(ClientNestedDependentObject, nullptr);
// Verify that they have replicated in expected order for initial objects
UE_NET_ASSERT_LT(ClientNestedDependentObject->LastRepOrderCounter, ClientDependentObject->LastRepOrderCounter);
UE_NET_ASSERT_LT(ClientObject->LastRepOrderCounter, ClientDependentObject->LastRepOrderCounter);
// Modify both parent and dependent
ServerObject->IntA = 1;
ServerDependentObject->IntA = 1;
ServerNestedDependentObject->IntA = 1;
// Send and deliver packet
Server->NetUpdate();
Server->SendAndDeliverTo(Client, true);
Server->PostSendUpdate();
// Verify that they have replicated in expected order
UE_NET_ASSERT_LT(ClientNestedDependentObject->LastRepOrderCounter, ClientDependentObject->LastRepOrderCounter);
UE_NET_ASSERT_LT(ClientObject->LastRepOrderCounter, ClientDependentObject->LastRepOrderCounter);
}
UE_NET_TEST_FIXTURE(FReplicationSystemServerClientTestFixture, TestLateAddedNestedDependentObjectScheduledBeforeParents)
{
UReplicationSystem* ReplicationSystem = Server->ReplicationSystem;
UReplicatedTestObjectBridge* Bridge = Server->GetReplicationBridge();
// Add a client
FReplicationSystemTestClient* Client = CreateClient();
// Spawn objects on server, abusing some assumptions about scheduling order based on assigned internal indices to try out ordering of dependent objects
UReplicatedSubObjectOrderObject* ServerDependentObject = Server->CreateObject<UReplicatedSubObjectOrderObject>();
UReplicatedSubObjectOrderObject* ServerObject = Server->CreateObject<UReplicatedSubObjectOrderObject>();
// Setup dependent object with a nested dependent object that is replicating before its parent
Bridge->AddDependentObject(ServerObject->NetRefHandle, ServerDependentObject->NetRefHandle);
// Set static prio to only replicate with parent
ReplicationSystem->SetStaticPriority(ServerDependentObject->NetRefHandle, 0.f);
// Reset RepOrderCounter
UReplicatedSubObjectOrderObject::RepOrderCounter = 0U;
// Send and deliver packet
Server->NetUpdate();
Server->SendAndDeliverTo(Client, true);
Server->PostSendUpdate();
// Verify that objects have replicated
UReplicatedSubObjectOrderObject* ClientObject = Cast<UReplicatedSubObjectOrderObject>(Client->GetReplicationBridge()->GetReplicatedObject(ServerObject->NetRefHandle));
UReplicatedSubObjectOrderObject* ClientDependentObject = Cast<UReplicatedSubObjectOrderObject>(Client->GetReplicationBridge()->GetReplicatedObject(ServerDependentObject->NetRefHandle));
UE_NET_ASSERT_NE(ClientObject, nullptr);
UE_NET_ASSERT_NE(ClientDependentObject, nullptr);
// Verify that they have replicated in expected order for initial objects
UE_NET_ASSERT_LT(ClientObject->LastRepOrderCounter, ClientDependentObject->LastRepOrderCounter);
// Create new dependent object
UReplicatedSubObjectOrderObject* ServerNestedDependentObject = Server->CreateObject<UReplicatedSubObjectOrderObject>();
Bridge->AddDependentObject(ServerDependentObject->NetRefHandle, ServerNestedDependentObject->NetRefHandle, EDependentObjectSchedulingHint::ScheduleBeforeParent);
ReplicationSystem->SetStaticPriority(ServerNestedDependentObject->NetRefHandle, 0.f);
// Modify parent to trigger replication of new dependent object
ServerObject->IntA = 1;
// Send and deliver packet
Server->NetUpdate();
Server->SendAndDeliverTo(Client, true);
Server->PostSendUpdate();
// Verify that new dependent object has been created
UReplicatedSubObjectOrderObject* ClientNestedDependentObject = Cast<UReplicatedSubObjectOrderObject>(Client->GetReplicationBridge()->GetReplicatedObject(ServerNestedDependentObject->NetRefHandle));
UE_NET_ASSERT_NE(ClientNestedDependentObject, nullptr);
// Verify that they have replicated in expected order
UE_NET_ASSERT_LT(ClientNestedDependentObject->LastRepOrderCounter, ClientObject->LastRepOrderCounter);
}
UE_NET_TEST_FIXTURE(FReplicationSystemServerClientTestFixture, TestLateAddedNestedDependentObjectPendingWaitOnCreateConfirmation)
{
UReplicationSystem* ReplicationSystem = Server->ReplicationSystem;
UReplicatedTestObjectBridge* Bridge = Server->GetReplicationBridge();
// Add a client
FReplicationSystemTestClient* Client = CreateClient();
// Spawn objects on server
UReplicatedSubObjectOrderObject* ServerSharedDependentObject = Server->CreateObject<UReplicatedSubObjectOrderObject>();
UReplicatedSubObjectOrderObject* ServerDependentObject = Server->CreateObject<UReplicatedSubObjectOrderObject>();
// Set static prio to only replicate with parent
ReplicationSystem->SetStaticPriority(ServerDependentObject->NetRefHandle, 1.f);
// Reset RepOrderCounter
UReplicatedSubObjectOrderObject::RepOrderCounter = 0U;
// Create server object
UReplicatedSubObjectOrderObject* ServerObject = Server->CreateObject<UReplicatedSubObjectOrderObject>();
// Add same dependent to both ServerObject and ServerDependentObject
Bridge->AddDependentObject(ServerObject->NetRefHandle, ServerDependentObject->NetRefHandle);
Bridge->AddDependentObject(ServerObject->NetRefHandle, ServerSharedDependentObject->NetRefHandle);
Bridge->AddDependentObject(ServerDependentObject->NetRefHandle, ServerSharedDependentObject->NetRefHandle);
// Send data
Server->NetUpdate();
Server->SendAndDeliverTo(Client, true);
Server->PostSendUpdate();
// Verify that objects have replicated
UReplicatedSubObjectOrderObject* ClientObject = Cast<UReplicatedSubObjectOrderObject>(Client->GetReplicationBridge()->GetReplicatedObject(ServerObject->NetRefHandle));
UReplicatedSubObjectOrderObject* ClientDependentObject = Cast<UReplicatedSubObjectOrderObject>(Client->GetReplicationBridge()->GetReplicatedObject(ServerDependentObject->NetRefHandle));
UReplicatedSubObjectOrderObject* ClientSharedDependentObject = Cast<UReplicatedSubObjectOrderObject>(Client->GetReplicationBridge()->GetReplicatedObject(ServerSharedDependentObject->NetRefHandle));
}
UE_NET_TEST_FIXTURE(FTestFilteredDependentObjectFixture, TestDependentObjectIsFilteredOutTogetherWithParent)
{
UReplicationSystem* ReplicationSystem = Server->ReplicationSystem;
UReplicatedTestObjectBridge* Bridge = Server->GetReplicationBridge();
// Add a client
FReplicationSystemTestClient* Client = CreateClient();
// Spawn objects on server
UTestReplicatedIrisObject* ServerObject = Server->CreateObject(UTestReplicatedIrisObject::FComponents{});
UTestReplicatedIrisObject* ServerDependentObject = Server->CreateObject(UTestReplicatedIrisObject::FComponents{});
Bridge->AddDependentObject(ServerObject->NetRefHandle, ServerDependentObject->NetRefHandle);
// Dynamically filter out dependent object
ReplicationSystem->SetFilter(ServerDependentObject->NetRefHandle, NotRoutedFilterHandle);
// Add parent object to MockFilter so we can filter in/out as desired.
SetMockFilterStatus(UE::Net::ENetFilterStatus::Allow);
ReplicationSystem->SetFilter(ServerObject->NetRefHandle, MockFilterHandle);
// Send data
Server->UpdateAndSend({Client});
// Verify that objects have replicated
UTestReplicatedIrisObject* ClientObject = Cast<UTestReplicatedIrisObject>(Client->GetReplicationBridge()->GetReplicatedObject(ServerObject->NetRefHandle));
UE_NET_ASSERT_NE(ClientObject, nullptr);
UTestReplicatedIrisObject* ClientDependentObject = Cast<UTestReplicatedIrisObject>(Client->GetReplicationBridge()->GetReplicatedObject(ServerDependentObject->NetRefHandle));
UE_NET_ASSERT_NE(ClientDependentObject, nullptr);
// Filter out parent object. Dependent object should be filtered out as well due to being filtered out by default.
SetMockFilterStatus(UE::Net::ENetFilterStatus::Disallow);
// Send data
Server->UpdateAndSend({Client});
// Both parent and dependent should now be filtered out.
ClientObject = Cast<UTestReplicatedIrisObject>(Client->GetReplicationBridge()->GetReplicatedObject(ServerObject->NetRefHandle));
UE_NET_ASSERT_EQ(ClientObject, nullptr);
ClientDependentObject = Cast<UTestReplicatedIrisObject>(Client->GetReplicationBridge()->GetReplicatedObject(ServerDependentObject->NetRefHandle));
UE_NET_ASSERT_EQ(ClientDependentObject, nullptr);
// Restore filtering such that both objects are expected to be replicated again.
SetMockFilterStatus(UE::Net::ENetFilterStatus::Allow);
// Send data
Server->UpdateAndSend({Client});
ClientObject = Cast<UTestReplicatedIrisObject>(Client->GetReplicationBridge()->GetReplicatedObject(ServerObject->NetRefHandle));
UE_NET_ASSERT_NE(ClientObject, nullptr);
ClientDependentObject = Cast<UTestReplicatedIrisObject>(Client->GetReplicationBridge()->GetReplicatedObject(ServerDependentObject->NetRefHandle));
UE_NET_ASSERT_NE(ClientDependentObject, nullptr);
}
UE_NET_TEST_FIXTURE(FReplicationSystemServerClientTestFixture, TestDependentObjectScheduledBeforeParentWithHighPriority)
{
UReplicationSystem* ReplicationSystem = Server->ReplicationSystem;
UReplicatedTestObjectBridge* Bridge = Server->GetReplicationBridge();
// Add a client
FReplicationSystemTestClient* Client = CreateClient();
// Spawn object on server
UReplicatedSubObjectOrderObject* ServerObject = Server->CreateObject<UReplicatedSubObjectOrderObject>();
// Spawn dependent object
UReplicatedSubObjectOrderObject* ServerDependentObject = Server->CreateObject<UReplicatedSubObjectOrderObject>();
Bridge->AddDependentObject(ServerObject->NetRefHandle, ServerDependentObject->NetRefHandle, EDependentObjectSchedulingHint::ScheduleBeforeParent);
// Set prio to only replicate with parent
ReplicationSystem->SetStaticPriority(ServerDependentObject->NetRefHandle, 0.f);
// Set high prio on parent
const float VeryHighPriority = 1.0E7f;
ReplicationSystem->SetStaticPriority(ServerObject->NetRefHandle, VeryHighPriority);
// Reset RepOrderCounter
UReplicatedSubObjectOrderObject::RepOrderCounter = 0U;
// Send and deliver packet
Server->NetUpdate();
Server->SendAndDeliverTo(Client, true);
Server->PostSendUpdate();
// Verify that objects have replicated
UReplicatedSubObjectOrderObject* ClientObject = Cast<UReplicatedSubObjectOrderObject>(Client->GetReplicationBridge()->GetReplicatedObject(ServerObject->NetRefHandle));
UReplicatedSubObjectOrderObject* ClientDependentObject = Cast<UReplicatedSubObjectOrderObject>(Client->GetReplicationBridge()->GetReplicatedObject(ServerDependentObject->NetRefHandle));
UE_NET_ASSERT_NE(ClientObject, nullptr);
UE_NET_ASSERT_NE(ClientDependentObject, nullptr);
// Verify that they have replicated in expected order for initial objects
UE_NET_ASSERT_LT(ClientDependentObject->LastRepOrderCounter, ClientObject->LastRepOrderCounter);
// Modify both parent and dependent
ServerObject->IntA = 1;
ServerDependentObject->IntA = 1;
// Send and deliver packet
Server->NetUpdate();
Server->SendAndDeliverTo(Client, true);
Server->PostSendUpdate();
// Verify that they have replicated in expected order
UE_NET_ASSERT_LT(ClientDependentObject->LastRepOrderCounter, ClientObject->LastRepOrderCounter);
}
}