XGameSaveReadBlobDataAsync
XGameSaveContainer から XGameSaveBlob データを非同期に読み取ります。
構文
HRESULT XGameSaveReadBlobDataAsync(
XGameSaveContainerHandle container,
const char** blobNames,
uint32_t countOfBlobs,
XAsyncBlock* async
)
パラメーター
container _In_
型: XGameSaveContainerHandle
gamesave BLOB データを保持するコンテナー。
blobNames_In_opt_z_count_(countOfBlobs)
型: char**
XGameSaveBlob の名前を表す文字列の配列へのポインター。
countOfBlobs_In_
型: uint32_t
読み取る BLOB の数。
async _In_
型: XAsyncBlock*
XGameSaveReadBlobDataAsync の呼び出しに対するコンテキストとコールバック関数が格納されている AsyncBlock。
戻り値
型: HRESULT
関数の結果です。
解説
結果とデータは、XGameSaveReadBlobDataResult 関数でキャプチャされます。 XGameSaveReadBlobDataResult では、コンテナー内の BLOB の数と BLOB データ自体が返されます。 この関数には、XGameSaveReadBlobData という名前の同期バージョンがあります。
// ASYNC Read - can be kicked off from a time sensitive thread
// actual work and completion will be scheduled based upon
// the configuration of the async_queue tied to the XAsyncBlock
void Sample::_ReadContainerBlobsAsync(const XGameSaveContainerInfo* container)
{
const char* blobNames[] = {
"WorldState",
"PlayerState",
"PlayerInventory"
};
struct LoadContext
{
LoadContext(Sample* s) : container(nullptr), self(s) {}
~LoadContext()
{
XGameSaveCloseContainer(container);
}
XAsyncBlock async;
XGameSaveContainerHandle container;
Sample* self;
};
HRESULT hr;
LoadContext* loadContext = new LoadContext(this);
if (loadContext == nullptr)
{
hr = E_OUTOFMEMORY;
}
auto completionCallback = [](XAsyncBlock* async)
{
auto ctx = reinterpret_cast<LoadContext*>(async->context);
auto self = ctx->self;
size_t allocatedSize;
XGameSaveBlob* blobData = nullptr;
uint32_t blobCount = 0;
HRESULT hr = GetAsyncStatus(async, false);
if (SUCCEEDED(hr))
{
// use local wrapper for GetAsyncResultSize to give strongly typed alloc
XGameSaveBlob* blobData = _AllocAsyncResult<XGameSaveBlob>(async, &allocatedSize);
if (blobData == nullptr)
{
hr = E_OUTOFMEMORY;
}
}
if (SUCCEEDED(hr))
{
// now that we have allocated the required buffers
// ask XGameSave to populate them
hr = XGameSaveReadBlobDataResult(async, allocatedSize, blobData, &blobCount);
}
if (SUCCEEDED(hr))
{
if (blobCount == _countof(blobNames))
{
for (uint32_t i = 0; i < blobCount; i++)
{
XGameSaveBlob* currentBlob = blobData + i;
if (strcmp(currentBlob->info.name, "WorldState") == 0)
{
hr = self->_LoadSaveBlob(currentBlob, self->_worldState);
}
else if (strcmp(currentBlob->info.name, "PlayerState") == 0)
{
hr = self->_LoadSaveBlob(currentBlob, self->_playerState);
}
else if (strcmp(currentBlob->info.name, "PlayerInventory") == 0)
{
hr = self->_LoadSaveBlob(currentBlob, self->_playerInventory);
}
if (FAILED(hr))
{
break;
}
}
}
else
{
// what containers are missing? Can we get by without XXX?
hr = E_UNEXPECTED;
}
}
self->_HandleContainerBlobErrors(hr);
if (blobData != nullptr)
{
// we own the buffer so better kill it
free(blobData);
}
// be sure to clear this since it will be no longer valid after we exit
self->_asyncLoad = nullptr;
// kill the temp context tracking the async op
delete ctx;
};
if (SUCCEEDED(hr))
{
loadContext->async.context = loadContext;
// set the XTaskQueueHandle so the completion will be done on our thread
// and then we can allocate the larger buffers with less lock contention
loadContext->async.queue = _asyncCompleteQueue;
loadContext->async.callback = completionCallback;
}
hr = XGameSaveCreateContainer(_provider, container->name, &loadContext->container);
if (SUCCEEDED(hr))
{
hr = XGameSaveReadBlobDataAsync(loadContext->container, blobNames, _countof(blobNames), &loadContext->async);
}
if (SUCCEEDED(hr))
{
// keep a reference to this so we can Cancel later if needed
_asyncLoad = &loadContext->async;
// hand over ownership to the async callback
loadContext = nullptr;
}
if (loadContext)
{
delete loadContext;
}
if (FAILED(hr))
{
_HandleContainerBlobErrors(hr);
}
}
// Allocate a strongly typed portion from an Async Result
template<typename T>
static T* _AllocAsyncResult(XAsyncBlock* async, size_t* allocatedSize)
{
*allocatedSize = 0;
size_t allocSize = 0;
HRESULT hr = XAsyncGetResultSize(async, &allocSize);
if (SUCCEEDED(hr) && allocSize > 0)
{
*allocatedSize = allocSize;
return reinterpret_cast<T*>(malloc(allocSize));
}
return nullptr;
}
/*static*/
DWORD Sample::_CompleteThreadProc(PVOID context)
{
auto self = reinterpret_cast<Sample*>(context);
while (DWORD wait = WaitForSingleObjectEx(self->_shutdownEvent, INFINITE, TRUE) == WAIT_IO_COMPLETION)
{
// loop waiting for APC, any other return should exit the thread
}
}
// Init thread and async queue
HRESULT Sample::_InitQueueThread()
{
HRESULT hr = S_OK;
_shutdownEvent = CreateEvent(nullptr, TRUE, FALSE, nullptr);
if (_shutdownEvent == nullptr)
{
hr = HRESULT_FROM_WIN32(GetLastError());
}
if (SUCCEEDED(hr))
{
_completeThread = CreateThread(nullptr, 0, _CompleteThreadProc, this, 0, &_completeThreadId);
if (_completeThread == nullptr)
{
hr = HRESULT_FROM_WIN32(GetLastError());
}
}
if (SUCCEEDED(hr))
{
hr = XTaskQueueCreate(XTaskQueueDispatchMode::ThreadPool, XTaskQueueDispatchMode::Manual, &_asyncCompleteQueue);
}
return hr;
}
void Sample::_CancelReadContainerBlobsAsync()
{
if (_asyncLoad)
{
XAsyncCancel(_asyncLoad);
}
}
要件
ヘッダー: XGameSave.h
ライブラリ: xgameruntime.lib
サポートされているプラットフォーム: Windows、Xbox One ファミリー本体、Xbox Series 本体
関連項目
XGameSave
XGameSaveBlobInfo
XGameSaveReadBlobDataResult
XGameSaveReadBlobData
ゲームのセーブ エラー