Amazon GameLift In C# 03: Sample Codeをビルドし、実行ファイルをGameLift上動かす

Amazon GameLift Walkthrough in C# (with Unity) Tutorial 03

概要

前の記事 : Amazon GameLift In C# 01: アカウント作成とサンプルゲームの接続確認 その記事でサンプルゲームを動かして、問題なく用意された公式Server BuildClient Buildの接続確認を行いました。
今回は公式のAmazon GameLift Custom Server sample codeを実際ビルド(.NET 5)し、Amazon GameLiftに動かしてみたいと思います。
初心者向けのシリーズ、最初は.NET 5での通信原理も紹介したいので、最後ゲームを作る際はUnityを使うけど、今回はただの.NET 5でサーバービルドを作ります。
事前.NET 5をインストールしてください : .NET Download Page

 
この記事のプロジェクトはGithubに上がっています : AGLW-CSharp-CustomServerBasicSample
今回のプロジェクト名はAGLW-CSharp-CustomServerBasicSampleにしますが、変更自由です。  
 

マシン環境

CPU : Intel i7-6920HQ
GPU : AMD Radeon Pro 460
Memory : 16GB
System : Windows 10 (with .NET 5 installed)
IDE : Visual Studio 2019 Community
Editor : Visual Studio Code
Terminal : Windows Terminal (or Command Prompt)

 

プロジェクトの作成

(他のバージョンでも大丈夫かもしれませんが).NET 5がインストールされる前提です。

 

