diff --git a/sdks/unreal/Agones/Source/Agones/Agones.cpp b/sdks/unreal/Agones/Source/Agones/Agones.cpp index 8a2cee5828..e3dcdb9137 100644 --- a/sdks/unreal/Agones/Source/Agones/Agones.cpp +++ b/sdks/unreal/Agones/Source/Agones/Agones.cpp @@ -86,7 +86,6 @@ void FAgonesModule::OnWorldInitialized(UWorld* World, const UWorld::Initializati if (World != nullptr && World->GetNetMode() == ENetMode::NM_DedicatedServer) { HookPtr = MakeShareable(new FAgonesHook()); - HookPtr->Ready(); } } diff --git a/sdks/unreal/Agones/Source/Agones/AgonesHook.cpp b/sdks/unreal/Agones/Source/Agones/AgonesHook.cpp index f9d5ea5f75..9336f93f98 100644 --- a/sdks/unreal/Agones/Source/Agones/AgonesHook.cpp +++ b/sdks/unreal/Agones/Source/Agones/AgonesHook.cpp @@ -19,6 +19,7 @@ #include "JsonObjectConverter.h" #include "Serialization/JsonReader.h" #include "GenericPlatform/GenericPlatformMisc.h" +#include "Model/Duration.h" #include "Model/KeyValuePair.h" #include "Runtime/Online/HTTP/Public/Http.h" #include "Serialization/JsonSerializer.h" @@ -43,6 +44,8 @@ FAgonesHook::FAgonesHook() , SetLabelSuffix(FString(TEXT("/metadata/label"))) , SetAnnotationSuffix(FString(TEXT("/metadata/annotation"))) , GetGameServerSuffix(FString(TEXT("/gameserver"))) + , AllocateSuffix(FString(TEXT("/allocate"))) + , ReserveSuffix(FString(TEXT("/reserve"))) { Settings = GetDefault(); check(Settings != nullptr); @@ -52,12 +55,17 @@ FAgonesHook::FAgonesHook() FHttpRetrySystem::FRetryLimitCountSetting(RetryLimitCount), FHttpRetrySystem::FRetryTimeoutRelativeSecondsSetting()); - UE_LOG(LogAgonesHook, Log, TEXT("Initialized Agones Hook, Sidecar address: %s, Health Enabled: %s, Health Ping: %f, Debug: %s, Request Retry Limit: %d") + UE_LOG(LogAgonesHook, Log, TEXT("Initialized Agones Hook, Sidecar address: %s, Health Enabled: %s, Health Ping: %f, Request Retry Limit: %d, Send Ready at Startup: %s") , *SidecarAddress , (Settings->bHealthPingEnabled ? TEXT("True") : TEXT("False")) , Settings->HealthPingSeconds - , (Settings->bDebugLogEnabled ? TEXT("True") : TEXT("False")) - , Settings->RequestRetryLimit); + , Settings->RequestRetryLimit + , (Settings->bSendReadyAtStartup ? TEXT("True") : TEXT("False"))); + + if (Settings->bSendReadyAtStartup) + { + Ready(); + } } FAgonesHook::~FAgonesHook() @@ -115,28 +123,26 @@ void FAgonesHook::SetLabel(const FString& Key, const FString& Value) { FKeyValuePair Label = { Key, Value }; FString Json; - if (FJsonObjectConverter::UStructToJsonObjectString(Label, Json)) + if (!FJsonObjectConverter::UStructToJsonObjectString(Label, Json)) { - SendRequest(SidecarAddress + SetLabelSuffix, Json, FHttpVerb::PUT, true); - } - else - { - UE_LOG(LogAgonesHook, Error, TEXT("Failed to send request, error serializing key-value pair (%s: %s)"), *Key, *Value); + UE_LOG(LogAgonesHook, Error, TEXT("Failed to set label, error serializing key-value pair (%s: %s)"), *Key, *Value); + return; } + + SendRequest(SidecarAddress + SetLabelSuffix, Json, FHttpVerb::PUT, true); } void FAgonesHook::SetAnnotation(const FString& Key, const FString& Value) { FKeyValuePair Annotation = { Key, Value }; FString Json; - if (FJsonObjectConverter::UStructToJsonObjectString(Annotation, Json)) + if (!FJsonObjectConverter::UStructToJsonObjectString(Annotation, Json)) { - SendRequest(SidecarAddress + SetAnnotationSuffix, Json, FHttpVerb::PUT, true); - } - else - { - UE_LOG(LogAgonesHook, Error, TEXT("Failed to send request, error serializing key-value pair (%s: %s)"), *Key, *Value); + UE_LOG(LogAgonesHook, Error, TEXT("Failed to set annotation, error serializing key-value pair (%s: %s)"), *Key, *Value); + return; } + + SendRequest(SidecarAddress + SetAnnotationSuffix, Json, FHttpVerb::PUT, true); } void FAgonesHook::GetGameServer(const FGameServerRequestCompleteDelegate& Delegate) @@ -167,6 +173,24 @@ void FAgonesHook::GetGameServer(const FGameServerRequestCompleteDelegate& Delega }); } +void FAgonesHook::Allocate() +{ + SendRequest(SidecarAddress + AllocateSuffix, TEXT("{}"), FHttpVerb::POST, true); +} + +void FAgonesHook::Reserve(const int64 Seconds) +{ + FDuration Duration = { Seconds }; + FString Json; + if (!FJsonObjectConverter::UStructToJsonObjectString(Duration, Json)) + { + UE_LOG(LogAgonesHook, Error, TEXT("Failed to send reserve request, error serializing duration (%d)"), Seconds); + return; + } + + SendRequest(SidecarAddress + ReserveSuffix, Json, FHttpVerb::POST, true); +} + TSharedRef FAgonesHook::MakeRequest(const FString& URL, const FString& JsonContent, const FHttpVerb Verb, const bool bRetryOnFailure) { TSharedRef Req = bRetryOnFailure @@ -184,16 +208,13 @@ TSharedRef FAgonesHook::SendRequest(const FString& URL, const FStr { TSharedRef Req = MakeRequest(URL, JsonContent, Verb, bRetryOnFailure); bool bSuccess = Req->ProcessRequest(); - if (Settings->bDebugLogEnabled) + if (bSuccess) { - if (bSuccess) - { - UE_LOG(LogAgonesHook, Log, TEXT("Send: %s"), *URL); - } - else - { - UE_LOG(LogAgonesHook, Error, TEXT("Failed sending: %s"), *URL); - } + UE_LOG(LogAgonesHook, Verbose, TEXT("Send: %s"), *URL); + } + else + { + UE_LOG(LogAgonesHook, Error, TEXT("Failed sending: %s"), *URL); } return Req; diff --git a/sdks/unreal/Agones/Source/Agones/AgonesHook.h b/sdks/unreal/Agones/Source/Agones/AgonesHook.h index 29795ab22d..3cf197c71f 100644 --- a/sdks/unreal/Agones/Source/Agones/AgonesHook.h +++ b/sdks/unreal/Agones/Source/Agones/AgonesHook.h @@ -94,6 +94,10 @@ class AGONES_API FAgonesHook : public FTickableGameObject void SetAnnotation(const FString& Key, const FString& Value); /** Retrieve the GameServer details from the sidecar */ void GetGameServer(const FGameServerRequestCompleteDelegate& Delegate); + /** Sends a request to allocate the GameServer **/ + void Allocate(); + /** Sends a request to mark the GameServer as reserved for the specified duration */ + void Reserve(const int64 Seconds); private: @@ -117,4 +121,6 @@ class AGONES_API FAgonesHook : public FTickableGameObject const FString SetLabelSuffix; const FString SetAnnotationSuffix; const FString GetGameServerSuffix; + const FString AllocateSuffix; + const FString ReserveSuffix; }; diff --git a/sdks/unreal/Agones/Source/Agones/AgonesSettings.cpp b/sdks/unreal/Agones/Source/Agones/AgonesSettings.cpp index 5c06602d69..38e7b7d8a5 100644 --- a/sdks/unreal/Agones/Source/Agones/AgonesSettings.cpp +++ b/sdks/unreal/Agones/Source/Agones/AgonesSettings.cpp @@ -18,8 +18,8 @@ UAgonesSettings::UAgonesSettings() : Super() , bHealthPingEnabled(true) , HealthPingSeconds(5.0f) - , bDebugLogEnabled(false) , RequestRetryLimit(30) + , bSendReadyAtStartup(true) { } diff --git a/sdks/unreal/Agones/Source/Agones/Model/Duration.h b/sdks/unreal/Agones/Source/Agones/Model/Duration.h new file mode 100644 index 0000000000..81a4d6dde1 --- /dev/null +++ b/sdks/unreal/Agones/Source/Agones/Model/Duration.h @@ -0,0 +1,27 @@ +// Copyright 2020 Google LLC All Rights Reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#pragma once + +#include "CoreMinimal.h" +#include "Duration.generated.h" + +USTRUCT() +struct FDuration +{ + GENERATED_BODY() + + UPROPERTY() + int64 Seconds; +}; diff --git a/sdks/unreal/Agones/Source/Agones/Public/AgonesSettings.h b/sdks/unreal/Agones/Source/Agones/Public/AgonesSettings.h index 5fbf7c8035..0679bd523d 100644 --- a/sdks/unreal/Agones/Source/Agones/Public/AgonesSettings.h +++ b/sdks/unreal/Agones/Source/Agones/Public/AgonesSettings.h @@ -38,9 +38,9 @@ class AGONES_API UAgonesSettings : public UObject UPROPERTY(EditAnywhere, config, Category = "Agones", meta = (DisplayName = "Health Ping Seconds")) float HealthPingSeconds; - UPROPERTY(EditAnywhere, config, Category = "Agones", meta = (DisplayName = "Debug Logging Enabled")) - bool bDebugLogEnabled; - UPROPERTY(EditAnywhere, config, Category = "Agones", meta = (DisplayName = "Request Retry Limit")) uint32 RequestRetryLimit; + + UPROPERTY(EditAnywhere, config, Category = "Agones", meta = (DisplayName = "Send Ready at Startup")) + bool bSendReadyAtStartup; }; diff --git a/site/content/en/docs/Guides/Client SDKs/unreal.md b/site/content/en/docs/Guides/Client SDKs/unreal.md index f1976891fe..363593d6fa 100644 --- a/site/content/en/docs/Guides/Client SDKs/unreal.md +++ b/site/content/en/docs/Guides/Client SDKs/unreal.md @@ -31,6 +31,40 @@ At this moment we do not provide binaries for the plugin. This requires you to c 2. Copy {{< ghlink href="sdks/unreal" >}}the Agones plugin directory{{< /ghlink >}} into the Plugins directory. 3. Build the project. +### Agones Hook + +To manually call the Agones SDK methods add the plugin as a dependency inside the `.Build.cs` file: + +``` +PublicDependencyModuleNames.AddRange( + new string[] + { + ... + "Agones" + }); +``` + +Then use `FAgonesModule::GetHook()` to get a reference to the Agones hook and call the SDK methods using the hook: + +``` +#include "Agones.h" + +... + +// Get a reference to the Agones hook. +FAgonesHook& Hook = FAgonesModule::GetHook(); + +Hook.Ready(); +Hook.SetLabel(TEXT("key"), TEXT("value")); + +// GetGameServerDelegate here is a class member of type FGameServerRequestCompleteDelegate. +Hook.GetGameServer(GetGameServerDelegate); +GetGameServerDelegate.BindLambda([](TSharedPtr GameServer, bool bSuccess) +{ + // ... +}); +``` + ## Settings The settings for the Agones Plugin can be found in the Unreal Engine editor `Edit > Project Settings > Plugins > Agones` @@ -39,6 +73,6 @@ Available settings: - Health Ping Enabled. Whether the server sends a health ping to the Agones sidecar. (default: `true`) - Health Ping Seconds. Interval of the server sending a health ping to the Agones sidecar. (default: `5`) -- Debug Logging Enabled. Debug logging for development of this Plugin. (default: `false`) - Request Retry Limit. Maximum number of times a failed request to the Agones sidecar is retried. Health requests are not retried. (default: `30`) +- Send Ready at Startup. Automatically send a Ready request when the server starts. Disable this to manually control when the game server should be marked as ready. (default: `true`)