This feature is still in beta and subject to constant change. We encourage you to use it in test projects and provide your feedback to us.
However, DO NOT use it in production where it creates dependencies! Always back up your projects to make sure that you can go back to a previous version.
The Universal Query System (UQS) is a system for undertaking spatial queries in a 3D world.
In a nutshell, the UQS allows to query items, rank and filter them and then return the best 'N' resulting items.
Over time it is intended that the UQS will supersede the Tactical Point System (TPS) of the CryAISystem.
In the TPS, queries are geared around so-called 'tactical points' which are basically positions in the world that are specific to the CryAISystem's object model.
UQS continues to support this concept, but at the same time expands on the idea of 'tactical points' and their context by breaking free from some of their restrictions and to also provide new features. Ultimately, the UQS aims to be a generic system that lends itself well to any new game project with very specific requirements for spatial reasoning.
Some of the main features that the UQS has been specifically designed for:
There are 4 main parts that comprise a query:
Items: Are used to represent the reasoning space that a query is working on. Simply speaking, a query will evaluate a set of items to work out the fitness of each item. Also, they are used as input parameters and return values in functions.
Functions: When called, act as input parameters for generators, evaluators and functions themselves. Also, functions can be used to convert between item types or to mix in some custom logic before propagating their return value to the caller.
Generators: Are responsible for generating items. Their purpose is to create the reasoning space via a set of items that will be evaluated by a query. For example, a generator could create a set of points in a grid-like layout.
Evaluators: Come in 2 flavors: InstantEvaluators and DeferredEvaluators. Both kinds are responsible to "evaluate" an item they have been passed. More precisely, their purpose is to either give the item a score between 0 and 1 (to express the fitness of that item) or to simply discard the item in case it doesn't meet a specific condition.
The difference between both kinds of evaluators is:
InstantEvaluators must return their evaluation outcome immediately. They lend themselves well for undertaking quick calculations. A typical use case would be to qualify the distance between 2 points given a reference distance.
DeferredEvaluators are free to run over time and return their outcome once they have finished processing the item. Whether they do time-sliced work or offload the actual work to a different system is up to them. From the query's point of view, it's only relevant that they are periodically updated until they come up with a result. A typical use case would be to start an asynchronous physics raycast between 2 points and wait until the raycast request has been fulfilled.
As mentioned above, evaluators are responsible for scoring an item. Generally speaking, each evaluator in a query will be asked to evaluate each generated item. Their scores will then be added together to form the overall score of that item. To allow a little more control over the individual scoring by a single evaluator, each evaluator comes with a weight that the score will be multiplied by before its added to the overall score.
The overall score of an item will be used to work out what the best 'N' items are to return in the final result set of a query.
For more technical information on how to work with these features, then see the following pages:
UQS::Client::CQueryHost
, UQS::Client::CQueryHostT<>.
UQS::DataSource_XML::CXMLDataSource
.Old namespaces:
New namespaces:
Due to the introduction of GUIDs and coder-defined comments in all of the UQS elements, then the way how factories for generators, functions, evaluators, etc. get registered has changed. Before, it was mainly about creating a global instance of that factory with a list of parameters as constructor arguments. Now all the parameters get bundled in a struct.
Old way (this will no longer compile):
static const UQS::Client::CGeneratorFactory<CGenerator_PointsOnPureGrid> generatorFactory_PointsOnPureGrid("std::PointsOnPureGrid");
New way:
UQS::Client::CGeneratorFactory<CGenerator_PointsOnPureGrid>::SCtorParams ctorParams;
ctorParams.szName = "std::PointsOnPureGrid";
ctorParams.guid = "498bce51-a2b9-4e77-b0f9-e127e8a5cc72"_uqs_guid;
ctorParams.szDescription =
"Generates points on a grid.\n"
"The grid is specified by a center, size (of one edge) and a spacing between the points.\n"
"Notice: this generator is very limited and doesn't work well if you intend to use it for things like uneven terrain.";
static const UQS::Client::CGeneratorFactory<CGenerator_PointsOnPureGrid> generatorFactory_PointsOnPureGrid(ctorParams);
It's also possible to use C++11 lambda expressions:
static const UQS::Client::CGeneratorFactory<CGenerator_PointsOnPureGrid> generatorFactory_PointsOnPureGrid(
[]()
{
UQS::Client::CGeneratorFactory<CGenerator_PointsOnPureGrid>::SCtorParams ctorParams;
ctorParams.szName = "std::PointsOnPureGrid";
ctorParams.guid = "498bce51-a2b9-4e77-b0f9-e127e8a5cc72"_uqs_guid;
ctorParams.szDescription =
"Generates points on a grid.\n"
"The grid is specified by a center, size (of one edge) and a spacing between the points.\n"
"Notice: this generator is very limited and doesn't work well if you intend to use it for things like uneven terrain.";
return ctorParams;
}()
);
Vec3
has been replaced by Pos3
, Ofs3
and Dir3
. Functions, generators and evaluators using the old data type have been adjusted accordingly.std::Vec3 Vec3Add ( std::Vec3 v1, std::Vec3 v2 )
has been superseded by std::Pos3 Pos3AddOfs3 ( std::Pos3 pos, std::Ofs3 ofs )
.