Issue with Motion Warping not triggering correctly in repeating montage

Repro steps is part of the issue. The linked issue has also a project repro where the issue occurs even on the current engine version.

Steps to Reproduce

Hi,

I’m encountering a problem with Motion Warping in my attack animation, where I use the MotionWarping component (from the engine plugin). The warping should only occur if an opponent is close enough to the player. When the opponent is within range, we update the warp target using the following line

MotionWarpingComponent->AddOrUpdateWarpTarget(Target)The issue arises when the montage is played, but the opponent is too far away. In this case, I don’t want to warp the actor, so I don’t call AddOrUpdateWarpTarget. Only RemoveWarpTarget is called.

However, when the opponent moves closer and I try to trigger the warping again, it doesn’t work. Even though I call AddOrUpdateWarpTarget, the warping still doesn’t occur.I’ve noticed motion warping notify state is not triggered at all.

To clarify: this scenario is using the same montage for both attacks. If I switch to different montage for the second attack the scenario is working as expected.

I will describe the bug once again in a simplified manner:

  1. Player character plays montage X without the opponent -- the motion warping notify state is triggered and we don’t call AddOrUpdateWarpTarget
  2. Player character moves to the opponent
  3. Player character plays montage X near the opponent -- the notify is not triggered and no warping is done

Note 1**:** If I skip step 1 (where the player character plays the montage without the opponent), step 3 works correctly (the warping occurs as expected).

Note 2: If I call AddOrUpdateWarpTarget during the first instance of that animation montage with some dummy location and rotation, step 3 also works correctly.

Can you help me figure out whether I’m doing something wrong or if this is potentially an engine bug?

I found a similar issue reported here: UE-173786. However, the proposed fix doesn’t seem applicable because the interface has changed since version 5.1.

We are using engine’s changelist 1083985.

Hi, thanks for reporting this, it does seem like a bug to me although I’ll need to speak with the dev team to confirm. The issue is similar to the JIRA that you mentioned, but not quite the same. The problem is that in URootMotionModifier_Warp::Update we disable the warp if no target is found. But we never re-enable the warp when a target is added later. That feels like an oversight to me. I think the fix should be quite simple, just check if the state is disabled, then check whether there is a valid target, and if so, re-enable the warp. I’ll look at putting something together for you tomorrow as a temporary fix.

There is another workaround for this, however, in the form of the switch off conditions (UMotionWarpingSwitchOffCondition and the derived types). You can use those conditions to modify the behaviour of warp while it’s still active - to cancel following the target, cancel the warp entirely, pause the warp, or pause the root motion. In your case you could setup your blueprint to do the following:

[Image Removed]This will play the montage and immediately set the warp target. But the switch off condition is then used to pause the warp until the actor is within the specified distance threshold from the target, at which point the warp is unpaused. I think that this should give you what you need for now but let me know if not.

The dev team have confirmed that this is a bug/missing functionality. I have a change for you to try out. Can you modify your implementation of UMotionWarpingComponent::AddOrUpdateWarpTarget to the following:

void UMotionWarpingComponent::AddOrUpdateWarpTarget(const FMotionWarpingTarget& WarpTarget)
{
	if (WarpTarget.Name != NAME_None)
	{
		// if we did not find the target, add it
		if (!FindAndUpdateWarpTarget(WarpTarget))
		{
			int32 Idx = WarpTargets.Add(WarpTarget);
 
			if (FSwitchOffConditionData* SwitchOffConditionData = FindSwitchOffConditionData(WarpTarget.Name))
			{
				SwitchOffConditionData->SetMotionWarpingTarget(&WarpTargets[Idx]);
			}
 
			// Warp modifiers may be deactivated if their target wasn't set initially so activate
			// any that use this target now
			for (URootMotionModifier* Modifier : Modifiers)
			{
				if (URootMotionModifier_Warp* WarpModifier = Cast<URootMotionModifier_Warp>(Modifier))
				{
					if (WarpModifier->WarpTargetName == WarpTarget.Name && WarpModifier->GetState() == ERootMotionModifierState::Disabled)
					{
						WarpModifier->SetState(ERootMotionModifierState::Active);
					}
				}
			}
		}
 
		MARK_PROPERTY_DIRTY_FROM_NAME(UMotionWarpingComponent, WarpTargets, this);
	}
}

That should activate any warp that was previously disabled (ie. didn’t have a target) when a target is set. Let me know if that gets things working for you.

EDIT: First I had some issues with reproducing it,

It appears your fix has resolved the issue. Is this going to be part of future engines releases?

Thank you very much for your time.

I will close the issue.

Thanks for confirming those changes resolved the issue for you. Yeah, I want to get this fixed along with a few other small fixes for motion warping that have come up recently. I can’t say for sure that the fix will be exactly the same code as this - I would prefer not to have to special case for the specific warp type in AddOrUpdateWarpTarget. But that may not be possible without refactoring how the warp objects interact with the warp targets. I’ve created a ticket for this so you can track the status here (it’ll take a day or two for the link to work).