【目次】
通信定義コマンド(namespace)
定数定義コマンド(assign)
構造体定義コマンド(structure)
関数群定義コマンド(interface)
・関数定義コマンド(function)
・引数指定コマンド(argument)
・戻り関数引数指定コマンド(retfunc)
RPCクラス定義コマンド(unit, inheritance)
ソースファイル吐き出しコマンド(generate)
通信定義コマンド(namespace)▲
■ RPCファイルの定義
RPC通信の定義は、namespace ~ end までの記述で1つの纏まりとなります。
namespace <ネームスペース名> do
定数定義コマンド
構造体定義コマンド
関数群定義コマンド
RPCクラス定義コマンド
ソースファイル吐き出しコマンド
end
namespace ~ end の間には、以下のコマンドを挿入することが出来ます。
・定数定義コマンド(assign)
・構造体定義コマンド(structure)
・関数群定義コマンド(interface)
・RPCクラス定義コマンド(unit, inheritance)
・ソースファイル吐き出しコマンド(generate)
定数定義コマンド(assign)▲
クライアント⇔サーバ間、あるいはサーバ⇔サーバ間で共有した定数を用いる場合、
RPC定義ファイル内に定数を定義することができます。(これは enum と同じような列挙型定数として扱われます。)
【書式】
assign <タグ名> do
id( <定数名> , <定数値> )
end
【説明】
assign ~ end 内に id コマンドを記述していくことで、定数を定義できます。
id コマンドの第一引数には定数名を、第二引数にはその定数値を記述することで、
RPC通信間での共有定数を定義できます。
なお、このid コマンドは assign ~ end 内に複数定義することができます。
【例】
assign( :BattleStatus ) do
id( :ENTERABLE, 0 ) # 入室中
id( :BATTLING, 1 ) # バトル中
id( :WAITING, 2 ) # 待機中
id( :RESERVED, 3 ) # 予約済み
end
という定義をコンバートすると
enum BattleStatus {
ENTERABLE = 0, # 入室中
BATTLING = 1, # バトル中
WAITING = 2, # 待機中
RESERVED = 3, # 予約済み
};
という形で列挙型定数が出力されます。
構造体定義コマンド(structure)▲
クライアント⇔サーバ間、あるいはサーバ⇔サーバ間で共有した構造体を用いる場合、
RPC定義ファイル内にその構造体を定義することができます。( struct と同じような列挙型定数として扱われます。)
【書式】
structure <タグ名> do
member( <変数名> , <変数型> )
end
【説明】
structure ~ end 内に member コマンドを記述していくことで、構造体メンバを定義できます。
member コマンドの第一引数には変数名を、第二引数にはその変数型を記述することで、
RPC通信間での共有構造体を定義できます。
なお、このmember コマンドは assign ~ end 内に複数定義することができます。
【例】
structure( :BattleStatusInfo ) do
member( :entered_num, :'unsigned char' )
member( :max_enter_num, :'unsigned char' )
member( :status, :'unsigned char' )
end
という定義をコンバートすると
struct BattleStatusInfo {
unsigned char entered_num;
unsigned char max_enter_num;
unsigned char status;
};
という形で構造体定義が出力されます。
関数群定義コマンド(interface)▲
RPC定義ファイル内における送受信制御の実体となるのが関数です。
その関数群を定義するためのコマンドが interface です。
【書式】
interface <インターフェース名> do
関数定義コマンド
end
【説明】
interface コマンド内に function コマンドを記述していくことにより、
実際に送受信するものをあらわす関数を記述できます。
ここに記述された関数群が、関数インターフェースの一群として提供されることになります。
後述する RPCクラス定義コマンド(unit) を使用し、この関数群をunit指定のクラスへ継承させる際に
「サーバとしての役割」を継承させるのか、「クライアントとしての役割」を継承させるのか、
または両方とも継承させるのか、を選択させることになります。
インターフェースを複数作成することで、より細分化された役割(サーバ機能の分散化など)を与えることができます。
なお、interface ~ end の間には 関数定義コマンド(function) コマンドを挿入できます。
関数定義コマンド(function)▲
送信・受信関数を定義するコマンドが function です。
【書式】
function( <:s2c または :c2s のどちらか>, <関数名> )do
引数定義コマンド
戻り関数引数定義コマンド
end
【説明】
function コマンドの第一引数には :s2c または :c2s のどちらかのみが指定できます。
:s2cは、この関数がサーバからクライアント方向への関数であること、
:c2sは、この関数がクライアントからサーバ方向への関数であることを示します。
第二引数は関数に付けたい名前を指定します。
なお、function ~ end の間には、以下の2種類のコマンドを挿入できます。(挿入しない場合には引数なしになります)
・引数指定コマンド(argument)
・戻り関数引数指定コマンド(retfunc)
引数指定コマンド(argument)▲
function で設定した関数にどのような引数を指定するかを定義するコマンドが argument です。
【書式】
function( <:s2c または :c2s のどちらか>, <関数名> ) do
argument( <引数名> , <引数型> )
end
【説明】
argument コマンドの第一引数には引数名を、第二引数には引数型を指定することで
引数の指定ができます。
なお、function 内に argument を複数並べることで引数を複数設定できます。
注意点として、同じfunction内では、argumentの第一引数同士の名前は被ってはいけません。
下記の例で解る通り、第一引数をそのまま変数名としているので、コンパイルが出来なくなってしまいます。
【例1】
function( :c2s, :Echo ) do
argument( :arg1, :'char' )
argument( :arg2, :'unsinged int' )
end
という関数定義をコンバートすると、クライアント側には
unsigned int Send_Echo( char arg1, unsigned int arg2 );
という形で送信関数が出力されます。
このときサーバ側には、
virtual void Recv_Echo( char arg1, unsigned int arg2 ) = 0;
という、受信用関数の純粋仮想インターフェースが作成され、
中身はユーザーが継承して作成するのが必須となっています。
【例2】
function( :s2c, :Echo ) do
argument( :arg1, :'char' )
argument( :arg2, :'unsinged int' )
end
という関数定義をコンバートすると、サーバ側には
unsigned int Send_Echo( char arg1, unsigned int arg2 );
クライアント側には、
virtual void Recv_Echo( char arg1, unsigned int arg2 ) = 0;
というふうに関数が出力されます。
戻り関数引数指定コマンド(retfunc)▲
送信した先の function から「送信し返すべき」関数を定義したい場合、retfuncを用います。
【書式】
function( <:s2c または :c2s のどちらか>, <関数名> ) do
retfunc( <引数名> , <引数型> )
end
【説明】
retfunc に書かれた内容が、送信した先の function から送信し返すべき関数の引数となります。
retfunc コマンドの第一引数には引数名を、第二引数には引数型を指定することで
引数の指定ができます。
なお、function 内に retfunc を複数並べることで引数を複数設定できます。
【例】
function( :c2s, :Echo ) do
argument( :arg1, :'char' )
argument( :arg2, :'unsinged int' )
retfunc( :ret1, :'char' )
retfunc( :ret2, :'short' )
end
という関数定義をコンバートすると、
クライアント側 : unsigned int Send_Echo( char arg1, unsigned int arg2 );
サーバ側 : unsigned int Send_EchoResult( char ret1, short ret2 );
という形で送信関数が出力されます。
と同時に、
クライアント側 : virtual void Recv_EchoResult( char ret1, short ret2 ) = 0;
サーバ側 : virtual void Recv_Echo( char arg1, unsigned int arg2 ) = 0;
という、受信用関数の純粋仮想インターフェースが作成され、
Send_Echo で送信されたデータを Recv_Echo で受信した際に、Send_EchoResult で送り返す、といった
使用法になります。
RPCクラス定義コマンド(unit, inheritance)▲
上述で定義した interface をベースにした、クラスの定義とその継承方法を指定します。
【書式】
unit( <名前>, <ラベル名> ) do
inheritance( <インターフェース名> , <:client または :server または :bidir> )
end
【説明】
unit の第一引数は、スタブコードとして出力するクラスの名前となります。
unit の第二引数は、後述の ソースファイル吐き出しコマンド(generate) が、関係のあるクラスを収集するための
識別子として使用します。
一方、inheritance の第一引数は、interface で指定したインタフェースの名前になります。
inheritance の第二引数には、:server , :client, :bidir のいずれかを指定し、その継承方法を指定します。
・serverを指定した場合は、このinterfaceはサーバ側としての機能を継承します。
・clientを指定した場合は、このinterfaceはクライアント側としての機能を継承します。
・bidirを指定した場合は、このinterfaceはサーバ・クライアント双方の機能を継承します。
なお、1つのクラスで多重継承する場合には、unit の中に複数の inheritance を含めるようにします。
【例】
interface(:A) do
function( :c2s, :AA ) do
argument( :aaa, :'unsigned int' )
end
end
interface(:B) do
function( :s2c, :BB ) do
argument( :bbb, :'unsigned char' )
end
end
unit( :ClassA, :ClassA )
inheritance( :A, server )
inheritance( :B, client )
end
unit( :ClassB, :ClassB )
inheritance( :B, server )
inheritance( :A, client )
end
という定義をコンバートすると、以下の2つのクラスが生成されます。
class ClassA
{
virtual void Recv_AA( unsigned int aaa ) = 0; // ユーザー定義
void Send_BB( unsigned char bbb ); // 実装済み
}
class ClassB
{
void Send_AA( unsigned int aaa ); // 実装済み
virtual void Recv_BB( unsigned char bbb ) = 0; // ユーザー定義
}
ソースファイル吐き出しコマンド(generate)▲
上記で設定した unit をスタブコードに吐き出すためのコマンドです。
【書式】
generate( Hash(オプション定義) )
【説明】
ここまで記述した内容を CPP(HPP)・CS に吐き出します。
ここで吐き出されたクラスを継承して、ユーザーは RPC の機能を使用します。
引数には、吐き出し位置・関連するunitの選択などを記述したオプション複数を連想配列で記述できます。
【例】
generate( { :Type => :Battle, :Folder=>"Battle", :Usage => :Default } )
:Type には、unit コマンドの第二引数と一致するものを代入し、それを1つのクラス単位として出力します。
例えば上述の場合、":Battle"を第二引数にもつ unit コマンドを選別し、クラスを生成してソースに吐き出します。
:Folder には、コマンドラインで指定した出力ディレクトリ内に更に子フォルダを指定したい場合に使用します。
指定フォルダが無ければ、そのフォルダを新規に作成します。
:Usage には、:CS を指定した場合、その出力ファイルはC#ソースファイルになります。
それ以外はすべて(指定しない場合を含め)C++ソースファイルとして吐き出されます。