GS2 Blog

Game Server Services(https://gs2.io/) の最新情報をお届けします

新しいランキングシステムを公開しました

はじめに

これまでも GS2-Ranking というランキングの仕組みを提供していました。
サービスの初期に設計したサービスということもあり、その後の機能拡張で最も歪みが生じていたマイクロサービスでもありました。

利用者からのフィードバックの反映に技術的負債の返済も兼ねて、新しくランキングシステムを再設計することにしました。

ご安心いただきたいのは GS2-Ranking のサポートは今後も継続するということです。
そのため、現在 GS2-Ranking をご利用の皆様は無理して新しい GS2-Ranking2 へ移行することを検討する必要はありません。
ただし、今後積極的な機能追加は行われなくなる点はご注意ください。
新規プロジェクトでランキングを導入する際には GS2-Ranking2 を利用することを推奨します。

再設計の背景

GS2-Ranking の主要コンセプトは「1億人を超えるプレイヤーでも正確な順位を即座に応答する」でした。
しかし、現実的にそのような規模のゲームはほとんど存在しないため、多くの開発者にとってフィットしない思想でした。

一方で「1億人を超えるプレイヤーでも正確な順位を即座に応答する」を実現するために、ランキングの即時反映を諦め一定間隔で集計処理を行い、プレイヤーは最新の集計結果を参照するアーキテクチャを採用しており、最新のランキングを取得できないことは多くの開発者の皆様からご不満の声を頂戴していました。

そこで、新しいランキングシステムを設計するにあたって、主要コンセプトを「上位ランカーが常に最新のランキングを参照できること」におくことにしました。
冷静になれば「あなたは1億位のプレイヤーです」と正確に表示されて嬉しいプレイヤーがいるわけないのです。
ランキングの存在意義は上位のプレイヤーが鎬を削るために存在し、上位プレイヤー以外にとってはそれほど存在価値のないものだというごくごく当たり前の事実に気づくのに時間をかけすぎました。

新設計されたランキング

ランキングは上位1000位しか集計しないこととし、それ以外のプレイヤーは圏外として処理することにしました。
ただし、レーティングと組み合わせることで「ブロンズ帯」「シルバー帯」「ゴールド帯」といったそれぞれのティアーに1000人のプレイヤーを入れて、ティアーを昇降させるような、より現代的なランキングを実現できるようにすることをメインコンセプトにすることにしました。

  • レーティングを使わない純粋な上位1000人のプレイヤーを集計する「グローバルランキング」
  • レーティングやギルドといったクラスター内の上位1000人のプレイヤーを集計する「クラスターランキング」
  • フレンド内ランキングのような購読したプレイヤーのスコアと競う「購読ランキング」

上記3つのモードを用意することにしました。

さらに、ループする GS2-Schedule のイベントを関連づけることで
ループする度にランキングがリセットされる機能も用意しました。

実装例

グローバルランキングを例に出しますが、他のモードも概ね同じようなインターフェースを持ちます。

スコアの登録

    var result = await gs2.Ranking2.Namespace(
        namespaceName: "namespace-0001"
    ).Me(
        gameSession: GameSession
    ).PutGlobalRankingAsync(
        rankingName: "ranking-0001",
        score: 100L,
        metadata: null
    );
    var item = await result.ModelAsync();

順位の取得

var result = await gs2.Ranking2.Namespace(
        namespaceName: "namespace-0001"
    ).GlobalRankingModel(
        rankingName: "ranking-0001"
    ).GlobalRankingSeason(
        season: null // current season
    ).GlobalRankingData(
        GameSession
    ).GetGlobalRankingRankAsync(
    );
    var item = await result.ModelAsync();

ランキングの取得

var items = await gs2.Ranking2.Namespace(
        namespaceName: "namespace-0001"
    ).GlobalRankingModel(
        rankingName: "ranking-0001"
    ).GlobalRankingSeason(
        season: null
    ).GlobalRankingsAsync(
    ).ToListAsync();
(C) Game Server Services, Inc.