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

# Game Saves UI 콜백

> 콜백을 등록하고, 상태 머신을 처리하며, 충돌 및 재시도를 위한 응답 API를 호출하여 PlayFab Game Saves에 대한 사용자 지정 동기화 UI를 구현합니다.

Game Saves는 게임이 동기화 작업 중 이벤트에 응답할 수 있도록 하는 UI 콜백 세트를 제공합니다. XBOX 및 Windows에서는 플랫폼이 이러한 이벤트에 대한 기본 제공 UI를 제공합니다. 다른 플랫폼(예: Steam Deck)에서는 게임이 이러한 콜백을 처리하여 자체 UI를 구현해야 합니다.

XBOX 및 Windows에서 콜백을 설정하면 플랫폼에서 제공하는 UI가 사용자 구현으로 재정의됩니다. 게임이 모든 플랫폼에서 일관된 플레이어 환경을 필요로 하는 경우 유용합니다. 모든 곳에 동일한 콜백을 등록하면 기본 제공 UI가 나타나지 않습니다.

## 상태 머신 작동 방식

Game Saves는 UI 콜백을 비동기 작업 수명 주기와 조정하기 위해 내부 상태 머신을 사용합니다. UI 콜백이 실행되면 비동기 작업이 일시 중지됩니다. 콜백이 해결될 때까지 `XAsyncBlock` 콜백은 실행되지 않습니다. 게임이 해당 응답 API를 호출하거나 비동기 작업이 취소될 때까지 상태 머신은 진행되지 않습니다.

이는 다음을 의미합니다.

* 각 콜백 유형에는 해당하는 응답 API가 있습니다. 다음에 무엇을 할지 시스템에 알리려면 응답 API를 호출하세요.
* 응답 API는 콜백 함수 내부 또는 외부에서 호출할 수 있습니다.
* 응답 액션이 `Retry`인 경우 작업이 재시도되고 동일한 콜백을 다시 트리거할 수 있습니다.
* `XAsyncBlock` 콜백은 작업이 종료 상태(성공, 취소 또는 오프라인 대체)에 도달한 후에만 실행됩니다.

예를 들어, 속도 제한으로 인해 업로드가 실패한 경우:

1. `PFGameSaveFilesUiSyncFailedCallback`이 오류와 함께 실행됩니다.
2. `XAsyncBlock` 콜백은 아직 실행되지 않습니다. 상태 머신이 응답을 기다립니다.
3. 사용자가 `Retry`를 선택하고 재시도도 실패하면 동기화 실패 콜백이 다시 실행됩니다.
4. 사용자가 `Cancel`을 선택하면 `XAsyncBlock` 콜백이 `E_PF_GAMESAVE_USER_CANCELLED`로 실행됩니다.
5. 재시도가 성공하면 `XAsyncBlock` 콜백이 `S_OK`로 실행됩니다.

## 콜백이 트리거되는 시점

UI 콜백은 두 가지 비동기 작업 중에만 실행됩니다.

| 작업 | 트리거할 수 있는 콜백 |
| - | - |
| `PFGameSaveFilesAddUserWithUiAsync` | Progress, Sync Failed, Active Device Contention, Conflict, Out of Storage |
| `PFGameSaveFilesUploadWithUiAsync` | Progress, Sync Failed |

## 콜백 등록

`PFGameSaveFilesAddUserWithUiAsync` 또는 `PFGameSaveFilesUploadWithUiAsync`를 호출하기 전에 모든 콜백을 등록하세요.

```cpp theme={null}
PFGameSaveUICallbacks callbacks{};
callbacks.progressCallback = MyProgressCallback;
callbacks.progressContext = nullptr;
callbacks.syncFailedCallback = MySyncFailedCallback;
callbacks.syncFailedContext = nullptr;
callbacks.activeDeviceContentionCallback = MyActiveDeviceContentionCallback;
callbacks.activeDeviceContentionContext = nullptr;
callbacks.conflictCallback = MyConflictCallback;
callbacks.conflictContext = nullptr;
callbacks.outOfStorageCallback = MyOutOfStorageCallback;
callbacks.outOfStorageContext = nullptr;

HRESULT hr = PFGameSaveFilesSetUiCallbacks(&callbacks);
```

## 콜백 참조

### Progress

