Property edit widgets and FComponentVisualizers in CDOs

I’m getting some weird behavior in some component functionality I’m implementing in the editor, and I’m hoping someone might have some insight.

So, here’s my setup:
I have a component. The component has an FTransform UProperty in it, which has the following properties:

	//** The point which follows the player hand if this handle is grabbed
	UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = Pickup, Meta = (MakeEditWidget = true))
	FTransform GrabPointOffset;

To assist in positioning this transform in actor blueprints which use this component, I have an FComponentVisualizer which draws a crude wireframe helper at the location of the FTransform.

void FGripComponentVisualizer::DrawVisualization(const UActorComponent* Component, const FSceneView* View, FPrimitiveDrawInterface* PDI)
{
	if (!IsValid(Component))
	{
		return;
	}

	// GrabPoint
	if (Component->IsA(UPickupHandle_GrabPoint_Base::StaticClass()))
	{
		const UPickupHandle_GrabPoint_Base* GrabPoint = Cast<UPickupHandle_GrabPoint_Base>(Component);
		if (IsValid(GrabPoint))
		{
			DrawWireSphere(PDI, GrabPoint->GetComponentLocation(), GrabPoint->Range, FColor::Yellow);
			DrawViveController(PDI, GrabPoint->GetGrabPointWorldTransform(), FColor::Yellow);
		}
	}
}

This setup is acting really strangely in the editor.

  1. If I set the GrabPointOffset FTransform to EditDefaultsOnly, it can still be edited by moving the editing widget on placed instances of the actor in level. I assume this is just a bug/oversight.

  2. The GrabPointOffset’s widget doesn’t appear when editing the CDO. It only appears when you select placed instances in the level. Which is annoying, but may just be their not being intended for use in CDOs for some reason.

  3. If I edit the GrabPointOffset in the class defaults tab of the instance, the transform (as shown by the FComponentVisualizer drawing at its location) doesn’t change in the CDO, or on instances placed in the level.

  4. However, if I select the instance in the level, and modify its GrabPointOffset (either by dragging the widget, or editing the properties of the component) then the position does update (indicating my drawing code is working properly.) I’ve added some logging to verify that the draw code on the component visualizer is being called.

  5. If in the CDO I set the component which contains GrabPointOffset to be “EditableWhenInherited = false” then the above behavior goes away, and editing the GrabPointOffset live updates both in the CDO’s viewport, and in instances placed in the level. So it doesn’t seem to be a result of some of my transform math calculating the draw point not working in the viewport.

I have no idea where to even look for things going wrong here. Everything I suspect of not working seems to be okay when I dig into it, which is in itself suspect since my FComponentVisualizer might be part of the problem. I’m just hoping something about this seems familiar to someone, and might have some glimmer of insight about where things might be going wrong.

Hey -

What type of component are you creating? Is the block of code provided inside your component class or another class? Are you able to reproduce this behavior in a new clean project? If so, can you provide the setup steps used to help me reproduce your issue on my end.

The first two issues appear to be known. There’s been an open bug on it since 4.7 : Unreal Engine Issues and Bug Tracker (UE-19243) (duped to Unreal Engine Issues and Bug Tracker (UE-13384)). It sounds like they sort of worked in the CDO view in 4.7.4, and then got worse sometime before 4.8.2, since the 4.7.4 version mentions then being drawn for the CDO, just incorrectly. (Now they don’t appear at all.)

The component I’m creating is a custom C++ class, which inherits from another custom abstract C++ class, which inherits from USceneComponent.

The first code block is on the new component. The second block of code is inside the FComponentVisualizer, which is a weird helper object which lives in an editor module, and registers itself with info about the class type it’s meant to draw in the StartupModule() function of the editor module. (See A new, community-hosted Unreal Engine Wiki - Announcements - Unreal Engine Forums)

Reproing it in a clean project is a question of definition of “clean project.” FComponentVisualizers have to live in Editor Modules, (they need to register PostEngineInit, and setting the main game module to PostEngineInit causes a crash) which are pretty complicated and finicky to set up. I’m also not sure whether the ComponentVisualizer is involved in the problem at all - all it’s doing is drawing the location of the editable FTransform, so if the problem lies in the FTransform not getting updated, it’s probably not necessary to do all the editor module setup.

Do you know of any way to draw the location of a transform/vector in real time in the editor? That’d allow a repro without setting up a whole editor module. (I suspect there isn’t one, if there were, I’d be using that instead of a ComponentVisualizer.) If not, I can try sending you a stripped down version of my project as a repro case.

