diff --git a/sdks/unreal/Agones/.gitignore b/sdks/unreal/Agones/.gitignore new file mode 100644 index 0000000000..c4ed221d06 --- /dev/null +++ b/sdks/unreal/Agones/.gitignore @@ -0,0 +1,2 @@ +Binaries/ +Intermediate/ \ No newline at end of file diff --git a/sdks/unreal/Agones/Agones.uplugin b/sdks/unreal/Agones/Agones.uplugin new file mode 100644 index 0000000000..c53754d565 --- /dev/null +++ b/sdks/unreal/Agones/Agones.uplugin @@ -0,0 +1,23 @@ +{ + "FileVersion": 3, + "Version": 1, + "VersionName": "0.1", + "FriendlyName": "Agones", + "Description": "Unreal Engine Plugin for Agones Game Server Client", + "Category": "Google", + "CreatedBy": "Google Inc", + "CreatedByURL": "https://agones.dev", + "DocsURL": "https://agones.dev/site/docs/", + "MarketplaceURL": "", + "SupportURL": "https://github.com/GoogleCloudPlatform/agones/issues", + "CanContainContent": false, + "IsBetaVersion": true, + "Installed": true, + "Modules": [ + { + "Name": "Agones", + "Type": "Runtime", + "LoadingPhase": "Default" + } + ] +} diff --git a/sdks/unreal/Agones/Resources/Icon128.png b/sdks/unreal/Agones/Resources/Icon128.png new file mode 100644 index 0000000000..f8ff978616 Binary files /dev/null and b/sdks/unreal/Agones/Resources/Icon128.png differ diff --git a/sdks/unreal/Agones/Source/Agones/Agones.Build.cs b/sdks/unreal/Agones/Source/Agones/Agones.Build.cs new file mode 100644 index 0000000000..c59446b946 --- /dev/null +++ b/sdks/unreal/Agones/Source/Agones/Agones.Build.cs @@ -0,0 +1,41 @@ +// Copyright 2019 Google Inc. 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. + +using UnrealBuildTool; + +public class Agones : ModuleRules +{ + public Agones(ReadOnlyTargetRules Target) : base(Target) + { + PCHUsage = ModuleRules.PCHUsageMode.UseExplicitOrSharedPCHs; + + PublicIncludePaths.AddRange( + new string[] { + }); + + PublicDependencyModuleNames.AddRange( + new string[] + { + "Core", + }); + + PrivateDependencyModuleNames.AddRange( + new string[] + { + "CoreUObject", + "Engine", + "Http", + }); + } +} diff --git a/sdks/unreal/Agones/Source/Agones/Agones.cpp b/sdks/unreal/Agones/Source/Agones/Agones.cpp new file mode 100644 index 0000000000..50e795dbc2 --- /dev/null +++ b/sdks/unreal/Agones/Source/Agones/Agones.cpp @@ -0,0 +1,80 @@ +// Copyright 2019 Google Inc. 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. + +#include "Agones.h" +#include "AgonesHook.h" + +#if WITH_EDITOR +#include "AgonesSettings.h" +#include "ISettingsModule.h" +#include "ISettingsSection.h" +#include "UObject/Class.h" +#include "UObject/WeakObjectPtr.h" +#endif + +#define LOCTEXT_NAMESPACE "AgonesModule" + +void FAgonesModule::StartupModule() +{ + FWorldDelegates::OnPostWorldInitialization.AddRaw(this, &FAgonesModule::OnWorldInitialized); + + +#if WITH_EDITOR + // register Agones settings + ISettingsModule* SettingsModule = FModuleManager::GetModulePtr("Settings"); + + if (SettingsModule != nullptr) + { + ISettingsSectionPtr SettingsSection = SettingsModule->RegisterSettings("Project", "Plugins", "Agones", + LOCTEXT("AgonesSettingsName", "Agones"), + LOCTEXT("AgonesSettingsDescription", "Configure the Agones plug-in."), + GetMutableDefault() + ); + } +#endif //WITH_EDITOR +} + +void FAgonesModule::ShutdownModule() +{ + FWorldDelegates::OnPostWorldInitialization.RemoveAll(this); + + if (HookPtr.IsValid()) + { + HookPtr->Shutdown(); + } + +#if WITH_EDITOR + // unregister Agones settings + ISettingsModule* SettingsModule = FModuleManager::GetModulePtr("Settings"); + + if (SettingsModule != nullptr) + { + SettingsModule->UnregisterSettings("Project", "Plugins", "Agones"); + } +#endif //WITH_EDITOR +} + +void FAgonesModule::OnWorldInitialized(UWorld* World, const UWorld::InitializationValues IVS) +{ + // Only start the agones hook if this is a dedicated server. + if (World != nullptr && World->GetNetMode() == ENetMode::NM_DedicatedServer) + { + HookPtr = MakeShareable(new FAgonesHook()); + HookPtr->Ready(); + } +} + +#undef LOCTEXT_NAMESPACE + +IMPLEMENT_MODULE(FAgonesModule, Agones) \ No newline at end of file diff --git a/sdks/unreal/Agones/Source/Agones/AgonesHook.cpp b/sdks/unreal/Agones/Source/Agones/AgonesHook.cpp new file mode 100644 index 0000000000..1a96bceb41 --- /dev/null +++ b/sdks/unreal/Agones/Source/Agones/AgonesHook.cpp @@ -0,0 +1,115 @@ +// Copyright 2019 Google Inc. 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. + +#include "AgonesHook.h" +#include "AgonesSettings.h" +#include "Runtime/Online/HTTP/Public/Http.h" + +#define LOCTEXT_NAMESPACE "AgonesHook" +DEFINE_LOG_CATEGORY(LogAgonesHook); + +FAgonesHook::FAgonesHook() + : FTickableGameObject() + , CurrentHealthTime(0.0f) + , Settings(nullptr) + , ReadySuffix(FString(TEXT("/ready"))) + , HealthSuffix(FString(TEXT("/health"))) + , ShutdownSuffix(FString(TEXT("/shutdown"))) +{ + Settings = GetDefault(); + check(Settings != nullptr); + + UE_LOG(LogAgonesHook, Log, TEXT("Initialized Agones Hook, Sidecar address: %s, Health Enabled: %s, Health Ping: %f, Debug: %s") + , *Settings->AgonesSidecarAddress + , (Settings->bHealthPingEnabled ? TEXT("True") : TEXT("False")) + , Settings->HealthPingSeconds + , (Settings->bDebugLogEnabled ? TEXT("True") : TEXT("False"))); +} + +FAgonesHook::~FAgonesHook() +{ + Settings = nullptr; +} + +void FAgonesHook::Tick(float DeltaTime) +{ + CurrentHealthTime += DeltaTime; + if (CurrentHealthTime >= Settings->HealthPingSeconds) + { + Health(); + CurrentHealthTime = 0.0f; + } +} + +bool FAgonesHook::IsTickable() const +{ + return Settings->bHealthPingEnabled; +} + +TStatId FAgonesHook::GetStatId() const +{ + RETURN_QUICK_DECLARE_CYCLE_STAT(FAgonesHook, STATGROUP_Tickables); +} + +bool FAgonesHook::IsTickableWhenPaused() const +{ + return true; +} + +static TSharedRef MakeRequest(const FString& URL) +{ + FHttpModule* http = &FHttpModule::Get(); + TSharedRef req = http->CreateRequest(); + req->SetURL(URL); + req->SetVerb("POST"); + req->SetHeader("Content-Type", "application/json"); + req->SetContentAsString("{}"); + return req; +} + +void FAgonesHook::Ready() +{ + SendRequest(Settings->AgonesSidecarAddress + ReadySuffix); +} + +void FAgonesHook::Health() +{ + SendRequest(Settings->AgonesSidecarAddress + HealthSuffix); +} + +void FAgonesHook::Shutdown() +{ + SendRequest(Settings->AgonesSidecarAddress + ShutdownSuffix); +} + + +bool FAgonesHook::SendRequest(const FString& URL) +{ + TSharedRef req = MakeRequest(URL); + bool bSuccess = req->ProcessRequest(); + if (Settings->bDebugLogEnabled) + { + if (bSuccess) + { + UE_LOG(LogAgonesHook, Log, TEXT("Send: %s"), *URL); + } + else + { + UE_LOG(LogAgonesHook, Error, TEXT("Failed sending: %s"), *URL); + } + } + return bSuccess; +} + +#undef LOCTEXT_NAMESPACE \ No newline at end of file diff --git a/sdks/unreal/Agones/Source/Agones/AgonesHook.h b/sdks/unreal/Agones/Source/Agones/AgonesHook.h new file mode 100644 index 0000000000..7520951e6c --- /dev/null +++ b/sdks/unreal/Agones/Source/Agones/AgonesHook.h @@ -0,0 +1,63 @@ +// Copyright 2019 Google Inc. 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 "Tickable.h" + +DECLARE_LOG_CATEGORY_EXTERN(LogAgonesHook, Verbose, All); + +class FAgonesHook : public FTickableGameObject +{ +public: + + /** Default constructor */ + FAgonesHook(); + + /** Deconstructor */ + ~FAgonesHook(); + + // FTickableObjectBase interface + virtual void Tick(float DeltaTime) override; + virtual bool IsTickable() const override; + virtual TStatId GetStatId() const override; + // End FTickableObjectBase interface + + // FTickableGameObject interface + virtual bool IsTickableWhenPaused() const override; + // End FTickableGameObject interface + + /** Sends ready request to sidecar **/ + void Ready(); + /** Sends health ping request to sidecar **/ + void Health(); + /** Sends shutdown request to sidecar **/ + void Shutdown(); + +private: + + /** Helper function to send requests with default debug output */ + bool SendRequest(const FString& URL); + + /** Time since last health ping */ + float CurrentHealthTime; + + /** Agones settings */ + const class UAgonesSettings* Settings; + + const FString ReadySuffix; + const FString HealthSuffix; + const FString ShutdownSuffix; +}; \ No newline at end of file diff --git a/sdks/unreal/Agones/Source/Agones/AgonesSettings.cpp b/sdks/unreal/Agones/Source/Agones/AgonesSettings.cpp new file mode 100644 index 0000000000..838d8d4b71 --- /dev/null +++ b/sdks/unreal/Agones/Source/Agones/AgonesSettings.cpp @@ -0,0 +1,26 @@ +// Copyright 2019 Google Inc. 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. + +#include "AgonesSettings.h" + +UAgonesSettings::UAgonesSettings() + : Super() + , AgonesSidecarAddress("http://localhost:59358") + , bHealthPingEnabled(false) + , HealthPingSeconds(5.0f) + , bDebugLogEnabled(false) +{ +} + + \ No newline at end of file diff --git a/sdks/unreal/Agones/Source/Agones/Public/Agones.h b/sdks/unreal/Agones/Source/Agones/Public/Agones.h new file mode 100644 index 0000000000..12fbb4f0d0 --- /dev/null +++ b/sdks/unreal/Agones/Source/Agones/Public/Agones.h @@ -0,0 +1,34 @@ +// Copyright 2019 Google Inc. 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 "ModuleManager.h" +#include "Engine/World.h" + +class FAgonesModule : public IModuleInterface +{ +public: + + /** IModuleInterface implementation */ + virtual void StartupModule() override; + virtual void ShutdownModule() override; + +private: + void OnWorldInitialized(UWorld* World, UWorld::InitializationValues IVS); + + /** Communicates with the Agones sidecar. */ + TSharedPtr HookPtr; +}; \ No newline at end of file diff --git a/sdks/unreal/Agones/Source/Agones/Public/AgonesSettings.h b/sdks/unreal/Agones/Source/Agones/Public/AgonesSettings.h new file mode 100644 index 0000000000..f0fb3b7145 --- /dev/null +++ b/sdks/unreal/Agones/Source/Agones/Public/AgonesSettings.h @@ -0,0 +1,46 @@ +// Copyright 2019 Google Inc. 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 "UObject/ObjectMacros.h" +#include "UObject/Object.h" +#include "AgonesSettings.generated.h" + +/** + * Implements the settings for Agones. + */ +UCLASS(config = Game) +class AGONES_API UAgonesSettings : public UObject +{ + GENERATED_BODY() + +public: + + /** Default constructor */ + UAgonesSettings(); + + UPROPERTY(EditAnywhere, config, Category = "Agones", meta = (DisplayName = "Agones Sidecar IP Address")) + FString AgonesSidecarAddress; + + UPROPERTY(EditAnywhere, config, Category = "Agones", meta = (DisplayName = "Health Ping Enabled")) + bool bHealthPingEnabled; + + UPROPERTY(EditAnywhere, config, Category = "Agones", meta = (DisplayName = "Health Ping Seconds")) + float HealthPingSeconds; + + UPROPERTY(EditAnywhere, config, Category = "Agones", meta = (DisplayName = "Debug Logging Enabled")) + bool bDebugLogEnabled; +}; diff --git a/site/content/en/docs/Guides/Client SDKs/unreal.md b/site/content/en/docs/Guides/Client SDKs/unreal.md new file mode 100644 index 0000000000..aaff26fefd --- /dev/null +++ b/site/content/en/docs/Guides/Client SDKs/unreal.md @@ -0,0 +1,38 @@ +--- +title: "Unreal Engine Game Server Client Plugin" +linkTitle: "Unreal Engine" +date: 2019-06-13T10:17:50Z +publishDate: 2019-06-13 +weight: 10 +description: "This is the Unreal Engine 4 Agones Game Server Client Plugin. " +--- + +Check the [Client SDK Documentation]({{< relref "_index.md" >}}) for more details on each of the SDK functions and how to run the SDK locally. + +## Download + +Download the source from the [Releases Page](https://github.com/GoogleCloudPlatform/agones/releases) +or {{< ghlink href="sdks/unreal" >}}directly from Github{{< /ghlink >}}. + +## Usage + +The Unreal Engine plugin is specifically designed to be as simple as possible. No programming should be required to use the plugin within your Unreal Engine project. + +### From source + +At this moment we do not provide binaries for the plugin. This requires you to compile the plugin yourself. In order to do this you need to have a C++ Unreal Engine project. + +1. Create a `Plugins` directory in your Unreal Engine project root directory. +2. Copy {{< ghlink href="sdks/unreal" >}}the Agones plugin directory{{< /ghlink >}} into the Plugins directory. +3. Build the project. + +## Settings + +The settings for the Agones Plugin can be found in the Unreal Engine editor `Edit > Project Settings > Plugins > Agones` + +Available settings: +- Agones Sidecar IP. (default: `http://localhost:59358`) +- 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`) +