UObject vs Actor vs ActorComponent in creating Nested Class Architectures in Multiplayer Games

Hi there,

I am working on a typical game, where you control a Pawn/Character and your PlayerController would hold such data as Items, Money and a Stat-Configuration(e.g. stamina, health- or defense-upgrades with which the player would spawn the next time).

Usually like e.g. in Java/C#(Unity), I would try to encapsulate behaviour and variables as much as possible.

I would combine Items and Money into an “Inventory Class”, which should be further splitted into a “ItemManager Class” and “CurrencyManager Class”.
Stat-Configuration would receive a “Stat Class”.
The Playercontroller should possess the Inventory and Stat Class.

The Class names and what they do, do not matter much for me right now. What’s really important about this structure is the nesting of these classes.
Since normally at least for Blueprints you can of course attach ActorComponents to an Actor, but no ActorComponent to another ActorComponent like you would do with Actor & ActorComponent. You could add them as variables of course, but right now I don’t know how to spawn an ActorComponent in Blueprint and what changes would still be needed for proper replication.

The question is now: Of what type should these Classes(Inventory, Stat) be, to actually achieve this hierarchy and allow proper replication and RPC-Calls from within these classes:

hierarchy.png

My previous research:
Possible considerations are: Actor, UObject, ActorComponent

UObject:

So to actually make this work with UObjects, you would be either constraint to only variable replication and no RPC from within the UObject or you would have to create your own “UNetworkedObject” to get RPC to work as well.

ActorComponent:

  • Replication works
  • RPC works.
  • can get role via “GetOwnerRole()” from Actor.

Is nesting of ActorComponent towards another ActorComponent possible?

Actor:

  • largest size of all
  • contains a world position, which I don’t really need for Inventory or Stats
  • would have it’s own Net-Priorities and so on,(which might cause trouble further on?)

Other statements I gathered:

  • Somewhere (don’t have source anymore) a developer stated, that replication was meant as a flat hierarchy, so only one Actor and ActorComponents attached to that one Actor.
  • Another one suggested to always use Actors for Networking and UObjects only if not network depended.

Okay, that were a lot of facts right now, but I just wanted to present you my current understanding of this topic.

So back to the question:
How did you handle more complex classes like this example?
I don’t really like the idea to actually create everything out of Actors or force my whole model into that flat hierarchy. My next try would be to nest ActorComponents.

Greetings,
smara :slight_smile:

Hi, In my opinion I’d invert your InventoryClass with ItemManager and make an InventoryManagerComponent. Your currency manager really depends on what you are doing with it. I’d also put the InventoryManager on the pawn instead of the player controller.

Really it comes down to this

Use a component when you want modularity to give Actors more functionality that could be used on other actors
Use Actors when they can have an independent role in the world
Use UObjects for modular utilities

Nesting really just depends on the role, your inventory manager can keep references to inventory actors, your currency manager can keep UObjects that carry out rules.

Just a high word of caution that the deeper you nest the more issues that can go on with replication.

Hi,

thanks for your post :slight_smile:

Okay, now you are trying to combine behaviour to be in the old Actor & ActorComponent pattern. And of course, somehow you would be able to achieve it.
But that is not what this thread was about for me. The Class Names don’t really matter.

It’s about the problem, that I would sometimes like to create behaviours for which a flat hierarchy of one Actor with ActorComponents wouldn’t be enough or otherwise confusing. Or formulated in other words: How would I be able to further encapsulate behaviour inside an ActorComponent, which supports Replication and RPCs?

Take another example: Again I would like to implement my Inventory as an ActorComponent. Furthermore I would like to select several items and the selection should be stored with the Inventory-ActorComponent since let’s say 3 other UMG Widgets depend on that shared selection. It wouldn’t make sense for me to store this selection in one of these UMG Widgets because then the other UMG widgets must have knowledge about the Widget which holds the selection, but the UMG Widgets should only have knowledge of the selection - nothing more. Furthermore this selection system should be reusable for other purposes like for a squad-overview(another UMG Widget) in which you would like to select several members of a memberlist and drag them together to a new position.

Normally you would do such a selection system with UObjects. But the problem is now that I want to safeguard my selection system(for examples sake) so that I would need Authority of the server to actually select an Item/Member. However UObjects only support Replication with some modifications, but no RPCs since they do not possess a given NetworkRole or Owners. So I cannot do a simple (if (Role == Role_Authority) {…}) check. I would have to that from my ActorComponent class, which again would break the principle to completely encapsulate behaviour.

What really matters is again: I would like to customize an ActorComponent with Objects (which have replication and RPCs) similiar to how I can customize my actors with ActorComponents, which are able to do replication and RPCs.

Aside from that: Why would you place your Inventory at the Pawn? My Inventory should persist even though the pawn gets destroyed, so in my opinion the Playercontroller is the right place.

Thanks for the overview! :slight_smile:

For Actors: I am currently somewhat confused what “independent role in the world” still means. I always thought an Actor would be an object, which always has a physical location in world space. After reading the docs again, it’s actually the rootcomponent which defines the transform. So my wanted objects I am searching for might have been Actors all the time :smiley:

Regarding UObject and modular utilities. Could you please give me an example for that? Right know I think of both UObject and AActor as simple Objects, but that UObject has no proper Multiplayer support(replication, RPC) without changing further stuff and Actor has the abilities of replication and RPC without further changes.

I think my main problem is/was, that I simply didn’t like the idea of using Actors as Subobjects of other Actors. It simply seemed illogical for me to have Actors placed in the world which wouldn’t actually need a position in the world. Furthermore I thought Actors should be an independent thing, which don’t have other Actors as subobjects. Hmm.

Thanks, I will keep this in mind :slight_smile: