プレイヤープレゼンスの取得と設定

Rajen Kishna, Technical Account Manager, Epic Games |
2021年10月12日
このレギュラーシリーズでは、Epic オンラインサービスをプロジェクトで使用する方法について様々な側面から説明しています。 前回の記事ではAuthインターフェースを使用してログインとログアウト機能を実装しましたので、今回はプレゼンス ステータスの取得と設定方法を見ていきます。この記事で説明する内容は以下のとおりです。
 

Presence インターフェースの使用目的

 Presence インターフェースの使用目的は2つあります。
 
  • 認証されたプレイヤーに(Rich)presence ステータスを設定する
    • プレゼンス ステータスの設定に加えて、任意のkey/value pair (キーバリューぺア)データをプレイヤーのフレンドに渡すためにも使用できます。これは、ゲームに参加できない理由(招待制のパーティーの場合など)や、プレイヤーが使用しているキャラクタースキンなど、ゲームで追加のコンテキストを表示するために使用するものであれば何でもかまいません。ただし、これはリアルタイムのデータではないため、時間的制約を受けないデータはこの方法で渡すのがよいでしょう。
  • プレイヤーのフレンドのプレゼンス情報へのクエリ
    • SDKは、ゲームが要求する許可に同意したプレイヤーのフレンドのみを返します。つまり、ゲームにログインして同意したフレンド、またはEpic Games Storeでゲームを購入したフレンドのみがクエリ可能となります(購入時に暗黙の了解として許諾されるため)。 

ここでは、両方のシナリオについて説明しますが、次項では、プレゼンスのクエリの実際の使用例を紹介し、フレンド インターフェースについて説明します。

アプリケーションにプレゼンス許可を追加する

同意については、プレイヤーがプレゼンス API の使用に同意するために、Epic アカウントサービス(EAS) アプリケーションに Online Presence の許可を追加する必要があります。
 
  1. デベロッパーポータル https://dev.epicgames.com/portal/にログインします。
  2. 対象の製品に移動し、左側のメニューから Epic Account Services をクリックします。
  3. 使用しているアプリケーションの横にある [Configure(設定)] ボタンをクリックして設定します。
  4. 右上の[Permissions(許可)] タブをクリックします。
  5. Online Presence(プレゼンス)の許可を有効にします。左側のプレビューが更新され、プレゼンス情報への同意が表示されます。
  6. [Save(保存)] をクリックして確定します。

Developer Portal Online Presence Permission

EAS アプリケーションに Online Presence 許可を追加


最後に、Visual Studioソリューションの ApplicationSettings.cs を開いて、プレゼン スScopeFlag を追加します。

public AuthScopeFlags ScopeFlags
{
    get
    {
        return AuthScopeFlags.BasicProfile | AuthScopeFlags.Presence;
    }
}


アプリを実行してAuthログインを起動すると、ブラウザに更新された同意画面が表示され、認証を正常に完了することができます。

プレイヤープレゼンスのクエリ

前述したように、ここではクエリ機能をより汎用的な方法で実装するため、次の記事ではこれを利用してフレンドのプレゼンスのクエリを実行することができます。認証を除いては、これが実装する初めてのインターフェースになるため、追加するサービスごとにタブができるように、UIを構築するための追加手順が必要になります。
 
  1. まず、プロジェクトのルートに Views というフォルダを作成します。
  2. PresenceView という名前の新しい UserControl をこのフォルダに追加します。
  3. 以下のXAMLをペーストし、空のGridノードを置き換えます。

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

    <StackPanel Grid.Column="1">
        <Button Width="100" Height="23" Margin="2" Content="Query presence" Command="{Binding PresenceQuery}" />
        <Button Width="100" Height="23" Margin="2" Content="Modify presence" Command="{Binding PresenceModifyStatus}" />
    </StackPanel>

    <StackPanel Grid.Column="0">
        <StackPanel Orientation="Horizontal">
            <TextBlock Text="Status:" Margin="2" />
            <ComboBox Width="150" HorizontalAlignment="Left" SelectedItem="{Binding Status}" ItemsSource="{Binding StatusOptions}" IsEnabled="{Binding ProductIdText, Converter={StaticResource StringToBooleanConverter}}" />
        </StackPanel>

        <StackPanel Orientation="Horizontal">
            <TextBlock Text="ProductId:" Margin="2" />
            <TextBlock Text="{Binding ProductIdText}" Margin="2" />
        </StackPanel>

        <StackPanel Orientation="Horizontal">
            <TextBlock Text="ProductVersion:" Margin="2" />
            <TextBlock Text="{Binding ProductVersionText}" Margin="2" />
        </StackPanel>

        <StackPanel Orientation="Horizontal">
            <TextBlock Text="Platform:" Margin="2" />
            <TextBlock Text="{Binding PlatformText}" Margin="2" />
        </StackPanel>

        <StackPanel Orientation="Horizontal">
            <TextBlock Text="Rich Text:" Margin="2" />
            <TextBlock Text="{Binding RichText}" Margin="2" />
        </StackPanel>
    </StackPanel>
