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
游戏保存错误