> ## Documentation Index
> Fetch the complete documentation index at: https://devdocs.xbox.com/llms.txt
> Use this file to discover all available pages before exploring further.

# XBOX ゲーム ライフ サイクル

> ゲーム ライフ サイクル イベントの状態、遷移、処理、およびそれらをデバッグするために利用可能なツールに関する詳細を提供します。

# XBOX ゲーム ライフ サイクル

このトピックでは、ゲーム ライフ サイクルを構成する概念とイベントを紹介します。ゲームのライフ サイクル イベントや状態変化イベントを実装して、ユーザーに流動的な体験を提供する方法を示します。また、認定要件を通過する方法を示し、これらのイベントをデバッグするために利用可能なツールと機能を紹介します。

Microsoft Game Development Kit (GDK) ゲームは、そのライフタイムを通じてさまざまなリソース状態間を遷移します。これらの状態を切り替えることで、XBOX コンソールはユーザーが期待する応答性の高いマルチタスキング体験を提供できます。また、ユーザーがゲームをプレイするときに、ゲームがコンソールから可能な限り多くのリソースを得られるようにします。ただし、これを達成するために、Microsoft Game Development Kit (GDK) ゲームが処理する準備をしておく必要のあるイベントとインタラクションがいくつかあります。

<br />

[はじめに](#introduction)

[ゲーム ライフ サイクル状態](#game-life-cycle-states)

[ライフ サイクル状態遷移](#life-cycle-state-transitions)

[ライフ サイクル イベント コールバック](#life-cycle-event-callbacks)

[Suspend および Resume への対応](#responding-to-suspend-and-resume)

[Constrain および Unconstrain への対応](#responding-to-constrain-and-unconstrain)

[起動](#launching)

[ライフ サイクルに関連するイベント](#events-related-to-life-cycle)

[GDK タイムアウトの取り扱い](#timeouts)

[Quick Resume](#quick-resume)

[デバッグ ツールと機能](#debugging-tools-and-features)

[付録](#appendix)

<br />

<a id="introduction" />

## はじめに

ゲーム ライフ サイクル状態とイベントにより、ユーザーはゲーム、XBOX シェル、およびその他のアプリ間を素早く効率的に切り替えることができます。このプロセスでは、ライフ サイクル状態間の遷移を処理できるように、ゲームおよびアプリが何らかのアクションを行う必要があります。うまく処理されると、ユーザーがゲームに切り替えたり、ゲームから切り替えたりする際にスムーズでシームレスな体験が提供されます。このトピックでは、ゲームのライフ サイクルを管理するさまざまな側面と、それらの側面をサポートするために利用可能なツールについて説明します。XBOX One Software Development Kit または Universal Windows Platform (UWP) アプリケーションのプロセス ライフタイム管理 (PLM) に慣れている場合、この情報は身近なものです。ただし、GDK アプリケーションではいくつかの重要な違いと改善点がある点に注意してください。

このトピックは、次の内容から始まります。

* さまざまなライフ サイクル状態に関する説明。
* それらの間の遷移。
* それらに関連するコールバック。

次に、このトピックでは、XBOX 要件 (XR) を通過するためにこれらの遷移を正常に処理するための要件を説明し、ほとんどのゲームが検討すべき一般的なユース ケースについて説明します。

最後に、このトピックでは、状態遷移の問題を理解して修正するのを容易にするツールとデバッグ機能を紹介します。

<br />

<a id="game-life-cycle-states" />

## ゲーム ライフ サイクル状態

XBOX コンソールにインストールされた Microsoft Game Development Kit (GDK) ゲームは、常に次の 5 つの可能な状態のうちの 1 つにあります。

1. Running
2. Constrained
3. Suspending
4. Suspended
5. Not Running

ゲームの状態は次で確認できます。

* [XBOX Manager](/ja-jp/tools/tools-console/xbom/xbom) の **Home** ビューにリストされた **State**。
* [Dev Home](/ja-jp/tools/tools-console/devhome/devhome) の **Games & apps** ビューのゲームの横にリストされた値。
* [XBOX Device Portal](/ja-jp/tools/tools-console/wdp/wdp)。
* [xbapp query](/ja-jp/tools/tools-console/commandlinetools/xbapp) コマンド ライン ツール。

### Running

ゲームが実行中のとき、フル リソースの可用性で実行されます。ゲームには入力フォーカスがあり、そのウィンドウはユーザーに表示されます。フル リソースの可用性とは、ゲームが次の状態で実行されていることを意味します。

* 6 つの物理 CPU コア (core0-core5) と、XBOX One ファミリー デバイスでは CPU core6 の 50 ～ 90%、XBOX Series コンソールでは CPU core6 の 100%。
* GPU の 97 ～ 100% を使用。オペレーティング システムが GPU の最大 3% を使用する可能性がある点に注意してください。
* MicrosoftGame.config の設定とゲームが実行されているコンソールに応じて 5 ～ 13 GB のメモリ。詳細については、[タイトル メモリの構成](/ja-jp/build/console-features/memory/system-memory-tooling)を参照してください。

Running 状態と Constrained 状態の間の CPU リソース変化をよりよく説明するために、ゲームが Running 状態にあるときの CPU コアの状態を示す以下の図を検討してください。

<img src="https://mintcdn.com/microsoft-4404708b/-_0FrcE2bDxzGxv-/images/gdk/lifecycle/cpu-resource-diagram-x1-running.png?fit=max&auto=format&n=-_0FrcE2bDxzGxv-&q=85&s=860d4002788745eb605483ca4d85c1d3" alt="ゲームが Running 状態にあるときの CPU コアの状態を示す図" width="600" height="171" data-path="images/gdk/lifecycle/cpu-resource-diagram-x1-running.png" />

XBOX Series コンソールは、同時マルチスレッド (SMT) を有効にでき、これにより図が若干変わります。SMT の詳細については、XBOX One と XBOX Series X|S の CPU およびメモリ、および SMT を使用した CPU コアの詳細を示す図の[付録](#smt-diagrams)を参照してください。

### Constrained

ゲームが Constrained 実行状態で実行される場合、リソースの可用性が減った状態で実行されます。ゲームはこの状態でユーザー入力を受け取ることができません。ゲームのウィンドウは、部分的に隠されているか、ユーザーに表示されていない可能性があります。ゲームは、ユーザーがいくつかの機能とやり取りしたり、Guide のようなメニュー、Settings のようなシステム アプリ、Account Picker のようなタイトル呼び出し可能 UI (TCUI) など、アクティブなゲーム以外のものを体験するとこの状態になります。ゲームが Constrained のとき、利用可能なリソースは次の状態に減少します。

* 4 つの物理 CPU コア。スレッドは次のパターンで折りたたまれます。
  * core0 および core1 のスレッドは影響を受けません。
  * core2 および core3 のスレッドは 1 つの物理 CPU コアにタイム スライスされます。
  * core4、core5、および core6 のスレッドは 1 つの物理 CPU コアにタイム スライスされます。
* GPU の約 45%。
* Running 状態と同じ利用可能メモリ。Constrained になっても、ゲームで利用可能なメモリ量は変わらない点に注意してください。

以下の図は、ゲームが Constrained 状態にあるときの CPU コアの状態を示します。

<img src="https://mintcdn.com/microsoft-4404708b/-_0FrcE2bDxzGxv-/images/gdk/lifecycle/cpu-resource-diagram-x1-constrained.png?fit=max&auto=format&n=-_0FrcE2bDxzGxv-&q=85&s=208b833caebeb949daa6877a76ceed6c" alt="ゲームが Constrained 状態にあるときの CPU コアの状態を示す図" width="595" height="128" data-path="images/gdk/lifecycle/cpu-resource-diagram-x1-constrained.png" />

### Suspending

ゲームが Suspending 実行状態で実行される場合、Constrained と同じリソースで実行されますが、コンソールがゲームを Suspended 状態に遷移させるプロセスを開始したことを示します。Suspending は一時的な状態です。そのため、実行状態を照会する頻度によっては、Suspending 実行状態を観察するのは難しい場合があります。

### Suspended

ゲームが Suspended 実行状態にあるとき、それはまだメモリに常駐していますが、実行されなくなります。そのスレッドはスケジュールされておらず、その結果 CPU または GPU の時間を使用していません。ゲームがサスペンドされている場合、ゲームが実行されている Game OS 全体も同様にサスペンドされ、別の状態遷移が発生するまでオペレーティング システムとメモリの状態はそのままです。

### Not Running

これは、実行されておらず、メモリにロードされておらず、コンソールのリソースを使用していないゲームの状態です。一部のツール (`xbapp query` など) は、この実行状態をパッケージ実行状態 0 (不明) として報告する場合があります。

<br />

<a id="life-cycle-state-transitions" />

## ライフ サイクル状態遷移

このセクションでは、各ライフ サイクル状態遷移について説明し、それぞれの例の原因を提供します。コンソールとの一部のユーザー インタラクションによって、これらのイベントの多くが順次、時には非常に迅速に発生する可能性がありますが、ゲームはこれらの遷移すべてを段階的に進みます。以下の図は、ライフ サイクル状態間の状態遷移を示しています。簡略化のため、この図はエラー以外の遷移のみを示しています。ゲームは、クラッシュの結果として任意の状態から Not Running 状態に遷移することもできる点に注意してください。

<img src="https://mintcdn.com/microsoft-4404708b/-_0FrcE2bDxzGxv-/images/gdk/lifecycle/gdk-life-cycle-state-transition-diagram.png?fit=max&auto=format&n=-_0FrcE2bDxzGxv-&q=85&s=45f4a5b0c2d951728a177354e447153d" alt="各ライフ サイクル状態遷移を示す図" width="624" height="552" data-path="images/gdk/lifecycle/gdk-life-cycle-state-transition-diagram.png" />

### Running から Constrained への遷移 (Constrain)

この遷移は、ゲームで利用可能なリソースの削減を表します。ゲームは、[RegisterAppConstrainChangeNotification](#life-cycle-event-callbacks) を呼び出すことで、これが発生したときにコールバックを受け取るように登録できます。この遷移は次の場合に発生します。

* ユーザーが Guide を開いたとき。
* TCUI が表示される (Account Picker など) とき。
* ユーザーが Home に戻ったとき。
* ゲームがフォーカスを失ったとき。

### Constrained から Suspending への遷移 (Suspend 開始)

ゲームがサスペンドされるプロセス中、最初に Suspending 状態に遷移します。[RegisterAppStateChangeNotification](#life-cycle-event-callbacks) で登録されたコールバックが発火します。ゲームは、すべてのコールバック ハンドラーから戻るか、1 秒のタイムアウトが発生するまで Suspending 状態のままです。ハンドラーがタイムアウトの前に戻ると、ゲームはサスペンションを完了します。そうでない場合、ゲームは終了します。ゲームは次の場合にサスペンドを開始します。

* コンソールが Connected Standby に入るとき。
* ゲームが 10 分間表示されていなかったとき。
* 新しいゲームが起動されたときなど、ゲームを終了する最初のステージが発生したとき。

<Note>
  この遷移は *quiesce* と呼ばれることがあります。
</Note>

### Suspending から Suspended への遷移 (Suspend 完了)

この遷移は、Suspending 状態のゲームが [RegisterAppStateChangeNotification](#life-cycle-event-callbacks) で登録されたコールバック ハンドラーから戻ると自動的に発生します。ゲームのスレッドは、この状態に入るとすぐに実行を停止します。

### Suspended から Not Running への遷移 (Terminate)

この遷移は、ゲームのメモリからの削除を表します。サスペンドされたゲームは実行されていないため、ゲームはこの遷移を制御したり、この遷移とやり取りしたりすることはできません。終了は次の場合に発生します。

* ユーザーが Home からゲームの終了を選択したとき。
* コンソールがシャットダウンする (Connected Standby に遷移しない) とき。
* 新しいゲームが起動されたときなど、ゲームをシャットダウンする最終ステージ。
* ゲーム セーブ データがクラウドと同期していないとき。詳細は [Connected Storage システムによる終了](#termination-connected-storage)を参照してください。

### Not Running から Running への遷移 (Launch)

この状態遷移は、Game OS 内でゲームを読み込んで実行することを表し、多くの場合、Game OS 自体の起動と一致します。これはユーザーが次のことを行うたびに発生します。

* ゲームのタイルを選択します。
* ゲーム招待を承諾します。
* XBOX シェルとシステム全体のゲームへの参照とやり取りします。

### Suspended から Constrained への遷移 (Resume)

この状態遷移は、多くの場合、Unconstrain イベントが続きます。これは、ゲームのスレッドが再び実行を開始することを表し、遷移は [RegisterAppStateChangeNotification](#life-cycle-event-callbacks) の任意のハンドラーへのコールバックで始まります。ゲームは、以前 Suspended 状態にあり、フォアグラウンドに持ち込まれたとき (通常、ゲームが Not Running 状態にあった場合にゲームを起動するのと同じインタラクションから) に再開されます。

### Constrained から Running への遷移 (Unconstrain)

この状態遷移は、Constrain 遷移の逆です。これは、ゲームの利用可能なリソースを Running 状態のフル量に戻すことを表します。この遷移はまた、[RegisterAppConstrainChangeNotification](#life-cycle-event-callbacks) の任意のハンドラーに関連するコールバックがあり、ゲームがフォアグラウンド アプリケーションになるといつでも発生します。

別のゲームの起動やコンソールのオフなど、典型的なコンソールのインタラクションによってゲームが終了する場合でも、終了前に最初に Suspended 状態に遷移します。これにより、現在実行中のゲームは、シャットダウンする前に状態を保存できます。ただし、ゲームがクラッシュしたりサスペンドに失敗したりすると、直接 Not Running 状態に遷移します。

<a id="termination-connected-storage" />

### Connected Storage システムによる終了

ゲームのローカル セーブ データがクラウドと同期していない場合、Connected Storage システムは次にゲームがサスペンドされたときに終了します。これにより、再度起動されたときに最新のセーブ データを同期できます。この理由による終了はクラッシュではなく、[XR-001](#xrs) の失敗を引き起こしません。

このケースは一般的ではありませんが、コンソールが XBOX ネットワーク (XBOX Live としても知られる) に接続されていない状態でゲームを起動し、実行中に再接続した場合に発生する可能性があります。これは、Connected Storage がタイトル用に適切に構成されていない場合、開発中にも発生する可能性があります。

このケースは、[xbWatson](/ja-jp/tools/tools-console/xbWatson/xbwatson) または Visual Studio 内の XBOX System Monitor ウィンドウで次のような行を探すことで認識できます。

```text theme={null}
 [ConsoleEtw] [1] SuspendComplete
 [ConsoleEtw] TerminateApplicationAfterSuspend <package name>
 [ConsoleEtw] Eviction of package <package name> because -2138890207
 [ConsoleEtw] [1] TerminateBegin Successful
 [ConsoleEtw] [1] TerminateComplete
```

<code>SuspendComplete</code> は、ゲームが正常にサスペンドされ、クラッシュまたはタイムアウトしなかったことを示します。<code>TerminateApplicationAfterSuspend</code> は、サスペンションが成功した後、システムによって終了が開始されたことを示します。-2138890207 の値は HRESULT の CS\_E\_TERMINATEDTITLE\_NOLOCK で、終了の理由を示します。

<br />

<a id="life-cycle-event-callbacks" />

## ライフ サイクル イベント コールバック

このセクションでは、ゲームが状態間をどのように遷移するかを説明します。また、ゲームがこれらの遷移がいつ発生するかをどのように判断し、これらの遷移にどのように対応するかも説明します。

Microsoft Game Development Kit (GDK) ゲームでは、状態変更情報を受け取るために登録できる 2 つのイベントがあります。これは次のコード例に示されています。

```cpp theme={null}
ULONG RegisterAppStateChangeNotification(
    _In_ PAPPSTATE_CHANGE_ROUTINE Routine,
    _In_opt_ PVOID Context,
    _Out_ PAPPSTATE_REGISTRATION* Registration
    );

ULONG RegisterAppConstrainedChangeNotification(
    _In_ PAPPCONSTRAIN_CHANGE_ROUTINE Routine,
    _In_opt_ PVOID Context,
    _Out_ PAPPCONSTRAIN_REGISTRATION* Registration
    );
```

詳細については、[RegisterAppStateChangeNotification](https://learn.microsoft.com/windows/win32/api/appnotify/nf-appnotify-registerappstatechangenotification) を参照してください。

<Note>
  Constrained 変更通知は XBOX コンソール固有であり、現在 API リファレンス ページはありません。API は非常に似ており、名前とパラメーターの "State" が "Constrained" にわずかに変わっただけです。
</Note>

`PVOID Context` は任意のものでよく、呼び出されるときに `Routine` 関数に渡されます。`Registration` を保持することで、`UnregisterAppStateChangeNotification` および `UnregisterAppConstrainedChangeNotification` でこれらのイベントの登録を解除できます。

register 関数に渡される `Routine` は、関連するイベントが発生したときに、タイトル内の既定のスレッド プールからのスレッドで呼び出されます。この関数で登録されたすべてのルーチンは、別のスレッド プール スレッドで非同期に呼び出されます。これはフレーム中の任意の時点で発生する可能性があります。`RegisterAppStateChangeNotification` の場合、コンソールがゲームを Suspending 状態に設定し、サスペンドのタイムアウトを開始するとすぐに、`Routine` はブール値 `true` で呼び出されます。ゲームを Suspended 状態から Running 状態に再開すると、`Routine` はブール値 `false` で呼び出されます。

`RegisterAppConstrainedChangeNotification` の場合、コンソールがゲームを Constrained 状態に設定すると、`Routine` はブール値 `true` で呼び出されます。Constrained 状態から Running 状態にゲームを制約解除すると、`Routine` はブール値 `false` で呼び出されます。

これらのイベントを設定して処理し、ゲームのフレームの一貫したポイントでメインスレッド上で処理されることを確認する方法を示す例については、[XBOX One 用 Microsoft Game Development Kit ポーティング ガイド](/ja-jp/build/console-features/porting-from-xbox-one-era/porting-guide-for-existing-era)のサンプル コードを参照してください。SimplePLM サンプルの main.cpp、または Visual Studio の Microsoft Game Development Kit (GDK) の Direct3D 12 XBOX Game プロジェクト テンプレートも参照できます。サンプルは [XBOX Developer Downloads](https://aka.ms/gdkdl) からダウンロードできます。

quiesce ハング ミニダンプを見ているとき、どのスレッドのスタックにも登録されたコールバックが見えないという少し混乱する状況に遭遇する可能性があります。これはテール コール最適化によるものです。これを回避するには、単にコールバックを次でラップしてください。

```cpp theme={null}
#pragma optimize( "", off ) 
/* ... */
#pragma optimize( "", on )
```

<Note>
  Windows PC で実行されている Microsoft Game Development Kit (GDK) ゲームはサスペンドされません。Windows PC では、これらのゲームは `RegisterAppStateChangeNotification` を呼び出せますが、`PAPPSTATE_CHANGE_ROUTINE` コールバックは発火しない点に注意してください。
</Note>

<br />

<a id="responding-to-suspend-and-resume" />

## Suspend および Resume への対応

ゲームがサスペンドするために行う必要があることがいくつかあります。これにより、ゲームに切り替えたり、ゲームから切り替えたりするユーザーにシームレスな体験を提供でき、ゲームが XR に通過することを保証できます。

### Suspend タイムアウト

サスペンションを完了する ([XR-001](#xrs) を通過するために必要) には、ゲームに `RegisterAppStateChangeNotification` で登録された少なくとも 1 つのコールバック ルーチンが必要です。コールバックが発火すると、すべての登録されたルーチンは別々の既定のスレッド プール スレッドで非同期に呼び出されます。ゲームは、すべての登録されたルーチンから戻るのに 1 秒しかありません。これはゲームを Suspended 状態に遷移できることをシステムに通知します。ゲームが 1 秒以内にサスペンド ルーチンから戻らないか、コールバックが登録されていない場合、ゲームは終了され、Not Running 状態に遷移します ([XR-001](#xrs) の失敗)。このプロセスにより、コンソールがゲーム間を素早く切り替えられると同時に、ゲームがサスペンド状態に入る前にサスペンションの準備ができていることが保証されます。

### Direct3D

サスペンド ルーチンが呼び出されたことに応じて、そこから戻る前に、ゲームはレンダー スレッドからその `ID3D12CommandQueue` で SuspendX を呼び出す必要があります。これにより、サスペンションの準備のために GPU 状態が保存されます。再開するときは、状態を復元するためにゲームは ResumeX を呼び出す必要があります。`SuspendX` と `ResumeX` の呼び出しの間に Direct3D API を呼び出すと、例外がスローされ、クラッシュが発生します。サスペンド ルーチンから戻る前に `SuspendX` を呼び出さないと、サスペンションが失敗し、タイトルが終了します (これも [XR-001](#xrs) の失敗)。詳細については、サスペンドと再開に対する Direct3D サポートを参照してください。

### XGameSave API

ゲームがサスペンド通知を受け取ると、サスペンドする前に 1 秒間の実行時間があります。ゲームが Suspended 状態のとき、追加の実行時間なしで Not Running 状態に遷移する可能性があります。つまり、その 1 秒のサスペンド時間中に、ゲームは Suspended 状態に入る前に、未保存のユーザー データを保存する必要があります。

[XGameSave](/ja-jp/build/core-features/common/game-save/game-saves-overview) API は、この限られた時間枠での保存をサポートするように設計されています。`XGameSave` API は、短いサスペンド時間ウィンドウ中のタイトルの書き込み速度を最大化するために、タイトル予約外の RAM を最初のストレージ ポイントとして使用します。[XR-052: User State](#xrs) は、タイトルがユーザー データ (ユーザー進行状況と状態を含む) の意図しない損失を引き起こしてはならないと規定しています。一般に、ゲームは、サスペンド処理の一部として確実にユーザー データを保存する必要があります。また、サスペンド中だけでなく、より頻繁に保存することもよいアイデアです。これにより、ゲームがタイムアウト中に大きな保存を準備する必要がなくなり、停電などによってユーザー データが大幅に失われることを防ぎます。詳細については、[Game Saves の概要](/ja-jp/build/core-features/common/game-save/game-saves-overview)および [GameSave サンプル](https://aka.ms/gdkdl)を参照してください。

`XGameSave` API の非同期バージョンを使用する方が望ましい点に注意してください。これにより、システムがゲーム セーブ データを書き出している間、タイトルは残りのサスペンド コードを続行できます。これがどのように行われるかの例については、XGameSaveSubmitUpdateAsync を参照してください。

ゲームを再開する前に、オペレーティング システムは、ゲームがサスペンドされている間に別のデバイスでセーブ ゲームが変更されたかどうかをチェックします。デバイスがオンラインで、このチェックによってセーブが変更されていることが示された場合、ゲームは終了され、ゲームが一貫した状態になるように再起動されます。チェックが行われたときにデバイスがオフラインの場合、ゲームは引き続き起動できます。

再開時、ゲームは常に XGameSaveInitializeProvider または XGameSaveInitializeProviderAsync のいずれかを呼び出して、セーブ ゲーム プロバイダーを再取得しようとする必要があります。プロバイダーを再初期化することで、最新のセーブ データが利用可能になります。

### ユーザーとユーザー コントローラーのペアリング

[XR-112: 初期アクティブ化と再開時のユーザーおよびコントローラーの確立](#xrs) では、タイトルが再開されるとき、ユーザー/コントローラーのペアリングを検証し、以前のユーザーのセッションを再開するか、新しいユーザー (または複数のユーザー) を取得することによって、それに応じて反応する必要があると規定しています。正確な動作は、ゲームがユーザーとコントローラーをどのように処理するかによって異なる場合があります。サスペンド前のユーザーまたはコントローラーの状態に関する情報に頼らないこと、および再開時にユーザーとコントローラーの状態を再確立することが重要です。ゲームがユーザー状態に関する更新を取得する方法であるため、サスペンド/再開サイクルを通じて `XUserHandle` を保持する必要があります。さらに、XUserRegisterForChangeEvent および XUserRegisterForDeviceAssociationChanged で登録されたコールバックが再開中に発火し、発生した状態変化でゲームを更新します。ユーザーとデバイスの管理の詳細については、ユーザー ID と XUser、およびユーザーと入力デバイスを参照してください。ゲームがこれをどのように処理するかの例については、[UserManagement サンプル](https://aka.ms/gdkdl)を参照してください。

### 権限と特権

ゲームがサスペンドされている間、ユーザーは自分がオンラインで許可されていること、他のユーザーとどのように通信できるかを決めるアカウント設定を変更できます。ゲームが再開されたとき、関連機能を有効または無効にする前にすべての権限または特権を再チェックして、ゲームの動作がユーザー設定の現在の状態を反映するようにする必要があります。[XR-015: プレイヤー通信の管理](#xrs) は、テキストおよび音声通信の権限を詳細に説明します。[XR-045: XBOX Live およびアカウント特権](#xrs) は、XBOX サービスに関連するアクションを許可または防止する特権を詳細に説明します。

### ネットワーキング

サスペンドされたゲームにはスケジュールされたスレッドがないため、ゲームが再開するとき、ネットワーク通信が影響を受けていることを予期する必要があります。この状況を処理するためのガイダンスについては、[ネットワーキング API の概要](/ja-jp/build/console-features/networking/introduction-networking)を参照してください。XBOX サービスに固有の詳細については、XBOX サービス API 入門を参照してください。マルチプレイヤー セッションの詳細については、Multiplayer Session の詳細なトピックを参照してください。

### 非同期 API

システム OS との通信が必要な一部の非同期 API は、ゲームがサスペンドされたときに進行中だった場合に失敗する可能性があります。これが発生する場合、`Xasync` API は `E_ABORT` で失敗する必要があります。これは XR とは関係ありません。代わりに、これは非同期 API を呼び出すときに認識しておくべきことです。この可能性を優雅に処理するエラー処理が確実に整備されているようにしてください。呼び出しがこのように失敗した場合、通常最良の対処方法は、ゲームが再開したときに単に再試行することです。

### Gaming Runtime API

ゲームがサスペンド イベントの AppStateChangedNotification ハンドラーを完了した後、Gaming Runtime は自動的にサスペンドされます。ランタイムは、再開イベントに対するゲームのハンドラーを呼び出す直前に再開されます。ランタイムがサスペンドされている間に他のスレッドで Gaming Runtime API が呼び出されると、E\_GAMERUNTIME\_SUSPENDED で失敗します。これは、たとえば、サスペンド ハンドラーが終了する直前に非同期 API が呼び出された場合に発生する可能性があります。ランタイムがサスペンドされた後、ゲームがスレッドのスケジューリングを停止する前に、コールバックが発火する可能性があります。

可能な場合は、Gaming Runtime がサスペンドされているこの間に Gaming Runtime の呼び出しを行うことを避けてください。これを避けられない場合、エラーを検出し、再開イベントの AppStateChangedNotification を受け取った後で呼び出しを再試行できます。

### オーディオ

サスペンドするとき、ゲームは [IMMDeviceEnumerator](https://learn.microsoft.com/windows/win32/api/mmdeviceapi/nn-mmdeviceapi-immdeviceenumerator) から取得したオブジェクト (`IMMDevice`、`IMMDeviceCollection`、`IMMEndpointDevice` を含む) を保持しないでください。最初に `IMMDeviceEnumerator` を使用してそれらを更新せずに再開後にこれらのインターフェイスを使用しようとすると、動作が未定義になります。ただし、ゲームが `IMMNotificationClient` を保持している場合、そのクライアントはサスペンドと再開の間で通常どおり機能し続けます。また、サスペンド中に任意のオーディオ ストリームを停止し、再開時に再開することがベスト プラクティスです (ただし必須ではありません)。

再開中、ゲームのオーディオ ストリームも無効になり、再初期化が必要になります。ゲームは、再開ハンドラーの実行中またはその後に、これらの無効化からの回復を行う必要があります。詳細については、XBOX One Software Development Kit と Microsoft Game Development Kit オーディオ API の比較を参照してください。

<Note>
  再開ハンドラーが実行を開始する前にオーディオ ストリームを再初期化しようとすると、動作が未定義になる可能性があります。
</Note>

<a id="dealing-with-time" />

### サスペンド中の時間変化への対処

ゲームがサスペンドされている間、多くのことが起こる可能性があります。1 つの確実なことは、ゲームがサスペンドされている間に時間が進むことです。ゲームはこれを考慮に入れ、ゲーム プレイに費やされた時間などのメトリックを計算するときに、ゲームがサスペンドされている間に費やされた時間を意図せずに含めないようにする必要があります。

2021 年 6 月の GDK から、ゲームがサスペンドされているとき、タイム スタンプ カウンター (TSC) は凍結され、ゲームが後で再開されるまで進みません。さらに、TSC はサスペンド中に費やされた時間を含めません。つまり、ゲームは以下を使用して、ゲームの実行中に費やされた時間を正確に報告できます。

* \_\_rdtscp
* QueryPerformanceCounter

サスペンド中に TSC は進みませんが、実世界の時間 (wall clock time) は進みます。つまり、ゲームが [GetSystemTime](https://learn.microsoft.com/windows/win32/api/sysinfoapi/nf-sysinfoapi-getsystemtime) または [GetLocalTime](https://learn.microsoft.com/windows/win32/api/sysinfoapi/nf-sysinfoapi-getlocaltime) を呼び出すと、時間が進んだことがわかります。

<br />

<a id="responding-to-constrain-and-unconstrain" />

## Constrain および Unconstrain への対応

ゲームが特定のアクションを実行することが期待され、コンソールがルーチンの戻りを待っているサスペンド通知とは異なり、アプリの制約変更通知に対応するものは何も必要ではありません。イベントが受信されたとき、Constrained 状態または Running 状態への遷移は既に発生しています。代わりに、このイベントはゲームに対して、利用可能なリソースが変化したこと、およびそれに応じてリソース使用量を減らしたり増やしたりする必要があることを通知します。

ゲームが制約されるときにどのように処理すべきかを決定するとき、ゲームは入力フォーカスがない場合にのみ制約されるという事実を考慮してください。したがって、ユーザーは制約されている間はゲームとやり取りできません。このため、ほとんどのゲームは制約されている間、ゲームプレイを一時停止 (または一時停止に最も近いもの) する必要があります。ただし、ゲームは制約されている間でも表示されている可能性があるため、ユーザーがゲームの状態を確認できるように、何かをレンダリングし続けることが重要です。また、ユーザーが間もなくゲームをフォアグラウンドに戻す可能性が高いため、マルチプレイヤー マッチや他のネットワーク通信を維持することは、ユーザーにとってより良い体験になる可能性があります。

最終的に、Constrain を処理するための唯一の目標は、CPU および GPU 時間の減少に合わせて調整しながらゲームを実行し続けることです。これを達成する最善の方法は、ゲームの個々のニーズに依存します。

<br />

<a id="launching" />

## 起動

Microsoft Game Development Kit (GDK) ゲームは Win32 で設計されており、従来の Windows メッセージ ループを備えています。そのため、起動されると、コードの最初の開発者向けエントリ ポイントは `WinMain` に渡されるパラメーターです。あるいは、ゲームは `GetCommandLine` 関数を使用して、起動されたときのパラメーターをクエリすることもできます。XBOX One ERA や UWP とは異なり、Microsoft Game Development Kit (GDK) ゲームはアクティブ化タイムアウトの対象ではなく、Activated イベント ハンドラーもありません。また、XBOX One ERA や UWP とは異なり、Microsoft Game Development Kit (GDK) ゲームは、アクティブ化や起動パラメーターを使用してゲーム招待を処理しません。代わりに、ゲーム招待を処理する必要がある Microsoft Game Development Kit (GDK) ゲームは、`XGameInviteRegisterForEvent` を使用してこれらのイベントに登録する必要があります。ゲームが登録を実行すると、利用可能な保留中の招待を取得します。

<br />

<a id="events-related-to-life-cycle" />

## ライフ サイクルに関連するイベント

これらのイベントは実際にはライフ サイクル イベントではありません。それらは、状態遷移の原因と条件に関連するイベントです。これらを特定してそれに応じて対応する方法を判断するのに役立ちます。

#### 入力フォーカス

ゲームに入力フォーカスがあるかどうかを知るには、Microsoft Game Development Kit (GDK) ゲームは `WindowProc` コールバックで `WM_ACTIVATEAPP` ウィンドウ通知をリッスンできます。これは Win32 の Windows PC 実装と同じで、同じドキュメントが適用されます。詳細については、[WM\_ACTIVATEAPP メッセージ](https://learn.microsoft.com/windows/win32/winmsg/wm-activateapp)を参照してください。

以下のコード例は、このイベントをリッスンする方法を示しています。

```cpp theme={null}
// Windows procedure.
LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
{
    switch (message)
    {
    case WM_ACTIVATEAPP:
        OutputDebugString((wParam) ? L"Activated\n" : L"Deactivated\n");
        break;
    ...
```

#### 可視性

ゲームのウィンドウが表示されているかどうかを判定するには (入力フォーカスと同様に)、Microsoft Game Development Kit (GDK) ゲームは `WindowProc` コールバックで `WM_SHOWWINDOW` ウィンドウ通知をリッスンできます。詳細については、[WM\_SHOWWINDOW メッセージ](https://learn.microsoft.com/windows/win32/winmsg/wm-showwindow)を参照してください。

以下のコード例は、`WindowProc` コールバックで `WM_SHOWWINDOW` ウィンドウ通知をリッスンする方法を示しています。

```cpp theme={null}
// Windows procedure.
LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
{
    switch (message)
    {
    case WM_SHOWWINDOW:
        OutputDebugString((wParam) ? L"Visible\n" : L"Not Visible\n");
        break;
    ...
```

<br />

<a id="timeouts" />

## GDK タイムアウトの取り扱い

XBOX One ERA および UWP 開発者は、アクティブ化、サスペンド、およびハング検出のためのさまざまなタイムアウトを扱います。Microsoft Game Development Kit (GDK) ゲームは Win32 で設計されており、ほとんどの場合、実行中のゲームで最大のリソースの可用性を確保するためにリソース状態を変更できる必要があるコンソールで実行する場合を除き、同等の概念はありません。次の表は、異なるプラットフォーム間のさまざまな動作を比較しています。

| ハンドラー/タイムアウト | Microsoft Game Development Kit (GDK) | XBOX One ERA | UWP |
| - | - | - | - |
| アクティブ化ハンドラー | 該当なし | `CoreApplicationView:: Activated` | `CoreApplicationView::Activated` |
| アクティブ化タイムアウト | 該当なし | 45 秒 | 10 秒 |
| サスペンド ハンドラー | `RegisterAppStateChangeNotification` | `CoreApplication:: Suspending` | `CoreApplication:: Suspending` |
| サスペンド タイムアウト | 1 秒 | 1 秒 | 5 秒 |
| 再開ハンドラー | `RegisterAppStateChangeNotification` | `CoreApplication:: Resuming` | `CoreApplication:: Resuming` |
| 再開タイムアウト | 該当なし | 該当なし | 該当なし |
| Constrain ハンドラー | `RegisterAppConstrainedChangeNotification` | `CoreApplication:: ResourceAvailabilityChanged` | 該当なし |
| Constrain タイムアウト | 該当なし | 該当なし | 該当なし |
| ハング タイムアウト | 該当なし | 2 秒 | 2 秒 |

<br />

<a id="quick-resume" />

## Quick Resume

Quick Resume は、XBOX Series コンソールの 2020 年 6 月のリカバリの新機能です。別のゲームが実行されている間もゲームをサスペンドしたままにすることで、ユーザーが以前よりも高速にゲーム間を切り替える方法を提供します。すべての XBOX One ファミリー デバイス、および 6 月のリカバリ前の XBOX Series コンソールでは、ゲームが実行中 (または制約または、サスペンド) のとき、ユーザーが新しいゲームを選択すると、最初のゲームは終了し、新しいゲームが起動します。2020 年 6 月のリカバリ以降の XBOX Series コンソールでは、代わりに最初のゲームをサスペンドでき、その後 Game OS 全体とそのメモリをサスペンド状態で保存できます。ユーザーが戻ってくると、Game OS が復元されます。その後、ゲームは再開できます。保存された Game OS は、コンソールの再起動後でも復元できます。ゲームの観点から、これは通常のサスペンド/再開と同じです。追加のステップやコードは必要ありません。ゲームがサスペンドと再開を正常に実行できる場合、Quick Resume も完全にサポートされます。

Quick Resume のため、ゲームが起動セッション内で数百時間実行することが容易になります。ゲームは、数日、数週間、または数か月間サスペンドされたままでいることがあります。つまり、サスペンド前に確立された状態情報 (特にユーザーに関する情報) が、再開時にも真であると想定されないことを確認することが重要です。たとえば、ゲームが深いソーシャル関係を活用している場合、新しい友人が追加されたり、他の友人が削除されたりした可能性があります。友人のプレゼンス情報を使用する場合、彼らが先週していたことがゲームが再開されたときにまったく同じであることはほとんどありません。同様の問題がアクセシビリティの設定、特権、およびリーダーボードにも当てはまります。

<Warning>
  時間の経過とともに簡単に変化する可能性のある状態については、再度クエリすることを確認してください。
</Warning>

<br />

<a id="debugging-tools-and-features" />

## デバッグ ツールと機能

このセクションでは、ゲームのライフ サイクルのデバッグとテストに役立つツール、ログ、および機能のいくつかを説明します。

### ライフ サイクル遷移ツール

デバッグとテストのために、ゲームがどの状態にあるかを知り、ゲームを状態間で遷移させることが重要です。現在のライフ サイクル状態を照会し、状態遷移を実行するために使用できるツールがいくつかあります。[XBOX Manager](/ja-jp/tools/tools-console/xbom/xbom)、[XBOX Device Portal](/ja-jp/tools/tools-console/wdp/wdp)、および [xbapp](/ja-jp/tools/tools-console/commandlinetools/xbapp) コマンド ライン ツールはすべて、アプリケーションの現在の状態をリストします。それらすべてが、さまざまな遷移を実行するためのコマンドを提供します。たとえば、以下のスクリーンショットは XBOX Manager の State および Actions メニューを示しています。

<img src="https://mintcdn.com/microsoft-4404708b/-_0FrcE2bDxzGxv-/images/gdk/lifecycle/xbom-life-cycle-tools.png?fit=max&auto=format&n=-_0FrcE2bDxzGxv-&q=85&s=bca79514d50eceeaaadd88e30150d4fe" alt="XBOX Manager の State および Actions メニューを示すスクリーンショット" width="1024" height="443" data-path="images/gdk/lifecycle/xbom-life-cycle-tools.png" />

<Note>
  より高速な反復時間を提供し、テストの柔軟性をサポートするために、'terminate' コマンドがパッケージ化されていないゲームで使用されると、最初にサスペンドされるのではなく、直接 Not Running 状態に遷移します。ゲームを通常終了される方法で終了するには、まず `suspend` コマンドでサスペンドしてください。
</Note>

実行中からサスペンドへの遷移は、開発キットのフロント パネル ボタンの 1 つを使用してトリガーすることもできます。Microsoft Game Development Kit (GDK) に付属する *Suspend\_Title* スクリプトは、[XBOX Manager](/ja-jp/tools/tools-console/xbom/xbom) または [XBOX Device Portal](/ja-jp/tools/tools-console/wdp/wdp) を使用してフロント パネル ボタンにマップできます。再開状態への遷移はフロント パネル ボタンからトリガーできない点に注意してください。再開は、Home または My games & apps からゲームのタイルを選択するか、[xbApp](/ja-jp/tools/tools-console/commandlinetools/xbapp)、[Visual Studio](/ja-jp/tools/tools-console/visualstudio/debugging-with-visualstudio)、または [XBOX Manager](/ja-jp/tools/tools-console/xbom/xbom) などの別のツールを使用して、コンソールのシェルから行う必要があります。

### xbWatson および Visual Studio での状態遷移ログ

状態遷移がいつ発生するかを知ることは、現在のライフ サイクル状態を知ることと同じくらい重要です。ライフ サイクル状態遷移に対する大幅なログ サポートが、[xbWatson](/ja-jp/tools/tools-console/xbWatson/xbwatson) および Visual Studio 内の XBOX System Monitor ウィンドウに表示されます。現在、状態遷移があるときはいつでも、アプリケーションの起動段階やシステム全体でのフォーカスの変化など、アプリに関連する他のイベントに関する情報とともにログが記録されます。

以下のスクリーンショットは、xbWatson を使用して状態遷移が発生するタイミングを示しています。

<img src="https://mintcdn.com/microsoft-4404708b/-_0FrcE2bDxzGxv-/images/gdk/lifecycle/xbwatson-state-transition-logging.png?fit=max&auto=format&n=-_0FrcE2bDxzGxv-&q=85&s=ce4fb9b46af97e85c05c3c975306cbf4" alt="xbWatson を使用して状態遷移が発生するタイミングを示すスクリーンショット" width="742" height="516" data-path="images/gdk/lifecycle/xbwatson-state-transition-logging.png" />

新しいログ機能には、ライフ サイクル イベントのエラーと失敗も含まれます。このログをチェックすると、何かがうまくいかないタイミングを特定するのに役立ちますし、任意のエラー ケースに関する詳細情報を提供することができます。エラーが発生し `HRESULT` が報告される場合、xberror コマンド ライン ツールをチェックすることで詳細情報を見つけることができます。前のスクリーンショットに示すエラー ケースでは、`xberror` は、タイトルがサスペンド ハンドラー中にタイムアウトした (`E_GAME_SUSPEND_TITLE_TIMEOUT`) ことを示しています。

### サスペンド タイムアウトでのブレーク

2020 年 6 月の Microsoft Game Development Kit (GDK) の新機能は、Visual Studio が Microsoft Game Development Kit (GDK) ゲームをデバッグしている場合、1 秒のタイムアウトによりサスペンドに失敗した場合に自動的にブレークインする機能です。この設定は既定でオフになっています。ただし、以下のスクリーンショットに示すように、プロジェクトのデバッグ プロパティで変更できます。

<img src="https://mintcdn.com/microsoft-4404708b/-_0FrcE2bDxzGxv-/images/gdk/lifecycle/vs-break-on-suspend-timeout.png?fit=max&auto=format&n=-_0FrcE2bDxzGxv-&q=85&s=455bf244914b06fd15d160da94a39317" alt="サスペンド タイムアウトでのブレークを示すスクリーンショット" width="832" height="245" data-path="images/gdk/lifecycle/vs-break-on-suspend-timeout.png" />

このプロパティは、プロジェクトを開いていなくても XBOX Gaming Explorer ウィンドウを使用してインストール済みのゲームに対して変更することもできます。XBOX Gaming Explorer でゲームを選択し、**Properties** ツール ウィンドウで **Break on Suspend Timeout** 設定を変更します。詳細については、[XBOX Gaming Explorer](/ja-jp/tools/tools-console/visualstudio/xbox-gaming-explorer) を参照してください。

これは、ハングがあるか、サスペンド プロセスの一部が予期したよりも長く時間がかかる可能性があるサスペンド失敗のデバッグに最適です。デバッガーは、INT3 を持つ新しいスレッドをゲーム プロセスに挿入してブレークを発生させることでこれを行います。つまり、デバッガーは最初、一見空のスレッドでブレークしますが、他のスレッドは、1 秒のタイムアウトが発生したときにあった場所でブレークされます。Visual Studio でゲームのライフ サイクル状態をデバッグする方法の詳細については、[Visual Studio を使用した XBOX プロジェクトのデバッグ](/ja-jp/tools/tools-console/visualstudio/debugging-with-visualstudio)を参照してください。

<a id="automatic-suspend-failure-dumps" />

### 自動サスペンド失敗ダンプ

サスペンドに失敗するといつでも、自動診断クラッシュ ダンプがコンソールに記録されます。ダンプは開発者ポータルにもアップロードされます。これらのダンプは *D:\LocalDumps\\* にコンソールに保存されます。2020 年 6 月の更新では、[xbWatson](/ja-jp/tools/tools-console/xbWatson/xbwatson) もコンソール上で利用可能なダンプを一覧表示します。また、メニューからダンプをダウンロードするオプションもあります。これらは *quiesce メモリ ダンプ* と呼ばれています。quiesce はサスペンションの別名だからです。以下のスクリーンショットは、コンソール上で利用可能な quiesce メモリ ダンプを示しています。

<img src="https://mintcdn.com/microsoft-4404708b/-_0FrcE2bDxzGxv-/images/gdk/lifecycle/xbwatson-quiesce-memory-dumps.png?fit=max&auto=format&n=-_0FrcE2bDxzGxv-&q=85&s=bc878ec0e3a3f69493b625fb98c86233" alt="コンソール上で利用可能な quiesce メモリ ダンプを示すスクリーンショット" width="940" height="637" data-path="images/gdk/lifecycle/xbwatson-quiesce-memory-dumps.png" />

診断ダンプは、サスペンド コールバック (`PAPPSTATE_CHANGE_ROUTINE`) が呼び出されるはずだったが、登録されたサスペンド ハンドラーがない場合にも作成されます。また、サスペンド ハンドラーを終了する前に `ID3D12CommandQueue::SuspendX` が呼び出されなかった場合にも診断ダンプが作成されます。

### 手動での状態遷移の発生

コンソールとやり取りすることで、各状態遷移を手動でトリガーできます。以下の表は、ツールなしで各状態遷移をトリガーする方法をリストしています (ゲームが遷移のための適切な開始状態にあると仮定)。

| 遷移 | アクション |
| - | - |
| Launch | **Home** または **My games & apps** からゲームのタイルを選択します。 |
| Constrain | コントローラーの **XBOX** ボタンを押して **Guide** を開きます。 |
| Suspend | 電源モードが **Instant-on** に設定されているときにコンソールをオフにします。 |
| Terminate | ゲームのタイルを選択した状態で、コントローラーの **Menu** ボタンを押し、次に **Quit** を選択します。 |
| Resume | **Home** または **My games & apps** からゲームのタイルを選択します。制約解除も避けるには、遷移中に **Guide** を開きます。 |
| Unconstrain | コントローラーの **XBOX** ボタンを押して **Guide** を閉じます。 |

<br />

<a id="appendix" />

## 付録

<a id="xrs" />

### XR の閲覧

#### XR の一覧をダウンロードするには

1. [XBOX Developer Downloads](https://aka.ms/gdkdl) に移動します。
2. ファイル タイプで **Partner, Publishing, and Release Management Information** を選択します。
3. **Confirm** を選択します。
4. ビルド/バージョン番号で、使用しているリリースに一致する XGD Partner Documentation のバージョンを選択します。
5. **Confirm** を選択します。**Download Now** ボタンが表示され、ドキュメントをダウンロードするよう促されます。

### ライフ サイクル イベントの診断テレメトリ

コンソール プラットフォームは、以下の表に示すイベントのテレメトリを送信します。

| イベント | 説明 |
| - | - |
| Launch time | ゲームを開始するために `CreateProcess` が呼び出されてから、ゲームが最初の present 呼び出しを行うまでの時間。 |
| Resume time | ゲーム パーティションが再開されてから、ゲームが次の present を行うまでの時間。 |

<a id="smt-diagrams" />

### SMT が有効な XBOX Series コンソールの CPU リソース図

SMT の詳細については、XBOX One vs. XBOX Series X|S の CPU およびメモリを参照してください。

#### Running

以下の図は、Running ゲームの CPU コアと仮想コア間のマッピングを示しています。

<img src="https://mintcdn.com/microsoft-4404708b/-_0FrcE2bDxzGxv-/images/gdk/lifecycle/cpu-resource-diagram-smt-running.png?fit=max&auto=format&n=-_0FrcE2bDxzGxv-&q=85&s=f74e206f1a1c658a3cfcac5513c9a381" alt="Running ゲームの CPU コアと仮想コア間のマッピングを示す図" width="603" height="135" data-path="images/gdk/lifecycle/cpu-resource-diagram-smt-running.png" />

#### Constrained

以下の図は、Constrained ゲームの CPU コアと仮想コア間のマッピングを示しています。

<img src="https://mintcdn.com/microsoft-4404708b/-_0FrcE2bDxzGxv-/images/gdk/lifecycle/cpu-resource-diagram-smt-constrained.png?fit=max&auto=format&n=-_0FrcE2bDxzGxv-&q=85&s=c479b8f5ea2e3834c68edd7745b0ffe7" alt="Constrained ゲームの CPU コアと仮想コア間のマッピングを示す図" width="593" height="130" data-path="images/gdk/lifecycle/cpu-resource-diagram-smt-constrained.png" />


## Related topics

- [XGameUiShowErrorDialogAsync](/ja-jp/reference/system/xgameui/functions/xgameuishowerrordialogasync.md)
- [XGameUiShowMessageDialogAsync](/ja-jp/reference/system/xgameui/functions/xgameuishowmessagedialogasync.md)
- [XGameUiShowAchievementsAsync](/ja-jp/reference/system/xgameui/functions/xgameuishowachievementsasync.md)
- [XGameUiShowPlayerProfileCardAsync](/ja-jp/reference/system/xgameui/functions/xgameuishowplayerprofilecardasync.md)
- [XGameUiShowSendGameInviteAsync](/ja-jp/reference/system/xgameui/functions/xgameuishowsendgameinviteasync.md)
