// Copyright Epic Games, Inc. All Rights Reserved. #include "TestRemoteObjectReferenceNetSerializer.h" #include "Iris/Core/NetObjectReference.h" #include "Iris/Serialization/InternalNetSerializationContext.h" #include "Iris/Serialization/ObjectNetSerializer.h" #include "Tests/ReplicationSystem/RPC/RPCTestFixture.h" #include "Tests/ReplicationSystem/ReplicationSystemServerClientTestFixture.h" #include "Tests/ReplicationSystem/ReplicatedTestObject.h" #include "UObject/Package.h" void UTestReplicatedObjectWithRemoteReference::GetLifetimeReplicatedProps(TArray& OutLifetimeProps) const { Super::GetLifetimeReplicatedProps(OutLifetimeProps); } void UTestReplicatedObjectWithRemoteReference::RemoteRPCWithRemoteReferenceParam_Implementation(FRemoteObjectReference RemoteReference) { RemoteRPCWithRemoteReferenceParamCallCount++; LastReceivedRemoteReference = RemoteReference; } // These tests require remote reference support to be compiled in #if UE_WITH_REMOTE_OBJECT_REFERENCE namespace UE::Net::Private { UE_NET_TEST_FIXTURE(FRPCTestFixture, TestRemoteObjectReference) { // Add a client FReplicationSystemTestClient* Client = CreateClient(); // Spawn objects on server UTestReplicatedObjectWithRemoteReference* TestObject = Server->CreateObject(); UReplicatedTestObject* ReferencedObject = Server->CreateObject(); TestObject->bIsServerObject = true; TestObject->ReplicationSystem = Server->GetReplicationSystem(); Server->ReplicationSystem->SetOwningNetConnection(TestObject->NetRefHandle, Client->ConnectionIdOnServer); TestObject->RemoteReferenceProperty = FRemoteObjectReference(ReferencedObject); TestObject->RemoteRPCWithRemoteReferenceParam(FRemoteObjectReference(ReferencedObject)); Server->NetUpdate(); Server->SendAndDeliverTo(Client, true); Server->PostSendUpdate(); UTestReplicatedObjectWithRemoteReference* ClientTestObject = Client->GetObjectAs(TestObject->NetRefHandle); UE_NET_ASSERT_NE(ClientTestObject, nullptr); UE_NET_ASSERT_EQ(ClientTestObject->RemoteRPCWithRemoteReferenceParamCallCount, 1); // Verify that we received valid references UE_NET_ASSERT_TRUE(ClientTestObject->LastReceivedRemoteReference.GetRemoteId().IsValid()); UE_NET_ASSERT_TRUE(ClientTestObject->RemoteReferenceProperty.GetRemoteId().IsValid()); // Verify that the replicated references resolve to the correct object UReplicatedTestObject* ResolvedRPCParameter = Cast(ClientTestObject->LastReceivedRemoteReference.Resolve()); UReplicatedTestObject* ResolvedProperty = Cast(ClientTestObject->RemoteReferenceProperty.Resolve()); // These are expected to resolve to to server object in this test case, since both the client and server // exist in the same engine instance. UE_NET_ASSERT_EQ(ResolvedRPCParameter, ReferencedObject); UE_NET_ASSERT_EQ(ResolvedProperty, ReferencedObject); } UE_NET_TEST_FIXTURE(FRPCTestFixture, TestRemoteObjectReferencePaths) { // Add a client FReplicationSystemTestClient* Client = CreateClient(); // Don't want these to trigger in this test FScopedRemoteDelegateOverride ScopedDelegateOverride; // Spawn replicated object on server to do the replication UTestReplicatedObjectWithRemoteReference* TestObject = Server->CreateObject(); // Spawn a non-replicated object with a deterministic path, it will be the one referenced by the FRemoteObjectReferece UTestNamedObject* ServerReferencedObject = NewObject(GetTransientPackage(), UTestNamedObject::StaticClass(), "TestNamedObject"); TestObject->bIsServerObject = true; TestObject->ReplicationSystem = Server->GetReplicationSystem(); Server->ReplicationSystem->SetOwningNetConnection(TestObject->NetRefHandle, Client->ConnectionIdOnServer); TestObject->RemoteReferenceProperty = FRemoteObjectReference(ServerReferencedObject); TestObject->RemoteRPCWithRemoteReferenceParam(FRemoteObjectReference(ServerReferencedObject)); Server->NetUpdate(); Server->SendTo(Client); Server->PostSendUpdate(); // Simulate having different instances of objects on the client & server, this forces the FRemoteObjectReference // to look up the object by path on the client. We accomplish this by destroying, GCing, and recreating the object. ServerReferencedObject->MarkAsGarbage(); CollectGarbage(GARBAGE_COLLECTION_KEEPFLAGS); ServerReferencedObject = nullptr; UTestNamedObject* ClientReferencedObject = NewObject(GetTransientPackage(), UTestNamedObject::StaticClass(), "TestNamedObject"); // Deliver to client now that the referenced object has been recreated Server->DeliverTo(Client, true); UTestReplicatedObjectWithRemoteReference* ClientTestObject = Client->GetObjectAs(TestObject->NetRefHandle); UE_NET_ASSERT_NE(ClientTestObject, nullptr); UE_NET_ASSERT_EQ(ClientTestObject->RemoteRPCWithRemoteReferenceParamCallCount, 1); // Verify that we received a valid reference UE_NET_ASSERT_TRUE(ClientTestObject->LastReceivedRemoteReference.GetRemoteId().IsValid()); // Client should be able to resolve the remote reference by path UTestNamedObject* ClientResolvedObjectRPC = Cast(ClientTestObject->LastReceivedRemoteReference.Resolve()); UE_NET_ASSERT_EQ(ClientResolvedObjectRPC, ClientReferencedObject); UTestNamedObject* ClientResolvedObjectProperty = Cast(ClientTestObject->RemoteReferenceProperty.Resolve()); UE_NET_ASSERT_EQ(ClientResolvedObjectProperty, ClientReferencedObject); } } #endif