Download

EditInlineNew / Instanced not saving properly

I want to be able to make a modular weapon with various components to handle each specific aspect. I have found EditInlineNew / Instanced to be exactly what I need - Except for one main problem.

I define a BaseWeaponBallistics class and created two classes deriving from it:


UCLASS(Abstract, EditInlineNew, Blueprintable)
class UBaseWeaponBallistics : public UActorComponent

UCLASS(Blueprintable)
class UWeaponBallisticsProjectile : public UBaseWeaponBallistics

UCLASS(Blueprintable)
class UWeaponBallisticsHitscan : public UBaseWeaponBallistics

In my BaseWeapon class, I then add this as a property:


/** Weapon Ballistics */
UPROPERTY(EditAnywhere, Instanced, Category = "Weapon")
class UBaseWeaponBallistics* Ballistics;

Now, I can choose my subclass and set the various properties in the editor. Here, I am editing a Blueprint deriving from BaseWeapon:

5c1f2c4736bdd8ef1d1034b3f0e14bd48b55c13a.png

I can save this Blueprint, compile it, and everything works as expected when I Play In Editor. My weapon fires off the projectile or hitscan as expected. However when I close the editor and re-open it, my choice has been set to default:

f13a17df68cebc4edcef38f8c8e025ccbbe16a1f.png

How can I fix this?

Edit: It appears to be specific to UActorComponent. When I made the following change, the value persists across reloading the editor:


class UBaseWeaponBallistics : public UObject

Worth noting that it saves fine when derived from UActorComponent; ie changing it to UObject and then reloading the editor shows the selection that I had previously made. It seems to me that the problem is somehow in loading the component.

This can suffice for now, I can get by with manually setting the AActor owner for the component. However, I would like to know if this is expected behavior or not. Am I missing something, or should I report this as a bug?

Is your BaseWeapon class an Actor type? If so, why don’t you just add instances of your subclasses in the regular way, using the AddComponent button?

There is a lot of dedicated code for treating Components differently from other UObjects, so although I’m not sure if it’s a bug or not, it’s definitely not normal practice to try to create UActorComponent-derived classes manually via the EditInlineNew/Instanced approach.

How would I ensure that exactly one instance of my base class is added? The “normal way” implies the ability to add either none or multiple instances, both something I am wanting to avoid. I also need to hold a reference to this component since my BaseWeapon will directly interact with it, what is going to be the best way to accomplish that?

Yeah unfortunately there’s still no way to define a component in C++ and allow a blueprint to override the derived type of the component to use. This is something that I remember an Epic staff member saying they intended to implement, but that was probably 2 years ago now, there’s been no progress as far as I know.

There are various ways to get a reference to a blueprint-added component. Easiest is probably just calling FindComponentByClass. You could also use an FComponentReference property, but they’re name based I think. Either way, this would assume you could live with the possibility of someone adding more than one, you’d need to do a runtime check I guess.

Otherwise, there’s the approach you used, but I don’t know what would be required to make it play nice with the component system. You could try calling RegisterComponent whenever the instanced property was changed - without this, the component will be hanging and not registered with the actor as a true component. Even if you did that though, I’m not sure it would still solve the loading issue, I guess there’s some conflict there between regular loading of an instanced subobject, and special code dedicated to components.

My current solution appears to work fine, although there might be issues popping up later that I’m not aware of. I am now able to successfully choose a subclass and everything plays nicely with it:

BaseFiringMode.h


UCLASS(Abstract, DefaultToInstanced, EditInlineNew, Blueprintable)
class UBaseWeaponFiringMode : public UObject, public FTickableGameObject

BaseFiringMode.cpp


ABaseWeapon* UBaseWeaponFiringMode::GetOwningWeapon()
{
    return Cast<ABaseWeapon>(GetOuter());
}

BaseWeapon.h


/** Weapon Firing Mode */
UPROPERTY(EditAnywhere, Instanced, Category = "Weapon")
class UBaseWeaponFiringMode* FiringMode;

Sorry for hijacking the thread, I’ve been following it closely. As far as I know, creating Components using the EditInlineNew/Instanced approach was not uncommon back in UDK so I’m wondering why this has changed? For example see this page on the UDN: https://udn.epicgames.com/Three/DevelopmentKitGemsAddingSpritesMeshesParticleEffects.html or more specifically this image:

Or is it alright for PrimitiveComponents but not for ActorComponents?

@UnrealEverything Actually as I wrote that I vaguely remembered a thread of yours where you might have been doing this? To be honest I’ve never actually tried to create a component in this way myself, perhaps it can be made to work fine. Invariably though from what I’ve seen, people use Instanced properties with UObject-derived types but not component types, so was just speculating that that may have been the cause of the issue.

I never used UDK. Did it also have the dedicated AddComponent approach back then?

No, UDK does not have anything like AddComponent. The only thing that comes somewhat close to it is what’s described on the UDN page I’ve linked above.

What you’re remembering is this thread: Having trouble adding components from Construction Script. I don’t think it’s exactly the same problem but you’re right, I’ve successfully instanced a Static Mesh Component in my Blueprint. Besides the problems I’ve posted it is working correctly as far as I can tell. Again a Static Mesh Component is a Primitive Component as well, not just an Actor Component. So maybe this does make the difference.

I think I’ll give this a quick test as soon as I have some time available for it in the next couple of days.

Would be strange if there was such a difference, hard to see why primitive components would be treated any differently for the serialization process.

Sorry it took me so long to try it myself. First I was busy, then I forgot, then I was busy again. :smiley:

It only took a few minutes so here are my results (using a custom UE 4.11.0 build).

This is my Actor class:


//.h

#pragma once

#include "GameFramework/Actor.h"

#include "InstancedTestActor.generated.h"

UCLASS()
class SOME_API AInstancedTestActor : public AActor
{
	GENERATED_UCLASS_BODY()

public:
	UPROPERTY(Instanced, EditAnywhere, Category = "Instanced", BlueprintReadOnly)
	TArray<class UActorComponent*> InstancedComponents;

};


//.cpp

#include "Some.h"

#include "InstancedTestActor.h"

AInstancedTestActor::AInstancedTestActor(FObjectInitializer const & ObjectInitializer)
	: Super(ObjectInitializer)
{
	InstancedComponents.Empty();
}

Placing an instance of this class into a level, adding a StaticMeshComponent (derived from UPrimitiveComponent) and a GameplayTasksComponent (derived from UActorComponent) to the InstancedComponents array, then saving the level, closing the editor and reopening it worked. Both components were saved and loaded correctly.
If I now create a Blueprint subclass from this actor class and add the same kinds of components in its defaultproperties it still works as expected even after restarting the editor and reloading the level.