GS2 States Language 定義拡張

GS2 States Language を CDK で定義するための拡張構文について

GSL は可読性・記述性に優れたステートマシン定義言語ですが、IDEの入力支援や学習コストの観点で優れているとは言い難い側面があります。 各種プログラミング言語を使用して GSL を定義する方法として、CDK を利用することができます。

CDK の詳細

ステートマシンの定義の開始

ステートマシンを定義を開始するには以下の構文を使用します。

    class TestStateMachine extends io.gs2.cdk.stateMachine.integration.StateMachineDefinition {
        public TestStateMachine() {
            // ここにステート定義を記述
        }
    }
    class TestStateMachine extends \Gs2Cdk\StateMachine\Integration\StateMachineDefinition {
        public function __construct() {
            parent::__construct();

            // ここにステート定義を記述
        }
    }
    class TestStateMachine(gs2_cdk.state_machine.StateMachineDefinition):
        def __init__(self):
            # ここにステート定義を記述
    class TestStateMachine extends StateMachineDefinition {
        constructor() {
            super();

            // ここにステート定義を記述
        }
    }
    public class TestStateMachine : Gs2Cdk.Gs2StateMachine.Integration.StateMachineDefinition
    {
        public TestStateMachine()
        {
            // ここにステート定義を記述
        }
    }

ステートマシンの定義

    stateMachine(
            "MainStateMachine", // ステートマシンの名前
            new IVariable[]{
                new IntType("turn")
            } // ステートマシンが受け取るパラメーター
    )
        .entryPoint(task1.getName()) // ステートマシンの最初のステート名
        .task(
            task1,
            task2,
            error // ステートの種類
        );
    $this->stateMachine(
        "MainStateMachine", // ステートマシンの名前
        [
            new IntType("turn"),
        ] // ステートマシンが受け取るパラメーター
    )
        ->entryPoint($task1->getName()) // ステートマシンの最初のステート名
        ->task(
            $task1,
            $task2,
            $error // ステートの種類
        );
    self.state_machine(
        name="MainStateMachine", # ステートマシンの名前
        variables=[
            self.int_type("turn"),
        ], # ステートマシンが受け取るパラメーター
    ).entry_point(
        task_name=task1.name, # ステートマシンの最初のステート名
    ).task(
        task1,
        task2,
        error, # ステートの種類
    )
    this.stateMachine(
        "MainStateMachine", // ステートマシンの名前
        [
            this.intType("turn"),
        ] // ステートマシンが受け取るパラメーター
    )
        .entryPoint(task1.name) // ステートマシンの最初のステート名
        .task(
            task1,
            task2,
            error // ステートの種類
        )
    StateMachine(
        "MainStateMachine",  // ステートマシンの名前
        new IVariable[] {
            IntType("turn")
        } // ステートマシンが受け取るパラメーター
    )
        .EntryPoint(task1.Name) // ステートマシンの最初のステート名
        .Task(
            task1,
            task2,
            error // ステートの種類
        );

ステートの定義

Task

    var task1 = scriptTask(
            "Task1", // ステート名
            new IVariable[0], // ステートが受け取るパラメーターリスト
            """
            result = 'Pass'
            """ // ステートに遷移したときに実行する Lua スクリプト
    )
            .result(
                "Pass",  // スクリプトが発行する結果(Pass)
                new HashMap<>(), // 次のステートに渡すパラメーター
                task2.getName() // Pass が発行された場合に遷移するステート名
            )
            .result(
                "Error",  // スクリプトが発行する結果(Error)
                Map.of(
                    new StringType("reason"), // 次のステートに渡すパラメーターの名前と型
                    "reason" // パラメーターに渡す Lua 変数名
                ),
                error.getName() // Error が発行された場合に遷移するステート名
            );
    $task1 = $this->scriptTask(
        "Task1", // ステート名
        [], // ステートが受け取るパラメーターリスト
        "result = 'Pass'" // ステートに遷移したときに実行する Lua スクリプト
    )
        ->result(
            "Pass",  // スクリプトが発行する結果(Pass)
            [],  // 次のステートに渡すパラメーター
            $task2->getName() // Pass が発行された場合に遷移するステート名
        )
        ->result(
            "Error",  // スクリプトが発行する結果(Error)
            [
                [
                    new StringType('reason'),  // 次のステートに渡すパラメーターの名前と型
                    'reason' // パラメーターに渡す Lua 変数名
                ],
            ],
            $error->getName() // Error が発行された場合に遷移するステート名
        );
    task1 = self.script_task(
        name="Task1", # ステート名
        arguments=[], # ステートが受け取るパラメーターリスト
        script="""
        result = 'Pass'
        """, # ステートに遷移したときに実行する Lua スクリプト
    ).result(
        result_name="Pass", # スクリプトが発行する結果(Pass)
        emit_event_argument_variable_names={}, # 次のステートに渡すパラメーター
        next_task_name=task2.name, # Pass が発行された場合に遷移するステート名
    ).result(
        result_name="Error", # スクリプトが発行する結果(Error)
        emit_event_argument_variable_names={
            self.string_type("reason"):  # 次のステートに渡すパラメーターの名前と型
                "reason", # パラメーターに渡す Lua 変数名
        },
            next_task_name=error.name, # Error が発行された場合に遷移するステート名
    )
    let task1 = this.scriptTask(
        "Task1", // ステート名
        [], // ステートが受け取るパラメーターリスト
        `
        result = 'Pass'
        ` // ステートに遷移したときに実行する Lua スクリプト
    )
        .result(
            "Pass",  // スクリプトが発行する結果(Pass)
            new Map(),  // 次のステートに渡すパラメーター
            task2.getName() // Pass が発行された場合に遷移するステート名
        )
        .result(
            "Error",  // スクリプトが発行する結果(Error)
            new Map([
                [
                    new StringType("reason"),   // 次のステートに渡すパラメーターの名前と型
                    "reason" // パラメーターに渡す Lua 変数名
                ]
            ]),
            error.getName() // Error が発行された場合に遷移するステート名
        );
    var task1 = ScriptTask(
        "Task1", // ステート名
        new IVariable[0], // ステートが受け取るパラメーターリスト
        @"
        result = 'Pass'
        " // ステートに遷移したときに実行する Lua スクリプト
    )
        .Result(
            "Pass",  // スクリプトが発行する結果(Pass)
            new Dictionary<IVariable, string>(),  // 次のステートに渡すパラメーター
            task2.Name // Pass が発行された場合に遷移するステート名
        )
        .Result(
            "Error",  // スクリプトが発行する結果(Error)
            new Dictionary<IVariable, string> {
                {
                    new StringType("reason"),  // 次のステートに渡すパラメーターの名前と型
                    "reason"  // パラメーターに渡す Lua 変数名
                }
            },
            error.Name // Error が発行された場合に遷移するステート名
        );

SubStateMachineTask

    var task3 = subStateMachineTask(
            "ChoiceSkill", // ステート名
            "ChoiceSkill", // 遷移するサブステートマシン名
            new InParam[] {
                this.inParam(
                    this.intType("turn"), // 現在実行中のステートマシンの状態変数名
                    this.intType("turn") // サブステートマシンの最初のステートにパラメーターとして渡す引数名
                )
            },
            new OutParam[] {
                this.outParam(
                    this.intType("choiceSkill"), // サブステートマシンから結果として受け取る状態変数名
                    this.intType("choiceSkill") // ブステートマシンから戻ってきたあとのステートにパラメーターとして渡す引数名
                )
            },
            "InGame" // サブステートマシンから戻ってきたあとで遷移するステート名
    )
    $task3 = $this->subStateMachineTask(
        "ChoiceSkill", // ステート名
        "ChoiceSkill", // 遷移するサブステートマシン名
        [
            $this->inParam(
                $this->intType("turn"), // 現在実行中のステートマシンの状態変数名
                $this->intType("turn") // サブステートマシンの最初のステートにパラメーターとして渡す引数名
            )
        ],
        [
            $this->outParam(
                $this->intType("choiceSkill"),  // サブステートマシンから結果として受け取る状態変数名
                $this->intType("choiceSkill") // ブステートマシンから戻ってきたあとのステートにパラメーターとして渡す引数名
            )
        ],
        "InGame" // サブステートマシンから戻ってきたあとで遷移するステート名
    )
    task3 = self.sub_state_machine_task(
        name='ChoiceSkill', # ステート名
        sub_state_machine_name="ChoiceSkill", # 遷移するサブステートマシン名
        in_params=[
            self.in_param(
                self.int_type("turn"),  # 現在実行中のステートマシンの状態変数名
                self.int_type("turn") # サブステートマシンの最初のステートにパラメーターとして渡す引数名
            ),
        ],
        out_params=[
            self.out_param(
                self.int_type("choiceSkill"), # サブステートマシンから結果として受け取る状態変数名
                self.int_type("choiceSkill") # ブステートマシンから戻ってきたあとのステートにパラメーターとして渡す引数名
            ),
        ],
        next_task_name="InGame", # サブステートマシンから戻ってきたあとで遷移するステート名
    )
    let task3 = this.subStateMachineTask(
        "ChoiceSkill", // ステート名
        "ChoiceSkill", // 遷移するサブステートマシン名
        [
            this.inParam(
                this.intType("turn"),  // 現在実行中のステートマシンの状態変数名
                this.intType("turn") // サブステートマシンの最初のステートにパラメーターとして渡す引数名
            ),
        ],
        [
            this.outParam(
                this.intType("choiceSkill"),  // サブステートマシンから結果として受け取る状態変数名
                this.intType("choiceSkill") // ブステートマシンから戻ってきたあとのステートにパラメーターとして渡す引数名
            ),
        ],
        "InGame" // サブステートマシンから戻ってきたあとで遷移するステート名
    )
    var task3 = SubStateMachineTask(
        "ChoiceSkill", // ステート名
        "ChoiceSkill", // 遷移するサブステートマシン名
        new InParam[] {
            InParam(
                IntType("turn"),  // 現在実行中のステートマシンの状態変数名
                IntType("turn") // サブステートマシンの最初のステートにパラメーターとして渡す引数名
            )
        },
        new OutParam[] {
            OutParam(
                IntType("choiceSkill"),  // サブステートマシンから結果として受け取る状態変数名
                IntType("choiceSkill") // ブステートマシンから戻ってきたあとのステートにパラメーターとして渡す引数名
            )
        },
        "InGame" // サブステートマシンから戻ってきたあとで遷移するステート名
    )

