Essentially I’m trying to build a “ConstructionScript” for a component. I have a Blueprint derived from SceneComponent, which implements a “ConstructedComponent” interface, providing a “ComponnentConstructionScript” event. The Blueprint also has a couple of variables. For simplicity of the discussion, let’s say this just prints the values of those variables:
Now, this works brilliantly in the Blueprint editor’s “Viewport” tab. I can add a my component and editing the values of the variables will call the construction script on the parent actor, which again calls the “ComponnentConstructionScript” event, which then prints the edited variable values. Nice.
However, if I place the actor Blueprint in the level, this doesn’t work. I can edit component variables on the instance, my “ComponnentConstructionScript” event is called correctly. But the variables are all at their default values, not the values I set for the instance in the level. Trying to get the component variables directly in the actors construction script leads to the same result. Variables are at default values.
I also looked at using a ChildActorComponent instead. But that way I seem unable to edit variable values at all.
Some context: I’m working on a Blueprint that assembles a couple of static meshes using a ProceduralMeshComponent, e.g. bending them around a curve with angle/radius. I want to combine multiple of these into various Blueprints. Think “Procedural 3D tiles” or “Procedural Construction Kit parts”, which I use to build larger tiles/parts, which again assemble in larger parts and so on. Some of the larger parts, like an entire room, will only be used once, though, so it doesn’t seem to make sense to create a Blueprint and I would prefer to edit the instance directly in the level. Being used to the nested prefabs of Unity engine, I’m having a bit trouble getting used to the separation of Actors and Components.
Thanks, it’s a reasonable workaround. And I actually tried that yesterday
However, it means the user has to remember to press the button. Also, if the underlying Blueprint changes, I would have press the button for all instances in the level, which could be hundreds. Sure, I could build a global button somewhere that rebuilds everything in the level. But just changing variable values and auto-update only those things I actually changed seems way more intuitive. My construction kit parts are targeted to be used by others, not just myself, so being intuitive is important, too.
I was thinking of hooking into PostEditChangeChainProperty, PostEditChangeProperty, PostEditUndo, PostInitProperties and/or PostLoad of UActorComponent, calling for an update of my construction from there. Would that be the right way? Sadly the documentation of these is a bit thin, so it’s unclear whether some of these are redundant or if I cover all possible cases with that.
(Edit: Works, but poor performance, see below)
Muhaaa…thanks. You wrote to try OnRegister and then deleted the post 30 seconds later. BUT it seems you where correct. Although I gave it only a quick test, so there may be quirks.
Basically derive your Blueprint from ConstructableComponent (see code below) and override the ConstructionScript event in the Blueprint. Apparently no need for any extra logic in the Actor’s ConstructionScript to call this.
Header File:
#pragma once
#include "CoreMinimal.h"
#include "Components/SceneComponent.h"
#include "U2FConstructableComponent.generated.h"
UCLASS(Blueprintable, ClassGroup=(Custom))
class UNREAL2FOUNDRY_API UU2FConstructableComponent : public USceneComponent
{
GENERATED_BODY()
public:
UFUNCTION(BlueprintCallable, BlueprintImplementableEvent)
void ConstructionScript();
protected:
virtual void OnRegister() override;
};
While the above solution works and can be improved further by also listening to PostApplyToComponent and PostEditComponentMove, it’s not a good solution. The construction script will be called extremely often, which may become a performance problem if the construction script is non-trivial and/or the Blueprint is instanced often in the level. Editing a single variable value in the Blueprint Editor, while having the same Blueprint instanced 3 times in the level causes the construction script to be executed 30 times in total, with 13 different instances of the component, somehow. I don’t pretend to understand Unreal’s method of management, which seems a bit wasteful.
I experimented with using MarkForNeededEndOfFrameUpdate and call the ConstructionScript from that update, but that doesn’t appear work in the editor. Another attempt was made using FTSTicker::GetCoreTicker().AddTicker to get a single callback in the next frame no matter how often it was requested. I used a TWeakObjectPtr to ensure not updating, if the component was already deleted. That somewhat worked, but caused trouble when dragging the object as the component is destroyed and recreated every frame, so nothing is updated while moving.