Is there any way for EQS to Share Results?

Hi, I’ve only just started using EQS, having gone through the Runner tutorial. If my initial exploration of the end result is accurate there does not appear to be any way of “sharing” the result data between multiple Characters (Actors) as each has its own Query & results data.

How well does EQS scale to large numbers of agents? For example, the Runner generates approx 170 node points, then does two raycasts to every node point (from player and from runner), plus a load of distance checks. In the example given, this query only runs when needed, but what if the game was more fluid and this check needed to run multiple times per second (or once per frame)? What if, instead of one Runner, we had a dozen, or a hundred? Does EQS just stall, or does it deal with the load?

To flip the question round, is there any way for the results to be shared between agents. For example, rather than calculating points from the perspective of the Runner, of which there may be multiple instances running around, we could calculate points from the perspective of the Player (of which there should only be 1). This, obviously, only works if the Player can then “publish” these results in a form that is usable by each Runner.

Is this currently possible?

1 Like

Hi Stuart,

Sean’s answer is not quite correct. It very nicely shows how to use EQS in the most common way, but there’s a lot more to EQS than that.

There are means of reusing EQS results both in C++ and BP. In C++ we store FEnvQueryInstance with shared pointers, so you can easily reuse the result by simply storing the shared pointer you get when your “on query done” handler gets called.

In BP you use the RunEQSQuery function, which returns a special FEnvQueryInstance wrapper object, that can be stored and shared.

The part that’s missing is sharing the results, but that’s pretty simple and implementation details depend on your AI setup.

One last comment is EQS scales really well and is only as expensive as the queries you create and number of queries you spawn. I mean, there’s nothing we can do if you want to test line-of-sight to 10000 points. But if you want a single LoS-visible point from that set, that is within a certain distance and angle of given actor, the we do the cheap things first, and we’ll give you the first item that passes the expensive (LoS) test. EQS is smart that way, by design.

Also, EQS is time-sliced, meaning it has a fixed time budget and work that’s not done within that budget gets postponed till next frame. Currently this time budged is hardcoded to 0.01s (see UEnvQueryManager::Tick), but we are going to expose that in the future.

Let me know if you have any further questions regarding this.

Cheers,

–mieszko

1 Like

Hello,

EQS does not scale well when running many instances of it. It has been known to negatively affect performance. However, you can definitely set a key in another controller using an EQS that is run in a single instance of the original controller.

First, create your AI Controller, Behavior Tree, and Blackboard that you want to use to run your EQS. What I did was create an AI Character specifically to run the EQS. This can even be an empty actor if you so desire, because its sole purpose is to run the EQS to set the value that we are looking for, which in my case is TargetPlayer. Ensure that you run your Behavior Tree in your AI Controller.

Then, create your EQS. I am looking for TargetPlayer, which is looking for a TopDownCharacter.

Once you have your initial EQS set up, run it in your Behavior Tree.

Now that you’ve gotten the value of TargetPlayer, we need to pass this to another AI Controller, which will be the one that we use for our actual AI Characters. So go ahead and create another AI Character, and create and assign it a new AI Controller. I called my second AI Controller PassKeyValueHere. After you have created a new AI Controller, AI Character, Behavior Tree, and Blackboard (ensure that you create a new key to store the value that will be passed in), you can begin to set up the task that passes the value from your original AI Controller (the one running the EQS) to your new AI Controller (i.e. the one that you want to use to control your AI). Go into your original Behavior Tree (the one that is running the EQS) and create a new task.

In this task, I got all instances of the Pass Key Value Here AI Controller (the one that we are using to control our characters) and then ran a ForEachLoop. For each instance of that controller, we go through and set the value of the Player key in Pass Key Value Here’s behavior tree. In order to do this, we get the blackboard of the AI Controller that is running the EQS, and then get the value of the TargetPlayer key. We then use this value to set the value of the Player key in the other AI Controller.

Finally, we need to run this task in the Behavior Tree.

Also, if you are unsure of how to set the key value as I have done in the Task, you’ll need to promote the Key Name pin to a variable. Call the variable whatever you’d like (I typically like to use the name of the Blackboard Key). Then Compile your blueprint, and enter the actual name of the Blackboard Key into the Default Value section. This will ensure that the variable is connected to that Blackboard Key.

Feel free to ask any additional questions, or mention if anything needs to be clarified or expanded upon.

Have a great day,

Sean Flint

Wow, superb answer. Thank you very much :slight_smile: