Integre o Amazon GameLift Servers em um projeto Unreal Engine - Amazon GameLift Servers

Integre o Amazon GameLift Servers em um projeto Unreal Engine

Aprenda a integrar o Amazon GameLift Servers SDK para o Unreal Engine em seus projetos de jogos para acessar o conjunto completo de atributos do SDK do servidor.

Dica

Para uma implantação mais rápida, experimente o plug-in independente do Amazon GameLift Servers para o Unreal Engine. Ele fornece fluxos de trabalho de interface de usuário guiados para implantar rapidamente seu servidor de jogos com configuração mínima, para que você possa testar os componentes do jogo em ação. Consulte Amazon GameLift ServersPlug-in para Unreal Engine.

Recursos adicionais:

Instalar o SDK do servidor para o Unreal Engine

Obtenha o código aberto Amazon GameLift Servers SDK para o Unreal Engine no GitHub. Os arquivos readme do repositório contêm pré-requisitos e instruções de instalação.

Configure metas de construção e regras de módulo

Modifique seus arquivos de projeto de jogo para gerar corretamente componentes de compilação para uso com o Amazon GameLift Servers.

Para adicionar destinos de criação de cliente e servidor:
  1. Abra os arquivos de código do seu projeto de jogo e localize o arquivo .../Games/[your application name]Source/[your application name]Target.cs. Exemplo: .../Source/GameLiftUnrealAppTarget.cs. (Se você usa o Visual Studio, abra o arquivo do .sln do projeto.)

  2. Copie esse arquivo para criar dois novos arquivos de destino no diretório Source/.

    • Destino do cliente – Renomeie o novo arquivo para [your application name]Client.Target.cs. Edite o conteúdo para atualizar os valores do nome da classe e do tipo de destino, conforme ilustrado no código de exemplo a seguir:

      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 do servidor – Renomeie o novo arquivo para [your application name]Server.Target.cs. Edite o conteúdo para atualizar os valores do nome da classe e do tipo de destino, conforme ilustrado no código de exemplo a seguir:

      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. Gere novamente os arquivos do projeto. Se você estiver usando o Visual Studio, você pode clicar com o botão direito do mouse no arquivo .uproject do seu projeto de jogo e selecionar Gerar arquivos de projeto do Visual Studio.

Para atualizar as regras do módulo do projeto do jogo:

Atualize as regras do módulo do projeto de jogo para depender do plug-in.

  1. Abra os arquivos de código do seu projeto de jogo e localize o arquivo .../Games/[your application name]Source/[your application name].Build.cs. Exemplo: .../Source/GameLiftUnrealApp.Build.cs. (Se você usa o Visual Studio, abra o arquivo do .sln do projeto.)

  2. Localize a classe ModuleRules e atualize conforme ilustrado no código de exemplo a seguir:

    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. Depois de criar os novos arquivos de destino e modificar as regras do módulo, reconstrua seu projeto de jogo.

Adicione a funcionalidade de hospedagem de jogos ao código do seu servidor

Após a instalação e configuração do SDK do servidor, a próxima etapa é integrar a funcionalidade de hospedagem de jogos ao código do servidor. O SDK do servidor permite que seu servidor de jogos se comunique com o serviço do Amazon GameLift Servers, receba instruções para sessões de jogo, relate status e integridade e execute outras ações.

Este tópico fornece um exemplo de código que adiciona a funcionalidade mínima necessária para hospedar seu jogo com o Amazon GameLift Servers.

Etapa 1: atualizar o arquivo de GameMode compartilhado
  1. Abra os arquivos de código do seu projeto de jogo e localize o arquivo Your-application-nameGameMode.h. Exemplo: GameLiftUnrealAppGameMode.h. Se você usa o Visual Studio, abra o arquivo do .sln do projeto.

  2. Altere o arquivo de cabeçalho para incluir o código de exemplo a seguir. Certifique-se de substituir "GameLiftUnrealApp" pelo nome do seu próprio aplicativo.

// 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; };
Etapa 2: Adicione as chamadas necessárias do SDK do servidor ao código do servidor do jogo

Use o código de amostra nesta seção para integrar o código do servidor do jogo para uso com o Amazon GameLift Servers. Para obter detalhes sobre o que o código faz, consulte Inicializar o processo do servidor e SDK do servidor C++ (Unreal) para Amazon GameLift Servers 5.x – Ações.

nota

O sinalizador de pré-processador de WITH_GAMELIFT tem duas finalidades:

  • Restringe as chamadas de API de backend do Amazon GameLift Servers somente para compilações de servidores Unreal

  • Garante compatibilidade entre diferentes destinos de compilação do Unreal

  1. Abra o arquivo Your-application-nameGameMode.cpp de origem relacionado. Em nosso exemplo: GameLiftUnrealAppGameMode.cpp.

  2. Altere o código para alinhá-lo com o código de exemplo a seguir. Certifique-se de substituir qualquer instância de "GameLiftUnrealApp" pelo nome do seu próprio aplicativo.

    O exemplo de código fornecido mostra como adicionar os elementos necessários para integração com o Amazon GameLift Servers. Isso inclui:

    • Inicialize um cliente da API do Amazon GameLift Servers.

    • Implemente funções de retorno de chamada para responder às solicitações do serviço do Amazon GameLift Servers, inclusive OnStartGameSession, OnProcessTerminate e onHealthCheck.

    • Chame ProcessReady() para notificar o serviço do Amazon GameLift Servers quando estiver pronto para hospedar sessões do jogo.

// 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 }
Etapa 3: Reconstruir o projeto do jogo
  • Crie um projeto de jogo para os dois tipos de alvo a seguir: Editor de Desenvolvimento e Servidor de Desenvolvimento.

    nota

    Não é necessário reconstruir a solução. Em vez disso, crie o projeto na pasta /Games/ do seu aplicativo. Caso contrário, o Visual Studio reconstrói todo o projeto do UE5, o que pode levar até uma hora.

Inclua o servidor de jogos para hospedagem.

Com o código do servidor do jogo agora integrado à funcionalidade mínima necessária do SDK do servidor, você está pronto para empacotar a versão do seu servidor de jogos usando o Unreal Editor.

Para empacotar a versão do servidor de jogos.
  1. Abra o projeto do jogo no Unreal Editor.

  2. Siga as etapas do Unreal Editor para empacotar seu servidor de jogos:

    • Escolha sua plataforma de destino (Windows ou Linux).

    • Selecione o destino de compilação do seu servidor ([your application name]Server.

    O processo de empacotamento gera o executável do seu servidor de jogos: [your application name]Server.exe.

  3. Prepare a versão do seu servidor de jogos para implantação em recursos de hospedagem. A compilação deve incluir os seguintes arquivos.

    • Seu executável do servidor de jogos

    • Se você estiver usando a versão 5.5 ou anterior do Unreal Engine, inclua os seguintes arquivos para compilações do Windows. É possível encontrá-los na versão original do 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 as outras dependências necessárias para servidor de jogos.

    • Bibliotecas OpenSSL, se necessário. Você pode pular essa etapa se seu servidor de jogos estiver integrado ao SDK do servidor do Amazon GameLift Servers versão 5.3 ou posterior. A versão mais recente do SDK do servidor está disponível aqui.

Você deve incluir a mesma versão das bibliotecas do OpenSSL que foram usadas ao empacotar o servidor do jogo no Unreal. Essas bibliotecas estão localizadas na fonte do seu mecanismo de jogo. O local varia de acordo com o ambiente de desenvolvimento:

No 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

No 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 as bibliotecas do OpenSSL para o pacote de compilação do jogo no mesmo diretório do arquivo executável do servidor do jogo.

Próximas etapas

Agora que você preparou uma versão de servidor de jogos com a funcionalidade mínima necessária para hospedagem com o Amazon GameLift Servers, considere estas possíveis próximas etapas: