This issue occurs because post-BP compile reinstancing does not clear delegate bindings to other referenced Actor instances in the scene. Thus, the old BP actor instance remains in the referenced Actor delegate's InvocationList mapping as 'REINST_...' at the point where AActor::ExecuteConstruction() is called from within FActorReplacementHelper::Finalize(). The new instance is then mapped into the other Actor delegate's InvocationList by UBlueprintGeneratedClass::BindDynamicDelegates(), and then the old 'REINST' instance is later replaced within the InvocationList with the new instance, for which the end result is a duplicate binding. Each compile that follows repeats these steps, which results in a new duplicate binding for each occurrence.

Also to note, the duplicate bindings are serialized into the instance in the scene, so this behavior will propagate into a cooked build as well.

Steps to Reproduce
  1. Create a new, blank project.
  2. Create a new Actor-based Blueprint class (NewBlueprint).
  3. Double-click to edit, then add a new variable of type 'Actor' (ActorRef). Also click the eye icon to make it visible for editing on instances.
  4. Compile, save and close the Blueprint editor.
  5. Drag an instance of the Blueprint into the current scene.
  6. Drag a new Box Trigger actor into the current scene (TriggerBox).
  7. Select the 'NewBlueprint' instance in the scene, and in the Details panel, set the 'ActorRef' var to the 'TriggerBox' instance in the scene.
  8. Click the "Edit Blueprint" button in the Details panel and choose "Open Blueprint."
  9. In the Blueprint Editor window, in the "My Blueprint" panel, select the 'ActorRef' variable.
  10. In the "Details" panel, click the green "+" button next to the "On Actor Begin Overlap" event.
  11. In the Event Graph, find the "OnActorBeginOverlap" event node and wire up a "PrintString" node to it.
  12. Compile, but keep the Blueprint editor window open.
  13. PIE, walk into the Box Trigger, and notice how many times the PrintString node fires (should be 1).
  14. End PIE, and compile the Blueprint again.
  15. PIE again, and note that the PrintString node now fires twice.
  16. Repeat the steps above, and notice that each compile will cause PrintString to fire an additional time when overlapping the Box Trigger in the next iteration of PIE.
    Expected result: Compiling does not increase the number of times the bound delegate fires in PIE (i.e. it should remain only a single time regardless of how many times it's compiled before PIE).

Have Comments or More Details?

There's no existing public thread on this issue, so head over toAnswerHub just mention UE-64922 in the post.

Login to Vote

Cannot Reproduce
Fix Commit8988366
Main Commit9318896
CreatedOct 8, 2018
ResolvedSep 23, 2019
UpdatedOct 2, 2019