Epic Online Services でプレイヤー統計情報を管理する

Rajen Kishna、Epic Games テクニカル アカウント マネージャー |
2021年12月14日
これからこの ‘入門編’ シリーズの 3 つの記事では、密接に関連する 3 つのインターフェース、Stats (統計情報)Leaderboards (リーダーボード) 、および Achievements (アチーブメント) について説明します。まずは、収集したアイテムの数、プレイヤーがレベルを最速でクリアした時間、勝敗の合計数などのプレイヤー統計情報を管理するために使用される Stats から始めます。この記事では、次の項目について説明します。

Stats、Leaderboards、および Achievements

Stats の説明を始める前に、まずは Stats、Leaderboards、および Achievements の相互関係について説明したいと思います。Stats はプレイヤー統計情報を追跡する基盤となるシステムを提供します。これにより、Leaderboards を使用したプレイヤーのランキング作成、アチーブメントの自動アンロックなどを行うことができます。Stats は、Epic Online Services の他の機能を使用することなく、スタンドアロンで使用することもできます。

Achievements インターフェースでは、Stats に基づいてアチーブメントを自動的にアンロックするのではなく、手動でアンロックをトリガーするための API が提供されますが、Leaderboards は基盤となる Stat に関連付けられている場合にのみ機能します。この関連性については、次の 2 つの記事で詳しく説明します。

クライアント ポリシーを変更する