まず、コマンド(こちの場合はVS CodeでCtrl + ```で呼び出すコマンドツール)で好きなパスに入ります。
入りましたら、dotnet new console -n AGLW-CSharp-CustomServerBasicSample -o .\AGLW-CSharp-CustomServerBasicSampleで、新しい.NET Consoleプロジェクトを(-n name)AGLW-CSharp-CustomServerBasicSampleというプロジェクト名にし、(-o output)今のパスにAGLW-CSharp-CustomServerBasicSampleというパス名に(なければ勝手に作られる)作成します。
コマンドを実行したフォルダ構成は :
- obj (folder)
- Program.cs
- AGLW-CSharp-CustomServerBasicSample.csproj

Library(.dll)の追加

方法は二つあります。

Library追加方法の一 (手間がかかる)

Amazon GameLift Getting Startedページを開きます。

 

GameLift Managed Servers SDKをダウンロードします。

ダウンロードした.zipファイルを展開し、GameLift-SDK-Release-4.0.2\GameLift-CSharp-ServerSDK-4.0.2\にあるGameLiftServerSDKNet45.slnVisual Studio 2019で起動します。一部そのフォルダにあるREADME.mdにも書かれていますが、Visual Studioで起動したソリューションはビルドモードをReleaseにしてからBuild -> Build Solutionをします。...\GameLift-CSharp-ServerSDK-4.0.2\Net45\bin\Releaseパスに、必要なライブラリが置かれます。

Unityでサーバーを作る際は以上の.dllで問題ないですが、今回は.NET 5でサーバーを作りたいので、log4net.dllSystem.Configuration.ConfigurationManager.dllというライブラリに参照していますので、System.Configuration.ConfigurationManager.dllもダウンロードします。

NuGet : system.configuration.configurationmanagerこのリンクを開いて、Download packageをし、展開したものにあるSystem.Configuration.ConfigurationManager.dllというファイルを揃います。

プロジェクトフォルダ直下にlibフォルダを作って、構成はこうなります :
- obj (folder)
- lib (folder) - Program.cs
- AGLW-CSharp-CustomServerBasicSample.csproj

揃った.dllファイルをすべてlib\に入れて、lib\の中身はこうなります :
- GameLiftServerSDKNet45.dll - Google.Protobuf.dll - log4net.dll
- Newtonsoft.Json.dll
- System.Buffers.dll
- System.Collections.Immutable.dll
- System.Configuration.ConfigurationManager.dll
- System.Memory.dll
- System.Runtime.CompilerServices.Unsafe.dll
- websocket-sharp.dll

lib\に追加だけで認識されないので、手入力で下記のソースをAGLW-CSharp-CustomServerBasicSample.csprojファイルに追加してください。

  <ItemGroup>

    <Reference Include="websocket-sharp">
      <HintPath>lib\websocket-sharp.dll</HintPath>
    </Reference>

    <Reference Include="System.Runtime.CompilerServices.Unsafe">
      <HintPath>lib\System.Runtime.CompilerServices.Unsafe.dll</HintPath>
    </Reference>

    <Reference Include="log4net">
      <HintPath>lib\log4net.dll</HintPath>
    </Reference>

    <Reference Include="System.Buffers">
      <HintPath>lib\System.Buffers.dll</HintPath>
    </Reference>

    <Reference Include="Google.Protobuf">
      <HintPath>lib\Google.Protobuf.dll</HintPath>
    </Reference>

    <Reference Include="System.Memory">
      <HintPath>lib\System.Memory.dll</HintPath>
    </Reference>

    <Reference Include="GameLiftServerSDKNet45">
      <HintPath>lib\GameLiftServerSDKNet45.dll</HintPath>
    </Reference>

    <Reference Include="Newtonsoft.Json">
      <HintPath>lib\Newtonsoft.Json.dll</HintPath>
    </Reference>

    <Reference Include="System.Collections.Immutable">
      <HintPath>lib\System.Collections.Immutable.dll</HintPath>
    </Reference>

    <Reference Include="System.Configuration.ConfigurationManager">
      <HintPath>lib\System.Configuration.ConfigurationManager.dll</HintPath>
    </Reference>

  </ItemGroup>

他の<Group>...</Group>に挟まないように、下記の位置に追加するのはおすすめです。

<Project Sdk="Microsoft.NET.Sdk">
  <PropertyGroup>
  </PropertyGroup>

    <!-- ここに追加するのはおすすめです。他のGroupに挟まないようにしてください -->

</Project>

上記は方法の一でライブラリの追加が完了です。

 
 

Library追加方法の二

Amazon Web Sevicesは膨大なので、ドキュメンテーションは少し不十分もあって、SDKを探すのも大変かもしれません。そのため、今回使うライブラリを揃って、NuGetにアップロードしました。
リンク : DevIO Amazon GameLift Custom Server Lib Collection

プロジェクトフォルダのパス直下(記事の場合は...\AGLW-CSharp-CustomServerBasicSample)に :
dotnet add package devio.amazon.gamelift.server.lib.collection --version 0.0.1
上記のコマンドを実行します。
実行できたら、下記のように、AGLW-CSharp-CustomServerBasicSample.csprojファイルにパッケージが追加されます。

  <ItemGroup>
    <PackageReference Include="devio.amazon.gamelift.server.lib.collection" Version="0.0.1" />      
  </ItemGroup>

 

GameServerの作成(改造したサンプルソースコード)

プロジェクトフォルダにGameServer.csというファイルを作って、下記のソース(Original Code.NET 5向けて改造した)を入れます(Modified Offical Sample):

using Aws.GameLift.Server;
using System.Collections.Generic;

public class GameServer
{
    // A GameServer status flag
    public bool IsAlive {get; private set;} = false;

    //This is an example of a simple integration with GameLift server SDK that makes game server 
    //processes go active on Amazon GameLift
    public void Start()
    {
        // Set GameServer status flag to true when GameServer is started
        IsAlive = true;

        //Set the port that your game service is listening on for incoming player connections (hard-coded here for simplicity)
        var listeningPort = 7777;

        //InitSDK establishes a local connection with the Amazon GameLift agent to enable 
        //further communication.
        var initSDKOutcome = GameLiftServerAPI.InitSDK();
        if (initSDKOutcome.Success)
        {
            ProcessParameters processParameters = new ProcessParameters(
                (gameSession) => {
                    //Respond to new game session activation request. GameLift sends activation request 
                    //to the game server along with a game session object containing game properties 
                    //and other settings. Once the game server is ready to receive player connections, 
                    //invoke GameLiftServerAPI.ActivateGameSession()
                    GameLiftServerAPI.ActivateGameSession();
                },
                () => {
                    //OnProcessTerminate callback. GameLift invokes 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 GameLift we are indeed going to shut down.
                    GameLiftServerAPI.ProcessEnding();
                }, 
                () => {
                    //This is the HealthCheck callback.
                    //GameLift invokes 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. 
                    //GameLift will default to 'false' if the game server doesn't respond in time.
                    //In this case, we're always healthy!
                    return true;
                },
                //Here, the game server tells GameLift what port it is listening on for incoming player 
                //connections. In this example, the port is hardcoded for simplicity. Active game
                //that are on the same instance must have unique ports.
                listeningPort, 
                new LogParameters(new List<string>()
                {
                    //Here, the game server tells GameLift what set of files to upload when the game session ends.
                    //GameLift uploads everything specified here for the developers to fetch later.
                    "/local/game/logs/myserver.log"
                }));

            //Calling ProcessReady tells GameLift this game server is ready to receive incoming game sessions!
            var processReadyOutcome = GameLiftServerAPI.ProcessReady(processParameters);
            if (processReadyOutcome.Success)
            {
                // print("ProcessReady success.");
            }
            else
            {
                // print("ProcessReady failure : " + processReadyOutcome.Error.ToString());
            }
        }
        else
        {
            // print("InitSDK failure : " + initSDKOutcome.Error.ToString());
        }
    }

    // This is a function for Unity delegate, but we are using pure ".NET 5", might not be called
    void OnApplicationQuit()
    {
        // Set GameServer status flag to true when application is quit
        IsAlive = false;

        //Make sure to call GameLiftServerAPI.ProcessEnding() when the application quits. 
        //This resets the local connection with GameLift's agent.
        GameLiftServerAPI.ProcessEnding();
    }
}

そしてProgram.csに、下記のソースを入れます:

class Program
{
    static private GameServer server = null;

    static void Main(string[] args)
    {
        server = new GameServer();
        server.Start();

        // It might be looping forever.
        // It's just a test for the build,
        // we will terminate the GameLift fleet manually ourself.
        // So nothing to worry here.
        while(server.IsAlive)
        {

        }
    }
}

コマンドツールでプロジェクトのパスに入って、下記のコマンドでWINDOWS_2012向けの実行ファイルを作ります(パス自由、こちはD:ドライブに):
dotnet publish --runtime win81-x64 -o d:\BasicServerForWin

ビルドをGameLift上に実行する

 

 

ConsoleのServicesからAmazon GameLiftに入ります。そしてBuildページに入って、ビルドをアップロードするコマンドを確認できます。

ビルドしたのはWINDOWS_2012向けなので、コマンドツールで下記のコマンドを実行すれば、すこし待ちましたら、アップロードされます(AWS CLIのインストールと設定がされていない方は前回の記事に確認をお願いします)。
aws gamelift upload-build --name BasicServerForWin --build-version 0.0.1 --build-root d:\BasicServerForWin --operating-system WINDOWS_2012 --region ap-northeast-1

 

Amazon GameLiftBuildsページに確認し、アップロードされるビルドからFleetを作ります。

 

 

 

 

図のように設定し、Initialize fleetボタンを押せば、Fleetが作られます。勝手にFleetのページに進むので、20分以上を待ってたら、FleetACTIVEの状態になります。これでビルドのFleetが無事に動くことになります。

 

GameLiftの無料枠を超えないように、テスト終わったら、Terminate fleetからDeleteします。

 
 
この記事の内容はこれでおしまいです。