GS2-Exchange

ゲーム内リソースの交換機能

GS2 が提供するマイクロサービスの中でも特に重用される機能です。 あらゆるマイクロサービスのリソースを、全く異なるマイクロサービスのリソースに変換する役割を担います。

ゲームの仕様にはリソースの交換に関するものが多数存在し、その度に GS2-Exchange の出番が発生します。

リソース交換の例

強化素材の変換

GS2-Inventory で管理する ★1 の強化素材 10個を、同じく GS2-Inventory で管理する ★2 の強化素材 1個と交換

6時間に1回アイテムを入手できる

GS2-Stamina で管理する6時間で1回復するスタミナ1を、GS2-Inventory で管理するアイテムと交換

アイテムを売却

GS2-Inventory で管理するアイテムを、同じく GS2-Inventory で管理するゲーム内通貨と交換

交換の種類

GS2-Exchange はマスターデータで定められた交換レートで直ちに交換できるダイレクト交換と 交換を実行した後、現実時間で一定時間経過したのちに交換結果を得られる非同期交換 購入する度にコストが上昇するコスト情報型交換の3つのモードが存在します。

非同期交換を使用した場合、交換を実行したタイミングで対価は消費され、 報酬を得る代わりに Await オブジェクトが作成されます。 Await オブジェクトの作成時刻からマスターデータで定義された交換待機時間が経過すると報酬を受け取ることができます。

非同期交換の例

拠点の強化

街づくり系のゲームで、拠点を成長させるために資源を消費した後 8時間経過することで実際に拠点の経験値を加算する

遠征

パーティを編成し、冒険にでたのち3時間後に冒険の結果として報酬を受け取れる

非同期交換のスキップ

非同期交換の時間経過待ちを、更なる対価を支払うことでスキップできるようにすることができます。 一般的にこのような仕様を入れる場合は、マネタイズのための機能として実装されることが多いですが、 現金で購入した GS2-Money で管理するゲーム内通貨を消費することで、待ち時間を時短可能な仕様を実現できます。

コスト上昇型交換の例

強化(インフレゲーム)

強化する度に強化に必要なゴールドの消費量が増加する

スタミナ回復コストが増加

スタミナを購入する度に購入するために必要な課金通貨の消費量が上昇する。 購入回数は毎日リセットされる

コスト上昇量の計算

コストの上昇量のは3つのモードが存在し、IncrementalRateModel で指定します。

linear

baseValue + (coefficientValue * 交換回数)

baseValue = 100, coefficientValue = 50

交換回数コスト
0100
1150
2200
3250
4300

power

coefficientValue * (交換回数 + 1) ^ 2

coefficientValue = 50

交換回数コスト
050
1200
2450
3800
41250

gs2_script

GS2-Script の実行結果をもとに算出します。 複雑な条件を元にコストを計算したい場合に使用できます。

currentExchangeCount = args.currentExchangeCount
quantity = quantity

cost = 100
for i = 1 , quantity do
	cost = cost + (i + currentExchangeCount - 1) * 50
end

result = {
    cost=cost
}
交換回数コスト
0100
1150
2200
3250
4300

実装例

交換の実行

    var result = await gs2.Exchange.Namespace(
        namespaceName: "namespace-0001"
    ).Me(
        gameSession: GameSession
    ).Exchange(
    ).ExchangeAsync(
        rateName: "rate-0001",
        count: 1,
    );
    const auto Domain = Gs2->Exchange->Namespace(
        "namespace-0001" // namespaceName
    )->Me(
        AccessToken
    )->Exchange(
    );
    const auto Future = Domain->Exchange(
        "rate-0001",
        1,
        nullptr // config
    );
    Future->StartSynchronousTask();
    if (Future->GetTask().IsError()) return false;

Await の一覧取得

    var items = await gs2.Exchange.Namespace(
        namespaceName: "namespace-0001"
    ).Me(
        gameSession: GameSession
    ).AwaitsAsync(
    ).ToListAsync();
    const auto Domain = Gs2->Exchange->Namespace(
        "namespace-0001" // namespaceName
    )->Me(
        AccessToken
    );
    const auto It = Domain->Awaits( // rateName
    );
    TArray<Gs2::UE5::Exchange::Model::FEzAwaitPtr> Result;
    for (auto Item : *It)
    {
        if (Item.IsError())
        {
            return false;
        }
        Result.Add(Item.Current());
    }

Await 待機時間経過後の報酬受け取り

    var result = await gs2.Exchange.Namespace(
        namespaceName: "namespace-0001"
    ).Me(
        gameSession: GameSession
    ).Await(
        rateName: "material_n_to_r",
        awaitName: "await-0001"
    ).AcquireAsync(
    );
    const auto Domain = Gs2->Exchange->Namespace(
        "namespace-0001" // namespaceName
    )->Me(
        AccessToken
    )->Await(
        "await-0001", // awaitName
        "material_n_to_r" // rateName
    );
    const auto Future = Domain->Acquire(
    );
    Future->StartSynchronousTask();
    if (Future->GetTask().IsError()) return false;

Await 待機時間のスキップ

    var result = await gs2.Exchange.Namespace(
        namespaceName: "namespace-0001"
    ).Me(
        gameSession: GameSession
    ).Await(
        rateName: "material_n_to_r",
        awaitName: "await-0001"
    ).SkipAsync(
    );
    const auto Domain = Gs2->Exchange->Namespace(
        "namespace-0001" // namespaceName
    )->Me(
        AccessToken
    )->Await(
        "await-0001", // awaitName
        "material_n_to_r" // rateName
    );
    const auto Future = Domain->Skip(
    );
    Future->StartSynchronousTask();
    if (Future->GetTask().IsError()) return false;

コスト上昇型交換の実行

    var result = await gs2.Exchange.Namespace(
        namespaceName: "namespace-0001"
    ).Me(
        gameSession: GameSession
    ).Exchange(
    ).IncrementalExchangeAsync(
        rateName: "rate-0001",
        count: 1,
    );
    const auto Domain = Gs2->Exchange->Namespace(
        "namespace-0001" // namespaceName
    )->Me(
        AccessToken
    )->Exchange(
    );
    const auto Future = Domain->IncrementalExchange(
        "rate-0001",
        1,
        nullptr // config
    );
    Future->StartSynchronousTask();
    if (Future->GetTask().IsError()) return false;

詳細なリファレンス