</Grid>

 
  • デザインビューを見るとわかるように、これにより、問い合わせるプレゼンス情報を表示するシンプルなUIが追加され、対応するModify(変更)ボタンでステータスを変更するオプションが追加されます。
 
  1. PresenceView.xaml.cs を開き、DataContext を定義します。

public partial class PresenceView : UserControl
{
    public PresenceViewModel ViewModel { get { return ViewModelLocator.Presence; } }

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

 
  1. ViewModel フォルダに PresenceViewModel.cs クラスを追加します。

public class PresenceViewModel : BindableBase
{
    private Status _status;
    public Status Status
    {
        get { return _status; }
        set { SetProperty(ref _status, value); }
    }

    private string _productIdText;
    public string ProductIdText
    {
        get { return _productIdText; }
        set { SetProperty(ref _productIdText, value); }
    }

    private string _productVersionText;
    public string ProductVersionText
    {
        get { return _productVersionText; }
        set { SetProperty(ref _productVersionText, value); }
    }

    private string _platformText;
    public string PlatformText
    {
        get { return _platformText; }
        set { SetProperty(ref _platformText, value); }
    }

    private string _richText;
    public string RichText
    {
        get { return _richText; }
        set { SetProperty(ref _richText, value); }
    }

    private List<Enum> _statusOptions;
    public List<Enum> StatusOptions
    {
        get { return _statusOptions; }
        set { SetProperty(ref _statusOptions, value); }
    }
}

 
  1. PresenceViewModel へのスタティック リファレンスを ViewModelLocator に追加します。

private static PresenceViewModel _presence;
public static PresenceViewModel Presence
{
    get { return _presence ??= new PresenceViewModel(); }
}

 
  1. Service フォルダに PresenceService.cs クラスを追加します。

public static void Query(EpicAccountId targetUserId)
{
    var queryPresenceOptions = new QueryPresenceOptions()
    {
        LocalUserId = EpicAccountId.FromString(ViewModelLocator.Main.AccountId),
        TargetUserId = targetUserId
    };

    ViewModelLocator.Main.StatusBarText = "Querying user presence...";

   App.Settings.PlatformInterface.GetPresenceInterface()
.QueryPresence(queryPresenceOptions, null, (QueryPresenceCallbackInfo queryPresenceCallbackInfo) =>
    {
        Debug.WriteLine($"QueryPresence {queryPresenceCallbackInfo.ResultCode}");

        if (queryPresenceCallbackInfo.ResultCode == Result.Success)
        {
            Copy(queryPresenceCallbackInfo.LocalUserId, queryPresenceCallbackInfo.TargetUserId);
        }
        else if (Common.IsOperationComplete(queryPresenceCallbackInfo.ResultCode))
        {
            Debug.WriteLine("Query presence failed: " + queryPresenceCallbackInfo.ResultCode);
            ViewModelLocator.Main.StatusBarText = string.Empty;
        }
    });
}

public static void Copy(EpicAccountId localUserId, EpicAccountId targetUserId)
{
    var copyPresenceOptions = new CopyPresenceOptions()
    {
        LocalUserId = localUserId,
        TargetUserId = targetUserId
    };

    var result = App.Settings.PlatformInterface.GetPresenceInterface()
.CopyPresence(copyPresenceOptions, out var info);
    if (result == Result.Success)
    {
        ViewModelLocator.Main.StatusBarText = "User presence retrieved.";

        if (localUserId == targetUserId)
        {
            ViewModelLocator.Presence.Status = info.Status;
            ViewModelLocator.Presence.ProductIdText = info.ProductId;
            ViewModelLocator.Presence.ProductVersionText = info.ProductVersion;
            ViewModelLocator.Presence.PlatformText = info.Platform;
            ViewModelLocator.Presence.RichText = info.RichText;
        }

        ViewModelLocator.Main.StatusBarText = string.Empty;
    }
}

 
  • ここでは2つのメソッドを実装します。 
    • Query() : 認証されたプレイヤー以外のユーザーのプレゼンスを取得する場合。 Authインターフェイスを使用した時と同じパターンに従います。オプションクラスをインスタンス化し、Presenceインターフェイスで QueryPresence を呼び出して、コールバックメソッドを渡し、結果を検証します。
    • • Copy() : QueryPresenceが結果をローカルにキャッシュし、認証されたプレイヤーのAuth インターフェース ログインの呼び出しが成功すると、プレゼンスが自動的に利用可能になります。 CopyPresence を使用して、キャッシュから実際のプレゼンス情報を取得します。
  • ローカルユーザーとターゲットユーザーが同じであるこのケースでは、プレゼンス情報を使って PresenceViewModel を生成し、UIに情報が表示されるようにします。
 
