Dynamically add world actors to an array as they are spawned?

Hello everyone,

So I’m working on creating a component for my game framework called the Attribute Manager Component. Basically, any actor in the game world may have an Attribute Component, which holds attributes for that actor. At spawn, the Attribute Manager Component, added to the Game State class by the developer (since I don’t want to override base classes if I can avoid it; this is meant to be plug-and-play in case a dev also wants to use features from another gameplay framework), gets all actors in the world, saves them to an array of Actors, and then sorts through them to check if they have an Attribute Component. It then adds all attribute components to an array of their own, so that the developer can do things like binding attributes to other properties.

It’s a little complicated but if you need the source code to see how it works I’ll share it - I don’t want to post it here directly because it’s a lot of code split across two modules.

The major problem I have is that I need to also be able to add Attribute Components that may be spawned at runtime to the Attribute Manager Component. Currently, my solution would be to have to constantly call GetAllActorsOfClass() (probably in either TickComponent() or a slower timer of some sort), update the Actors array, and then update the Attribute Components array. It’s, to say the least, inefficient, and because the framework is designed to be expandable from anything down to a tiny indie project to a massive RPG, well, having to grab every actor in the game world in something like a huge RPG would definitely be undesirable.

Is there an alternative method that I can use? Some kind of delegate that I can bind to, so that when a new actor of any class is spawned, I can iterate over its components and add it to the array? I haven’t been able to find one looking at the source code yet.

Here are some pointers:

  • I want to avoid overriding base framework classes (Actor, Pawn, Character, Player Controller [already had to override that one, but I’m trying out a workaround], Game State, Game Mode, etc.), but if I have to, I will
  • I am working in C++ so if it’s specific to C++ that’s fine
  • The framework must be multiplayer-compatible; however, the Attribute Manager Component is server-authoritative and may not be replicated to clients (I still haven’t decided on that part yet), kind of like the Game Mode but it still exists for clients.
  • Casts are okay; of course, this binding would only be done on startup

Thank you to anyone who can provide help! If there is no available function I may just have to settle for a slow timer.

I don’t know if I understood correctly.

If you don’t want to modify the engine classes (AActor, APawn, etc) then all you have to do is modify the object creation path.
You can create your versions of the SpawnActor/NewObject function and check if the given class contains the component/function/variable you are interested in. If so, then you add the instance to the array

You just have to force the user to use your methods instead of the original ones to create objects.

In pure c++ you can do this with metaprogramming.
If this has to work with blueprints as well, UE reflection can be used.

1 Like

I will try this.

Maybe to help clear up exactly what I’m saying: Basically, to make the unnecessarily long original post shorter, yes, I need to add actors to this array as they are spawned instead of constantly getting the world actors.

For existing projects I suppose it would require the developers to do some refactoring but it probably wouldn’t be too bad.

I’ll mark your post as the answer and post my code here if it all works out, thanks!

I’ve yet to figure out how to bind to these but for now this is something I found in World.h:

DECLARE_MULTICAST_DELEGATE_OneParam(FOnActorSpawned, AActor*);
DECLARE_MULTICAST_DELEGATE_OneParam(FOnActorDestroyed, AActor*);

Again, haven’t been able to make it work yet. Still looking for publicly-available dispatchers to bind to.

I finally figured out a way to get around this.

All I had to do this whole time was tell the Attribute Components on startup to call a Server RPC on the Manager Component to add itself. Considering the manager doesn’t need to know jack squat about the actors themselves, this should’ve been obvious.

I can’t believe how stupid I am sometimes.