IDL「Baal」について

はじめに

こんにちは、ソーシャルゲーム事業部 Unityエンジニアの佐藤です。
今年は体重が9kg増加するという成長ぶりでした( ・`ω・´)
もうちょっとで桁が一つ増えるところまで来てしまいました...(´・ω・`)

この記事はカヤックUnityアドベントカレンダー2016 20日目の記事となります。

今回は、社内で使っているIDLについてご説明したいと思います。

Baalとは

BaalはKAYACで用いているIDL(インターフェース定義言語)です。
Unityで作ったクライアントアプリと、サーバーが通信する際のデータ形式の定義をしたものです。
ドキュメントの生成や、データ定義に基づいたC#ファイルの生成などを行います。

Baalを導入した経緯

Baal導入以前は、サーバーサイド担当のエンジニアとクライアント担当のエンジニアでAPIの設計を話して作るというフローでしたが、

  • 設計の認識にズレが生じることがある
  • エンドポイント毎に、APIを実行するクラスやレスポンスのデータ型、パーサーを書くのが大変

といった問題が度々発生しました。

それらの問題を解決するためにBaalが導入されました。

Baalは、APIやデータの型の定義する書式から、APIの実装やデータの型クラスファイル、パーサーを自動で生成することができます。

Baalの利用例

  • データ型の定義(ステージの構成・敵の配置・アイテムの効果など)
  • APIの定義(リクエスト・レスポンス)

Baalの使い方

Baalの定義例です。 ユーザーがログインするAPIのサンプルで紹介したいと思います。

Baal定義

定義を元に、C#のソースコードを生成したいと思います。

ランタイムはat.pkgs.baalを使用します。

生成されたファイルは下記となります。

// UserAPI_generated.cs

/*
 * This file is auto-generated by program.
 * Changes to this file may lost.
 */

using System.Collections.Generic;
using Kayac;
using Kayac.Net.Http;
using Models;
using Models.Data;
using Models.Data.Response;

namespace Models.Service
{
    /// <summary>
    /// ユーザーに関するAPI
    /// </summary>
    public sealed partial class UserAPI : APIBase<UserAPI.Api>
    {
        public enum Api
        {
            Login
        }

        /// <summary>
        /// ログイン
        /// このメソッドはリクエストをキャンセルできません
        /// </summary>
        public Operation<LoginResponse> Login(
            System.String email,
            System.String password
        )
        {
            return Login(
                email,
                password,
                CancellationToken.None
            );
        }

        /// <summary>
        /// ログイン
        /// </summary>
        public Operation<LoginResponse> Login(
            System.String email,
            System.String password,
            CancellationToken cancellationToken
        )
        {
            var context = GetContext(HttpMethod.Post, "api/login", Api.Login);

            context.AddParameter("email", email);
            context.AddParameter("password", password);

            return context.GetResponseAsync<JsonResponse<LoginResponse>>(cancellationToken).
                Select(resp => resp.Result.resultObject);
        }

    }
}
// LoginResponse_generated.cs

namespace Data.Response
{
    public class LoginResponse
    {
        public System.Boolean result
        {
            get;
            private set;
        }
    }
}

このようにBaalを用いてデータ定義をクラスにしたり、API定義を自動で実装したり...ということをKAYACではやっています。

また、データ型の継承もBaal定義で行うことが出来ます。

namespace Data.Request
{
  abstract entity WithDeviceId
  {
    DeviceId: !string
  }

  entity LoginRequest
  += WithDeviceId             // ←←DeviceIdがLoginRequestクラスに追加される
  {
    Email: !string;
    Password: !string;
  }
}

生成するファイルのテンプレートをカスタムできるので、プロジェクト毎に必要な形式を用意できます。

実務での利用

  • GitHubを用いている場合は、Baal定義のプルリクエストを作り、サーバー/クライアントエンジニアでレビューする
  • Git Subtreeを用いて、サーバーとクライアント、それぞれのリポジトリに定義を反映する
  • Baal定義に問題がないか、自動テストをまわす
  • Baal定義からのソースコード生成をJenkinsのジョブにする

といったようにプロジェクト毎にBaalのワークフローを拡張して開発速度や精度をあげる取り組みを行っています。

おわりに

明日はアファトのパフォーマンスチューニングについての記事です。

サクサク動くゲームってそれだけで楽しくなりますよね! ヒントは明日の記事にあるかと思いますので、ぜひ御覧ください!!