Integración de Amazon GameLift Servers en un proyecto de Unreal Engine - Amazon GameLift Servers

Integración de Amazon GameLift Servers en un proyecto de Unreal Engine

Aprenda a integrar el SDK de Amazon GameLift Servers para Unreal Engine en sus proyectos de juegos para acceder al conjunto completo de características del SDK del servidor.

Sugerencia

Para agilizar la implementación, pruebe el complemento independiente de Amazon GameLift Servers para Unreal Engine. Proporciona flujos de trabajo de la IU guiados que le permitirán implementar rápidamente el servidor de juegos con una configuración mínima, para así poder probar los componentes del juego en acción. Consulte Complemento de Amazon GameLift Servers para Unreal Engine.

Recursos adicionales:

Instalación del SDK del servidor para Unreal

Obtenga el SDK de código abierto de Amazon GameLift Servers para Unreal Engine de GitHub. Los archivos readme del repositorio contienen los requisitos previos y las instrucciones de instalación.

Configure los objetivos de compilación y las reglas de los módulos

Modifique los archivos del proyecto del juego para generar correctamente los componentes de compilación para usarlos con Amazon GameLift Servers.

Para añadir objetivos de compilación para el cliente y el servidor, sigue estos pasos:
  1. Abra los archivos de código del proyecto de juego y localice el archivo .../Games/[your application name]Source/[your application name]Target.cs. Ejemplo: : .../Source/GameLiftUnrealAppTarget.cs. Si utiliza Visual Studio, abra el archivo .sln del proyecto.

  2. Copie este archivo para crear dos nuevos archivos de destino en el Source/ directorio.

    • Destino del cliente: cambie el nombre del nuevo archivo a [your application name]Client.Target.cs. Edite el contenido para actualizar el nombre de clase y los valores de tipo de destino, como se muestra en el siguiente ejemplo de código:

      using UnrealBuildTool; using System.Collections.Generic; public class GameLiftUnrealAppClientTarget : TargetRules { public GameLiftUnrealAppClientTarget ( TargetInfo Target ) : base ( Target ) { Type = TargetType.Client; DefaultBuildSettings = BuildSettingsVersion.V2; IncludeOrderVersion = EngineIncludeOrderVersion.Unreal5_1; ExtraModuleNames.Add( "GameLiftUnrealApp"); } }
    • Destino del servidor: cambie el nombre del nuevo archivo a [your application name]Server.Target.cs. Edite el contenido para actualizar el nombre de clase y los valores de tipo de destino, como se muestra en el siguiente ejemplo de código:

      using UnrealBuildTool; using System.Collections.Generic; public class GameLiftUnrealAppServerTarget : TargetRules { public GameLiftUnrealAppServerTarget ( TargetInfo Target ) : base ( Target ) { Type = TargetType.Server; DefaultBuildSettings = BuildSettingsVersion.V2; IncludeOrderVersion = EngineIncludeOrderVersion.Unreal5_1; ExtraModuleNames.Add( "GameLiftUnrealApp"); } }
  3. Regenere los archivos del proyecto. Si utiliza Visual Studio, puede hacer clic con el botón derecho en el .uproject archivo del proyecto de juego y seleccionar Generar archivos de proyecto de Visual Studio.

Para actualizar las reglas del módulo de proyectos de juego:

