GS2 Blog

Game Server Services(https://gs2.io/) の最新情報をお届けします

【事例紹介】株式会社スタジオリール SOCCER DUEL ONLINE

f:id:kazutomo:20171124153120j:plain

SOCCER DUEL ONLINE について

サッカーとチェスを組み合わせたオンライン対戦ゲーム。
相手との読み合いが勝利へのカギとなる。
思考型のゲームだが、試合はリアルタイムで進むため、意外と忙しい。
海外をメイン市場に据えた商品。

基本無料。
消費型アイテム課金制。
アプリ内広告あり。

GS2 が選ばれた理由

資金決済法に対応する課金通貨購入、管理してくれるサービスを探していたところ、GS2を見つけました。
SOCCER DUEL ONLINE は Unity で開発を進めており、Unity 向けの SDK を提供している GS2 はすぐに導入できました。
また、初期費用を低く抑えたいと考えており、初期費用が一切必要無い GS2 はその点でも魅力的でした。
ゲームサーバの多くは様々な機能がオールインワンになっているものが多いのですが、
GS2 は機能単位で契約して使用できるため、余計な機能に費用が発生することがないのが魅力的でした。

GS2 に対する開発面での感想

サンプルを見ながらスムーズに組み込むことができました。
何カ所か実装中につまずいたこともあったのですが、丁寧にサポートしていただけました。
今後導入する方のためにコミュニティがあるといいと思います。つまづいたところなどを共有したいです。

GS2 に対する運用面での感想

REST API であらゆる機能がアクセス出来るようになっており、好きなように運営ツールも作れそうなのはとてもよい。
反面、マネージメントコンソールでは 絞り込み・ソートなどの検索まわり・エクスポート機能 といった機能が不足していると感じる。
今後の改善に期待しています。

GS2 に対する費用面での感想

トライアル期間として十分な無料枠があることで導入検討しやすかったです。おかげでリリース直前まで費用が一切かかりませんでした。
ただ、API呼び出し回数などで費用計算されるため、リリース後に、実際はどの程度の費用が発生するかの見積もりが難しかったです。

GS2全体を通しての感想

正直に申し上げて、現時点でのGS2は採用実績が乏しく採用するにあたっては不安がありました。
しかし、いろいろな質問をサポートに問い合わせた際に、設計面や思想まで含めて丁寧に答えていただけたことで安心感につながりました。

GS2 CEO の丹羽さんと直接お会いする機会がありましたが、誠実で信頼のできる方でした。
今ではGS2を選んで良かったと思っています。


Game Server Services は現在アカウント登録していただいた皆様に 30,000円分のクーポン(有効期限: 登録日から3ヶ月間)をプレゼントしています。
この機会にお試しください。
gs2.io

SOCCER DUEL ONLINE

SOCCER DUEL ONLINE

  • studio R.E.E.L
  • ゲーム
  • 無料

play.google.com

【新機能公開】GS2-Script によるサービス間の連携機能を公開

みなさん、こんにちは。GS2 CEO の丹羽です。

先日告知していた GS2-Script によるサービス間の連携機能を公開しました。
これにより、GS2 のマイクロサービス間をサーバレスで繋いで利用できるようになります。

利用例は以下のようになります。
f:id:kazutomo:20171122095120p:plain

f:id:kazutomo:20171122095135p:plain

スクリプトの実装・編集はマネージメントコンソール上で行えます。
引数はドロップダウンボックスでイベントの種類を選択するだけで、適切なパラメータのサンプル値が設定されます。

f:id:kazutomo:20171122110449p:plain

GS2-Script の API リファレンスは以下でご確認いただけます。
GS2-Script 内で使用できるAPIリファレンス - GS2 Documents

今後も GS2 ではゲーム開発者の皆さんがサーバレスでゲーム開発が出来るよう機能の拡充を進めます。

それでは、また。

【新機能】GS2-Script によるマイクロサービス間を協調動作できるように

みなさんこんにちは。GS2の丹羽です。

今日は近日公開予定の新機能の案内をしたいと思います。
今回紹介する機能は GS2 にとって今後重要な役割を果たす機能です。

GS2のいろいろなマイクロサービスで発生したイベントをトリガーとして GS2-Script を起動できるようになります。
また、GS2-Script 内で GS2-SDK が利用可能となり、そのイベント内でさらに GS2 の様々なマイクロサービスを呼び出すことが出来るようになります。

例として、GS2-ConsumableItem と GS2-Stamina を使って説明したいと思います。
GS2-ConsumableItem には アイテムの設定値として『アイテムを消費したとき』 をトリガーとして GS2-Script を起動できます。
その際に以下のパラメータが GS2-Script に渡されます。

{
  "itemPoolName": "アイテムプール名",
  "itemName": "アイテム名",
  "userId": "使用者のユーザID",
  "count": "消費数量",
  "accessToken": "アクセストークン"
}

『アイテムを消費したとき』のレスポンスとしては result に消費を許可するかをbool値で返します。
オプションで count を返すことで指定された消費数量を異なる値に変更することも出来ます。

result = {
  permit=true
}

では、さっそくこの仕組みを使用してスタミナを回復するアイテムを実装してみます。
スタミナを回復する『StaminaPotion』というアイテムを作成し、アイテムを消費したときのイベントとして 『UseStaminaPotion』 という GS2-Script を関連づけます。
これで、StaminaPotion を消費したときに GS2-Script が実行されるようになります。

次に 『UseStaminaPotion』というスクリプトに以下の実装をします。

stamina_client = client('stamina')
stamina_client:change_stamina({
  staminaPoolName='stamina-0001',
  variation=10*args.count,
  maxValue=100,
  overflow=false,
  accessToken=args.accessToken
})
result = {
  permit=true
}

これで、『StaminaPotion』を消費したときに GS2-Stamina の 『stamina-0001』のスタミナ値が 消費数量×10 回復します。
※ スタミナの最大値である maxValue を引数で取るようになっていますが、
  GS2-Script 側でスタミナの最大値を取得する GS2-Script を定義でき、こちらを定義した場合は maxValue の指定は不要になります。

では、もうすこしちゃんとエラーハンドリングをして、スタミナの回復に失敗したときにはアイテムを消費しないようにします。

stamina_client = client('stamina')
response = stamina_client:change_stamina({
  staminaPoolName='stamina-0001',
  variation=10*args.count,
  maxValue=100,
  overflow=false,
  accessToken=args.accessToken
})
result = {
  permit=not(response.isError)
}

permit への戻り値に 『stamina_client:change_stamina』の戻り値に含まれるAPIの実行に成功したかを含むことで
何らかの理由でAPIの呼び出しに失敗した場合はアイテムを消費しないようにできます。

『スタミナの回復』 というチートされるとゲームバランスを崩壊されかねない操作を GS2-Script を経由して実行することで、より安全に設計することが出来るようになります。
このように、独自のゲームサーバを持たずとも『高い自由度』で『安全』で『スケールする』サーバプログラム開発を行えるようにしていきます。

それでは、また。

Serverlessconf Tokyo 2017 に登壇しました。そのほか雑感

みなさん、こんにちは。GS2 CEO の丹羽です。

昨日から始まった Serverlessconf Tokyo 2017 ですが、無事終わりましたね。
参加者の皆さん、スタッフの皆さん、スピーカーの皆さん。本当にお疲れ様でした。

オープニングで昨年の約300人の参加に対して、今年は450人以上と約1.5倍に参加者が増えたと聞きました。
一方で、今年は昨年の1トラックだったのに対して、2トラックになったことで一体感が薄れてしまったのか
Twitterハッシュタグがトレンド入りした昨年に対して、今年はそこまでTwitter上での盛り上がりが無かったように感じたのが少し残念でした。
参加者の傾向としては、まだまだ私服の人が多く、身軽なベンチャー系のエンジニアの人が興味を持っている段階というのは変わってないようです。
私の登壇時にゲーム系の開発者がどのくらいいるのか。というの質問を昨年に引き続き、今年もしたのですが数パーセント程度という状態も変わってないようです。
昨年は直前にはチケットが売り切れていた記憶がありますので、もしかすると潜在的にはそれほど1年で変化がでていない。という可能性もありそうです。
Serverless の普及という文脈で考えたとき、この一年でサーバレスに興味をもつ人たちのユーザ層を増やせていない。という状態なのだろうな。と課題を感じました。

足元の環境の考察は置いておいて、セッションの内容は昨年と比べて今年はどう変わったのだろう。と振り返ってみました。

yoshidashingo.hatenablog.com
Serverlessconf Tokyo を主催している吉田さんのブログに昨年のセッションのまとめがあります。

昨年は概念的な話や方法論的な話が多かったのに対して、今年は具体的な実装の話が増えたように感じます。
昨年ホットだったワードは《サーバレスとは?》《ピタゴラ装置》《ステートレス》だったのに対して、
今年は《コールドスタート》《トランザクション》《冪当性》と、より具体的なワードがいろいろなセッションで見ることが多くなったように感じました。
なので、先駆者達はこの1年で確実に技術スタックを積み上げてきている。と感じています。

そして、興味深いのは昨年のランチセッションで きはるさんが Firebase のセッションをしたときに
Twitter上では「FirebaseってServerlessなの?ServerlessってLambdaのことじゃないの?」とざわつきましたが、
今年は Firebase をはじめとした マネージドサービスもサーバレスだという文脈で皆さんとらえていたように感じました。

それに対して、原さんがSaaSはサーバレスって言えるの?と一石投じるセッションをしていたり、興味深い流れも感じました。

実は、私もSaaSはサーバレスなのか?という事に対しては、ちょっと思うところがあります。
私はフルマネージドサービスはサーバレスだと思いますが、マネージドサービスはサーバレスではない。と思っているためです。
また、別の言い方をすると、スケールに限界があるモノはサーバレスではない。と思っています。
つまり、使用方法さえ間違えなければ《勝手に》《無限に》スケールするフルマネージドサービスこそがサーバレス。と言えるのではないか。と思っています。

なので、インスタンスタイプを明示してキャパシティ管理が必要なRDSやElastiCacheはサーバレスではないし、
リード/ライトキャパシティユニットを予約する必要のあるDynamoDBもあやしい。と思っています。ただ、明確な上限が無いという面ではRDSなどと比べて明らかな違いがあります。
(なので、キャパシティのオートスケールが実装されたので、ギリギリセーフかも?)

そうなると、サービスクラスによってIOレートを予約する必要のあるGS2はサーバレスではないSaaS。ということになってしまうのでしょう。
この裏には、DynamoDBのキャパシティ予約だったり、Lambdaの同時実行数の制限緩和などいろいろな事情があるので仕方がない部分もあるのですが、
今後の課題としてサービスクラスという考え方自体を廃止していけるのであれば廃止していきたいな。と改めて考えさせられました。

さて、ながながと感想を書きましたが、以下が私の登壇時に使用したスライドです。

それでは、また。

【新サービス提供開始】チャットとゲーム内プッシュ通知

みなさんこんにちは。GS2 CEOの丹羽です。

先日概要をお伝えしていた GS2-Chat / GS2-InGamePushNotification のサービス提供を開始しました。
GS2-SDK for Unity も同時にリリースしており、今すぐ Unity からサービスをご利用いただけます。

GS2-InGamePushNotification の使用例

通知サーバに接続するためにクライアント証明書を取得する必要があります。
GS2-Auth で認証をした GS2セッション と、通知サーバの識別子である GS2-InGamePushNotificationゲーム名 を指定して取得します。

yield return gs2.InGamePushNotification.CreateCertificate(
    r =>
    {
        if (r.Error != null)
        {
            // 例外が発生
        }
        else
        {
            Certificate certificate = r.Result;
        }
    },
    Session, // GS2セッション
    GameName // GS2-InGamePushNotification ゲーム名
    );

次に通知サーバに接続し、通知を受け取るための通知セッションを作成します。

yield return gs2.InGamePushNotification.CreateSession(
    r =>
    {
        if (r.Error != null)
        {
            // 例外が発生
        }
        InGamePushNotificationSession session = r.Result;
        session.OnConnect += () =>
        {
            // 通知サーバに接続に成功した場合に呼び出されます。
        };
        session.OnReceive += (subject, body) =>
        {
            // 通知を受信したときに呼び出されます。
        };
        session.OnClose += () =>
        {
            // 何らかの理由により通知サーバから切断された場合に呼び出されます。
        };
    },
    Session, // GS2セッション
    GameName, // GS2-InGamePushNotification ゲーム名
    certificate  // クライアント証明書
    );

あとは通知セッションにイベントハンドラを登録すれば通知を受けることが出来ます。

session.OnConnect += () =>
{
    // 通知サーバとの接続に成功した場合に呼び出されます。
}

session.OnReceive += (subject, body) =>
{
    // 通知を受け取った場合に呼び出されます。
}

session.OnClose += () =>
{
    // 通知サーバから切断された場合に呼び出されます。
}

イベントハンドラは以下の種類があります。

OnConnect()
通知サーバとのセッションが確立できたときに呼び出されます。
このコールバックが戻るまでは通知を受け取ることが出来ません。

OnReceive(string subject, string body)
通知を受け取ったときに呼び出されます。

OnClose()
何らかの理由でセッションが切断されたときに呼び出されます。
再接続するなど、必要な処理を実装してください。

通知の送信は GS2-Matchmaking / GS2-Chat といったGS2のサービスから出せるのは当然として、
サーバサイドSDKを使用することで、自分で作成したサーバプログラムから送信することも出来ます。
マネージメントコンソールからGUIを通して通知を送信し、動作確認も行えますのでお気軽にお試しください。

GS2-Chat の使用例

GS2-Chat ではまずルームを作成する必要があります。
しかし、Unity-SDK からはデフォルトで割り当てられたアクセスポリシーではルームを作成する権限を付与していません。
これはルームの作成を無秩序に行われることを望まない開発者がいることを想定しているためです。
ポリシーに権限を割り当てることで、Unityクライアントからルームを作成したり削除する権限を付与することも可能です。

ルームはマネージメントコンソールからGUIを通して作成することも出来ますし、サーバサイドSDKを通して作成することもできます。

作成したルームにメッセージを送信する場合は以下のようなコードになります。

yield return gs2.Chat.Send(
    r =>
    {
        if (r.Error != null)
        {
            // 例外が発生
        }
    },
    Session,    // ゲームセッション
    LobbyName,  // ロビー名
    RoomId,     // ルームID
    "Hello",    // メッセージテキスト
    "meta",     // メッセージメタデータ
    null        // パスワード(ルームにパスワードが設定されている場合に必要)
);

ルームに届いたメッセージを受信する場合は以下です。

yield return gs2.Chat.List(
    r =>
    {
        if (r.Error != null)
        {
            // 例外が発生
        }
        if (r.Result.Count > 0)
        {
            // メッセージの受信処理
            foreach (var message in r.Result)
            {
                Debug.Log("From: " + message.From);
                Debug.Log("Text: " + message.Text);
                Debug.Log("Meta: " + message.Meta);
                Debug.Log("SendDate: " + message.SendDate);    // 最後に受信したメッセージの送信時刻を、次回以降メッセージを取得する際の startAt に指定することでメッセージをストリーム出来ます。 
            }
        }
    },
    Session,    // ゲームセッション
    LobbyName,  // ロビー名
    RoomId,     // ルームID
    10,         // メッセージの取得件数
    startAt     // メッセージの取得開始日時(現在時刻から1時間前まで指定可能)
    );

次に、ルームに新着メッセージが届いたことを知らせて欲しい場合はどうするか?です。
まず、新着メッセージの通知を受けたいルームを購読します。

yield return Gs2.Chat.Subscribe(
    r =>
    {
        if (r.Error != null)
        {
            // 例外が発生
        }
    },
    Session,    // ゲームセッション
    LobbyName,  // ロビーの名前
    RoomId,     // 購読するルームID
    false,      // 通知を送信したときにユーザがオフラインだったときに転送するか
    null        // オフライン転送時のモバイルプッシュ通知転送の通知音に使用するファイル名
);

サーバからの新着メッセージ通知はWebHookまたは、GS2-InGamePushNotification を組み合わせて実現します。
Unity SDK では GS2-InGamePushNotification との連携がインテグレートされています。

Gs2.Chat.OnReceiveMessage += notification =>
{
    Debug.Log("RoolID: " + notification.RoomId);
    Debug.Log("UserId: " + notification.UserId);
    Debug.Log("Message.Text: " + notification.Message.Text);
    Debug.Log("Message.Meta: " + notification.Message.Meta);
};
Gs2.Chat.SetInGamePushNotificationSession(session);

session は GS2-InGamePushNotification の通知サーバとの接続セッションです。
これで、新着メッセージを受信したときにイベントハンドラが呼び出されるようになります。
たったこれだけのコードでスケールし、オフライン時にモバイルプッシュ通知を受けられるチャットシステムをご利用いただけます。
ぜひ、ご検討ください。

それでは、また。

【新サービス】チャットとゲーム内プッシュ通知システム

みなさんこんにちは。GS2 CEOの丹羽です。

本日は近日公開予定の新サービスの紹介をさせてください。
新サービスは2つで、GS2-InGamePushNotification と GS2-Chat です。

GS2-InGamePushNotification

GS2-InGamePushNotification はゲーム内で使用できるプッシュ通知システムです。
MQTT/WebSocket でサーバに常時接続し、サーバからクライアントに対してプッシュ通知を出すことが出来る仕組みです。
GS2-InGamePushNotification は1時間あたり2円(月額およそ1,440円)から利用を開始でき、1時間あたり2円のサービスクラスで1秒間に3回通知をだすことができます。
固定料金とは別に、プッシュ通知送信 1,000回あたり10円。APIリクエスト1,000回あたり3円で利用できます。

GS2-InGamePushNotification はプレイヤーのオンライン状態を管理し、オンライン中のプレイヤーに対しては MQTT/WebSocket を使用してプッシュ通知を出します。
しかし、もしプレイヤーがオフラインだった場合は、モバイルプッシュ通知に転送する機能を持っています。(通知メッセージのペイロードで転送を無効化することも出来ます)

ローンチ時点で、GS2内のサービスでは GS2-Matchmaking と GS2-Chat と連携できます。
GS2-Matchmaking と連携する場合は、マッチメイキングリクエストを出した後、他プレイヤーとのマッチメイキングが成立していく過程で参加者の増減や、完了をプッシュ通知で受けることが出来ます。
完了プッシュ通知はモバイルプッシュ通知転送が有効な状態で出されます。
マッチメイキングリクエストを出した後でゲームをサスペンドしたとしても、マッチメイキングが成立した段階でモバイルプッシュ通知が呼び出され、ゲームの再開を促すことが出来ます。

これまで GS2-Matchmaking はポーリングで参加者の集まり具合や完了確認を行ってきました。GS2-SDK for Unity ではデフォルト3秒間隔でサーバと通信していました。
これによって GS2-Matchmaking のクオータを消費していたり、マッチメイキングの進行状態のハンドリングの即応性がよかったとは言えなかった点が改善されます。

GS2-Chat

GS2-Chat はチャットサービスを提供できるサービスです。
GS2-Chat は1時間あたり3円(月額およそ2,160円)から利用を開始でき、1時間あたり3円のサービスクラスで1秒間に3回のメッセージ送受信が行えます。
固定料金とは別に、メッセージ送信 10,000回あたり10円。メッセージ受信 10,000メッセージあたり5円。APIリクエスト1,000回あたり3円で利用できます。

GS2-Chat はチャットルームを作成し、ルームにメッセージを送信します。
あとは、ルームに対して指定した日時以降のメッセージを取得する。というリクエストを出すことでメッセージを取り出すことが出来ます。

チャットルームに対する新着メッセージ通知を受けたい場合はルームを購読することで、誰かがルームに発言すると通知を受けることが出来ます。
通知を受ける手段は WebHook と GS2-InGamePushNotification が指定できます。
購読する際にモバイルプッシュ通知に転送するか?通知を受けるときに通知音はどうするか?を指定できます。

これによって、フレンドからの tell メッセージや、ギルドチャットの新着メッセージを受けたときにゲームを起動していなくても、
モバイルプッシュ通知で通知を受けることが出来、それぞれで異なる着信音を設定することができます。
ゲームセッションチャットはゲーム中であれば MQTT/WebSocket で新着通知をうけたいけど、モバイルプッシュ通知転送は行わない。というような設定も可能です。

チャットログは1ヶ月単位で指定した期間保存でき、いつでも検索が出来ます。
ログの保管料金として毎月1GBあたり10円。チャットログの検索は検索時に読み込んだログデータのサイズ 1GB あたり 5円と、検索リクエスト1,000回あたり5円が必要です。
特定のユーザのチャットログを追跡したり、不適切なキーワードで発言しているログなどを検索するといった調査にも利用可能です。

提供開始時期

これらのサービスは今月中のリリースを目指して最終的な確認作業に入っています。

それでは、また。

GS2マネージメントコンソールを Google App Engine Standard Java8 に移設しました。

f:id:kazutomo:20170928125054p:plain

みなさんこんにちは。GS2 CEOの丹羽です。

某フレンズの話題で持ちきりで、あまり話題になっていなかったように思いますが、
昨日 Google App Engine Standard Java8 が GA しました。
cloudplatform.googleblog.com

GS2 はサーバレスアーキテクチャを全面に押し出したゲームサーバを開発・提供をしていることを特徴としていますが、
マネージメントコンソールは各マイクロサービスの非公開APIを使用して実現していることもあり、サーバレス化が難しい箇所でした。
(html + javascript でサーバレス化ができなくもないのですが、非公開APIが公開状態になってしまいます)

そこで、やむを得ずマネージメントコンソールは仮想サーバを使用した設計になっていました。
ずっとこの部分はなんとかしたいと思っていた箇所で、過去に Google App Engine も検討したのですが、Flexible の更新ばかりで Standard の更新が長らく止まっており、採用に至らなかった経緯があります。
# Flexible は初期に Compute Engine Managed VMs と呼ばれていたことからわかるように、GCE に皮をかぶせて PaaS に仕立てたもので、
# Standard と比べると制限は緩和されますが、リクエストに合わせて IaaS である GCE のインスタンスが起動し応答するというもので、Standard のようなコスト感やクイックさに欠けます。

このたび GAE Standard が Java8 に対応し、GAしたということで、マネージメントコンソールを Google App Engine に載せることが実現しました。
昨日リリースし、一日様子を見ていましたが問題無さそうですのでこうして発表いたします。おそらく国内で初めてプロダクションに投入した事例なのではないかとおもいます。

GS2を利用したゲームを開発をする際にマネージメントコンソールにアクセスする機会は初期設定や設定変更時のみですので
現状では初回アクセス時にコールドスタートになる事が多く、ページの表示までの待ち時間がこれまでと比べて長くなる点でご迷惑をおかけしますが、
今後のスケーラビリティ確保と障害時の対応体制としてGS2よりもGoogleのほうが優れているという点で、ご理解いただければとおもいます。

今回の移設にあたって GAE を前提とせずに設計・実装されたマネージメントコンソールを GAE 上で動かすには、いくつかの困難が有りましたが、
Google App Engine Standard Java8 ではこれまであったような 利用可能なAPI制限が撤廃されるなど、これまで障害となっていた多くの問題が取り除かれており、想像していたより少ない作業で移設が出来ました。
それらの情報も下記ページで告知している ServerlessConf Tokyo 2017 でかいつまんで説明したいと考えておりますので、ご興味があればご来場ください。
当日参加するのが困難な場合も後日資料をアップロードする予定ですので、このブログの読者になるなどしてウォッチいただければ幸いです。
gs2.hatenablog.com

GS2 では今後も AWS Lambda や API Gateway といった AWS サービスはもちろん、
Google App Engine や Cloud DataStore、Cloud PubSub といった GCP のサービスも含めて個々のサービスのいいところを見極め、活用したサービスを提供していきます。

それでは、また。

(C) Game Server Services, Inc.