WaitTask

    var task4 = this.waitTask(
            "WaitChoiceSkill" // ステート名
    ).result(
            "ChoiceSkill", // 待ち受けるイベントの名前
            new HashMap<>() {{ // 待ち受けるイベントのパラメーター
                put(
                    stringType("skill"), // 遷移先のステートに渡すパラメーターの型と名前
                    "skill" // イベントで受け取るパラメーターの名前
                );
            }},
            "ChoiceSkill" // このイベントを受け取ったときに遷移するステート名
    ).result(
            "ReLotterySkill", // 待ち受けるイベントの名前
            new HashMap<>(), // 待ち受けるイベントのパラメーター
            "ReLotterySkill" // このイベントを受け取ったときに遷移するステート名
    )
    $task4 = $this->waitTask(
        "WaitChoiceSkill" // ステート名
    )->result(
        "ChoiceSkill", // 待ち受けるイベントの名前
        [ // 待ち受けるイベントのパラメーター
            [
                $this->stringType("skill"),  // 遷移先のステートに渡すパラメーターの型と名前
                "skill" // イベントで受け取るパラメーターの名前
            ]
        ],
        "ChoiceSkill" // このイベントを受け取ったときに遷移するステート名
    )->result(
        "ReLotterySkill", // 待ち受けるイベントの名前
        [], // 待ち受けるイベントのパラメーター
        "ReLotterySkill" // このイベントを受け取ったときに遷移するステート名
    )
    task4 = self.wait_task(
        name="WaitChoiceSkill", # ステート名
    ).result(
        result_name="ChoiceSkill", # 待ち受けるイベントの名前
        emit_event_argument_variable_names={ # 待ち受けるイベントのパラメーター
            self.int_type("skill"): # 遷移先のステートに渡すパラメーターの型と名前
                "skill", # イベントで受け取るパラメーターの名前
        },
        next_task_name="ChoiceSkill", # このイベントを受け取ったときに遷移するステート名
    ).result(
        result_name="ReLotterySkill", # 待ち受けるイベントの名前
        emit_event_argument_variable_names={ # 待ち受けるイベントのパラメーター
        },
        next_task_name="ReLotterySkill", # このイベントを受け取ったときに遷移するステート名
    )
    let task4 = this.waitTask(
        "WaitChoiceSkill" // ステート名
    ).result(
        "ChoiceSkill", // 待ち受けるイベントの名前
        new Map<IVariable, string>() // 待ち受けるイベントのパラメーター
            .set(
                this.stringType("skill"),  // 遷移先のステートに渡すパラメーターの型と名前
                "skill" // イベントで受け取るパラメーターの名前
            ),
        "ChoiceSkill" // このイベントを受け取ったときに遷移するステート名
    ).result(
        "ReLotterySkill", // 待ち受けるイベントの名前
        new Map<IVariable, string>(), // 待ち受けるイベントのパラメーター
        "ReLotterySkill" // このイベントを受け取ったときに遷移するステート名
    )
    var task4 = this.WaitTask(
        "WaitChoiceSkill" // ステート名
    ).Result(
        "ChoiceSkill", // 待ち受けるイベントの名前
        new Dictionary<IVariable, string>{{  // 待ち受けるイベントのパラメーター
            StringType("skill"),  // 遷移先のステートに渡すパラメーターの型と名前
            "skill" // イベントで受け取るパラメーターの名前
        }},
        "ChoiceSkill" // このイベントを受け取ったときに遷移するステート名
    ).Result(
        "ReLotterySkill", // 待ち受けるイベントの名前
        new Dictionary<IVariable, string>(), // 待ち受けるイベントのパラメーター
        "ReLotterySkill" // このイベントを受け取ったときに遷移するステート名
    )

