GS2-News

おしらせ配信機能

ゲーム内のお知らせをHTML形式で配信するための仕組みです。 配信するHTMLコンテンツは hugo(https://gohugo.io/) で生成する必要があります。

hugo

hugo は静的 Webページを生成するためのジェネレーターです。

ページのレイアウトやデザインを決定するためのテンプレートと、マークダウン形式で記述した記事データをビルドすることでHTMLファイルを生成します。 hugo の利用方法については、hugoの公式サイト または 各種解説サイトをご確認ください。

GS2 では最小限の hugo テンプレートと記事データのサンプルを GitHub で公開しています。

https://github.com/gs2io/gs2-news-sample

イベントと連動する記事

GS2-News では、GS2-Schedule で管理するイベントと連動する記事データを管理できます。

記事データのマークダウンファイルの Front Matter に以下の記述をすることで、連携を有効化できます。

x_gs2_scheduleEventId: ${GS2-Schedule のイベントGRN}

また、GS2-Schedule の Event ID には以下のプレースホルダが利用できます。

プレースホルダ置換される値
{region}リージョン名
{ownerId}GS2のオーナーID

記述例は以下です。

x_gs2_scheduleEventId: grn:gs2:{region}:{ownerId}:schedule:schedule-0001:event:event-0001

記事データのビルド

GS2-News で配信する記事データはzip で圧縮した hugo のテンプレートと記事ファイルをアップロードすることで更新します。 その後、GS2-News は記事データをビルドして配信します。

記事データ内に x_gs2_scheduleEventId の記述がある場合は、各記事が公開状態・非公開状態 のそれぞれのバージョンを事前にビルドしてWebサーバーに配置します。

その後、プレイヤーが記事データにアクセスしようとした時に現在のイベントの開催状況から最も適切なコンテンツのURLをプレイヤーに応答します。

記事データのアクセス権

記事データは事前に全てのパターンをビルドして配信すると説明しました。 悪意のあるプレイヤーがURLを特定して、本来ならまだ配信してはならないコンテンツにアクセスできてはいけません。

この問題を避けるために、GS2-News は Cookie を用いたアクセス制限を実装しています。 現在有効なコンテンツのURLを取得するとともに、そのURLにアクセスするための Cookie 情報を配信します。 ブラウザにその Cookie を設定した上でコンテンツURLにアクセスすることで、コンテンツのダウンロードが可能となります。

取得した Cookie は有効期限が設定されており、1時間が経過するとその Cookie ではコンテンツにアクセスできなくなります。

Zip形式で Webコンテンツをダウンロード

GS2-News がホスティング した HTML に WebView を使用してアクセスする方法だけでなく、GS2-News がビルドした HTMLファイル全体を zip 形式でダウンロードすることも可能です。

こちらの方法を利用すれば、zip でダウンロードした HTML コンテンツをローカルストレージに展開し、それをブラウザで表示することでより快適にコンテンツを閲覧できるようになるとともに、同じコンテンツを何度もダウンロードしなくて良くなります。

zip ファイルをダウンロードしなおすべきかを判断するために、GS2-News はテンプレートファイルのハッシュ値と、GS2-Scheduleに基づいて公開状態になっているコンテンツのハッシュ値を取得できるようにしています。 これらの値を使用することで、zip ファイルを再ダウンロードするべきか判断することが可能となります。

実装例

コンテンツURLを取得

    var result = await gs2.News.Namespace(
        namespaceName: "namespace-0001"
    ).Me(
        gameSession: GameSession
    ).News(
    ).GetContentsUrlAsync(
    );

    List<EzSetCookieRequestEntry> cookies = new List<EzSetCookieRequestEntry>();
    var items = result.ToList();
    foreach (var item in items)
    {
        var entry = await item.ModelAsync();
        cookies.Add(entry);
    }
    var browserUrl = domain.BrowserUrl;
    var zipUrl = domain.ZipUrl;
    const auto Domain = Gs2->News->Namespace(
        "namespace-0001" // namespaceName
    )->Me(
        AccessToken
    )->News(
    );
    const auto Future = Domain->GetContentsUrl(
    );
    Future->StartSynchronousTask();
    if (Future->GetTask().IsError()) return false;
    TArray<EzSetCookieRequestEntryPtr> Cookies;
	const auto It = Future->GetTask().Result();
	foreach (auto Item in It)
	{
        const auto Future2 = Item.Model();
        Future2->StartSynchronousTask();
        if (Future2->GetTask().IsError()) return false;
        Cookies.Add(Future->GetTask().Result());
	}
    const auto BrowserUrl = Domain->BrowserUrl;
    const auto ZipUrl = Domain->ZipUrl;

記事データの一覧を取得

このAPIで残高の消費処理を行うことは推奨していません。 GS2-Showcase といったサービスを通して課金通貨の消費を行う代わりに 何らかの処理を実行することを推奨します。

    var domain = gs2.News.Namespace(
        namespaceName: "namespace-0001"
    ).Me(
        gameSession: GameSession
    );
    var items = await domain.NewsesAsync(
    ).ToListAsync();
    var templateHash = domain.TemplateHash;
    var contentHash = domain.ContentHash;
    const auto Domain = Gs2->News->Namespace(
        "namespace-0001" // namespaceName
    )->Me(
        AccessToken
    );
    const auto It = Domain->Newses(
    );
    TArray<Gs2::UE5::News::Model::FEzNewsPtr> Result;
    for (auto Item : *It)
    {
        if (Item.IsError())
        {
            return false;
        }
        Result.Add(Item.Current());
    }

詳細なリファレンス