// © 2024 Long Ly. All rights reserved. Any unauthorized use, reproduction, or distribution of this trademark is strictly prohibited and may result in legal action.


#include "Nodes/AnimGraphNode_OLSMask.h"

#include "Kismet2/BlueprintEditorUtils.h"

#define LOCTEXT_NAMESPACE "OLSNodes"

UAnimGraphNode_OLSMask::UAnimGraphNode_OLSMask(const FObjectInitializer& objectInitializer) : Super(objectInitializer)
{
	Node.BlendMasks.Reserve(1);
	Node.MaskBlendWeights.Reserve(1);
	Node.AllBoneBlendWeights.Reserve(1);
}

FLinearColor UAnimGraphNode_OLSMask::GetNodeTitleColor() const
{
	return FLinearColor(0.0f, 204.0f, 204.0f);
}

FText UAnimGraphNode_OLSMask::GetTooltipText() const
{
	return LOCTEXT("AnimGraphNode_OLSMask_Tooltip", "OLS Mask Node");
}

FText UAnimGraphNode_OLSMask::GetNodeTitle(ENodeTitleType::Type TitleType) const
{
	return LOCTEXT("AnimGraphNode_OLSMaskBlend_Title", "Per Body Part Mask");
}

void UAnimGraphNode_OLSMask::PostEditChangeProperty(FPropertyChangedEvent& PropertyChangedEvent)
{
	const FName PropertyName = (PropertyChangedEvent.Property ? PropertyChangedEvent.Property->GetFName() : NAME_None);


	if (PropertyName == GET_MEMBER_NAME_STRING_CHECKED(FAnimNode_OLSMask, BlendMasks))
	{
		FScopedTransaction Transaction(LOCTEXT("AddedBlendMask", "Add Blend Mask"));
		Modify();

		const int32 NumMasks = Node.BlendMasks.Num();
		Node.MaskBlendWeights.SetNum(NumMasks);
		Node.AllBoneBlendWeights.SetNum(NumMasks);
		FBlueprintEditorUtils::MarkBlueprintAsStructurallyModified(GetBlueprint());
		ReconstructNode();
	}

	Super::PostEditChangeProperty(PropertyChangedEvent);
}

FString UAnimGraphNode_OLSMask::GetNodeCategory() const
{
	return TEXT("Blends|OLS Nodes");
}

void UAnimGraphNode_OLSMask::PreloadRequiredAssets()
{
	const TObjectPtr<UAnimBlueprint> animBlueprint = GetAnimBlueprint();
	if (animBlueprint && !GIsCookerLoadingPackage && animBlueprint->TargetSkeleton)
	{
		const int32 numBlendMasks = Node.BlendMasks.Num();
		if (numBlendMasks > 0)
		{
			for (int32 maskIndex = 0; maskIndex < numBlendMasks; ++maskIndex)
			{
				const FName blendProfileName = Node.BlendMasks[maskIndex].BlendProfileName;
				if (const TObjectPtr<UBlendProfile> blendProfile = animBlueprint->TargetSkeleton->GetBlendProfile(
					blendProfileName))
				{
					Node.BlendMasks[maskIndex].BlendProfile = blendProfile;
				}

				const TObjectPtr<UBlendProfile> blendMask = Node.BlendMasks[maskIndex].BlendProfile;
				PreloadObject(blendMask);
			}
		}
	}

	Super::PreloadRequiredAssets();
}

void UAnimGraphNode_OLSMask::BakeDataDuringCompilation(FCompilerResultsLog& MessageLog)
{
	const TObjectPtr<UAnimBlueprint> animBlueprint = GetAnimBlueprint();
	if (!GIsCookerLoadingPackage && animBlueprint->TargetSkeleton)
	{
		const int32 numBlendMasks = Node.BlendMasks.Num();
		for (int32 maskIndex = 0; maskIndex < numBlendMasks; ++maskIndex)
		{
			const FOLSMaskSettings& currentMask = Node.BlendMasks[maskIndex];
			const FName& blendProfileName = Node.BlendMasks[maskIndex].BlendProfileName;
			if (const TObjectPtr<UBlendProfile> bendProfile = animBlueprint->TargetSkeleton->GetBlendProfile(
				blendProfileName))
			{
				Node.BlendMasks[maskIndex].BlendProfile = bendProfile;
			}

			if (currentMask.bShouldAddSlot)
			{
				animBlueprint->TargetSkeleton->RegisterSlotNode(currentMask.SlotName);
			}
		}
	}
}

void UAnimGraphNode_OLSMask::ValidateAnimNodeDuringCompilation(USkeleton* skeleton, FCompilerResultsLog& MessageLog)
{
	if (skeleton)
	{
		// ensure to cache the per-bone blend weights
		if (!Node.ArePerBoneBlendWeightsValid(skeleton))
		{
			Node.RebuildPerBoneBlendWeights(skeleton);
		}

		if (Node.BlendMasks.Num() > 0)
		{
			const int32 numBlendMasks = Node.BlendMasks.Num();
			for (int32 maskIndex = 0; maskIndex < numBlendMasks; ++maskIndex)
			{
				const FName& blendProfileName = Node.BlendMasks[maskIndex].BlendProfileName;
				const TObjectPtr<UBlendProfile> blendProfile = skeleton->GetBlendProfile(blendProfileName);
				if (blendProfile)
				{
					Node.BlendMasks[maskIndex].BlendProfile = blendProfile;
				}

				if (!blendProfile)
				{
					MessageLog.Error(
						*FText::Format(
							LOCTEXT("BlendProfileIsNull", "@@ has null BlendMask In Index {0}. "),
							FText::AsNumber(maskIndex)).ToString(), this, blendProfile);
					continue;
				}
				if (!blendProfile->IsBlendMask())
				{
					MessageLog.Error(
						*FText::Format(LOCTEXT("BlendProfileModeError",
						                       "@@ is using a BlendProfile(@@) without a BlendMask mode In Index {0}. "), FText::AsNumber(
							               maskIndex)).ToString(), this, blendProfile);
				}
			}
		}
	}
	Super::ValidateAnimNodeDuringCompilation(skeleton, MessageLog);
}

#undef LOCTEXT_NAMESPACE
