Hi,
We’ve also been experiencing this issue for a while (currently running on 5.4.2).
So I’ve decided to dig into it a bit myself and add more repro steps here for clarity.
Repro Steps:
- Create a new project and enable the ViewModel plugin.
- Create a new User Interface Widget Blueprint and open it.
- Add any ViewModel to the widget using the Viewmodels tab (the base MVVMViewModelBase will do).
- Add an Overlay to the widget and add a Text widget within that.
- Copy and paste the Text Widget to create a duplicate.
- Hit Compile at this point to check that the widget does in fact compile.
- Press Ctrl+Z to undo the widget duplication.
- Hit Compile and see that the widget does not compile anymore, with the error ‘The setter name X already exists and could not be autogenerated.’
Note that once you get into this state it’s difficult to get out of without restarting the editor.
You can reload the widget blueprint from the saved file state (even saving in this state is safe, because it’s only transient data that has gone wrong).
However I’ve found that reloading a widget blueprint in isolation can expose other problems with more complex setups, so restarting the editor is the safest course of action.
From debugging, what seems to be happening is that in FMVVMViewBlueprintCompiler::CreatePublicFunctionsDeclaration() each time we compile we are generating a new function graph for the viewmodel setter. These UEdGraph objects have the Widget Blueprint as their outer object and must be uniquely named across the other objects with that parent.
To accomplish this across subsequent compiles, the UMVVMBlueprintView holds onto these generated UEdGraph setters in the ‘TemporaryGraph’ member, then they can be reparented to the transient package before generating a new one and setting that in the TemporaryGraph for next time (effectively throwing the old one away).
However if the user uses undo, then before the recompile runs, the old setter UEdGraph (that was thrown away at the start of the previous compile) gets its state restored and is reparented back to the Widget Blueprint (so we effectively have 2 at that point). Then the one that was held onto in TemporaryGraph gets thrown away and we attempt to generate a new one, but this fails because we’ve already restored one (from 2 compiles ago!)
A workaround that I’ve found that seems to work is to ensure that the generated UEdGraphs are not serialised for undo/redo.
The graph gets recompiled after each undo/redo anyway, so it doesn’t seem necessary, however there may be a reason that they are instantiated as Transactional that I haven’t seen yet.
For this workaround, add this at line 1042 of MVVMViewBlueprintCompiler.cpp after UE::MVVM::FunctionGraphHelper::CreateIntermediateFunctionGraph() is called:
Setter.SetterGraph->ClearFlags(RF_Transactional);
It would be great if we could get an official fix for this, as it’s an issue that our UI artists encounter often.
Thanks,
Dave