업로드 또는 다운로드 진행 상황을 보고합니다. 콜백 내부에서 `PFGameSaveFilesUiProgressGetProgress`를 사용하여 현재 `PFGameSaveFilesSyncState`, 완료된 바이트 및 전체 바이트를 검색합니다.

**콜백**: `PFGameSaveFilesUiProgressCallback`

**응답 API**: `PFGameSaveFilesSetUiProgressResponse`

| 액션 | 효과 |
| - | - |
| `Cancel` | 작업을 취소합니다. `XAsyncBlock` 콜백이 `E_PF_GAMESAVE_USER_CANCELLED`로 실행됩니다. |

> [!NOTE]
>
> 진행률 콜백은 계속 진행하기 위해 응답이 필요하지 않습니다. 작업은 자체적으로 계속 진행됩니다. 사용자가 취소하려는 경우에만 응답 API를 호출하세요.

#### 동기화 상태

`PFGameSaveFilesSyncState` 열거형은 작업이 어느 단계에 있는지를 나타냅니다.

| 상태 | 설명 | 세이브 폴더에 써도 안전한지 여부 |
| - | - | - |
| `NotStarted` | 작업이 시작되지 않음 | 예 |
| `PreparingForDownload` | 클라우드에서 다운로드 준비 중 | 예 |
| `Downloading` | 클라우드에서 다운로드 중 | 아니요 |
| `PreparingForUpload` | 로컬 파일 읽기 및 압축 중 | 아니요 |
| `Uploading` | 클라우드로 업로드 진행 중(로컬 파일 캡처됨) | 예 |
| `SyncComplete` | 작업 완료 | 예 |

### Sync failed

예를 들어 네트워크 문제나 속도 제한으로 인해 동기화 작업이 실패할 때 실행됩니다.

**콜백**: `PFGameSaveFilesUiSyncFailedCallback`

**매개 변수**: `PFGameSaveFilesSyncState`(실패한 단계)와 `HRESULT`(오류 코드)를 받습니다.

**응답 API**: `PFGameSaveFilesSetUiSyncFailedResponse`

| 액션 | 효과 |
| - | - |
| `Cancel` | 작업을 취소합니다. `XAsyncBlock` 콜백이 `E_PF_GAMESAVE_USER_CANCELLED`로 실행됩니다. |
| `Retry` | 실패한 작업을 재시도합니다. 재시도가 실패하면 이 콜백이 다시 실행됩니다. |
| `UseOffline` | `PFGameSaveFilesAddUserWithUiAsync` 중에만 유효합니다. `XAsyncBlock` 콜백이 `S_OK`로 실행되지만 시스템은 오프라인 모드로 진입합니다. 이 상태를 감지하려면 `PFGameSaveFilesIsConnectedToCloud()`를 사용하세요. |

오프라인 모드 동작에 대한 자세한 내용은 [Game Saves 오프라인 모드](https://docs.xbox.com/ko/services/playfab/player-progression/game-saves/offline.md)를 참조하세요.

### Active device contention

이 사용자에 대해 다른 디바이스가 이미 활성 디바이스인 경우 `PFGameSaveFilesAddUserWithUiAsync` 중에 실행됩니다. 콜백은 로컬 및 원격 세이브 데이터 모두에 대한 `PFGameSaveDescriptor` 구조체를 받으며, 여기에는 사용자의 결정을 돕기 위해 표시할 수 있는 디바이스 이름, 타임스탬프 및 세이브 크기가 포함됩니다.

**콜백**: `PFGameSaveFilesUiActiveDeviceContentionCallback`

**응답 API**: `PFGameSaveFilesSetUiActiveDeviceContentionResponse`

| 액션 | 효과 |
| - | - |
| `Cancel` | 작업을 취소합니다. `XAsyncBlock` 콜백이 `E_PF_GAMESAVE_USER_CANCELLED`로 실행됩니다. |
| `Retry` | 재시도합니다. 사용자가 다른 디바이스가 곧 해제될 것으로 예상하는 경우 유용합니다. 다른 디바이스가 여전히 활성 상태이면 이 콜백이 다시 실행됩니다. |
| `SyncLastSavedData` | 로컬 디바이스를 활성화하고 동기화합니다. 원격 디바이스는 더 이상 업로드할 수 없으며 활성 디바이스 변경 알림을 받습니다. |

활성 디바이스 동작에 대한 자세한 내용은 [Game Saves 활성 디바이스 변경](https://docs.xbox.com/ko/services/playfab/player-progression/game-saves/activedevicechanges.md)을 참조하세요.

### Conflict

로컬 세이브 데이터와 클라우드 세이브 데이터가 서로 달라진 경우 `PFGameSaveFilesAddUserWithUiAsync` 중에 실행됩니다. 콜백은 로컬 및 원격 세이브 데이터 모두에 대한 `PFGameSaveDescriptor` 구조체를 받습니다.

**콜백**: `PFGameSaveFilesUiConflictCallback`

**응답 API**: `PFGameSaveFilesSetUiConflictResponse`

| 액션 | 효과 |
| - | - |
| `Cancel` | 작업을 취소합니다. `XAsyncBlock` 콜백이 `E_PF_GAMESAVE_USER_CANCELLED`로 실행됩니다. |
| `TakeLocal` | 로컬 세이브 데이터를 유지하고 클라우드에 업로드합니다. |
| `TakeRemote` | 로컬 변경 사항을 버리고 클라우드 세이브 데이터를 다운로드합니다. |

> [!NOTE]
>
> 충돌 해결은 개별 파일이나 폴더가 아니라 세이브 전체에 적용됩니다. 원자 단위 수준에서 충돌이 감지되고 전역적으로 해결되는 방식에 대한 자세한 내용은 [Game Saves 충돌](https://docs.xbox.com/ko/services/playfab/player-progression/game-saves/conflicts.md)을 참조하세요.

### Out of storage

로컬 디바이스에 클라우드에서 세이브 데이터를 다운로드할 디스크 공간이 충분하지 않은 경우 `PFGameSaveFilesAddUserWithUiAsync` 중에 실행됩니다. 콜백은 필요한 공간을 나타내는 `requiredBytes`를 받습니다.

**콜백**: `PFGameSaveFilesUiOutOfStorageCallback`

**응답 API**: `PFGameSaveFilesSetUiOutOfStorageResponse`

| 액션 | 효과 |
| - | - |
| `Cancel` | 작업을 취소합니다. `XAsyncBlock` 콜백이 `E_PF_GAMESAVE_USER_CANCELLED`로 실행됩니다. |
| `Retry` | 사용자가 로컬 저장 공간을 확보한 후 재시도합니다. 여전히 공간이 충분하지 않으면 이 콜백이 다시 실행됩니다. |

## In-process 및 Out-of-process(시스템 UI) 비교

Game Saves가 실행되는 위치는 플랫폼에 따라 다르며, 이는 UI 이벤트가 처리되는 방식에 영향을 줍니다.

* **Out-of-process(XBOX 및 Windows)**: XBOX와 Windows에서 Game Saves는 항상 out-of-process로 실행됩니다. 플랫폼(Connected Storage / GRTS)이 동기화를 수행하고 동기화 실패, 충돌, 활성 디바이스 경합 및 저장 공간 부족에 대한 기본 제공 시스템 UI 대화 상자를 제공합니다. 플레이어는 해당 대화 상자와 직접 상호 작용하며, 플랫폼은 그 결과를 게임이 in-process에서 받는 것과 동일한 비동기 완료 코드로 변환합니다. 기본 제공 UI를 대체하기 위해 여전히 콜백을 등록할 수 있습니다.
* **In-process(Steam Deck 같은 기타 플랫폼)**: 플랫폼 서비스를 사용할 수 없는 경우 게임이 Game Saves 동기화 엔진을 호스트하고 위에서 설명한 콜백을 통해 UI 이벤트를 처리합니다. 게임이 응답 API를 사용하여 상태 머신을 완전히 구동합니다.

### 취소는 항상 가능한 결과입니다

경로와 관계없이 **모든** UI 흐름은 동기화가 성공하지 않은 채 사용자가 취소하는 것으로 끝날 수 있으므로, 게임은 항상 종료 취소를 처리해야 합니다.

| 사용자 의도 | 비동기 완료 | `IsConnectedToCloud()` | 세이브 폴더 여부 |
| - | - | - | - |
| 온라인으로 계속(성공) | `S_OK` | `true` | 예 |
| 오프라인으로 플레이 | `S_OK` | `false` | 예 |
| 취소/종료(플레이어) | `E_PF_GAMESAVE_USER_CANCELLED`(`0x800704C7`) | 해당 없음 | **아니요** |
| 취소(게임이 `XAsyncCancel` 호출) | `E_ABORT`(`0x80004004`) | 해당 없음 | **아니요** |

플레이어가 계속 플레이할 수 있는 유일한 "취소" 액션은 동기화 실패 프롬프트의 **Use Offline**(성공 결과)입니다. 그 밖의 모든 Cancel은 종료 결과이며 세이브 폴더를 남기지 않습니다. *플레이를 허용하지 않음*으로 처리하세요. [Game Saves 오프라인 모드](https://docs.xbox.com/ko/services/playfab/player-progression/game-saves/offline.md#when-game-saves-enters-offline-mode-or-returns-an-error)를 참조하세요.

기본 제공(out-of-process) 시스템 UI에서는 이러한 선택지가 플랫폼 문구로 표시됩니다. 예를 들어 동기화 실패 대화 상자는 **"Try again"** / \*\*"Play offline"\*\*을, 경합 대화 상자는 **"Stop sync & continue"** / \*\*"Quit game"\*\*을 제공합니다. "Play offline"은 오프라인 모드(`S_OK`, 연결되지 않음)에 해당하고, "Quit game"은 `E_PF_GAMESAVE_USER_CANCELLED`에 해당합니다.

**충돌** 프롬프트를 취소하는 것은 두 경로 모두에서 종료 결과입니다. `E_PF_GAMESAVE_USER_CANCELLED`로 완료되며 동기화 실패 프롬프트로 이어지지 않습니다.

사용자 지정 크로스 플랫폼 UI(예: Steam Deck 구현과 일치시키는 경우)를 사용하려면 모든 곳에 콜백을 등록하고 대상 하드웨어에서 out-of-process 흐름을 검증하세요. 경로와 관계없이 완료 결과에 따라 플레이를 제어하세요. `S_OK` + 연결됨 → 온라인으로 플레이, `S_OK` + 연결되지 않음 → 오프라인으로 플레이(플레이어에게 경고), 폴더 없이 취소/실패 → 플레이 차단.

## 플랫폼 요구 사항

| 플랫폼 | UI 콜백 |
| - | - |
| **XBOX 및 Windows** | 선택 사항입니다. 기본 제공 UI를 재정의하려면 콜백을 설정하세요. |
| **기타 플랫폼**(예: Steam Deck) | **필수**입니다. 기본 제공 UI가 없으므로 게임이 모든 콜백을 처리해야 합니다. |

Steam Deck 구현에 대한 자세한 내용은 [Steam Deck 구현 가이드](https://docs.xbox.com/ko/services/playfab/player-progression/game-saves/steam-deck-implementation.md)를 참조하세요.

## 관련 콘텐츠

* [Game Saves 빠른 시작](https://docs.xbox.com/ko/services/playfab/player-progression/game-saves/quickstart.md)
* [Game Saves 오프라인 모드](https://docs.xbox.com/ko/services/playfab/player-progression/game-saves/offline.md)
* [Game Saves 충돌](https://docs.xbox.com/ko/services/playfab/player-progression/game-saves/conflicts.md)
* [Game Saves 활성 디바이스 변경](https://docs.xbox.com/ko/services/playfab/player-progression/game-saves/activedevicechanges.md)


## Related topics

- [Game Saves 빠른 시작](https://docs.xbox.com/ko/services/playfab/player-progression/game-saves/quickstart.md)
- [Game Saves 오류 처리 FAQ](https://docs.xbox.com/ko/services/playfab/player-progression/game-saves/error-handling-faq.md)
- [PlayFab Game Saves용 Steam Deck 구현 가이드](https://docs.xbox.com/ko/services/playfab/player-progression/game-saves/steam-deck-implementation.md)
- [Game Saves 오프라인 모드](https://docs.xbox.com/ko/services/playfab/player-progression/game-saves/offline.md)
- [PFGameSaveFilesSetUiCallbacks](https://docs.xbox.com/ko/services/playfab/api-references/c/pfgamesavefilesui/functions/pfgamesavefilessetuicallbacks.md)
