Bp ActorComponent from c++ in Bp Actor from c++ seems [bugged /corrupt]

Hello there,

I don’t really know if here or the c++ subcategory is more apropriate but I’ll try my luck.

My issue is that I have 2 c++ classes :

  • Mistral
  • MistralShootingStateMachine

And 2 BP classes that inherit from them :

  • BP_Mistral
  • BP_MistralShootingStateMachine

The c++ “Mistral” class has an attribute of type “MistralShootingStateMachine” but I wanted in the blueprint “BP_Mistral” to replace the attribute type to a “BP_MistralShootingStateMachine”.
To do so I went in the BP editor, selected the c++ -inherited “MistralShootingStateMachine” attribute and changed the “Component class” to the Blueprint version “BP_MistralShootingStateMachine” :
image

And as soon as I did this, I have multiple problems

  • Error at project startup, “BP_MistralShootingStateMachine_C” makes a memory access error when calling class-GetFName() method
  • Error in Output log at project startup
LogUObjectGlobals: Error: LinkerPlaceholderClass /Game/Blueprints/BP_Mistral.PLACEHOLDER-CLASS__BP_MistralShootingStateMachine_C_0 is not a legal override for component MistralShootingStateMachine because it does not derive from Class /Script/ServeurSimulation.MistralShootingStateMachine. Using Class /Script/ServeurSimulation.MistralShootingStateMachine to construct component.
LogLinker: Error: Failed import: class 'BP_MistralShootingStateMachine_C' name 'MistralShootingStateMachine' outer 'Default__BP_Mistral_C'. There is another object (of 'MistralShootingStateMachine' class) at the path.
LogLinker: Error: Failed import: class 'BP_MistralShootingStateMachine_C' name 'MistralShootingStateMachine' outer 'Default__BP_Mistral_C'. There is another object (of 'MistralShootingStateMachine' class) at the path.
LogLinker: Error: Failed import: class 'BP_MistralShootingStateMachine_C' name 'MistralShootingStateMachine' outer 'Default__BP_Mistral_C'. There is another object (of 'MistralShootingStateMachine' class) at the path.
LogOutputDevice: Warning: Script Stack (0 frames):
LogOutputDevice: Error: Ensure condition failed: !bLayoutChanging [File:D:\build\++UE5\Sync\Engine\Source\Runtime\CoreUObject\Private\UObject\Class.cpp] [Line: 3822] 
Class named BP_MistralShootingStateMachine_C creating its CDO while changing its layout
LogStats:             FDebug::EnsureFailed -  0.001 s
LogAudioMixer: Warning: AudioMixerPlatformInterface Timeout [18063ms] waiting for h/w. InstanceID=1
LogOutputDevice: Warning: Script Stack (0 frames):
LogOutputDevice: Error: Ensure condition failed: false [File:D:\build\++UE5\Sync\Engine\Source\Editor\Kismet\Private\BlueprintCompilationManager.cpp] [Line: 1359] 
ClassDefaultObject for BP_MistralShootingStateMachine created at the wrong time - it may be corrupt. It is recommended that you save all data and restart the editor session
  • Sometimes my “BP_Mistral” Actor crashes because the component becomes corrupt : clicking on the inherited - c++ - component does not open details panel, its just the grey background, but clicking on the variable node show that the variable component type is none and can be reseted to default value which un-corrupts the component until the next corruption

This is an important issue for me because this corruption generates an error when building a debug or release package.

Do you guys have any idea why that happens ? Am I doing something wrong ?
I feel like this is a very usual use-case of c++ <-> blueprint mix that just explodes.

Thanks !

2 Likes

I can’t put my finger on it but I don’t believe this mix of C++ and BP are going to behave properly. I think you’re getting into one of those grey areas with C++/BP interaction where one piece doesn’t know about the other at the right time. Unfortunately I’m not in front of the editor to test some thoughts out.

What I can say though is that if I were putting these layers together I would likely not define the actor component in the c++ side of my actor class if I planned to use a BP subclass of it. Instead, I would add the BP subclassed actor component to the actor directly in the editor. Then maybe on begin play for the actor (in c++) you can then do something like a GetComponentsByClass and look for any MistralShootingStateMachine component attached to the actor. Keeping in mind that you won’t have access to any of the BP specified functionality from within C++…only the functionality defined in the C++ version of the actor component.

Make sense?

1 Like

Right so I Found what I believe the issue is :
The “Component Class” attribute in the details panel (see above) had a tooltip I didn’t see that warns that “only native types are supported at this time”.

This makes a lot of sense since I went through the source code and the “BP_Mistral.PLACEHOLDER-CLASS__BP_MistralShootingStateMachine_C_0” is a Blueprint way to avoid recursive dependencies.
I feel like the issue is that the class is not yet loaded but is used and I guess it simply doesn’t work. Then also it is a bit strange that there isn’t a native class only filter on it :thinking:.