PassTask

    var task2 = passTask(
        "Task2" // ステート名
    );
    $task2 = $this->passTask(
        "Task2" // ステート名
    );
    task2 = self.pass_task(
        name="Task2" # ステート名
    )
    let task2 = this.passTask(
        "Task2" // ステート名
    );
    var task2 = PassTask(
        "Task2" // ステート名
    );

ErrorTask

    var error = errorTask(
        "Error" // ステート名
    );
    $error = $this->errorTask(
        "Error" // ステート名
    );
    error = self.error_task(
        name="Error" # ステート名
    )
    let error = this.errorTask(
        "Error" // ステート名
    );
    var error = ErrorTask(
        "Error" // ステート名
    );

スタックへの登録

    new io.gs2.cdk.stateMachine.model.Namespace(
            this, // Stack オブジェクト
            "state-machine-0001" // GS2-StateMachine のネームスペース名
    ).stateMachine(
            new io.gs2.cdk.script.model.Namespace(
                this, // Stack オブジェクト
                "script-0001" // GS2-Script のネームスペース名
            ),
            new TesStateMachine() // StateMachineDefinition オブジェクト
    );
    (new \Gs2Cdk\StateMachine\Model\Namespace_(
        $this, // Stack オブジェクト
        "state-machine-0001" // GS2-StateMachine のネームスペース名
    ))->stateMachine(
        new \Gs2Cdk\Script\Model\Namespace_(
            $this, // Stack オブジェクト
            "script-0001" // GS2-Script のネームスペース名
        ),
        new TestStateMachine() // StateMachineDefinition オブジェクト
    );
    gs2_cdk.state_machine.Namespace(
        self, # Stack オブジェクト
        name='state-machine-0001', # GS2-StateMachine のネームスペース名
    ).state_machine(
        script_namespace=gs2_cdk.script.Namespace(
            self, # Stack オブジェクト
            name='script-0001', # GS2-Script のネームスペース名
        ),
        definition=TestStateMachine(), # StateMachineDefinition オブジェクト
    )
    new StateMachineNamespace(
        this, // Stack オブジェクト
        "state-machine-0001" // GS2-StateMachine のネームスペース名
    ).stateMachine(
        new ScriptNamespace(
            this, // Stack オブジェクト
            "script-0001" // GS2-Script のネームスペース名
        ),
        new TestStateMachine() // StateMachineDefinition オブジェクト
    );
    new Gs2Cdk.Gs2StateMachine.Model.Namespace(
        this,  // Stack オブジェクト
        "state-machine-0001" // GS2-StateMachine のネームスペース名
    ).StateMachine(
        Gs2Cdk.Gs2Script.Model.Namespace(
            this, // Stack オブジェクト
            "script-0001" // GS2-Script のネームスペース名
        ),
        new TestStateMachine() // StateMachineDefinition オブジェクト
    );

