Amazon GameSparks(preview)のMessage機能のデータ型がどのようにC#コードで表現されるか試してみた
前回の記事では、Amazon GameSparksのMessage機能を使ってゲームクライアントとバックエンドサーバ間の双方向通信を実現しました。その際、GameSparksが生成したC#コードをUnityに組み込んで使用しました。このC#コードには、GameSparks上で定義づけたMessageのデータ型を元にしたDTOクラスなどが書かれていました。
今回は、GameSparks上で定義したデータ型がどのようなC#コードとして出力されるのかを具体的に見ていきたいと思います。
例として使用するデータ構造
今回は、位置情報ゲームのプレイヤーデータを扱うことを想定してMessage機能を使っていきます。
プレイヤーデータの構造は以下のようなものとします。
名前 | 用途 | 形式 |
---|---|---|
name | プレイヤー名 | 文字列 |
age | 年齢(任意入力) | 整数 |
level | 現在のレベル | 整数 |
isPro | 有料課金プレイヤー判定 | yesかnoの二値 |
lat | 現在の緯度 | 実数 |
lon | 現在の経度 | 実数 |
moveType | 移動方式 | 徒歩、自転車、車のうちの1つ |
GameSparksでのデータ型の作成
上記のデータ構造を元に、実際にGameSparks上でデータ型の設定をしていきます。
GameSparksでは、プリミティブ型として以下のものが使用できます。
- String
- Integer
- Boolean
- Decimal
- Any
また、以下のような特殊なデータ型も設定することができます。
- List
- Map
- Enum
- Structure
- Variant
この記事では、これらのデータ型全てを使用する形で設定を進めていきます。
GameSparksでは、Manage Game-defined shapesという画面でオリジナルのデータ型を登録できます。
これは、プログラミングであらかじめ独自の型定義をするのと同じような機能であり、データ型の登録をしておくことで、それを各Messageのデータ構造を設定する画面で呼び出すことができます。
この機能を使うことで、RequestsやNotifaicationsで同じデータ型を使い回すなどといったことが可能です。また、データ構造の変更が必要になった時、登録していたデータ型を修正するだけで全てのMessageにその内容が自動的に反映されます。
生成されたC#コードを見る
GameSparksでの設定とそれを元に生成されたC#コードを見比べていきましょう。
Structure
GameSparksでの設定
Structure型のフィールドとして、以下の項目を設定
名前 | データ型 |
---|---|
name | String |
age | Integer (Not required) |
level | Integer |
isPro | Boolean |
lat | Decimal |
lon | Decimal |
moveType | MoveType |
other | Any |
C#コード
public sealed class Player { [JsonProperty] public string name { get; } [JsonProperty] public int? age { get; } [JsonProperty] public int level { get; } [JsonProperty] public bool isPro { get; } [JsonProperty] public Decimal lat { get; } [JsonProperty] public Decimal lon { get; } [JsonProperty] public MoveType moveType { get; } [JsonProperty] public dynamic other { get; } public Player( string name, int? age = null, int level, bool isPro, Decimal lat, Decimal lon, MoveType moveType, dynamic other) { this.name = name; this.age = age; this.level = level; this.isPro = isPro; this.lat = lat; this.lon = lon; this.moveType = moveType; this.other = other; } public override string ToString() { return string.Concat( $"{nameof(name)}: { name }", Environment.NewLine, $"{nameof(age)}: { age }"); $"{nameof(level)}: { level }", Environment.NewLine, $"{nameof(isPro)}: { isPro }", Environment.NewLine, $"{nameof(lat)}: { lat }", Environment.NewLine, $"{nameof(lon)}: { lon }", Environment.NewLine, $"{nameof(moveType)}: { moveType }", Environment.NewLine, $"{nameof(other)}: { other }", Environment.NewLine, } }
GameSparks上では、構造体としてPlayerを定義した形です。このようにGame-defined shapesとしてデータ型を登録することで、各Messageに流用できます。
一方で、C#コードではGameSparksの構造体の設定を元に典型的なDTOクラスが作成されています。
次に、この構造体の各フィールドについて細かく見ていきましょう。
一般的な型
GameSparksでの設定
名前 | データ型 |
---|---|
name | String |
age | Integer (Not required) |
level | Integer |
isPro | Boolean |
lat | Decimal |
lon | Decimal |
C#コード
string name int? age int level bool isPro Decimal lat Decimal lon
文字列、整数、ブール、小数とGameSparks上での設定がそのままC#コードに反映されている形です。
任意項目として設定したageだけは、C#でnull許容を意味する?
が付いています。
Any
GameSparksでの設定
名前 | データ型 |
---|---|
other | Any |
C#コード
public dynamic other
otherというフィールドは元々のデータ構造にはありませんでしたが、Anyの解説のために付け足しました。
AnyについてGameSparks上のドキュメントで解説している箇所は見当たりませんが、様々な言語に存在するAny型と同じく動的な型という意味で解釈して良いようです。
出力されたコードのように、C#では動的な型はdynamic
型として表現します。
型による保護が無くなるため、遅延評価など特殊な用途以外での使用は推奨されません。
Enum
GameSparksでの設定
名前 | データ型 | 値 |
---|---|---|
MoveType | Enum | walk, bicycle, car |
C#コード
public enum MoveType { walk, bicycle, car }
GameSparks上で値の種類を登録することで、それが自動的にC#コードのEnumに反映されます。
List
Player StructureをListとして扱うようにデータ型を登録することもできます。
GameSparksでの設定
名前 | データ型 | 値の型 |
---|---|---|
PlayerList | List | Player |
C#コード
List<Player> playerList
複数のPlayerデータをListにまとめることで、Playerの一覧を表示したり集計したりという用途に使えそうです。
Map
ListだけでなくMapとして扱うこともできます。
GameSparksでの設定
名前 | Keyの型 | データ型 | 値の型 |
---|---|---|---|
PlayerMap | String(固定) | Map | Player |
C#コード
Dictionary<string, Player> playerMap
C#ではMapはDictionaryと表現します。
また、Keyの型はGameSpark上でStringに固定されているため、他の型を設定することはできません。
任意の文字列KeyとPlayerデータを関連付けて保持したい場合に便利でしょう。
Variant
Anyと同じく元々のデータ構造から外れますが、解説のためGameSparks上に設定しました。
Variantは少し特殊なデータ型です。公式の解説では、C言語のUnion型(共用体)に近いものと書かれています。
A variant data type. This shape is similar in nature to a C union data type.
GameSparksでの設定
Variant型のフィールドとして、以下の項目を設定
名前 | データ型 |
---|---|
aaa | String |
bbb | Integer |
C#コード
public sealed class test { [JsonProperty] public string aaa { get; } [JsonProperty] public int bbb { get; } private test( string aaa = null, int bbb = null) { this.aaa = aaa; this.bbb = bbb; } public static test Fromaaa(string aaa) { return new test(aaa: aaa); } public static test Frombbb(int bbb) { return new test(bbb: bbb); } public override string ToString() { return string.Concat( $"{nameof(aaa)}: { aaa }", Environment.NewLine, $"{nameof(bbb)}: { bbb }"); } }
コンストラクタがprivate化されており、フィールドのどれか1つだけに値をセットしてインスタンス生成をすることを矯正されています。
こちらについては、私の方ではUnityでどのような用途に使用できるのか分かりませんでしたが、一般的にunion型は1つのメモリ領域を複数の型が共有するために使用するようです。
まとめ
GameSparks上で設定できる全てのデータ型について、C#コードを生成した際にどのようなコードになるかを見てきました。
基本的に、GameSparksでの設定内容がそのままC#コードを通してUnityに反映されるようになっています。
こういった情報を把握しておくことで、Unityでどのようなデータを取り扱うことになるか理解することができるでしょう。