Thanks in advance for anyone taking the time to ready this feature request, I hope more developers out there can resonate with this request and vote it up so it can be addressed soon.
Background on our use case
So we’ve recently been adopting interfaces more heavily into our commercial project (VR Action Shooter).
Interfaces are amazing not only for their decoupling and abstractions but for us they provide a very convenient way of getting all actors that match a specific criteria.
This is probably obvious but a short example would be - "Get All Actors with Interface ‘Damageable Interface’ " to get all actors that can be take damage and then calling a specific interface function on them.
It would be impossible to do something like this with “Get all Actors of Class” as there are just too many possible classes in our project that can be damaged.
The Issue:
So the problem with this is that the “Get all actors with interface” is just way more performance demanding in term of the amount of milliseconds it takes in the specific frame (tick) that it runs.
In performance tests we’ve run we’ve noticed up for 4000% longer run times for “Get all Actors with Interface” as compared to “Get all Actors of Class”.
I was surprised to find out the performance gap got even wider as more actors were introduced into the level.
I haven’t checked how the engine implementation of both functions differ from one another, but I can only assume that a list of actors classes is being cached or uploaded to memory whilst the interfaces of those actor’s are not, maybe the amounts of threads… anyway something like that could explain why it takes exponentially more time to get with interfaces as more actors of introduced.
Further Testing and Findings:
Since we’re starting to become more and more dependent on interfaces in our project I’ve taken the time to create a clean project,reproduce this issue and perform some further testing, here are some key findings:
The issue is completely reproducible in a clean project and is not specific to ours.
Even non-blueprint / CPP actors (such as for example StaticMeshActors) which for as much as I know can’t even implement interfaces, have a similar effect on performance which seems kind of an unnecessary waste of compute resources.
The performance difference is significant and for larger scenes can even be critical, especially for VR where having a frame suddenly take (in our case) 200 ms is immediately noticeable and has a very negative impact on the player experience, especially if the task that utilizes the “Get All Actors with Interface” is run multiple times (for example a timer loop that check if all damageable actors have been destroyed).
Although as I mentioned this issue is easily reproducible in any clean project I would be happy to provide our testing project if required.
PS: I know 4.15 has improved a lot on the usage of GameplayTags which seems like the perfect tool for queries such a the ones we’re performing.
As of 4.15.0 I’ve been unable to use the “Get All Actors of Matching Tag Query” node with blueprints and I’ve seen multiple people run in to this issue, so I’m assuming that node is not working as intended.
But besides it being the perfect querying tool (even more convenient than using Interfaces in my own opinion) I have no idea how it fares in term of performance.
Any comment on this subject would be much appreciated
The difference is that the GetAllActorsWithInterface iterates over all Actors and checks if the Actor Implements the Interface. (Same with GetAllActorsWithTag)
But generaly speaking it looks like you deal with a Design issue. Why dont you simply keep Track of the Number of Spawned Actors that have this Interface and decrease it before you call Destroy on them?
If you need additional Information than just the amount of Damagable Actors store them in a Array or Set instead. There is very rarely the need for GetAllOfAnything in the Majority of cases. Most of the time only used once right after Level is completly loaded after that avoid using it.
Your other Issue that you cant get the “Get All Actors of Matching Tag Query” to work is because you need to inherit and implement the IGameplayTagAssetInterface from C++ on the UObject you are Query over. Its currently only used in the Experimental Gameplay Ability Plugin. Would not fit in your case since you still filter with a base Actor Class and because you dont know what Actor has the Interface you End up iterating over all again. The Node itself is working as intended
Hey Nachtmahr,
That’s really great advice, we had someone propose just that yesterday while we discussed this issue internally.
It would be very convenient to get all actors every time as it creates a very dynamic and decoupled system in which you can just slap an interface on to an actor and there you go you get full functionality without having to tie him in to a life cycle process that keeps track of existing actors of that interface.
You’d have to manage the life cycle of every interface you might be calling an “all actors” call upon.
I guess managing arrays of actors is doable and considering the performance cost it would probably be the best thing to do.
We’re probably going to manage arrays of actors by relevant interfaces.
If the cost of “get all actors with interface” was closer to that of “get all actors of class” I would probably go with it instead of the actor tracking design as it allows for much simpler maintenance and faster development.
Note that query time never changes when you get all actors of a specific class no matter the amount of other actors not belonging to that class are currently on the scene.
The engine doesn’t query every actor in the scene to get its class information, the time remains constant.
Just as the engine needn’t iterate over every actor in the scene to query its class it seems possible and logical to not have to iterate over every actor just to get its interface.
So I would appreciate if Epic would consider implementing the proposed “tracking of actors with a specific interface” logic in a more efficient and generic way into the engine (if not with interfaces than at least with tags).
Actors can’t change interfaces at runtime just as they can’t change classes, these interfaces are a static and fundamental property of that actor.
PS could you elaborate on using the Gameplay Tags?
Just to clarify I am trying to get it to work with the blueprint node.
I’ve added a Gameplay Tags Container variable to a specific actor class for testing and gave it some tags.
We continue to query with a “get all matching tags” blueprint node I get Null.
Not sure what to elaborate? Its basicly working like GetAllActorsOfClass but it needs the interface (Not implementable via Blueprint, has to be trough C++) to know what Container you are refering to since you can have multiple, none or Combine Multiple into one before you check against the Query. Asside from that the interface has 3 other Functions that are self explaining.
Check the Source there is not much Magic going on =)
Hmm… well I’m working pretty much exclusively using blueprints at the moment.
It is indeed pretty straight forward, and still from the testing I’ve performed (again, using Blueprints) I’ve not bee able to get it to query properly, and it pretty much always returns None.