  1. Command フォルダに PresenceQueryCommand.cs クラスを追加します。

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

    public override void Execute(object parameter)
    {
        if (parameter == null)
        {
            PresenceService.Copy(EpicAccountId
.FromString(ViewModelLocator.Main.AccountId), EpicAccountId.FromString(ViewModelLocator.Main.AccountId));
        }
    }
}

 
  • ここでクエリメソッドをスキップするために null パラメータをチェックできますが、フレンドについて説明する次の記事でクエリを実装します。
 
  1. PresenceViewModel.cs を再度開いて PresenceQueryCommand をインスタンス化します。

public PresenceQueryCommand PresenceQuery { get; set; }

public PresenceViewModel()
{
    StatusOptions = Enum.GetValues(Status.GetType()).Cast<Enum>().ToList();

    PresenceQuery = new PresenceQueryCommand();
}

 
  • Epic.OnlineServices.Presence.Status 列挙型が保持するすべてのオプションを使用して StatusOptions をインスタンス化していることに留意してください。
 
  1. ViewModelLocator RaiseAuthCanExecuteChanged() メソッドに次の行を追加して、ユーザーがログインしているときにのみ [Query presence(プレゼンスのクエリ)] ボタンが有効になるようにします。

Presence.PresenceQuery.RaiseCanExecuteChanged();
 
  1. 最後に、PresenceView を MainWindowTabControl に追加します。

<TabItem x:Name="Presence" Header="Presence">
    <views:PresenceView />
</TabItem>


これで、アプリを実行し、認証して、ブラウザで更新された許可に同意できます。その後、[Query presence(プレゼンスのクエリ)] ボタンを使用して、キャッシュから現在のプレゼンス ステータスと関連情報を取得できます。
 
App MainWindow Queried Presence UI
認証されたプレイヤーのプレゼンス情報

また、本番ゲームでは常にAddNotifyOnPresenceChanged を実装して、QueryPresence を再度呼び出さなくても、プレゼンス ステータスが変更されたときに通知を受け取とれるようにする必要があります。

プレゼンスステータスの設定

これで、ドロップダウンで選択した内容に基づいてプレゼンスステータスを設定に移ることができます。 
 
  1. PresenceService.cs を開いて、次のメソッドを追加します。

public static void ModifyStatus()
{
    var createPresenceModificationOptions = new CreatePresenceModificationOptions()
    {
        LocalUserId = EpicAccountId.FromString(ViewModelLocator.Main.AccountId)
    };

    ViewModelLocator.Main.StatusBarText = "Creating presence modification...";

    var result = App.Settings.PlatformInterface.GetPresenceInterface()
.CreatePresenceModification(createPresenceModificationOptions, out var presenceModification);

    Debug.WriteLine($"CreatePresenceModification {result}");

    if (result == Result.Success)
    {
        var setStatusOptions = new PresenceModificationSetStatusOptions()
        {
            Status = ViewModelLocator.Presence.Status
        };

        result = presenceModification.SetStatus(setStatusOptions);
        Debug.WriteLine($"SetStatus {result}");

        var setPresenceOptions = new SetPresenceOptions()
        {
            LocalUserId = EpicAccountId.FromString(ViewModelLocator.Main.AccountId),
            PresenceModificationHandle = presenceModification
        };

        ViewModelLocator.Main.StatusBarText = "Setting presence status...";

        App.Settings.PlatformInterface.GetPresenceInterface()
.SetPresence(setPresenceOptions, null, (SetPresenceCallbackInfo setPresenceCallbackInfo) =>
        {
            Debug.WriteLine($"SetPresence {setPresenceCallbackInfo.ResultCode}");
            if (Common.IsOperationComplete(setPresenceCallbackInfo.ResultCode))
            {
                if (presenceModification != null)
                {
                    presenceModification.Release();
                    presenceModification = null;
                }

                ViewModelLocator.Main.StatusBarText = string.Empty;
            }
        });
    }
    else if (Common.IsOperationComplete(result))
    {
        Debug.WriteLine("Create presence modification failed: " + result);
        ViewModelLocator.Main.StatusBarText = string.Empty;
    }
}

 
  • プレゼンスは、まず PresenceModification オブジェクトを作成し、そのオブジェクトを操作して、SetPresence メソッドに渡すことによって変更されます。
  • この場合、ステータスを変更するために SetStatus のみを使用しますが、プレゼンスに関連付けられたリッチテキストを変更 することもできます(たとえば、プレイヤーがプレイしているレベルを示すためなど)。上記のように、カスタム プレゼンスデータを追加や置き換え、もしくは削除して、任意のキー/バリューペアデータを渡すこともできます。
  • 最後に、プレゼンスで JoinInfo を設定することもできます。これを使用して、EOSオーバーレイからゲームに情報を渡し、ゲームのロジックに基づいてフレンドがゲームに参加できるようにします。その際、たとえば、プレイヤーが参加リクエストを受け入れたときに通知されるオーバーレイ通知を登録することができます。
 
  1. プレゼンスの変更コマンドの CanExecuteChanged 動作にもトリガーを追加します。これにより、プレイヤーのプレゼンスの最初のクエリを実行した後にのみ使用できるようになります。

以下を 

ViewModelLocator.Presence.PresenceModifyStatus.
RaiseCanExecuteChanged();


PresenceService.Copy()の次のコードに追加します。

if (result == Result.Success)
{
    ViewModelLocator.Main.StatusBarText = "User presence retrieved.";

    ViewModelLocator.Presence.Status = info.Status;
    ViewModelLocator.Presence.ProductIdText = info.ProductId;
    ViewModelLocator.Presence.ProductVersionText = info.ProductVersion;
    ViewModelLocator.Presence.PlatformText = info.Platform;
    ViewModelLocator.Presence.RichText = info.RichText;

    ViewModelLocator.Main.StatusBarText = string.Empty;

ViewModelLocator.Presence.PresenceModifyStatus.
RaiseCanExecuteChanged();
}

 
  1. Commands フォルダに PresenceModifyStatusCommand.cs クラスを追加します。

public class PresenceModifyStatusCommand : CommandBase
{
    public override bool CanExecute(object parameter)
    {
        return !string.IsNullOrWhiteSpace(ViewModelLocator.Presence.ProductIdText);
    }

    public override void Execute(object parameter)
    {
        PresenceService.ModifyStatus();
    }
}

 
  1. PresenceViewModel.cs で新しいコマンドを宣言して初期化します。

public PresenceModifyStatusCommand PresenceModifyStatus { get; set; }
PresenceModifyStatus = new PresenceModifyStatusCommand();


これで、アプリを実行したときに最初のプレゼンス ステータスを問い合わせ、ドロップダウンでステータスを変更し、[Modify Presence(プレゼンスの変更)]を押して新しいステータスを設定することができます。

コードの取得

この記事のコードは以下の通りです。『Visual Studio 2019 で EOS 用に C# ソリューションを設定する方法』の記事にある C# ソリューションの設定セクションの5 と9の手順に従って SDK をソリューションに追加し、ApplicationSettings.cs を編集して SDK の認証情報を含めるようにしてください。
質問やフィードバックがありましたらお知らせください。次回の記事では、Epic のフレンドとそのステータスについて詳しく説明します。 このシリーズのすべての記事は、シリーズ記事一覧からいつでもご覧いただけます。

    あなたが成功するとき、私たちは成功します

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