Stats を使用するには、最初にクライアント ポリシーにアクションを追加する必要があります。
 
  1. デベロッパー ポータル (https://dev.epicgames.com/portal/) にログインします。
  2. 左側のメニューで [Your Product (あなたの製品)] > [Product Settings (製品の設定)] に移動し、[Product Settings] 画面にある [Clients (クライアント)] タブをクリックします。
  3. 使用するクライアント ポリシーの横にある [...] をクリックし、[Details (詳細)] をクリックします。
  4. [Features (機能)] まで下にスクロールし、[Stats] の横にあるトグル ボタンをクリックします。
  5. [findStatsForLocalUser] アクションおよび [ingestForLocalUser] アクションの横にあるボックスをオンにします。
    • ここでは、必要最低限のアクションのみを使用することが重要です。これにより、サービスの呼び出しの乱用を防ぐことができます。
  6. [Save & Exit (保存して終了)] をクリックして確定します。
 
Developer Portal Client Policy Stats
Stats のクライアント ポリシーで許可されている機能とアクション

Developer Portal で統計情報を作成する

統計情報は Developer Portal で作成され、 4 つの集計タイプの 1 つとして定義することができます。
 
  • SUM— 取り込んだすべての統計情報の合計
  • LATEST— 取り込んだすべての統計情報の中で最新のもの
    • このタイプは唯一、アチーブメントの自動アンロックに使用できないことに注意してください
  • MIN— 取り込んだすべての統計情報の中で最小の整数
  • MAX— 取り込んだすべての統計情報の中で最大の整数

すべての統計情報集計タイプは、単一の 32 ビット整数として取り込まれる統計情報に依存しています。

それでは、集計タイプごとに 1 つの統計情報を定義し、サンプル アプリで動作を確認してみましょう。
  1. 左側のメニューで [Your Product (あなたの製品)] > [Game Services (ゲームのサービス)] > [Stats (スタッツ)] に移動します。
  2. ここでは、製品用に設定したデプロイメントごとに既存の統計情報を確認することができます。サンプル アプリで使用するデプロイメントを選択し、画面の右上にある青い [New Stat (新規統計情報)] ボタンをクリックします。
  3. 名前を「SumStat」と入力し、SUM 集計タイプを選択します。青い [Create (作成)] ボタンをクリックして作成を完了します。
  4. 手順 3 を LATEST、MIN、および MAX の各集計タイプで繰り返し、統計情報の名前をそれぞれ「LatestStat」、「MinStat」、および「MaxStat」にします。

Developer Portal Stats
Developer Portal の Stats

右上の [Search (検索)] ボタンの横には接続アイコンがあります。これをクリックすると、Stats が接続されている Leaderboards や Achievements を調べることができます。現時点ではここには何も表示されませんが、この後の Leaderboards および Achievements の記事で説明します。

最後に、青い [New Stat] ボタンの隣にある [Reset Player Stats (プレイヤー統計情報をリセット)] ボタンを見てください。これを使用すると、PUID によってプレイヤーを検索し、統計情報の定義自体に影響を与えることなく個々の統計情報をリセットすることができるフライアウトが表示されます。

マウスのクリックで統計情報をシミュレートする



サンプル アプリで統計情報をシミュレートするために、クリック カウンターのあるボタンを設定します。
 
  1. 「Views」フォルダに新しいユーザー コントロールを「StatsView」という名前で作成します。

<Grid>
    <Grid.ColumnDefinitions>
        <ColumnDefinition Width="*" />
        <ColumnDefinition Width="Auto" />
    </Grid.ColumnDefinitions>
    <Grid.RowDefinitions>
        <RowDefinition Height="Auto" />
        <RowDefinition Height="*" />
    </Grid.RowDefinitions>

    <StackPanel Grid.Column="1" Grid.Row="0" Grid.RowSpan="2">
        <Button Width="100" Height="23" Margin="2" Content="Ingest stats" Command="{Binding StatsIngest}" />
        <Button Width="100" Height="23" Margin="2" Content="Query stats" Command="{Binding StatsQuery}" />
    </StackPanel>

    <StackPanel Grid.Column="0" Grid.Row="0">
        <StackPanel Orientation="Horizontal">
            <TextBlock Text="Clicks:" Margin="2" />
            <TextBlock Text="{Binding Clicks}" Margin="2" />
        </StackPanel>

        <Button HorizontalAlignment="Left" Width="100" Height="23" Margin="2" Content="Add click" Command="{Binding StatsClick}" />
    </StackPanel>
</Grid>

 
  1. 「StatsView.xaml.cs」を開いて ViewModel をアタッチします。

public partial class StatsView :UserControl
{
    public StatsViewModel ViewModel { get { return ViewModelLocator.Stats; } }

    public StatsView()
    {
        InitializeComponent();
        DataContext = ViewModel;
    }
}

 
  1. StatsViewModel.cs クラスを「ViewModels」フォルダに追加します。

public class StatsViewModel :BindableBase
{
    private int _clicks;
    public int Clicks
    {
        get { return _clicks; }
        set { SetProperty(ref _clicks, value); }
    }
}

 
  1. 「ViewModelLocator.cs」で StatsViewModel への参照を追加します。

private static StatsViewModel _statsViewModel;
public static StatsViewModel Stats
{
    get { return _statsViewModel ??= new StatsViewModel(); }
}

 
  1. Add a StatsClickCommand.cs class to the Commands folder:

public class StatsClickCommand : CommandBase
{
    public override bool CanExecute(object parameter)
    {
        return !string.IsNullOrWhiteSpace(ViewModelLocator.Main.ProductUserId);
    }

    public override void Execute(object parameter)
    {
        ViewModelLocator.Stats.Clicks++;
    }
}

 
  1. 「StatsViewModel.cs」を開き、次のコマンドを宣言してインスタンス化します。

public StatsClickCommand StatsClick { get; set; }

public StatsViewModel()
{
    StatsClick = new StatsClickCommand();
}

 
  1. Connect インターフェースを使用して正常にログインした後にのみ、Stats UI 機能を呼び出せるように、次の行を「ViewModelLocator.cs」にある RaiseConnectCanExecuteChanged() メソッドに追加します。

Stats.StatsClick.RaiseCanExecuteChanged();
 
  1. 最後に、「MainWindow.xaml」にある TabControl に StatsView を追加します。

<TabItem x:Name="Stats" Header="Stats">
    <views:StatsView />
</TabItem>


これで、アプリを実行して Auth および Connect を介して認証すると、[Stats] タブに移動し、ボタンを使用してクリック カウンターを上げることができるようになりました。次は、これを使用して統計情報を取り込みます。

App Stats Click
アプリの UI でクリックをシミュレートする

統計情報を取り込む

作成したクリック カウンターを使用して、作成した 4 つの Stats すべてに同時に取り込みます。これにより、集計タイプの動作の違いが強調され、統計情報取り込みの呼び出しが簡素化されます。 
 
  1. StatsService.cs クラスを「Services」フォルダに追加し、取り込みのロジックを保持します。

public static class StatsService
{
    public static void Ingest(int count)
    {
        var ingestStatOptions = new IngestStatOptions()
        {
            LocalUserId = ProductUserId.FromString(ViewModelLocator.Main.ProductUserId),
            TargetUserId = ProductUserId.FromString(ViewModelLocator.Main.ProductUserId),
            Stats = new IngestData[]
            {
                new IngestData() { StatName = "SumStat", IngestAmount = count },
                new IngestData() { StatName = "LatestStat", IngestAmount = count },
                new IngestData() { StatName = "MinStat", IngestAmount = count },
                new IngestData() { StatName = "MaxStat", IngestAmount = count }
            }
        };

        ViewModelLocator.Main.StatusBarText = $"Ingesting stats (count: <{count}>)...";

        App.Settings.PlatformInterface.GetStatsInterface()
.IngestStat(ingestStatOptions, null, (IngestStatCompleteCallbackInfo ingestStatCompleteCallbackInfo) =>
        {
            Debug.WriteLine($"IngestStat {ingestStatCompleteCallbackInfo.ResultCode}");

            if (ingestStatCompleteCallbackInfo.ResultCode == Result.Success)
            {
                ViewModelLocator.Stats.Clicks = 0;
            }
            ViewModelLocator.Main.StatusBarText = string.Empty;
        });
    }
}

 
  • ここでの呼び出しは非常に簡単です。PUID と取り込みたい統計情報の配列を使用して Stats.IngestStatOptions をインスタンス化します。
  • 次に Stats.IngestStat を呼び出し、オプション構造体を渡して取り込みを完了します。
 
  1. StatsIngestCommand.cs クラスを「Commands」フォルダに追加します。

public class StatsIngestCommand : CommandBase
{
    public override bool CanExecute(object parameter)
    {
        return !string.IsNullOrWhiteSpace(ViewModelLocator.Main.ProductUserId);
    }

    public override void Execute(object parameter)
    {
        StatsService.Ingest(ViewModelLocator.Stats.Clicks);
    }
}

 
  1. 「StatsViewModel.cs」を開き、次のコマンドを宣言してインスタンス化します。

public StatsClickCommand StatsClick { get; set; }
public StatsIngestCommand StatsIngest { get; set; }

public StatsViewModel()
{
    StatsClick = new StatsClickCommand();
    StatsIngest = new StatsIngestCommand();
}

 
  1. 次の行を「ViewModelLocator.cs」にある RaiseConnectCanExecuteChanged() メソッドに追加します。

Stats.StatsIngest.RaiseCanExecuteChanged();

それでは、もう一度アプリを実行して認証し、クリック カウンターを少し上げましょう。それにより、[Ingest stats (統計情報を取り込む)] ボタンをクリックして値をバックエンドに送信することができます。これをもう一度繰り返し (何度かクリックして取り込み)、Developer Portal に移動して結果を確認します。
 
  1. ProductUserId をアプリの UI からクリップボードにコピーします。
  2. 左側のメニューで [Your Product] > [Game Services] > [Stats] に移動します。
  3. [Reset Player Stats (プレイヤー統計情報をリセット)] ボタンをクリックし、フライアウトで先ほどコピーした PUID を検索ボックスに貼り付け、[Search (検索)] ボタンをクリックします。

これで、このユーザーの 4 つの統計情報がすべて、対応する集計動作とともに表示されます。
 
Developer Portal Stats Reset Player Stats
Developer Portal でプレイヤー統計情報の UI をリセットする

統計情報をクエリする

最後に、アプリでこれらの統計情報をクエリする必要があります。それにより、それらを Developer Portal からではなく、直接表示することができます。
 
  1. 「StatsView.xaml」に次の ListView を、メインのグリッド要素の最後の子ノードとして追加します。

<ListView x:Name="StatsListView" Grid.Row="1" Margin="2" ItemsSource="{Binding Stats}">
    <ListView.View>
        <GridView>
            <GridViewColumn Header="Name" Width="200" DisplayMemberBinding="{Binding Name}">
                <GridViewColumn.HeaderContainerStyle>
                    <Style TargetType="{x:Type GridViewColumnHeader}">
                        <Setter Property="HorizontalContentAlignment" Value="Left" />
                    </Style>
                </GridViewColumn.HeaderContainerStyle>
            </GridViewColumn>
            <GridViewColumn Header="StartTime" Width="150" DisplayMemberBinding="{Binding StartTime}">
                <GridViewColumn.HeaderContainerStyle>
                    <Style TargetType="{x:Type GridViewColumnHeader}">
                        <Setter Property="HorizontalContentAlignment" Value="Left" />
                    </Style>
                </GridViewColumn.HeaderContainerStyle>
            </GridViewColumn>
            <GridViewColumn Header="EndTime" Width="150" DisplayMemberBinding="{Binding EndTime}">
                <GridViewColumn.HeaderContainerStyle>
                    <Style TargetType="{x:Type GridViewColumnHeader}">
                        <Setter Property="HorizontalContentAlignment" Value="Left" />
                    </Style>
                </GridViewColumn.HeaderContainerStyle>
            </GridViewColumn>
            <GridViewColumn Header="Value" Width="100" DisplayMemberBinding="{Binding Value}">
                <GridViewColumn.HeaderContainerStyle>
                    <Style TargetType="{x:Type GridViewColumnHeader}">
                        <Setter Property="HorizontalContentAlignment" Value="Left" />
                    </Style>
                </GridViewColumn.HeaderContainerStyle>
            </GridViewColumn>
        </GridView>
    </ListView.View>
</ListView>

 
  1. 「StatsViewModel.cs」を開き、次のメンバーを追加します。

private ObservableCollection<Stat> _stats;
public ObservableCollection<Stat> Stats
{
    get { return _stats; }
    set { SetProperty(ref _stats, value); }
}

 
  1. 「StatsService.cs」を開き、次のメソッドを追加します。

public static void Query()
{
    var queryStatsOptions = new QueryStatsOptions()
    {
        LocalUserId = ProductUserId.FromString(ViewModelLocator.Main.ProductUserId),
        TargetUserId = ProductUserId.FromString(ViewModelLocator.Main.ProductUserId)
    };

    ViewModelLocator.Main.StatusBarText = $"Querying stats...";

    App.Settings.PlatformInterface.GetStatsInterface()
.QueryStats(queryStatsOptions, null, (OnQueryStatsCompleteCallbackInfo onQueryStatsCompleteCallbackInfo) =>
    {
        Debug.WriteLine($"QueryStats {onQueryStatsCompleteCallbackInfo.ResultCode}");

        if (onQueryStatsCompleteCallbackInfo.ResultCode == Result.Success)
        {
            var getStatCountOptions = new GetStatCountOptions()
            {
                TargetUserId = ProductUserId.FromString(ViewModelLocator.Main.ProductUserId)
            };
            var statCount = App.Settings.PlatformInterface
.GetStatsInterface().GetStatsCount(getStatCountOptions);

            for (uint i = 0; i < statCount; i++)
            {
                var copyStatByIndexOptions = new CopyStatByIndexOptions()
                {
                    StatIndex = i,
                    TargetUserId = ProductUserId.FromString(ViewModelLocator.Main.ProductUserId)
                };
                var result = App.Settings.PlatformInterface.GetStatsInterface()
.CopyStatByIndex(copyStatByIndexOptions, out var stat);

                if (result == Result.Success)
                {
                    ViewModelLocator.Stats.Stats.Add(stat);
                }
            }
        }

        ViewModelLocator.Main.StatusBarText = string.Empty;
    });
}
  • Stats.QueryStats を使用し、Epic Online Services の統計情報をキャッシュに入力します。
    • オプションで Stats.QueryStats にある統計情報名の配列を指定し、特定の統計情報のみをクエリすることができます。
  • 次に Stats.GetStatsCount を使用して反復する必要がある統計情報の数を確認し、Stats.CopyStatByIndex を使用してキャッシュから統計情報データを取得します。
 
  1. StatsQueryCommand.cs クラスを「Commands」フォルダに追加します。

public class StatsQueryCommand : CommandBase
{
    public override bool CanExecute(object parameter)
    {
        return !string.IsNullOrWhiteSpace(ViewModelLocator.Main.ProductUserId);
    }

    public override void Execute(object parameter)
    {
        ViewModelLocator.Stats.Stats = new ObservableCollection<Stat>();
        StatsService.Query();
    }
}

 
  1. 「StatsViewModel.cs」を開き、次のコマンドを宣言してインスタンス化します。

public StatsClickCommand StatsClick { get; set; }
public StatsIngestCommand StatsIngest { get; set; }
public StatsQueryCommand StatsQuery { get; set; }

public StatsViewModel()
{
    StatsClick = new StatsClickCommand();
    StatsIngest = new StatsIngestCommand();
    StatsQuery = new StatsQueryCommand();
}

\n 
  1. 次の行を「ViewModelLocator.cs」にある RaiseConnectCanExecuteChanged() メソッドに追加します。

Stats.StatsQuery.RaiseCanExecuteChanged();

これで、もう一度アプリを起動して [Query stats (統計情報をクエリ)] ボタンを使用し、現在のプレイヤーの統計情報を直接 UI に表示することができます。
 
App Stats Query
アプリで統計情報をクエリする

使用上の制限事項

Stats には、すべてのユーザーに対して信頼性と可用性を保証するために設定された使用上の制限事項があります。この記事の作成時点では次の制限事項があります (最新情報については こちらのドキュメント を参照してください)。
  • デプロイメントごとの統計情報定義の合計数: 500
  • 取り込み呼び出しごとのプレイヤー統計情報の最大数: 3000
  • 統計情報名の長さ: 256 文字

さらに、クライアントまたはサーバー呼び出し用の API 呼び出しには、それぞれユーザーごと、またはデプロイメントごとのレート制限があります。これについては こちらのドキュメント を参照してください。

コードを入手する

この記事に記載しているコードは次の場所から取得できます。GitHub リポジトリ に記載されている使用方法に従って、ダウンロードしたコードを設定してください。
今回はプレイヤー統計情報を管理する方法について学びました。次は、EOS Leaderboards を使用したこれらのスコアのランキングについて説明します。

このシリーズの記事の一覧については、 「シリーズの記事リスト」 を参照してください。フィードバックや質問がある場合は、コミュニティ フォーラムにアクセスしてお知らせください。

    デベロッパーみなさんの成功が、Epic の成功です

    Epic は、オープンで統合されたゲーム コミュニティを大切にしています。
    オンライン サービスをすべての人に無料で提供することにより、より多くのデベロッパーがそれぞれのプレイヤー コミュニティにサービスを提供できるようにすることが目標です。