In the meantime, I’m going to try building a custom hitproxy rather than relying on the build-in makeeditwidget meta value, hoping that building one manually will work in the CDO.

Hey -

I’ve done some additional investigation into the edit widget behavior and want to confirm the behavior I’m seeing based on your five points in your original post:

  1. Setting EditDefaultsOnly causes GrabPointOffset to not be available on placed instances of the actor using my scene component. The ability to still use the edit widget is because it is changing the transform setting of the scene component independent of your transform variable. This appears to be the expected behavior in this case.

  2. This is indeed a bug as you mentioned: Unreal Engine Issues and Bug Tracker (UE-13384)

3 & 4) When you say “…in the class defaults tab of the instance” in #3, are you referring the blueprint or the placed instance? It’s difficult to say if editing Grab Point Offset in the blueprint details actually affects the edit widget since the widget is not visible in the blueprint. Editing the variable in a placed instance does update the widget as you mention in #4

  1. It appears that this setting is allowing the instance settings to override the blueprint settings. With this set to false the blueprint settings are the only controlling factor, so the placed instance will update to match the blueprint. If it is set to true, it seems to ignore the blueprint value in favor of the individual instance settings. This behavior has been reported here: Unreal Engine Issues and Bug Tracker (UE-36550)

Cheers

Re 1): This is a little confusing. Why would the widget be editing the transform of the component? It’s liked to a property which is a transform, but that transform property shouldn’t be affecting the transform of the component. Those should be unrelated values, yes?

Re 3): I was talking about editing the blueprint CDO (the one in the content browser). I could only tell that it wasn’t affecting the value of the transform because the visualizer which was drawing the transform wasn’t moving. (As you say, the widget itself wouldn’t be drawn in the blueprint’s viewport).

Re 5): I’ve noticed a number of places where changing properties in code are “underwriting” the value on the instance. As in, the instance, despite not having its own value for a property it’s inheriting from its default object, is creating a value which overwrites the default object’s value when the default object’s value changes.

As in:

  • I have a code class Foo_Code which
    creates a float UProperty Bar = 1.0f
  • I create a blueprint Foo_BP which
    inherits from Foo_Code. Its value for
    Bar is set to 1.0f, and has no little
    “reset” arrow.
  • I edit my code to set Foo_Code’s Bar
    to = 2.0f
  • I recompile in editor
  • Foo_BP’s value for Bar is still 1.0f,
    but now there’s a little “reset”
    arrow, which when pushed, sets Bar to
    2.0f

I believe this is happening only if you do a compile while the editor is open. If you do it when it is closed, Foo_BP’s Bar will correctly match Foo_Code’s Bar when you reopen the level.

So I suspect this is part of a larger, rather impactful bug with how BP variables manage inheriting non-overwritten values from parent classes. No idea how that’s working under the hood, but most engines I’ve used that don’t have problems with this have a sort of hidden, explicit “this value has been overwritten” flag associated with all of its designer-facing properties, which will automatically be set if the value is changed in the editor, but can be manually set, manually reset (which will cause the value to revert to the inherited value) but which will never be automatically reset. (Which prevents problems with bob the designer setting a value which is by default false to true, but then having a programmer set the value to true by default, and then to false by default later, clearing Bob’s deliberately set values.)

In #1 I was referring to the following. The first image is after placing an instance of the blueprint in the level. The second is after using the transform widget to move the MyScene component.

Note that if I edit Location under Grab Point Offset, the blue diamond position will change while the widget stays in place. If the UPROPERTY is marked as EditDefaultsOnly, GrabPointOffset does not show in the details panel, but the transform widget is still able to move the MyScene component.

Ah, I see what you’re talking about. That wasn’t what I was doing. I was editing the transform’s widget (the blue octahedron) which can be selected and moved separately from the component (the white sphere and axis markers.)
If you drag or rotate the octahedron around, it sets its associated property (grab point offset) to a value which corresponds to its offset from its parent component. You’ll see the value of GrabPointOffset change accordingly.

However, this shouldn’t be possible to do, since GrabPointOffset is set to EditDefaultsOnly. Effectively, the edit widget is allowing you to violate the UPROPERTY’s data protection rules.

Since at the moment, you can’t edit the property using the widget in the CDO’s viewport (that’s the bug form #2) there’s little reason to set a property which is EditDefaultsOnly to have an edit widget. But once that’s fixed, this’ll be an issue since it means that any widget you add to data you intend to only be edited in the default will actually be editable on instances.

Okay, I see the difference now. I’ve entered a report regarding this behavior here: Unreal Engine Issues and Bug Tracker (UE-36584)

You can track the report’s status as the issue is reviewed by our development staff.

Cheers