Overview
Running a query involves several steps at different points in time:
The Easy Way
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.
The Explicit Way
Starting a Query
Starting a query is comprised of several steps:
- Using a CQueryBlueprintID to specify the query blueprint to instantiate
- Providing runtime parameters that are specific for the query that you want to run
- Providing a callback for when the query finishes
- Checking for errors
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()); } }
Callback
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 (Optional)
Canceling a query can be useful in certain situations:
- The querier is no longer interested in the result of the started query
- The querier is about to go out of scope and needs to clean up the callback provided to the running query
if (UQS::Core::IHub* pHub = UQS::Core::IHubPlugin::GetHubPtr()) { pHub->GetQueryManager().CancelQuery(m_queryID); m_queryID = UQS::Core::CQueryID::CreateInvalid(); }