Actualice las reglas del módulo del proyecto de juego para que dependan del complemento.

  1. Abra los archivos de código del proyecto de juego y localice el archivo .../Games/[your application name]Source/[your application name].Build.cs. Ejemplo: : .../Source/GameLiftUnrealApp.Build.cs. Si utiliza Visual Studio, abra el archivo .sln del proyecto.

  2. Localice la ModuleRules clase y actualícela como se ilustra en el siguiente código de ejemplo:

    using UnrealBuildTool; public class GameLiftUnrealApp : ModuleRules { public GameLiftUnrealApp ( ReadOnlyTargetRules Target ) : base ( Target ) { PCHUsage = PCHUsageMode.UseExplicitOrSharedPCHs; PublicDependencyModuleNames.AddRange( new string[] { "Core", "CoreUObject", "Engine", "InputCore", "HeadMountedDisplay", "EnhancedInput" }); // Add the following section if (Target.Type == TargetType.Server) { PublicDependencyModuleNames.Add("GameLiftServerSDK"); } else { PublicDefinitions.Add("WITH_GAMELIFT=0"); } bEnableExceptions = true; } }
  3. Tras crear los nuevos archivos de destino y modificar las reglas del módulo, reconstruye tu proyecto de juego.

Añade la funcionalidad de alojamiento de juegos al código de tu servidor

Tras instalar y configurar el SDK del servidor, el siguiente paso es integrar la funcionalidad de alojamiento de juegos en el código del servidor. El SDK del servidor permite al servidor de juegos comunicarse con el servicio Amazon GameLift Servers, recibir instrucciones sobre las sesiones de juego, e informar sobre el estado general y de progreso, y realizar otras acciones.

En este tema se proporciona un ejemplo de código que añade la funcionalidad mínima necesaria para alojar el juego en Amazon GameLift Servers.

Paso 1: Actualizar el archivo de encabezado GameMode
  1. Abra los archivos de código del proyecto de juego y localice el archivo Your-application-nameGameMode.h. Ejemplo: : GameLiftUnrealAppGameMode.h. Si utiliza Visual Studio, abra el archivo .sln del proyecto de juego.

  2. Cambie el archivo de encabezado para incluir el siguiente código de ejemplo. Asegúrese de reemplazar “GameLiftUnrealApp” por el nombre de su propia aplicación.

// Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. // SPDX-License-Identifier: Apache-2.0 #pragma once #include "CoreMinimal.h" #include "GameFramework/GameModeBase.h" #include "GameLiftUnrealAppGameMode.generated.h" struct FProcessParameters; DECLARE_LOG_CATEGORY_EXTERN(GameServerLog, Log, All); UCLASS(minimalapi) class AGameLiftUnrealAppGameMode : public AGameModeBase { GENERATED_BODY() public: AGameLiftUnrealAppGameMode(); protected: virtual void BeginPlay() override; private: void InitGameLift(); private: TSharedPtr<FProcessParameters> ProcessParameters; };
Paso 2: Añadir las llamadas del SDK del servidor necesarias al código del servidor de juegos

Utilice el código de ejemplo de esta sección para integrar el código del servidor de juegos y usarlo con Amazon GameLift Servers. Para obtener más información sobre los efectos de este código, consulte Inicialización del proceso del servidor y SDK 5.x del servidor de C++ (Unreal) para Amazon GameLift Servers: acciones.

nota

El indicador de preproceso WITH_GAMELIFT sirve para dos fines:

  • Restringe las llamadas a la API de backend de Amazon GameLift Servers a solo las compilaciones de servidor de Unreal

  • Garantiza la compatibilidad entre los diferentes objetivos de compilación de Unreal

  1. Abra el archivo Your-application-nameGameMode.cpp del archivo de origen relacionado. En nuestro ejemplo: GameLiftUnrealAppGameMode.cpp.

  2. Cambie el código para alinearlo con el siguiente código de ejemplo. Asegúrese de reemplazar cualquier instancia de “GameLiftUnrealApp” por el nombre de su propia aplicación.

    El ejemplo de código proporcionado muestra cómo añadir los elementos necesarios para la integración con Amazon GameLift Servers. Entre ellos se incluyen:

    • Inicializar un cliente de API de Amazon GameLift Servers.

    • Implemente funciones de devolución de llamada para responder a las solicitudes del servicio de Amazon GameLift Servers, incluidas OnStartGameSession, OnProcessTerminate y onHealthCheck.

    • Llame a ProcessReady() para informar al servicio Amazon GameLift Servers cuando el proceso esté listo para alojar sesiones de juego.

// Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. // SPDX-License-Identifier: Apache-2.0 #include "GameLiftUnrealAppGameMode.h" #include "UObject/ConstructorHelpers.h" #include "Kismet/GameplayStatics.h" #if WITH_GAMELIFT #include "GameLiftServerSDK.h" #include "GameLiftServerSDKModels.h" #endif #include "GenericPlatform/GenericPlatformOutputDevices.h" DEFINE_LOG_CATEGORY(GameServerLog); AGameLiftUnrealAppGameMode::AGameLiftUnrealAppGameMode() : ProcessParameters(nullptr) { // Set default pawn class to our Blueprinted character static ConstructorHelpers::FClassFinder<APawn> PlayerPawnBPClass(TEXT("/Game/ThirdPerson/Blueprints/BP_ThirdPersonCharacter")); if (PlayerPawnBPClass.Class != NULL) { DefaultPawnClass = PlayerPawnBPClass.Class; } UE_LOG(GameServerLog, Log, TEXT("Initializing AGameLiftUnrealAppGameMode...")); } void AGameLiftUnrealAppGameMode::BeginPlay() { Super::BeginPlay(); #if WITH_GAMELIFT InitGameLift(); #endif } void AGameLiftUnrealAppGameMode::InitGameLift() { #if WITH_GAMELIFT UE_LOG(GameServerLog, Log, TEXT("Calling InitGameLift...")); // Getting the module first. FGameLiftServerSDKModule* GameLiftSdkModule = &FModuleManager::LoadModuleChecked<FGameLiftServerSDKModule>(FName("GameLiftServerSDK")); //Define the server parameters for a GameLift Anywhere fleet. These are not needed for a GameLift managed EC2 fleet. FServerParameters ServerParametersForAnywhere; bool bIsAnywhereActive = false; if (FParse::Param(FCommandLine::Get(), TEXT("glAnywhere"))) { bIsAnywhereActive = true; } if (bIsAnywhereActive) { UE_LOG(GameServerLog, Log, TEXT("Configuring server parameters for Anywhere...")); // If GameLift Anywhere is enabled, parse command line arguments and pass them in the ServerParameters object. FString glAnywhereWebSocketUrl = ""; if (FParse::Value(FCommandLine::Get(), TEXT("glAnywhereWebSocketUrl="), glAnywhereWebSocketUrl)) { ServerParametersForAnywhere.m_webSocketUrl = TCHAR_TO_UTF8(*glAnywhereWebSocketUrl); } FString glAnywhereFleetId = ""; if (FParse::Value(FCommandLine::Get(), TEXT("glAnywhereFleetId="), glAnywhereFleetId)) { ServerParametersForAnywhere.m_fleetId = TCHAR_TO_UTF8(*glAnywhereFleetId); } FString glAnywhereProcessId = ""; if (FParse::Value(FCommandLine::Get(), TEXT("glAnywhereProcessId="), glAnywhereProcessId)) { ServerParametersForAnywhere.m_processId = TCHAR_TO_UTF8(*glAnywhereProcessId); } else { // If no ProcessId is passed as a command line argument, generate a randomized unique string. FString TimeString = FString::FromInt(std::time(nullptr)); FString ProcessId = "ProcessId_" + TimeString; ServerParametersForAnywhere.m_processId = TCHAR_TO_UTF8(*ProcessId); } FString glAnywhereHostId = ""; if (FParse::Value(FCommandLine::Get(), TEXT("glAnywhereHostId="), glAnywhereHostId)) { ServerParametersForAnywhere.m_hostId = TCHAR_TO_UTF8(*glAnywhereHostId); } FString glAnywhereAuthToken = ""; if (FParse::Value(FCommandLine::Get(), TEXT("glAnywhereAuthToken="), glAnywhereAuthToken)) { ServerParametersForAnywhere.m_authToken = TCHAR_TO_UTF8(*glAnywhereAuthToken); } FString glAnywhereAwsRegion = ""; if (FParse::Value(FCommandLine::Get(), TEXT("glAnywhereAwsRegion="), glAnywhereAwsRegion)) { ServerParametersForAnywhere.m_awsRegion = TCHAR_TO_UTF8(*glAnywhereAwsRegion); } FString glAnywhereAccessKey = ""; if (FParse::Value(FCommandLine::Get(), TEXT("glAnywhereAccessKey="), glAnywhereAccessKey)) { ServerParametersForAnywhere.m_accessKey = TCHAR_TO_UTF8(*glAnywhereAccessKey); } FString glAnywhereSecretKey = ""; if (FParse::Value(FCommandLine::Get(), TEXT("glAnywhereSecretKey="), glAnywhereSecretKey)) { ServerParametersForAnywhere.m_secretKey = TCHAR_TO_UTF8(*glAnywhereSecretKey); } FString glAnywhereSessionToken = ""; if (FParse::Value(FCommandLine::Get(), TEXT("glAnywhereSessionToken="), glAnywhereSessionToken)) { ServerParametersForAnywhere.m_sessionToken = TCHAR_TO_UTF8(*glAnywhereSessionToken); } UE_LOG(GameServerLog, SetColor, TEXT("%s"), COLOR_YELLOW); UE_LOG(GameServerLog, Log, TEXT(">>>> WebSocket URL: %s"), *ServerParametersForAnywhere.m_webSocketUrl); UE_LOG(GameServerLog, Log, TEXT(">>>> Fleet ID: %s"), *ServerParametersForAnywhere.m_fleetId); UE_LOG(GameServerLog, Log, TEXT(">>>> Process ID: %s"), *ServerParametersForAnywhere.m_processId); UE_LOG(GameServerLog, Log, TEXT(">>>> Host ID (Compute Name): %s"), *ServerParametersForAnywhere.m_hostId); UE_LOG(GameServerLog, Log, TEXT(">>>> Auth Token: %s"), *ServerParametersForAnywhere.m_authToken); UE_LOG(GameServerLog, Log, TEXT(">>>> Aws Region: %s"), *ServerParametersForAnywhere.m_awsRegion); UE_LOG(GameServerLog, Log, TEXT(">>>> Access Key: %s"), *ServerParametersForAnywhere.m_accessKey); UE_LOG(GameServerLog, Log, TEXT(">>>> Secret Key: %s"), *ServerParametersForAnywhere.m_secretKey); UE_LOG(GameServerLog, Log, TEXT(">>>> Session Token: %s"), *ServerParametersForAnywhere.m_sessionToken); UE_LOG(GameServerLog, SetColor, TEXT("%s"), COLOR_NONE); } UE_LOG(GameServerLog, Log, TEXT("Initializing the GameLift Server...")); //InitSDK will establish a local connection with GameLift's agent to enable further communication. FGameLiftGenericOutcome InitSdkOutcome = GameLiftSdkModule->InitSDK(ServerParametersForAnywhere); if (InitSdkOutcome.IsSuccess()) { UE_LOG(GameServerLog, SetColor, TEXT("%s"), COLOR_GREEN); UE_LOG(GameServerLog, Log, TEXT("GameLift InitSDK succeeded!")); UE_LOG(GameServerLog, SetColor, TEXT("%s"), COLOR_NONE); } else { UE_LOG(GameServerLog, SetColor, TEXT("%s"), COLOR_RED); UE_LOG(GameServerLog, Log, TEXT("ERROR: InitSDK failed : (")); FGameLiftError GameLiftError = InitSdkOutcome.GetError(); UE_LOG(GameServerLog, Log, TEXT("ERROR: %s"), *GameLiftError.m_errorMessage); UE_LOG(GameServerLog, SetColor, TEXT("%s"), COLOR_NONE); return; } ProcessParameters = MakeShared<FProcessParameters>(); //When a game session is created, Amazon GameLift Servers sends an activation request to the game server and passes along the game session object containing game properties and other settings. //Here is where a game server should take action based on the game session object. //Once the game server is ready to receive incoming player connections, it should invoke GameLiftServerAPI.ActivateGameSession() ProcessParameters->OnStartGameSession.BindLambda([=](Aws::GameLift::Server::Model::GameSession InGameSession) { FString GameSessionId = FString(InGameSession.GetGameSessionId()); UE_LOG(GameServerLog, Log, TEXT("GameSession Initializing: %s"), *GameSessionId); GameLiftSdkModule->ActivateGameSession(); }); //OnProcessTerminate callback. Amazon GameLift Servers will invoke this callback before shutting down an instance hosting this game server. //It gives this game server a chance to save its state, communicate with services, etc., before being shut down. //In this case, we simply tell Amazon GameLift Servers we are indeed going to shutdown. ProcessParameters->OnTerminate.BindLambda([=]() { UE_LOG(GameServerLog, Log, TEXT("Game Server Process is terminating")); // First call ProcessEnding() FGameLiftGenericOutcome processEndingOutcome = GameLiftSdkModule->ProcessEnding(); // Then call Destroy() to free the SDK from memory FGameLiftGenericOutcome destroyOutcome = GameLiftSdkModule->Destroy(); // Exit the process with success or failure if (processEndingOutcome.IsSuccess() && destroyOutcome.IsSuccess()) { UE_LOG(GameServerLog, Log, TEXT("Server process ending successfully")); } else { if (!processEndingOutcome.IsSuccess()) { const FGameLiftError& error = processEndingOutcome.GetError(); UE_LOG(GameServerLog, Error, TEXT("ProcessEnding() failed. Error: %s"), error.m_errorMessage.IsEmpty() ? TEXT("Unknown error") : *error.m_errorMessage); } if (!destroyOutcome.IsSuccess()) { const FGameLiftError& error = destroyOutcome.GetError(); UE_LOG(GameServerLog, Error, TEXT("Destroy() failed. Error: %s"), error.m_errorMessage.IsEmpty() ? TEXT("Unknown error") : *error.m_errorMessage); } } }); //This is the HealthCheck callback. //Amazon GameLift Servers will invoke this callback every 60 seconds or so. //Here, a game server might want to check the health of dependencies and such. //Simply return true if healthy, false otherwise. //The game server has 60 seconds to respond with its health status. Amazon GameLift Servers will default to 'false' if the game server doesn't respond in time. //In this case, we're always healthy! ProcessParameters->OnHealthCheck.BindLambda([]() { UE_LOG(GameServerLog, Log, TEXT("Performing Health Check")); return true; }); //GameServer.exe -port=7777 LOG=server.mylog ProcessParameters->port = FURL::UrlConfig.DefaultPort; TArray<FString> CommandLineTokens; TArray<FString> CommandLineSwitches; FCommandLine::Parse(FCommandLine::Get(), CommandLineTokens, CommandLineSwitches); for (FString SwitchStr : CommandLineSwitches) { FString Key; FString Value; if (SwitchStr.Split("=", &Key, &Value)) { if (Key.Equals("port")) { ProcessParameters->port = FCString::Atoi(*Value); } } } //Here, the game server tells Amazon GameLift Servers where to find game session log files. //At the end of a game session, Amazon GameLift Servers uploads everything in the specified //location and stores it in the cloud for access later. TArray<FString> Logfiles; Logfiles.Add(TEXT("GameLiftUnrealApp/Saved/Logs/server.log")); ProcessParameters->logParameters = Logfiles; //The game server calls ProcessReady() to tell Amazon GameLift Servers it's ready to host game sessions. UE_LOG(GameServerLog, Log, TEXT("Calling Process Ready...")); FGameLiftGenericOutcome ProcessReadyOutcome = GameLiftSdkModule->ProcessReady(*ProcessParameters); if (ProcessReadyOutcome.IsSuccess()) { UE_LOG(GameServerLog, SetColor, TEXT("%s"), COLOR_GREEN); UE_LOG(GameServerLog, Log, TEXT("Process Ready!")); UE_LOG(GameServerLog, SetColor, TEXT("%s"), COLOR_NONE); } else { UE_LOG(GameServerLog, SetColor, TEXT("%s"), COLOR_RED); UE_LOG(GameServerLog, Log, TEXT("ERROR: Process Ready Failed!")); FGameLiftError ProcessReadyError = ProcessReadyOutcome.GetError(); UE_LOG(GameServerLog, Log, TEXT("ERROR: %s"), *ProcessReadyError.m_errorMessage); UE_LOG(GameServerLog, SetColor, TEXT("%s"), COLOR_NONE); } UE_LOG(GameServerLog, Log, TEXT("InitGameLift completed!")); #endif }
Paso 3: Recompilar el proyecto del juego
  • Compile un proyecto de juego para los dos tipos de destino siguientes: Editor de desarrollo y Servidor de desarrollo.

    nota

    No es necesario volver a compilar la solución. En su lugar, compile el proyecto en la carpeta /Games/ de su aplicación. De lo contrario, Visual Studio volverá a compilar todo el proyecto de UE5, algo que podría tardar hasta una hora.

Empaquetado del servidor de juegos para su alojamiento

Ahora que el código del servidor de juegos está integrado con la funcionalidad mínima requerida del SDK del servidor, ya está listo para empaquetar la compilación del servidor de juegos con el editor de Unreal.

Empaquetado de la compilación del servidor de juegos
  1. Abra el proyecto del juego en Unreal Editor.

  2. Siga los pasos del editor de Unreal para empaquetar el servidor de juegos:

    • Elija la plataforma de destino (Windows o Linux).

    • Seleccione el destino de la compilación del servidor ([your application name]Server.

    El proceso de empaquetado genera el ejecutable del servidor de juegos: [your application name]Server.exe.

  3. Prepare la compilación del servidor de juegos para su implementación en los recursos de alojamiento. La compilación debe incluir los siguientes archivos.

    • El archivo ejecutable del servidor de juegos

    • Si está utilizando la versión 5.5 o anterior de Unreal Engine, incluya los siguientes archivos para las compilaciones de Windows. Los encontrará en su versión integrada de Unreal Engine:

      • VC_redist.x64.exe (UnrealEngine\Engine\Source\Programs\PrereqInstaller\Resources\VCRedist\)

      • UEPrereqSetup_x64.exe or UE5PrereqSetup_x64.exe (UnrealEngine\Engine\Extras\Redist\en-us\)

    • Todas las demás dependencias necesarias para el servidor de juegos.

    • Bibliotecas de OpenSSL, si es necesario. Puede saltarse este paso si el servidor de juegos está integrado con la versión 5.3 o posterior del SDK del servidor de Amazon GameLift Servers. La última versión del SDK del servidor está disponible aquí.

Debe incluir la misma versión de las bibliotecas de OpenSSL que se usaron al empaquetar el servidor de juegos en Unreal. Estas bibliotecas se encuentran en el origen del motor de juegos. La ubicación varía en función del entorno de desarrollo:

En Windows:

  • [ENGINE_ROOT_DIR]\Engine\Extras\ThirdPartyNotUE\libimobiledevice\x64\libssl-1_1-x64.dll

  • [ENGINE_ROOT_DIR]\Engine\Extras\ThirdPartyNotUE\libimobiledevice\x64\libcrypto-1_1-x64.dll

En Linux:

  • Engine/Source/Thirdparty/OpenSSL/1.1.1n/include/libssl.so.1.1

  • Engine/Source/Thirdparty/OpenSSL/1.1.1n/include/libcrypto.so.1.1

Copie las bibliotecas de OpenSSL en el paquete de compilación del juego, en el mismo directorio que el archivo ejecutable del servidor de juegos.

Pasos a seguir a continuación

Ahora que ha preparado una compilación del servidor de juegos con la funcionalidad mínima necesaria para el alojamiento con Amazon GameLift Servers, considere la posibilidad de seguir estos pasos: