diff --git a/CHANGELOG.md b/CHANGELOG.md index 2a452f0674..a64f104987 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -6,6 +6,18 @@ 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-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. +- 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 ### Breaking Changes: 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). 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 2cddad8fb3..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,26 +1441,7 @@ 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 USpatialReceiver::ApplyRPC(UObject* TargetObject, UFunction* Function, const RPCPayload& Payload, const FString& SenderWorkerId, bool bApplyWithUnresolvedRefs /* = false */) { bool bApplied = false; @@ -1494,7 +1465,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 +1509,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/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/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/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 f3e3d13e7f..f916c731cd 100644 --- a/SpatialGDK/Source/SpatialGDK/Public/Interop/SpatialReceiver.h +++ b/SpatialGDK/Source/SpatialGDK/Public/Interop/SpatialReceiver.h @@ -180,10 +180,8 @@ 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 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/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{}; 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 diff --git a/SpatialGDK/Source/SpatialGDKEditor/Private/SpatialGDKEditorSettings.cpp b/SpatialGDK/Source/SpatialGDKEditor/Private/SpatialGDKEditorSettings.cpp index dc3b465adc..53a7708456 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(); @@ -216,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())