From 5cb4e609f3aa3d6db37f02fde32199f9392d099e Mon Sep 17 00:00:00 2001 From: aleximprobable <48994762+aleximprobable@users.noreply.github.com> Date: Wed, 7 Aug 2019 13:34:32 +0100 Subject: [PATCH 1/8] UNR-1857 Unresolved RPC parameters can cause permanent queue blocking (#1277) * Apply RPC with unresolved refs after it's been queued for a while. * Updated Changelog.md * Moved logic to process RPCs with unresolved references to ApplyRPC function. Added SecondsToProcessRPCWithUnresolvedRefs setting with 1.0 as default value * Update SpatialGDK/Source/SpatialGDK/Public/Utils/RPCContainer.h Co-Authored-By: improbable-valentyn <32096431+improbable-valentyn@users.noreply.github.com> * Added logging for RPCs processed with unresolved parameters. * Updated CHANGELOG.md * Updated CHANGELOG.md * Fixed a couple of typos * Update SpatialGDK/Source/SpatialGDK/Public/SpatialGDKSettings.h Co-Authored-By: Michael Samiec * Changed SecondsToProcessRPCWithUnresolvedRefs to WaitTimeBeforeProcessingReceivedRPCWithUnresolveRefs, exposed it GDK settings. * Fixed UI issue for a new setting * Update CHANGELOG.md Co-Authored-By: Michael Samiec * Renamed Timestamp -> QueuedTimestamp * Renamed WaitTimeBeforeProcessingReceivedRPC_WithUnresolvedRefs -> QueuedIncomingRPCWaitTime, but kept the same DisplayName * Update CHANGELOG.md --- CHANGELOG.md | 1 + .../SpatialGDK/Private/Interop/SpatialReceiver.cpp | 14 +++++++++++--- .../SpatialGDK/Private/SpatialGDKSettings.cpp | 1 + .../SpatialGDK/Private/Utils/RPCContainer.cpp | 1 + .../SpatialGDK/Public/Interop/SpatialReceiver.h | 2 +- .../Source/SpatialGDK/Public/SpatialGDKSettings.h | 4 ++++ .../Source/SpatialGDK/Public/Utils/RPCContainer.h | 2 ++ 7 files changed, 21 insertions(+), 4 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 2a452f0674..39a4da4090 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -5,6 +5,7 @@ The format of this Changelog is based on [Keep a Changelog](https://keepachangel and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). ## [Unreleased-`x.y.z`] - 2019-xx-xx +- RPCs that have been queued for execution for more than 1 second (default value in SpatialGDKSettings QueuedIncomingRPCWaitTime) are executed with unresolved parameters. ## [`0.6.0`] - 2019-07-31 diff --git a/SpatialGDK/Source/SpatialGDK/Private/Interop/SpatialReceiver.cpp b/SpatialGDK/Source/SpatialGDK/Private/Interop/SpatialReceiver.cpp index 2cddad8fb3..b59af254e2 100644 --- a/SpatialGDK/Source/SpatialGDK/Private/Interop/SpatialReceiver.cpp +++ b/SpatialGDK/Source/SpatialGDK/Private/Interop/SpatialReceiver.cpp @@ -1470,7 +1470,7 @@ void USpatialReceiver::RegisterListeningEntityIfReady(Worker_EntityId EntityId, } } -bool USpatialReceiver::ApplyRPC(UObject* TargetObject, UFunction* Function, const RPCPayload& Payload, const FString& SenderWorkerId) +bool USpatialReceiver::ApplyRPC(UObject* TargetObject, UFunction* Function, const RPCPayload& Payload, const FString& SenderWorkerId, bool bApplyWithUnresolvedRefs /* = false */) { bool bApplied = false; @@ -1494,7 +1494,7 @@ bool USpatialReceiver::ApplyRPC(UObject* TargetObject, UFunction* Function, cons TSharedPtr RepLayout = NetDriver->GetFunctionRepLayout(Function); RepLayout_ReceivePropertiesForRPC(*RepLayout, PayloadReader, Parms); - if (UnresolvedRefs.Num() == 0) + if ((UnresolvedRefs.Num() == 0) || bApplyWithUnresolvedRefs) { if (GetDefault()->bCheckRPCOrder) { @@ -1538,7 +1538,15 @@ bool USpatialReceiver::ApplyRPC(const FPendingRPCParams& Params) return false; } - return ApplyRPC(TargetObjectWeakPtr.Get(), Function, Params.Payload, FString{}); + bool bApplyWithUnresolvedRefs = false; + const float TimeDiff = (FDateTime::Now() - Params.QueuedTimestamp).GetTotalSeconds(); + if (GetDefault()->QueuedIncomingRPCWaitTime < TimeDiff) + { + UE_LOG(LogSpatialReceiver, Warning, TEXT("Executing RPC %s::%s with unresolved references after %f seconds of queueing"), *TargetObjectWeakPtr->GetName(), *Function->GetName(), TimeDiff); + bApplyWithUnresolvedRefs = true; + } + + return ApplyRPC(TargetObjectWeakPtr.Get(), Function, Params.Payload, FString{}, bApplyWithUnresolvedRefs); } void USpatialReceiver::OnReserveEntityIdsResponse(const Worker_ReserveEntityIdsResponseOp& Op) diff --git a/SpatialGDK/Source/SpatialGDK/Private/SpatialGDKSettings.cpp b/SpatialGDK/Source/SpatialGDK/Private/SpatialGDKSettings.cpp index a2f546901d..2b961e8908 100644 --- a/SpatialGDK/Source/SpatialGDK/Private/SpatialGDKSettings.cpp +++ b/SpatialGDK/Source/SpatialGDK/Private/SpatialGDKSettings.cpp @@ -22,6 +22,7 @@ USpatialGDKSettings::USpatialGDKSettings(const FObjectInitializer& ObjectInitial , OpsUpdateRate(1000.0f) , bEnableHandover(true) , MaxNetCullDistanceSquared(900000000.0f) // Set to twice the default Actor NetCullDistanceSquared (300m) + , QueuedIncomingRPCWaitTime(1.0f) , bUsingQBI(true) , PositionUpdateFrequency(1.0f) , PositionDistanceThreshold(100.0f) // 1m (100cm) diff --git a/SpatialGDK/Source/SpatialGDK/Private/Utils/RPCContainer.cpp b/SpatialGDK/Source/SpatialGDK/Private/Utils/RPCContainer.cpp index d969286a62..64ab18960a 100644 --- a/SpatialGDK/Source/SpatialGDK/Private/Utils/RPCContainer.cpp +++ b/SpatialGDK/Source/SpatialGDK/Private/Utils/RPCContainer.cpp @@ -10,6 +10,7 @@ FPendingRPCParams::FPendingRPCParams(const FUnrealObjectRef& InTargetObjectRef, : ReliableRPCIndex(InReliableRPCIndex) , ObjectRef(InTargetObjectRef) , Payload(MoveTemp(InPayload)) + , QueuedTimestamp(FDateTime::Now()) { } diff --git a/SpatialGDK/Source/SpatialGDK/Public/Interop/SpatialReceiver.h b/SpatialGDK/Source/SpatialGDK/Public/Interop/SpatialReceiver.h index f3e3d13e7f..5f8fbfa082 100644 --- a/SpatialGDK/Source/SpatialGDK/Public/Interop/SpatialReceiver.h +++ b/SpatialGDK/Source/SpatialGDK/Public/Interop/SpatialReceiver.h @@ -183,7 +183,7 @@ class USpatialReceiver : public UObject void RegisterListeningEntityIfReady(Worker_EntityId EntityId, Schema_Object* Object); bool ApplyRPC(const FPendingRPCParams& Params); - bool ApplyRPC(UObject* TargetObject, UFunction* Function, const SpatialGDK::RPCPayload& Payload, const FString& SenderWorkerId); + bool ApplyRPC(UObject* TargetObject, UFunction* Function, const SpatialGDK::RPCPayload& Payload, const FString& SenderWorkerId, bool bApplyWithUnresolvedRefs = false); void ReceiveCommandResponse(const Worker_CommandResponseOp& Op); diff --git a/SpatialGDK/Source/SpatialGDK/Public/SpatialGDKSettings.h b/SpatialGDK/Source/SpatialGDK/Public/SpatialGDKSettings.h index f48b5396e2..266477bc16 100644 --- a/SpatialGDK/Source/SpatialGDK/Public/SpatialGDKSettings.h +++ b/SpatialGDK/Source/SpatialGDK/Public/SpatialGDKSettings.h @@ -87,6 +87,10 @@ class SPATIALGDK_API USpatialGDKSettings : public UObject UPROPERTY(EditAnywhere, config, Category = "Replication", meta = (ConfigRestartRequired = false)) float MaxNetCullDistanceSquared; + /** Seconds to wait before executing a received RPC substituting nullptr for unresolved UObjects*/ + UPROPERTY(EditAnywhere, config, Category = "Replication", meta = (ConfigRestartRequired = false, DisplayName = "Wait Time Before Processing Received RPC With Unresolved Refs")) + float QueuedIncomingRPCWaitTime; + /** Query Based Interest is required for level streaming and the AlwaysInterested UPROPERTY specifier to be supported when using spatial networking, however comes at a performance cost for larger-scale projects.*/ UPROPERTY(config, meta = (ConfigRestartRequired = false)) bool bUsingQBI; diff --git a/SpatialGDK/Source/SpatialGDK/Public/Utils/RPCContainer.h b/SpatialGDK/Source/SpatialGDK/Public/Utils/RPCContainer.h index 5444e31f77..50a1132c84 100644 --- a/SpatialGDK/Source/SpatialGDK/Public/Utils/RPCContainer.h +++ b/SpatialGDK/Source/SpatialGDK/Public/Utils/RPCContainer.h @@ -20,6 +20,8 @@ struct FPendingRPCParams int ReliableRPCIndex; FUnrealObjectRef ObjectRef; SpatialGDK::RPCPayload Payload; + + FDateTime QueuedTimestamp; }; class FRPCContainer From b6c4af04acda4a8acf17829edd50792e9aa2e1d5 Mon Sep 17 00:00:00 2001 From: Michael Samiec Date: Wed, 7 Aug 2019 13:42:19 +0100 Subject: [PATCH 2/8] IsListening and ownership fix (#1246) (#1284) * Initial commit * Cleaned outdated code * Iterate through an Actor's children when its ownership changes. * Update SpatialActorChannel.h * Update SpatialActorChannel.cpp * Changed Schema_GetBool -> GetBoolFromSchema * Update SpatialGDK/Source/SpatialGDK/Public/Schema/ServerRPCEndpoint.h Co-Authored-By: Michael Samiec * Use 0 NetGuid for Actors that are not replicated --- .../EngineClasses/SpatialActorChannel.cpp | 42 +++++++++++++++++-- .../EngineClasses/SpatialPackageMapClient.cpp | 4 ++ .../Private/Interop/SpatialReceiver.cpp | 33 +-------------- .../Interop/SpatialStaticComponentView.cpp | 14 +++++++ .../EngineClasses/SpatialActorChannel.h | 6 +-- .../Public/Interop/SpatialReceiver.h | 2 - .../Public/Schema/ClientRPCEndpoint.h | 15 +++++++ .../Public/Schema/ServerRPCEndpoint.h | 15 +++++++ 8 files changed, 92 insertions(+), 39 deletions(-) diff --git a/SpatialGDK/Source/SpatialGDK/Private/EngineClasses/SpatialActorChannel.cpp b/SpatialGDK/Source/SpatialGDK/Private/EngineClasses/SpatialActorChannel.cpp index 3a3615740b..26f29664f4 100644 --- a/SpatialGDK/Source/SpatialGDK/Private/EngineClasses/SpatialActorChannel.cpp +++ b/SpatialGDK/Source/SpatialGDK/Private/EngineClasses/SpatialActorChannel.cpp @@ -17,9 +17,11 @@ #include "EngineClasses/SpatialNetConnection.h" #include "EngineClasses/SpatialNetDriver.h" #include "EngineClasses/SpatialPackageMapClient.h" -#include "Interop/SpatialSender.h" -#include "Interop/SpatialReceiver.h" #include "Interop/GlobalStateManager.h" +#include "Interop/SpatialReceiver.h" +#include "Interop/SpatialSender.h" +#include "Schema/ClientRPCEndpoint.h" +#include "Schema/ServerRPCEndpoint.h" #include "SpatialConstants.h" #include "SpatialGDKSettings.h" #include "Utils/RepLayoutUtils.h" @@ -77,7 +79,6 @@ USpatialActorChannel::USpatialActorChannel(const FObjectInitializer& ObjectIniti , bCreatingNewEntity(false) , EntityId(SpatialConstants::INVALID_ENTITY_ID) , bInterestDirty(false) - , bIsListening(false) , bNetOwned(false) , NetDriver(nullptr) , LastPositionSinceUpdate(FVector::ZeroVector) @@ -549,6 +550,26 @@ void USpatialActorChannel::DynamicallyAttachSubobject(UObject* Object) } } +bool USpatialActorChannel::IsListening() const +{ + if (NetDriver->IsServer()) + { + if (SpatialGDK::ClientRPCEndpoint* Endpoint = NetDriver->StaticComponentView->GetComponentData(EntityId)) + { + return Endpoint->bReady; + } + } + else + { + if (SpatialGDK::ServerRPCEndpoint* Endpoint = NetDriver->StaticComponentView->GetComponentData(EntityId)) + { + return Endpoint->bReady; + } + } + + return false; +} + const FClassInfo* USpatialActorChannel::TryResolveNewDynamicSubobjectAndGetClassInfo(UObject* Object) { const FClassInfo* Info = nullptr; @@ -1014,6 +1035,21 @@ void USpatialActorChannel::ServerProcessOwnershipChange() return; } + UpdateEntityACLToNewOwner(); + + for (AActor* Child : Actor->Children) + { + Worker_EntityId ChildEntityId = NetDriver->PackageMap->GetEntityIdFromObject(Child); + + if (USpatialActorChannel* Channel = NetDriver->GetActorChannelByEntityId(ChildEntityId)) + { + Channel->ServerProcessOwnershipChange(); + } + } +} + +void USpatialActorChannel::UpdateEntityACLToNewOwner() +{ FString NewOwnerWorkerAttribute = SpatialGDK::GetOwnerWorkerAttribute(Actor); if (SavedOwnerWorkerAttribute != NewOwnerWorkerAttribute) diff --git a/SpatialGDK/Source/SpatialGDK/Private/EngineClasses/SpatialPackageMapClient.cpp b/SpatialGDK/Source/SpatialGDK/Private/EngineClasses/SpatialPackageMapClient.cpp index 57b7a33430..69e47aae9b 100644 --- a/SpatialGDK/Source/SpatialGDK/Private/EngineClasses/SpatialPackageMapClient.cpp +++ b/SpatialGDK/Source/SpatialGDK/Private/EngineClasses/SpatialPackageMapClient.cpp @@ -89,6 +89,10 @@ FNetworkGUID USpatialPackageMapClient::TryResolveObjectAsEntity(UObject* Value) } AActor* Actor = Value->IsA() ? Cast(Value) : Cast(Value->GetOuter()); + if (!Actor->GetIsReplicated()) + { + return NetGUID; + } if (Actor->GetClass()->HasAnySpatialClassFlags(SPATIALCLASS_Singleton)) { diff --git a/SpatialGDK/Source/SpatialGDK/Private/Interop/SpatialReceiver.cpp b/SpatialGDK/Source/SpatialGDK/Private/Interop/SpatialReceiver.cpp index b59af254e2..426b8b5c0c 100644 --- a/SpatialGDK/Source/SpatialGDK/Private/Interop/SpatialReceiver.cpp +++ b/SpatialGDK/Source/SpatialGDK/Private/Interop/SpatialReceiver.cpp @@ -119,6 +119,8 @@ void USpatialReceiver::OnAddComponent(const Worker_AddComponentOp& Op) case SpatialConstants::RPCS_ON_ENTITY_CREATION_ID: case SpatialConstants::DEBUG_METRICS_COMPONENT_ID: case SpatialConstants::ALWAYS_RELEVANT_COMPONENT_ID: + case SpatialConstants::CLIENT_RPC_ENDPOINT_COMPONENT_ID: + case SpatialConstants::SERVER_RPC_ENDPOINT_COMPONENT_ID: // Ignore static spatial components as they are managed by the SpatialStaticComponentView. return; case SpatialConstants::SINGLETON_MANAGER_COMPONENT_ID: @@ -131,11 +133,6 @@ void USpatialReceiver::OnAddComponent(const Worker_AddComponentOp& Op) case SpatialConstants::STARTUP_ACTOR_MANAGER_COMPONENT_ID: GlobalStateManager->ApplyStartupActorManagerData(Op.data); return; - case SpatialConstants::CLIENT_RPC_ENDPOINT_COMPONENT_ID: - case SpatialConstants::SERVER_RPC_ENDPOINT_COMPONENT_ID: - Schema_Object* FieldsObject = Schema_GetComponentDataFields(Op.data.schema_type); - RegisterListeningEntityIfReady(Op.entity_id, FieldsObject); - return; } if (ClassInfoManager->IsSublevelComponent(Op.data.component_id)) @@ -1058,13 +1055,6 @@ void USpatialReceiver::ApplyComponentData(UObject* TargetObject, USpatialActorCh void USpatialReceiver::OnComponentUpdate(const Worker_ComponentUpdateOp& Op) { - if (Op.update.component_id == SpatialConstants::SERVER_RPC_ENDPOINT_COMPONENT_ID || - Op.update.component_id == SpatialConstants::CLIENT_RPC_ENDPOINT_COMPONENT_ID) - { - Schema_Object* FieldsObject = Schema_GetComponentUpdateFields(Op.update.schema_type); - RegisterListeningEntityIfReady(Op.entity_id, FieldsObject); - } - if (StaticComponentView->GetAuthority(Op.entity_id, Op.update.component_id) == WORKER_AUTHORITY_AUTHORITATIVE) { UE_LOG(LogSpatialReceiver, Verbose, TEXT("Entity: %d Component: %d - Skipping update because this was short circuited"), Op.entity_id, Op.update.component_id); @@ -1451,25 +1441,6 @@ void USpatialReceiver::ApplyComponentUpdate(const Worker_ComponentUpdate& Compon QueueIncomingRepUpdates(ChannelObjectPair, ObjectReferencesMap, UnresolvedRefs); } -void USpatialReceiver::RegisterListeningEntityIfReady(Worker_EntityId EntityId, Schema_Object* Object) -{ - if (Schema_GetBoolCount(Object, SpatialConstants::UNREAL_RPC_ENDPOINT_READY_ID) > 0) - { - bool bReady = GetBoolFromSchema(Object, SpatialConstants::UNREAL_RPC_ENDPOINT_READY_ID); - if (bReady) - { - if (USpatialActorChannel* Channel = NetDriver->GetActorChannelByEntityId(EntityId)) - { - Channel->StartListening(); - if (UObject* TargetObject = Channel->GetActor()) - { - Sender->SendOutgoingRPCs(); - } - } - } - } -} - bool USpatialReceiver::ApplyRPC(UObject* TargetObject, UFunction* Function, const RPCPayload& Payload, const FString& SenderWorkerId, bool bApplyWithUnresolvedRefs /* = false */) { bool bApplied = false; diff --git a/SpatialGDK/Source/SpatialGDK/Private/Interop/SpatialStaticComponentView.cpp b/SpatialGDK/Source/SpatialGDK/Private/Interop/SpatialStaticComponentView.cpp index 91adba2fde..679e0f0f16 100644 --- a/SpatialGDK/Source/SpatialGDK/Private/Interop/SpatialStaticComponentView.cpp +++ b/SpatialGDK/Source/SpatialGDK/Private/Interop/SpatialStaticComponentView.cpp @@ -2,10 +2,12 @@ #include "Interop/SpatialStaticComponentView.h" +#include "Schema/ClientRPCEndpoint.h" #include "Schema/Component.h" #include "Schema/Heartbeat.h" #include "Schema/Interest.h" #include "Schema/RPCPayload.h" +#include "Schema/ServerRPCEndpoint.h" #include "Schema/Singleton.h" #include "Schema/SpawnData.h" @@ -73,6 +75,12 @@ void USpatialStaticComponentView::OnAddComponent(const Worker_AddComponentOp& Op case SpatialConstants::RPCS_ON_ENTITY_CREATION_ID: Data = MakeUnique>(Op.data); break; + case SpatialConstants::CLIENT_RPC_ENDPOINT_COMPONENT_ID: + Data = MakeUnique>(Op.data); + break; + case SpatialConstants::SERVER_RPC_ENDPOINT_COMPONENT_ID: + Data = MakeUnique>(Op.data); + break; default: // Component is not hand written, but we still want to know the existence of it on this entity. Data = nullptr; @@ -111,6 +119,12 @@ void USpatialStaticComponentView::OnComponentUpdate(const Worker_ComponentUpdate case SpatialConstants::POSITION_COMPONENT_ID: Component = GetComponentData(Op.entity_id); break; + case SpatialConstants::CLIENT_RPC_ENDPOINT_COMPONENT_ID: + Component = GetComponentData(Op.entity_id); + break; + case SpatialConstants::SERVER_RPC_ENDPOINT_COMPONENT_ID: + Component = GetComponentData(Op.entity_id); + break; default: return; } diff --git a/SpatialGDK/Source/SpatialGDK/Public/EngineClasses/SpatialActorChannel.h b/SpatialGDK/Source/SpatialGDK/Public/EngineClasses/SpatialActorChannel.h index a2051e3848..c990a6bf30 100644 --- a/SpatialGDK/Source/SpatialGDK/Public/EngineClasses/SpatialActorChannel.h +++ b/SpatialGDK/Source/SpatialGDK/Public/EngineClasses/SpatialActorChannel.h @@ -152,8 +152,7 @@ class SPATIALGDK_API USpatialActorChannel : public UActorChannel FORCEINLINE void MarkInterestDirty() { bInterestDirty = true; } FORCEINLINE bool GetInterestDirty() const { return bInterestDirty; } - FORCEINLINE void StartListening() { bIsListening = true; } - FORCEINLINE bool IsListening() { return bIsListening; } + bool IsListening() const; const FClassInfo* TryResolveNewDynamicSubobjectAndGetClassInfo(UObject* Object); protected: @@ -174,6 +173,8 @@ class SPATIALGDK_API USpatialActorChannel : public UActorChannel void InitializeHandoverShadowData(TArray& ShadowData, UObject* Object); FHandoverChangeState GetHandoverChangeList(TArray& ShadowData, UObject* Object); + + void UpdateEntityACLToNewOwner(); public: // If this actor channel is responsible for creating a new entity, this will be set to true once the entity is created. @@ -187,7 +188,6 @@ class SPATIALGDK_API USpatialActorChannel : public UActorChannel private: Worker_EntityId EntityId; bool bInterestDirty; - bool bIsListening; // Used on the client to track gaining/losing ownership. bool bNetOwned; diff --git a/SpatialGDK/Source/SpatialGDK/Public/Interop/SpatialReceiver.h b/SpatialGDK/Source/SpatialGDK/Public/Interop/SpatialReceiver.h index 5f8fbfa082..f916c731cd 100644 --- a/SpatialGDK/Source/SpatialGDK/Public/Interop/SpatialReceiver.h +++ b/SpatialGDK/Source/SpatialGDK/Public/Interop/SpatialReceiver.h @@ -180,8 +180,6 @@ class USpatialReceiver : public UObject void ApplyComponentUpdate(const Worker_ComponentUpdate& ComponentUpdate, UObject* TargetObject, USpatialActorChannel* Channel, bool bIsHandover); - void RegisterListeningEntityIfReady(Worker_EntityId EntityId, Schema_Object* Object); - bool ApplyRPC(const FPendingRPCParams& Params); bool ApplyRPC(UObject* TargetObject, UFunction* Function, const SpatialGDK::RPCPayload& Payload, const FString& SenderWorkerId, bool bApplyWithUnresolvedRefs = false); diff --git a/SpatialGDK/Source/SpatialGDK/Public/Schema/ClientRPCEndpoint.h b/SpatialGDK/Source/SpatialGDK/Public/Schema/ClientRPCEndpoint.h index 5072ff1bef..3720f7cb39 100644 --- a/SpatialGDK/Source/SpatialGDK/Public/Schema/ClientRPCEndpoint.h +++ b/SpatialGDK/Source/SpatialGDK/Public/Schema/ClientRPCEndpoint.h @@ -18,6 +18,21 @@ struct ClientRPCEndpoint : Component ClientRPCEndpoint() = default; + ClientRPCEndpoint(const Worker_ComponentData& Data) + { + Schema_Object* EndpointObject = Schema_GetComponentDataFields(Data.schema_type); + bReady = GetBoolFromSchema(EndpointObject, SpatialConstants::UNREAL_RPC_ENDPOINT_READY_ID); + } + + void ApplyComponentUpdate(const Worker_ComponentUpdate& Update) + { + Schema_Object* EndpointObject = Schema_GetComponentUpdateFields(Update.schema_type); + if (Schema_GetBoolCount(EndpointObject, SpatialConstants::UNREAL_RPC_ENDPOINT_READY_ID) > 0) + { + bReady = GetBoolFromSchema(EndpointObject, SpatialConstants::UNREAL_RPC_ENDPOINT_READY_ID); + } + } + Worker_ComponentData CreateRPCEndpointData() { Worker_ComponentData Data{}; diff --git a/SpatialGDK/Source/SpatialGDK/Public/Schema/ServerRPCEndpoint.h b/SpatialGDK/Source/SpatialGDK/Public/Schema/ServerRPCEndpoint.h index 8c7636cd4d..f328d9b7f9 100644 --- a/SpatialGDK/Source/SpatialGDK/Public/Schema/ServerRPCEndpoint.h +++ b/SpatialGDK/Source/SpatialGDK/Public/Schema/ServerRPCEndpoint.h @@ -18,6 +18,21 @@ struct ServerRPCEndpoint : Component ServerRPCEndpoint() = default; + ServerRPCEndpoint(const Worker_ComponentData& Data) + { + Schema_Object* EndpointObject = Schema_GetComponentDataFields(Data.schema_type); + bReady = GetBoolFromSchema(EndpointObject, SpatialConstants::UNREAL_RPC_ENDPOINT_READY_ID); + } + + void ApplyComponentUpdate(const Worker_ComponentUpdate& Update) + { + Schema_Object* EndpointObject = Schema_GetComponentUpdateFields(Update.schema_type); + if (Schema_GetBoolCount(EndpointObject, SpatialConstants::UNREAL_RPC_ENDPOINT_READY_ID) > 0) + { + bReady = GetBoolFromSchema(EndpointObject, SpatialConstants::UNREAL_RPC_ENDPOINT_READY_ID); + } + } + Worker_ComponentData CreateRPCEndpointData() { Worker_ComponentData Data{}; From 3fa3957fa06a43ad8af99820134464eb76873462 Mon Sep 17 00:00:00 2001 From: Joshua Huburn <31517089+joshuahuburn@users.noreply.github.com> Date: Thu, 8 Aug 2019 10:06:56 +0100 Subject: [PATCH 3/8] =?UTF-8?q?UNR-1864=20Use=20GetPlugin=20helper=20metho?= =?UTF-8?q?d=20to=20resolve=20sim=20player=20laun=E2=80=A6=20(#1278)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * Used GetPlugin helper method to resolve sim player launch config * Updated changelog --- CHANGELOG.md | 5 +++++ .../SpatialGDKEditor/Private/SpatialGDKEditorSettings.cpp | 3 +-- 2 files changed, 6 insertions(+), 2 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 39a4da4090..39d2c68b81 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -7,6 +7,11 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ## [Unreleased-`x.y.z`] - 2019-xx-xx - RPCs that have been queued for execution for more than 1 second (default value in SpatialGDKSettings QueuedIncomingRPCWaitTime) are executed with unresolved parameters. +## [`0.6.1`] - 2019-xx-xx + +### Bug fixes: +- Fixed Simulated Players launch configurations not being valid when using an Engine Plugin installation. + ## [`0.6.0`] - 2019-07-31 ### Breaking Changes: diff --git a/SpatialGDK/Source/SpatialGDKEditor/Private/SpatialGDKEditorSettings.cpp b/SpatialGDK/Source/SpatialGDKEditor/Private/SpatialGDKEditorSettings.cpp index dc3b465adc..98b474a08a 100644 --- a/SpatialGDK/Source/SpatialGDKEditor/Private/SpatialGDKEditorSettings.cpp +++ b/SpatialGDK/Source/SpatialGDKEditor/Private/SpatialGDKEditorSettings.cpp @@ -24,8 +24,7 @@ USpatialGDKEditorSettings::USpatialGDKEditorSettings(const FObjectInitializer& O , bStopSpatialOnExit(false) , bAutoStartLocalDeployment(true) , PrimaryDeploymentRegionCode(ERegionCode::US) - , SimulatedPlayerLaunchConfigPath(FPaths::ConvertRelativePathToFull(FPaths::Combine(FPaths::ProjectDir() / - TEXT("Plugins/UnrealGDK/SpatialGDK/Build/Programs/Improbable.Unreal.Scripts/WorkerCoordinator/SpatialConfig/cloud_launch_sim_player_deployment.json")))) + , SimulatedPlayerLaunchConfigPath(FSpatialGDKServicesModule::GetSpatialGDKPluginDirectory(TEXT("SpatialGDK/Build/Programs/Improbable.Unreal.Scripts/WorkerCoordinator/SpatialConfig/cloud_launch_sim_player_deployment.json"))) , SimulatedPlayerDeploymentRegionCode(ERegionCode::US) { SpatialOSLaunchConfig.FilePath = GetSpatialOSLaunchConfig(); From d0984cfd17d774214871684df92cbfbde30c7e4d Mon Sep 17 00:00:00 2001 From: anne-edwards <32169118+anne-edwards@users.noreply.github.com> Date: Fri, 9 Aug 2019 10:36:05 +0100 Subject: [PATCH 4/8] DOC-1255 Clarify elements of the GDK in readme (#1287) * Clarify elements of the GDK * Apply suggestions from code review Co-Authored-By: Laura <36853437+ElleEss@users.noreply.github.com> * Updates from review --- README.md | 21 ++++++++++++--------- 1 file changed, 12 insertions(+), 9 deletions(-) diff --git a/README.md b/README.md index 4bc7934acc..344c148940 100644 --- a/README.md +++ b/README.md @@ -2,20 +2,23 @@ ![](SpatialGDK/Documentation/spatialos-gdkforunreal-header.png) -The SpatialOS Game Development Kit (GDK) for Unreal is an Unreal Engine plugin which gives you the features of [SpatialOS](https://spatialos.improbable.io/docs/reference/latest), within the familiar workflows and APIs of Unreal Engine. For more information, please see the GDK's [documentation website](https://docs.improbable.io/unreal/latest). - -If you’re an Unreal game developer and you’re ready to try out the GDK, follow the [Get started guide](https://docs.improbable.io/unreal/latest/content/get-started/introduction). +The SpatialOS Game Development Kit (GDK) for Unreal is an Unreal Engine fork and plugin with associated projects. It gives you the features of [SpatialOS](https://spatialos.improbable.io/docs/reference/latest), within the familiar workflows and APIs of Unreal Engine. For more information, please see the GDK's [documentation website](https://docs.improbable.io/unreal/latest). > The SpatialOS GDK for Unreal is in alpha. It is ready to use for development of single-server games, but not recommended for public releases. We are committed to rapid development of the GDK to provide a performant release - for information on this, see our [development roadmap](https://github.com/spatialos/UnrealGDK/projects/1) and [Unreal features support](https://docs.improbable.io/unreal/latest/unreal-features-support) pages, and contact us via our forums, or on Discord. -## Where to get the GDK and related projects -The GDK and its related projects are available on GitHub. -* [GDK: github.com/spatialos/UnrealGDK](https://github.com/spatialos/UnrealGDK) +This is the repository for the GDK plugin, which includes the Starter Template (a blank starter project). + +In addition to the plugin, the GDK also includes: + * [The SpatialOS Unreal Engine fork](https://github.com/improbableio/UnrealEngine) -* [The Example Project](https://github.com/spatialos/UnrealGDKExampleProject) -## Unreal Engine changes -In order to transform Unreal from a single server engine to a distributed model, we have made a number of small changes to the UE4 code. We will attempt to consolidate and remove (or submit as PR to Epic) as many of these changes as possible. You can see the changes in our forked [Unreal Engine repo](https://github.com/improbableio/UnrealEngine). + You must be a member of the [Epic Games organization](https://github.com/EpicGames) on GitHub to access this. If you aren't, the link returns a 404 error. +* [The Example Project](https://github.com/spatialos/UnrealGDKExampleProject) + +If you’re an Unreal game developer and you’re ready to try out the GDK, follow the [Get started guide](https://docs.improbable.io/unreal/latest/content/get-started/introduction). + +## SpatialOS Unreal Engine fork changes +In order to transform Unreal from a single-server engine to a distributed model, we made a number of small changes to Unreal Engine code. We are attempting to consolidate and remove (or submit as PR to Epic) as many of these changes as possible. You can see the changes in the [SpatialOS Unreal Engine fork repository](https://github.com/improbableio/UnrealEngine). > In order to get access to this fork, you need to link your GitHub account to a verified Epic Games account, and to have agreed to Epic's license. You will not be able to use the GDK for Unreal without doing this first. To do this, see the [Unreal documentation](https://www.unrealengine.com/en-US/ue4-on-github). From b65b006b33b83979baf7cb1137fcdc91240c1ee1 Mon Sep 17 00:00:00 2001 From: Oliver Balaam Date: Wed, 14 Aug 2019 17:46:08 +0100 Subject: [PATCH 5/8] Update CHANGELOG.md --- CHANGELOG.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 39d2c68b81..59091150e8 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -5,12 +5,12 @@ The format of this Changelog is based on [Keep a Changelog](https://keepachangel and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). ## [Unreleased-`x.y.z`] - 2019-xx-xx -- RPCs that have been queued for execution for more than 1 second (default value in SpatialGDKSettings QueuedIncomingRPCWaitTime) are executed with unresolved parameters. ## [`0.6.1`] - 2019-xx-xx ### Bug fixes: -- Fixed Simulated Players launch configurations not being valid when using an Engine Plugin installation. +- Simulated player launch configurations are no longer invalid when the GDK is installed as an Engine Plugin. +- RPCs that have been queued for execution for more than 1 second (the default value in `SpatialGDKSettings QueuedIncomingRPCWaitTime`) are now executed even if there are unresolved parameters. This stops unresolved parameters from blocking the execution queue. ## [`0.6.0`] - 2019-07-31 From b64163113fa24caa865cc3b6d0b21cc88032a3f3 Mon Sep 17 00:00:00 2001 From: Michael Samiec Date: Thu, 15 Aug 2019 10:11:14 +0100 Subject: [PATCH 6/8] Switch validity checks to use whats defaulted (#1300) --- .../SpatialGDKEditor/Private/SpatialGDKEditorSettings.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/SpatialGDK/Source/SpatialGDKEditor/Private/SpatialGDKEditorSettings.cpp b/SpatialGDK/Source/SpatialGDKEditor/Private/SpatialGDKEditorSettings.cpp index 98b474a08a..53a7708456 100644 --- a/SpatialGDK/Source/SpatialGDKEditor/Private/SpatialGDKEditorSettings.cpp +++ b/SpatialGDK/Source/SpatialGDKEditor/Private/SpatialGDKEditorSettings.cpp @@ -215,8 +215,8 @@ bool USpatialGDKEditorSettings::IsDeploymentConfigurationValid() const bool result = IsAssemblyNameValid(AssemblyName) && IsDeploymentNameValid(PrimaryDeploymentName) && IsProjectNameValid(ProjectName) && - !SnapshotPath.FilePath.IsEmpty() && - !PrimaryLaunchConfigPath.FilePath.IsEmpty() && + !GetSnapshotPath().IsEmpty() && + !GetPrimaryLanchConfigPath().IsEmpty() && IsRegionCodeValid(PrimaryDeploymentRegionCode); if (IsSimulatedPlayersEnabled()) From 31d519b1cbeb3602b90e6c06abe587e5c4eece4a Mon Sep 17 00:00:00 2001 From: Oliver Balaam Date: Thu, 15 Aug 2019 11:45:43 +0100 Subject: [PATCH 7/8] Update CHANGELOG.md --- CHANGELOG.md | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 59091150e8..94c8cb9228 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -6,11 +6,16 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ## [Unreleased-`x.y.z`] - 2019-xx-xx -## [`0.6.1`] - 2019-xx-xx +## [`0.6.1`] - 2019-08-15 + +### Features: +- The [Multiserver zoning shooter tutorial](https://docs.improbable.io/unreal/alpha/content/tutorials/multiserver-shooter/tutorial-multiserver-intro) has been updated to use the Example Project. ### Bug fixes: - Simulated player launch configurations are no longer invalid when the GDK is installed as an Engine Plugin. - RPCs that have been queued for execution for more than 1 second (the default value in `SpatialGDKSettings QueuedIncomingRPCWaitTime`) are now executed even if there are unresolved parameters. This stops unresolved parameters from blocking the execution queue. +- Offloading is no longer enabled by default in the Example Project. You can toggle offloading on using [these steps](https://docs.improbable.io/unreal/alpha/content/tutorials/offloading-tutorial/offloading-setup#step-4-enable-offloading). +- Guns no longer intermittently detatch from simulated players in the Example Project. ## [`0.6.0`] - 2019-07-31 From e2539b22e25ec89fc58fcda389f8f80ab7361f8d Mon Sep 17 00:00:00 2001 From: Oliver Balaam Date: Thu, 15 Aug 2019 11:59:44 +0100 Subject: [PATCH 8/8] Update CHANGELOG.md --- CHANGELOG.md | 1 + 1 file changed, 1 insertion(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 94c8cb9228..a64f104987 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -16,6 +16,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 - RPCs that have been queued for execution for more than 1 second (the default value in `SpatialGDKSettings QueuedIncomingRPCWaitTime`) are now executed even if there are unresolved parameters. This stops unresolved parameters from blocking the execution queue. - Offloading is no longer enabled by default in the Example Project. You can toggle offloading on using [these steps](https://docs.improbable.io/unreal/alpha/content/tutorials/offloading-tutorial/offloading-setup#step-4-enable-offloading). - Guns no longer intermittently detatch from simulated players in the Example Project. +- Default cloud deployment settings are now correctly set. This means you don't need to manually reset them before doing a cloud deployment. ## [`0.6.0`] - 2019-07-31