When to create Sub-Objects of a blueprint class

I am trying to code a modular weapon system. The weapon is an Actor with a number of components that are responsible for different parts of the weapon.

class ARangedWeapon : public AWeapon
{
protected:
    UPROPERTY(VisibleAnywhere, BlueprintReadOnly, Category=Ammo, meta=(AllowPrivateAccess = "true"))
    class UWeaponVisualsComponent* VisualsComponent;

    UPROPERTY(VisibleAnywhere, BlueprintReadOnly, Category=Ammo, meta=(AllowPrivateAccess = "true"))
    class UWeaponAmmoComponent* AmmoComponent;
    ....
}

Each component would have events that are fired when, say the weapon is fired, or reloaded etc.
Ideally I would like to be able to subclass each component in blueprints to allow for custom behaviour and then just put them together in the Weapon blueprint, but I know that you cannot change the class of a Component.

Instead I decided that each component would have a assignable sub-object that actually did the heavy lifting of the class.

class UWeaponAmmoComponent : public UActorComponent
{
public:
    UPROPERTY(EditAnywhere)
    TSubclassOf<UWeaponAmmoManager> AmmoManagerClass;

protected:
    UPROPERTY(BlueprintReadOnly)
    class UWeaponAmmoManager AmmoManager;
}

That way I could just subclass the manager in blueprints, and set the “AmmoManagerClass” variable to be the blueprint that I want to use.

I now have two questions:

  1. Is this the best way of doing this? Is there a way that I can bypass having to have another sub-object, and just subclass the ActorComponents?
  2. How can I spawn an object of the AmmoManagerClass?

I can’t spawn it in the constructor as the value of AmmoManagerClass wouldn’t have been set in the editor yet. I tried creating the Manager in the PostInitProperty() and InitializeComponent() functions, but the normal ways of creating UObjects (ConstructObject()) caused the engine to crash with the error: “class object none was created in UWeaponAmmoComponent instead of package”.

I’m sort of all out of ideas at the moment, any help would be much appreciated.


Edit:

The two errors I’m getting are:

Object BlueprintGeneratedClass None created in WeaponAmmoComponent instead of Package

Which happens when I use this in InitializeComponent() in the AmmoComponent:

 NewObject<UWeaponAmmoManager>(this, AmmoManagerClass->GetClass())

And:

Assertion failed: ClassAddReferencedObjects != NULL

Which happens when I use this in the same function:

ConstructObject<UWeaponAmmoManager>(AmmoManagerClass->GetClass())

But this one happens after I stop the test whereas the first one is a soon as I start it.

  1. seems pretty sound. you can make as many subclasses as you like which is kind of the beauty of c++. If you don’t want an ammo manager, some more information on what it does would let us provide better answers on how to approach this.

  2. Are you trying to create it with blueprints or C++? If it is going to have a position in the world it should be an actor in which case you would add a child component. You should be able to create an object normally though. From the error it looks like it could not find the class you where telling it to construct. What did you have when trying to create the object?

Thanks for the help.

  1. The AmmoComponent/AmmoManager are meant to handle the weapon’s ammo. When the weapon shoots, one bullet will be taken out of the clip, and when the clip is empty, they will tell the weapon actor that it can no longer shoot. I wanted to be able to subclass AmmoComponent or AmmoManager in blueprints so I could add other behaviors to the ammo (like an energy ammo etc.).
  2. I’m trying to create the object in c++ as the AmmoComponent is spawned or initialized.

I also added some more information in the original question that describes the errors that I am getting.

I managed to fix the problem, or more like I just changed it.
I added the EditInlineNew specifier to the AmmoManager, and just had a pointer to it from the weapon actor that was specified as Instanced. This let me create an instance of any subclass of AmmoManager directly from the defaults tab and I could do away with the AmmoComponent altogether.