Variables in notify states not being instance independent. They get overwritten.

Hello! I hope you can help me with this issue. I have multiple custom AnimNotifyStates that I use in my game, many of which have variables that I set at runtime. The most obvious example would be my UTctAnimNotifyState, which is my parent class for all my custom AnimNotifyStates, and has a Timer variable to track the elapsed time since the AnimNotifyState started.

The problem I have found with these variables is that (I presume for optimization) they seem to be shared or overwritten in cases where different characters are executing the same AnimNotifyState at once.

I have come up with strange and cumbersome solutions for this, e.g Having a TMap<UAnimNotifyState, TypeOfVariableIWantToTrack> for each AnimNotifyState, but it demands a lot of code and makes it very tricky.

Is there a way to easily disable this optimization so that each active NotifyState contains isolated data (variables) that will not be overriden? Alternatively, is there a quick and easy solution for this that doesn’t involve changing my entire architecture for this? (tracking state in the character instead of the notify state is not a viable change to make at this point in development).

I know the AnimNotifyState functions have the FAnimNotifyEventReference& EventReference parameter. Maybe I can use this to store and update data in this way? I can’t seem to wrap my head around how this would work.

Video Demonstration

Code:

.h File

// Tessera Studios placeholder copyright - All rights reserved

#pragma once

#include "CoreMinimal.h"
#include "Animation/AnimNotifies/AnimNotifyState.h"
#include "TctAnimNotifyState.generated.h"

/**
 * Base anim notify state class.
 */
UCLASS()
class TESSERACOMMONTOOLS_API UTctAnimNotifyState : public UAnimNotifyState
{
	GENERATED_BODY()

public:

	UTctAnimNotifyState();
	virtual void NotifyBegin(USkeletalMeshComponent* MeshComp, UAnimSequenceBase* Animation, float TotalDuration, const FAnimNotifyEventReference& EventReference) override;
	virtual void NotifyTick(USkeletalMeshComponent* MeshComp, UAnimSequenceBase* Animation, float FrameDeltaTime, const FAnimNotifyEventReference& EventReference) override;

protected:

	UPROPERTY(BlueprintReadOnly, Transient, Category = "Properties")
	float Duration = 0.0f;

	UPROPERTY(BlueprintReadOnly, Transient, Category = "Properties")
	float Timer = 0.0f;
};

.cpp file

// Tessera Studios placeholder copyright - All rights reserved

#include "Anim/Notifies/TctAnimNotifyState.h"

UTctAnimNotifyState::UTctAnimNotifyState()
{

}

void UTctAnimNotifyState::NotifyBegin(USkeletalMeshComponent* MeshComp, UAnimSequenceBase* Animation, float TotalDuration, const FAnimNotifyEventReference& EventReference)
{
	Super::NotifyBegin(MeshComp, Animation, TotalDuration, EventReference);

	Duration = TotalDuration;
	Timer = 0.0f;

	if (IsValid(Animation))
	{
		Duration /= Animation->RateScale;
	}
}

void UTctAnimNotifyState::NotifyTick(USkeletalMeshComponent* MeshComp, UAnimSequenceBase* Animation, float FrameDeltaTime, const FAnimNotifyEventReference& EventReference)
{
	Super::NotifyTick(MeshComp, Animation, FrameDeltaTime, EventReference);

	Timer += FrameDeltaTime;
	if (Timer > Duration) Timer = Duration;	// clamp it to duration, just in case
}

Thankyou so much in advance for any help! I hope you have a quick solution for this since I have been struggling with this issue for weeks.

Kinds regards,

Jorge Dinarés.