@gh0stfase1
My workflow on this project has been to do as much as possible in c++ and when needed, do the music / FX / textures / etc… in blueprint. From a purely higher standpoint, It’s a bit a pity because it would make extending c++ to blueprint so much more logical and easy (imo).

I’ll try your suggestions and maybe look into the c++ OnConstruction event but i feel like I will lose the component defaults panel details, which again is a shame.
Another idea I had was to create a BP_MistralShootingStateMachine in BP_Mistral and then override the existing MistralShootingStateMachine attribute.

I’ll keep it updated so that if anyone stumbles across this topic with the same issue, they’ll have a tested solution in hands.

Thanks !

1 Like

Right so after some digging, it seems to me that some Blueprint corruption took place in the Component Blueprint. It seems to me it is due to live coding after editing some headers.

The solution was to re-create the blueprint and to avoid new corruption (I could not reproduce anyway), not use the “Component Class” setting. The ugly solution I used right now was to replace the c++ component by a BP component but only in the BP constructor. That way I can have c++ only or c++ extended with BP.

1 Like

I just went through the same journey as described in your posts here. At first I was excited that I can just define my own component class. Then: it crashed on next startup (live coding worked until then). My search eventually led me here and I find it very sad that it turns out this feature is simply not supported: you simply can’t define a BP class for a component class -yet the editor sugget you could pick a BP class. Definitely, this is an engine bug! At least until they official support this feature - which imo they should.

Here is the UE5 tooltip btw so people can find this thread more easily:
“The class to use when creating this component for this class. This can only be done for components defined in native at this time.”

My solution was:

  • BP C++ classes that should contain the component now don’t directly spawn the component but get an interface inherited that includes a getter for the component. (Makes it accessible by C++)
  • The BP C++ classes which inherit this “component owner interface” store a pointer to the component
  • In the parent BP i add the component manually
  • In the BP event graph, on beginplay, i save the BP component to the C++ component pointer

This way I have a contract that the component can be returned from those classes, but i have freedom regarding how or when i add this as long as its a subtype of that C++ component type. It is a few extra steps in the BP but that’s quite acceptable.

Here is my interface:


UINTERFACE(BlueprintType, meta=(CannotImplementInterfaceInBlueprint))
class ULgcHighlightableEntityInterface : public UInterface
{
	GENERATED_BODY()
};

class ILgcHighlightableEntityInterface
{
	GENERATED_BODY()
public:
	UFUNCTION(BlueprintCallable)
	virtual void SetHighlightableEntityComponent(ULgcHighlightableEntityComponent* InHighlightableComponent) = 0;
	
	UFUNCTION(BlueprintCallable)
	virtual ULgcHighlightableEntityComponent* GetHighlightableEntityComponent() = 0;

	virtual const ULgcHighlightableEntityComponent* GetHighlightableEntityComponent() const = 0;
	
	UFUNCTION(BlueprintCallable)
	virtual void SetHighlightableMeshes(const TArray<UMeshComponent*>& InHighlightableMeshes);
};

It is quite generic except for the SetHighlightableMeshes function which is quite unique and I use to to trigger an event on the components, if the component is not nullptr :wink:

1 Like

The above solution works great if you want to reuse the component in different setups and have it addressable via CPP interface as a contract.

I had the component BP issue come up again for me where I did not need an interface and I tried to go with the simpler setup @dominique57 suggested. Here is a short rundown:

I added the component as a simple GC-tracked but not BP exposed pointer:

UPROPERTY()
ULgcCharacterSpawnComponent* CharacterSpawnComponent;`

I created a Setter function for BP that does nothing but set the value:

	UFUNCTION(BlueprintCallable)
	void SetCharacterSpawnComponent(ULgcCharacterSpawnComponent* InCharacterSpawnComponent);

In the BeginPlay() function of the actor I added my custom assert that triggers a graceful exit next frame, and instantiated a default CPP component instance just so it won’t blow up should the component be used anywhere until then:


	if (CharacterSpawnComponent == nullptr)
	{
		GAMEPLAY_ASSERT_MESSAGE(false, "Did you forget to set the CharacterSpawnComponent in the GameMode's BP ConstructionScript?");
		CharacterSpawnComponent = NewObject<ULgcCharacterSpawnComponent>(this, TEXT("CharacterSpawnComponent"));
		CharacterSpawnComponent->RegisterComponent();
	}

And finally in the Blueprint I manually added the BP-Overridden component to the Actor and then in the ConstructionScript I call the setter with it:

1 Like

This is a BP corruption issue thats been around for years. work around is (Make backup first) to reparent the blueprint to a lower level parent, eg if your BP inherits from MyCppCharacterClass, change its parent to default engine Character class, save the BP(ignore the errors), then change parent back to your CPP class then save. it should fix the issue

1 Like