Running a query involves several steps at different points in time:
If you don't care too much about the internal details such as the book-keeping of the running status and the setup of a callback of a query, then here's some good news: as of release 5.4 we added 2 helper classes that do most work for you.
UQS::Client::CQueryHost
UQS::Client::CQueryHostT<>
All you need to do is keep an instance of this class and start a query on it whenever you wish to. This class allows for polling or notification (once a query finishes) so that you can pick up the resulting items from it.
Starting a query is comprised of several steps:
Here's an example of how the code to start a single query could look like:
if (UQS::Core::IHub* pHub = UQS::Core::IHubPlugin::GetHubPtr())
{
// this is the query blueprint that we want to instantiate
const char* szQueryBlueprintName = "HideFromEnemy";
//
// find the blueprint ID of the query blueprint that we want to start (we could also cache the CQueryBlueprintID and re-use it at any time)
//
const UQS::Core::CQueryBlueprintID blueprintID = pHub->GetQueryBlueprintLibrary().FindQueryBlueprintIDByName(szQueryBlueprintName);
assert(blueprintID.IsOrHasBeenValid());
//
// runtime params
//
UQS::Shared::CVariantDict runtimeParams;
runtimeParams.AddOrReplaceFromOriginalValue("actor", self);
//
// make a query request and start it
//
UQS::Client::SQueryRequest queryRequest(blueprintID, runtimeParams, "Human_1", functor(*this, &CMyGame::OnUQSQueryFinished));
UQS::Shared::CUqsString error;
const UQS::Core::CQueryID queryID = pHub->GetQueryManager().StartQuery(queryRequest, error);
//
// check for errors (e. g. missing runtime parameters)
//
if (!queryID.IsValid())
{
// oops
CryWarning(VALIDATOR_MODULE_GAME, VALIDATOR_WARNING, "UQS: failed to start query '%s': %s", queryRequest.queryBlueprintID.GetQueryBlueprintName(), error.c_str());
}
}
Once the query finishes, it will use the callback provided by the earlier SQueryRequest to notify of its result:
void CMyGame::OnUQSQueryFinished(const UQS::Core::SQueryResult& queryResult)
{
const bool bSuccess = (queryResult.status == UQS::Core::SQueryResult::EStatus::Success);
// Notice: success doesn't guarantee that any items were found (the result set might very well be empty!) - it only means that no unexpected runtime errors occurred)
if (bSuccess)
{
const UQS::Shared::CTypeInfo& itemType = queryResult.pResultSet->GetItemFactory().GetItemType();
// sanity check: expect Vec3 as items (Careful: this assumes that the query actually produces Vec3 items!)
if (itemType == UQS::Shared::SDataTypeHelper<Vec3>::GetTypeInfo())
{
const size_t numFoundItems = queryResult.pResultSet->GetResultCount();
if (numFoundItems > 0)
{
// run through all found items
for (size_t i = 0; i < numFoundItems; ++i)
{
const Vec3* pItem = static_cast<const Vec3*>(queryResult.pResultSet->GetResult(i).pItem);
// ... do something with the retrieved item ...
}
}
}
}
else
{
// an unexpected runtime error occurred (e. g. the query's reasoning space got corrupted)
UQS::Shared::CUqsString queryIdAsString;
queryResult.queryID.ToString(queryIdAsString);
CryWarning(VALIDATOR_MODULE_GAME, VALIDATOR_WARNING, "CMyGame::OnUQSQueryFinished: query #%s ended up with an error: %s", queryIdAsString.c_str(), queryResult.error);
}
}
Canceling a query can be useful in certain situations:
if (UQS::Core::IHub* pHub = UQS::Core::IHubPlugin::GetHubPtr())
{
pHub->GetQueryManager().CancelQuery(m_queryID);
m_queryID = UQS::Core::CQueryID::CreateInvalid();
}