XGameSave 기술 개요
XGameSave를 사용하면 사용자가 게임 데이터를 클라우드에 저장할 수 있습니다. 이 주제에서는 저장 데이터가 콘솔과 클라우드 저장소 사이에서 업데이트 또는 동기화될 때 내부적으로 이루어지는 작업을 설명합니다.
XGameSaveSubmitUpdateAsync 동작
XGameSave로 일부 데이터를 저장하고 나중에 클라우드로 저장하려면 데이터 추가, 삭제 또는 업데이트를 위해 XGameSaveSubmitUpdateAsync 메서드를 호출해야 합니다. XGameSaveSubmitUpdateAsync를 호출하면 XGameSaveSubmitBlobWrite 및 XGameSaveSubmitBlobDelete에 의해 호출에 제공된 버퍼가 앱 파티션에서 시스템 파티션의 전용 메모리 공간으로 신속하게 복사됩니다. 시스템 파티션으로 메모리가 성공적으로 복사되면 XGameSaveSubmitUpdateAsync 결과가 반환되며, 데이터를 위해 로컬로 할당한 메모리를 해제해도 좋음을 앱에 나타냅니다.
그러면 시스템이 본체의 하드 드라이브에 blob을 저장하고 해당 컨테이너에서 전체 작업을 커밋하는 최종 컨테이너 업데이트를 통해 작업을 완료합니다.
XGameSaveSubmitUpdateAsync 데이터를 수신하기 위해 공유된 파티션의 메모리에 16MB 한도가 적용됩니다. 전용 16MB 버퍼에 여유 메모리가 충분하지 않아 시스템에서 XGameSaveSubmitUpdateAsync에 대한 호출에 대해 즉각적으로 서비스를 제공할 수 없을 경우에는 호출이 서비스를 받기 위해 대기 상태가 됩니다. 시스템이 데이터를 16 MB 버퍼에서 하드 드라이브로 계속 전송합니다. 대기 중인 업데이트는 16 MB 버퍼에 공간이 마련되는 대로 요청한 순서에 따라 서비스를 받습니다.
업데이트된 데이터가 본체의 하드 드라이브에 복사된 이후에는 XGameSave 시스템에서 이를 선택하여 클라우드에 업로드할 수 있습니다. 이 업로드를 완료하려면 시스템에서 현재 컨테이너 상태의 스냅샷을 가져오고 변경 내용을 클라우드에 업로드합니다. 이 업로드는 게임을 플레이하는 동안 정기적으로, 또는 게임이 일시 중단 또는 종료될 때 발생합니다.
클라우드 업로드 프로세스는 변경된 데이터를 콘솔의 하드 드라이브에 복사하는 것과 비슷합니다. 개별 blob이 서비스에 업로드됩니다. 업로드된 다른 모든 blob을 참조하는 컨테이너 파일에 대한 최종 업데이트를 통해 업데이트 작업이 커밋됩니다. 클라우드에 업로드하는 과정에서 이처럼 단일 최종 업데이트에 통합되면 XGameSaveSubmitUpdateAsync 호출에서 참조된 모든 데이터가 완전히 커밋되거나 컨테이너가 변경되지 않은 상태로 남습니다. 이렇게 하면 업로드 작업 중에 시스템이 오프라인 상태가 되거나 정전이 발생하더라도 사용자가 또 다른 Xbox One 본체로 이동해 클라우드에서 데이터를 다운로드하고 모든 컨테이너를 일관성 있게 보면서 계속 플레이할 수 있습니다.
Important
컨테이너 간 데이터 종속성은 안전하지 않습니다. 개별 XGameSaveSubmitUpdateAsync
호출의 결과는 전체가 적용되거나 아예 적용되지 않도록 보장됩니다.
XGameSaveSubmitUpdateAsync 호출에서 컨테이너를 올바른 상태로 남기기 위해 향후 XGameSaveSubmitUpdateAsync 호출이 성공적으로 완료될 것이라고 가정해서는 안 됩니다. 다시 말해 앱은 두 개 이상의 XGameSaveSubmitUpdateAsync 호출을 사용해 모든 필수 데이터를 컨테이너에 저장할 수 없습니다. 각 XGameSaveSubmitUpdateAsync 호출에서 지정된 컨테이너의 콘텐츠를 올바른 상태로 유지해야만 앱에서 나중에 읽어들일 수 있습니다.
이 문제를 설명하려면 컨테이너가 Bob이라는 캐릭터가 보유하고 있는 골드와 음식의 양을 추적하는 시나리오를 떠올려 보세요. 게임에서는 음식 및 골드라는 2개의 blob을 저장할 수 있습니다. Bob은 100 금 단위로 시작하고, 다음 다이어그램에 표시된 것처럼 인벤토리에 음식 단위가 없습니다.
그림 1. Bob이 100골드로 시작합니다.
이제, Bob이 50 금 단위를 소비한 것입니다. 게임에서 골드 blob의 값을 50으로 업데이트하는 XGameSaveSubmitUpdateAsync 호출을 준비합니다.
시스템에서는 업데이트된 blob과 컨테이너 업데이트에 대한 정보를 업데이트 버퍼에 캡처합니다. 그런 다음, 시스템은 아래 다이어그램과 같이 새 blob 값을 하드 드라이브에 복사합니다.
그림 2. 시스템에서 업데이트된 정보를 캡처하고 하드 드라이브에 값을 복사합니다.
다음 다이어그램에 표시된 것처럼 새 blob을 참조하도록 시스템에서 하드 드라이브의 컨테이너 파일을 업데이트합니다. 결국 가비지 수집 작업으로 참조되지 않은 blob은 제거됩니다.
그림 3. 시스템에서 하드 드라이브에서 컨테이너 파일을 업데이트하고 참조되지 않은 blob을 제거합니다.
참고 항목
XGameSaveSubmitUpdateAsync 호출당 더 많은 blob을 사용할수록 데이터를 견고하게 저장하기 위해 파일 시스템 작업의 필요한 원자성 작업을 완료하는 데 더 많은 시간이 걸립니다. 위의 예제에서는 데이터 저장소의 세분화가 너무 작기는 하지만 하나의 컨테이너에서 여러 blob의 원자성 업데이트 동작을 명확하게 보여 주는 것이 목적입니다.
여러 Blob 업데이트 - 잘못된 방법
Bob이 음식을 사려 하는 시나리오를 상상해 보세요. 1 골드로 음식 한 개를 구매할 수 있는데, Bob은 음식 25개를 구매하고 싶어 합니다.
앱은 하나의 XGameSaveSubmitUpdateAsync 호출을 실행하여 25 단위의 식품을 추가한 다음, 또 다른 호출을 실행하여 Bob_Inventory 컨테이너에서 25 단위의 골드를 뺄 수 있습니다. 모든 XGameSaveSubmitUpdateAsync 호출에 대해 completed 처리기를 발급하더라도 정전 같은 이벤트로 인해 하드 드라이브에 데이터가 기록되지 않거나 클라우드에 대한 동기화가 완료되지 않아 잘못된 결과가 반환될 수 있습니다.
다음 다이어그램은 시스템에서 수행한 단계와 이 단계 중에 정전으로 인해 발생한 결과를 설명합니다.
XGameSaveSubmitUpdateAsync 호출 모두에서 나온 데이터가 이미 시스템의 업데이트 버퍼에 있고, 두 호출 모두에 대해 게임의 완료 처리기가 호출되었다고 가정하세요.
우선, 다음 다이어그램에 표시된 것처럼 시스템에서 식량 blob의 새 값에 대한 데이터를 하드 드라이브에 기록합니다.
그림 4. 시스템이 하드 드라이브에 음식 blob의 값을 기록합니다.
다음으로 시스템이 새로 기록된 값을 참조하도록 컨테이너를 업데이트합니다. 다음 다이어그램에서와 같이 이 단계와 다음 단계 사이에 정전이 발생하면 Bob은 인벤토리에서 상응하는 골드 단위 차감 없이 음식 25개를 얻습니다.
그림 5. 시스템이 새로 기록된 값을 참조하도록 컨테이너를 업데이트합니다.
다음으로, 아래 다이어그램에 표시된 것처럼 시스템에서 금 blob의 새 값에 대한 데이터를 하드 드라이브에 기록합니다. Bob_Inventory 컨테이너에서 참조하는 골드 값은 아직 업데이트되지 않았습니다. Bob에게 있어야 하는 것보다 25개 더 많은 금이 있지만 우리가 원하는 결과에 한 걸음 더 다가갔습니다.
그림 6. 시스템이 하드 드라이브에 골드 blob의 새 값에 대한 데이터를 기록합니다.
마지막으로 다음 다이어그램에 나와 있듯이 시스템이 골드에 대해 새로 기록된 blob을 참조해 원하는 결과에 이르도록 컨테이너 파일을 업데이트합니다.
그림 7. 시스템이 새로 기록된 골드 blob을 참조하도록 컨테이너 파일을 업데이트합니다.
여러 Blob 업데이트 - 올바른 방법
정전으로 인해 중간 상태가 잘못될 가능성 없이 Bob의 인벤토리에서 골드와 음식의 양이 전체적으로 업데이트되도록 하는 적절한 방법은 단일 XGameSaveSubmitUpdateAsync 호출에서 두 blob을 모두 업데이트하는 것입니다. 그러면 시스템이 다음 단계를 수행합니다.
우선, 다음 다이어그램에 표시된 것처럼 시스템에서 식량 blob의 새 값에 대한 데이터를 하드 드라이브에 기록합니다.
그림 8. 시스템이 디스크에 음식 blob의 새 값에 대한 데이터를 기록합니다.
다음으로, 아래 다이어그램에 표시된 것처럼 시스템에서 금 blob의 새 값에 대한 데이터를 하드 드라이브에 기록합니다.
그림 9. 시스템이 디스크에 골드 blob의 새 값에 대한 데이터를 기록합니다.
마지막으로 다음 다이어그램에 나와 있듯이 시스템에서 컨테이너 파일을 업데이트하여 새 blob 2개를 모두 참조합니다.
그림 10. 시스템에서 새 blob을 모두 참조하도록 HDD의 컨테이너 파일을 업데이트합니다.
이 예제가 매우 간단하기는 하지만, 원하는 모든 업데이트와 함께 단일 XGameSaveSubmitUpdateAsync 호출을 발급해 전체적으로 적용해야 하는 모든 수정 사항을 컨테이너의 데이터에 적용해야 하는 중요성을 보여줍니다. 골드로 음식을 구매하는 경우에 이렇게 하면 앱에서 경합 조건이 발생해 값 중 하나만 잘못 업데이트하고 캐릭터에게 너무 많은 골드를 남길 가능성이 방지됩니다.
XGameSave 저장소 공간 동기화
XGameSave
저장소 공간을 동기화할 때 XGameSave
서비스는 다음 4가지 프로세스를 거칩니다.
- 연결 확인
- 잠금 획득
- 컨테이너 목록, 비교, 병합 논리
- 컨테이너 다운로드
앱에서 XGameSave
저장소 공간에 대한 액세스 권한을 요청하면 시스템이 사용자의 저장된 데이터를 Xbox One 본체 간에 일관된 상태로 유지하고 사용자의 데이터를 오프라인 플레이에서도 사용할 수 있도록 하기 위해 동기화 프로세스를 수행합니다.
동기화에 걸리는 시간이 저마다 다르고 사용자가 결정을 해야 할 수도 있기 때문에 시스템에서는 프로세스의 여러 단계에서 사용자에게 UI를 표시할 수 있습니다.
사용자는 동기화 UI가 활성 상태이더라도 언제든지 Xbox 버튼을 눌러 앱에서 벗어날 수 있습니다. 시스템이 UI를 숨기고, 사용자 상호 작용 없이 최대한 길게 동기화가 계속됩니다.
사용자가 앱에 돌아오면 동기화가 완료되지 않은 한 UI가 다시 표시됩니다. UI가 숨겨져 있을 때 시스템은 사용자 선택에 대해 가정을 하지 않습니다.
사용자가 홈 화면에 있을 때 시스템에서 동기화 UI를 표시하지 않고 큰 앱 타일에서 여전히 앱의 렌더링을 볼 수 있기 때문에 XGameSaveInitializeProvider 호출이 완료되는 동안 앱에서 컨텍스트에 따라 적합한 시각 효과를 렌더링하는 것이 중요합니다. 렌더링이 계속된다는 것은 앱이 여전히 대화형이고 데이터가 로드되기를 기다리고 있다는 뜻입니다.
다음 다이어그램은 앱에서 XGameSave
저장소 공간을 요청할 때 시스템이 따르는 상위 수준의 시퀀스를 간략하게 설명합니다.
전체 시퀀스가 몇 초 이상 걸릴 경우 시스템에서 나온 동기화 UI가 표시됩니다.
그림 11. 앱에서 XGameSave 저장소 공간을 요청할 때 시스템에서 따르는 시퀀스입니다.
XGameSaveInitializeProvider 요청 처리 시 시스템은 4개 단계를 거칩니다.
- 연결 확인
- 잠금 획득
- 컨테이너 목록, 비교, 병합 논리
- 컨테이너 다운로드
연결 확인
XGameSaveInitializeProvider 요청에 대해 서비스를 시작하기 위해 시스템이 연결을 확인합니다.
콘솔이 오프라인인 경우 전체 동기화 프로세스는 건너뜁니다. 지정된 사용자에 대한 XGameSave
저장소 공간이 현재 세션에서 오프라인으로 표시됩니다.
수정된 데이터는 다음에 앱이 동일한 사용자의 XGameSave
저장소 공간에 액세스할 때 클라우드 스토리지에 맞게 조정되며, 시스템이 타이틀 저장소 서비스에 연결할 수 있습니다.
이 경우에는 UI가 표시되지 않습니다.
잠금 획득
연결을 확인한 후에 시스템에서는 앱 및 제공된 사용자와 연결된 클라우드 스토리지 공간에 대해 독점적인 액세스 권한을 얻으려 시도합니다.
이를 위해 타이틀 저장소의 XGameSave
저장소 영역에 잠금 파일을 배치하는 방법을 사용합니다.
본체가 온라인 상태이고 서비스에 연결할 수 있으며 짧은 시간 안에 잠금을 획득할 수 있는 경우 UI가 제공되지 않고 동기화 프로세스가 계속됩니다.
시스템에서 특정한 XGameSave
저장소 공간에 대해 잠금을 획득하고 앱에 XGameSave
저장소 공간의 인스턴스를 반환했다면 해당 XGameSave
저장소 공간 내의 데이터에서 작동하는 앱의 API 호출이 성공적인 웹 요청을 차단하지 않습니다.
잠금으로 충분한 보호가 되기 때문에 앱에서 XGameSave
저장소 공간을 획득한 후에 사용자가 시스템에서 네트워크 케이블을 분리할 수 없더라도 API 호출이 로컬에서 사용할 수 있는 데이터를 기반으로 작동합니다.
잠금 획득 단계 중에 가능한 오류 시나리오 몇 가지는 다음과 같습니다.
UI 동기화
본체가 온라인 상태이지만 짧은 시간 안에 서비스에서 잠금을 획득하지 못한 경우 '동기화 중' UI가 표시됩니다.
잠금 끊기
사용자가 현재 본체에서 마지막으로 플레이한 후에 다른 본체에서 앱을 플레이했다면 다른 본체에 저장소 공간에 대한 독점적인 액세스 권한이 있고 데이터 업로드 중일 수 있습니다. 다른 본체에서 데이터 업로드를 시작했지만 완료되기 전에 연결이나 전원이 끊겼을 수도 있습니다.
이 두 경우 모두 잠금 경합이라고 하며, 어떤 경우든 시스템에서 다른 본체가 데이터를 업로드하는 중임을 설명하기 위해 UI를 제공합니다. 사용자는 이 프로세스가 완료될 때까지 기다리거나 현재 클라우드에서 사용할 수 있는 데이터를 사용할 수 있습니다.
사용자가 클라우드 데이터를 사용하겠다고 선택하면 시스템에서 자체적으로 잠금을 가져가고(잠금 중단) 사용자 및 앱의 클라우드 스토리지에 대한 독점적인 액세스 권한을 획득합니다. 다른 본체에서 업로드가 취소되고 동기화 프로세스가 계속 진행됩니다.
컨테이너 목록, 비교, 병합 논리
잠금을 획득한 후에 시스템에서는 지정된 앱 및 사용자에 대해 클라우드에 있는 모든 컨테이너의 목록을 요청합니다. 그리고 나서 시스템은 로컬 하드 드라이브의 내용을 클라우드의 데이터와 비교하고 비교 결과에 따라 다음과 같이 `진행합니다.
클라우드와 일치하는 로컬 데이터
다른 콘솔에서 변경된 내용이 없고 클라우드의 데이터와 로컬 하드 드라이브의 데이터가 똑같다면 동기화가 완료된 것입니다. 이 시점의 결과로 XGameSaveInitializeProvider 반환되고 앱에서 로드와 저장을 진행할 수 있습니다.
로컬 데이터가 없음
클라우드에 데이터가 있지만 로컬 본체에는 없다면 클라우드의 데이터가 로컬로 다운로드됩니다. 이러한 상황은 예를 들어 사용자가 친구의 집에서 처음 플레이할 때 발생합니다.
로컬과 클라우드에서 수정된 동일한 컨테이너
사용자가 다른 본체에서 플레이해 클라우드에 있는 컨테이너를 수정했고 현재 본체를 오프라인에서 사용할 때 같은 컨테이너를 수정했다면 데이터를 자동으로 병합할 수 없습니다. 사용자에게 어떤 데이터를 유지할지 선택하라는 메시지가 표시됩니다. 충돌이 발생할 경우 사용자는 교체 정책을 선택할 수 있습니다. 로컬 데이터나 클라우드 데이터를 항상 유지하거나, 취소를 선택하고 선택을 연기할 수 있습니다. 사용자가 대체 정책으로 클라우드 또는 로컬 데이터를 선택하면 이름은 같지만 내용이 다른 컨테이너가 그에 따라 해결됩니다.
사용자가 취소를 선택하면 게임에서 마치 사용자가 오프라인으로 플레이하고 있는 것처럼 해결되지 않은 상태에서 저장 시스템에 액세스할 수 있습니다.
이 경우에 다음에 앱에서 XGameSave
저장소 공간에 대한 액세스 권한을 요청할 때 본체가 온라인 상태이면 충돌 해결 UI가 다시 한 번 표시됩니다.
컨테이너 다운로드
충돌을 해결하고 나면 시스템에 클라우드에서 어떤 컨테이너를 다운로드해야 할지 식별하는 데 필요한 모든 정보가 마련됩니다. 필요한 모든 컨테이너가 다운로드되고, XGameSaveInitializeProviderResult를 통해 호출되거나 XGameSaveInitializeProviderAsync가 대신 호출된 경우 XGameSaveInitializeProvider에서 결과가 반환됩니다. 그러면 앱에서 로드 및 저장을 계속할 수 있습니다.
컨테이너 다운로드 단계 중에 가능한 오류 시나리오 몇 가지는 다음과 같습니다.
로컬 저장소 부족
필요한 컨테이너에 대해 로컬 하드 드라이브 공간이 부족할 경우 사용자에게 로컬로 저장된 데이터를 제거해 하드 디스크 공간을 마련하라는 UI가 표시됩니다. 클라우드에 백업되지 않은 중요한 데이터가 영구히 삭제되지 않도록 하기 위해 UI는 단순히 로컬 캐시인 데이터와 현재 본체에 고유한 데이터를 확실하게 구분해 표시합니다.
사용자에게 UI가 제공되는 경우 다음과 같이 발생합니다.
사용자가 충분한 공간을 마련하면 동기화가 계속되고 완료됩니다.
사용자가 충분한 공간을 확보하지 않고 UI를 취소하면
XGameSave
초기화 공급자에서 반환되는 값은E_GS_OUT_OF_LOCAL_STORAGE
입니다. 앱에서 사용자가 데이터를 저장하지 못하는 상태에서 플레이하려 한다는 사실을 확인해야 합니다. 사용자가 동의하면 앱이 해당 사용자에 대해 데이터를 저장하지 않고 계속 진행해야 합니다. 사용자가 플레이하는 동안에 데이터를 저장하겠다고 하면 앱이 XGameSaveInitializeProvider 호출을 반복하고 다시 여유 공간을 마련하라는 UI가 표시됩니다.
장치 유형에 따라 게임 저장에 사용할 수 있는 로컬 저장소의 양이 다릅니다.
장치 | 게임 저장을 위한 최대 로컬 스토리지 |
---|---|
개발 키트 | 1 GB |
소매 Xbox One, Xbox One S, Xbox One X | 9GB |
소매 Xbox Series S, Xbox Series X, xCloud | 4GB |
소매 데스크톱 PC | PC의 사용 가능한 공간으로 제한됨 |
사용자가 동기화를 취소함
사용자가 동기화가 완료될 때까지 기다리지 않고 취소를 선택하면 저장된 데이터 중 일부를 사용하지 못한다는 알림을 받습니다. 그러나 게임은 그렇지 않습니다. XGameSaveInitializeProvider 호출의 결과가 반환되고 앱에서 로드 및 저장을 계속할 수 있습니다.
네트워크 시간 제한
네트워크나 서비스 가용성의 문제로 인해 데이터 다운로드 시간이 초과되면 사용자가 동기화를 다시 시도할 수 있는 옵션이 제공됩니다. 사용자가 이 옵션을 선택하지 않으면 저장된 데이터 중 일부를 사용하지 못하고 게임이 누락된 데이터를 인식하지 못한다는 알림을 받습니다. XGameSaveInitializeProvider 호출의 결과가 반환되고 앱에서 로드 및 저장을 계속할 수 있습니다.