サンプル全文

    class TestStateMachine extends StateMachineDefinition {
        public TestStateMachine() {
            ErrorTask error = errorTask("Error");

            PassTask task2 = passTask("Task2");

            Task task1 = scriptTask(
                    "Task1",
                    new IVariable[0],
                    """
                    result = 'Pass'
                    """
            )
                    .result("Pass", new HashMap<>(), task2.getName())
                    .result("Error", Map.of(new StringType("reason"), "reason"), error.getName());

            stateMachine(
                    "MainStateMachine",
                    new IVariable[]{new IntType("turn")}
            )
                    .entryPoint(task1.getName())
                    .task(task1, task2, error);
        }
    }

    class TestStateMachineStack extends Stack {
        public TestStateMachineStack() {
            super();

            new io.gs2.cdk.stateMachine.model.Namespace(this, "state-machine-0001")
                .stateMachine(
                    new io.gs2.cdk.script.model.Namespace(this, "script-0001"),
                    new TesStateMachine()
                );
        }
    }
    class TestStateMachine extends StateMachineDefinition {
        public function __construct() {
            parent::__construct();

            $error = $this->errorTask("Error");

            $task2 = $this->passTask("Task2");

            $task1 = $this->scriptTask(
                "Task1",
                [],
                "result = 'Pass'"
            )
                ->result("Pass", [], $task2->getName())
                ->result("Error", [[new StringType('reason'), 'reason']], $error->getName());

            $this->stateMachine(
                "MainStateMachine",
                [new IntType("turn")]
            )
                ->entryPoint($task1->getName())
                ->task($task1, $task2, $error);
        }
    }

    class TestStateMachineStack extends Stack {
        public function __construct() {
            parent::__construct();

            (new \Gs2Cdk\StateMachine\Model\Namespace_($this, "state-machine-0001"))
                ->stateMachine(
                    new \Gs2Cdk\Script\Model\Namespace_($this, "script-0001"),
                    new TestStateMachine()
                );
        }
    }
    class TestStateMachine(gs2_cdk.state_machine.StateMachineDefinition):

        def __init__(self):

            task2 = self.pass_task("Task2")
            error = self.error_task("Error")

            task1 = self.script_task(
                name="Task1",
                arguments=[],
                script="""
                result = 'Pass'
                """,
            ).result(
                result_name="Pass",
                emit_event_argument_variable_names={},
                next_task_name=task2.name,
            ).result(
                result_name="Error",
                emit_event_argument_variable_names={
                    self.string_type("reason"): "reason",
                },
                next_task_name=error.name,
            )

            self.state_machine(
                name="MainStateMachine",
                variables=[
                    self.int_type("turn"),
                ],
            ).entry_point(
                task_name=task1.name,
            ).task(
                task1,
                task2,
                error,
            )


    class TestStateMachineStack(gs2_cdk.Stack):

        def __init__(self):
            super().__init__()

            gs2_cdk.state_machine.Namespace(
                self,
                name='state-machine-0001',
            ).state_machine(
                script_namespace=gs2_cdk.script.Namespace(
                    self,
                    name='script-0001',
                ),
                definition=TestStateMachine(),
            )
    class TestStateMachine extends StateMachineDefinition {
        constructor() {
            super();

            let error = this.errorTask("Error");
            let task2 = this.passTask("Task2");
            let task1 = this.scriptTask(
                "Task1",
                [],
                `
                result = 'Pass'
                `
            )
                .result("Pass", new Map(), task2.getName())
                .result("Error", new Map([[new StringType("reason"), "reason"]]), error.getName());

            this.stateMachine(
                "MainStateMachine",
                [new IntType("turn")]
            )
                .entryPoint(task1.getName())
                .task(task1, task2, error);
        }
    }

    class TestStateMachineStack extends Stack {
        constructor() {
            super();

            new StateMachineNamespace(
                this,
                "state-machine-0001"
            ).stateMachine(
                new ScriptNamespace(
                    this,
                    "script-0001"
                ),
                TestStateMachine()
            );
        }
    }
    public class TestStateMachine : StateMachineDefinition
    {
        public TestStateMachine()
        {
            var error = ErrorTask("Error");
            var task2 = PassTask("Task2");

            Task task1 = ScriptTask(
                    "Task1",
                    new IVariable[0],
                    @"
                    result = 'Pass'
                    "
            )
                .Result("Pass", new Dictionary<IVariable, string>(), task2.Name)
                .Result("Error", new Dictionary<IVariable, string> { { new StringType("reason"), "reason" } }, error.Name);

            StateMachine(
                    "MainStateMachine",
                    new IVariable[] { IntType("turn") }
            )
                .EntryPoint(task1.Name)
                .Task(task1, task2, error);
        }
    }

    public class TestStateMachineStack : Stack
    {
        public TestStateMachineStack()
        {
            new Gs2Cdk.Gs2StateMachine.Model.Namespace(
                    this,
                    "state-machine-0001"
            )
                .StateMachine(
                    new Gs2Cdk.Gs2Script.Model.Namespace(
                        this,
                        "script-0001"
                    ),
                    new TestStateMachine()
                );
        }
    }