Untitled

 avatar
user_8265478
plain_text
a year ago
4.6 kB
2
Indexable
//MultiGate.h//
// Copyright https://github.com/MothCocoon/FlowGraph/graphs/contributors

#pragma once

#include "Nodes/FlowNode.h"
#include "FlowNode_ExecutionMultiGate.generated.h"

/**
 * Executes a series of pins in order
 */
UCLASS(NotBlueprintable, meta = (DisplayName = "Multi Gate", Keywords = "series, loop, random"))
class FLOW_API UFlowNode_ExecutionMultiGate final : public UFlowNode
{
	GENERATED_UCLASS_BODY()

	UPROPERTY(EditAnywhere, Category = "MultiGate", meta = (EditCondition = "bParallel==false"))
	bool bRandom;

	// Allow executing output pins again, without triggering Reset pin
	// If set to False, every output pin can be triggered only once
	UPROPERTY(EditAnywhere, Category = "MultiGate")
	bool bLoop;
	
	//Allow the execution of the outputs in parallel
	UPROPERTY(EditAnywhere, Category = "MultiGate")
	bool bParallel;
	
	UPROPERTY(EditAnywhere, Category = "MultiGate")
	int32 StartIndex;

private:
	UPROPERTY(SaveGame)
	int32 NextOutput;

	UPROPERTY(SaveGame)
	TArray<bool> Completed;

public:
#if WITH_EDITOR
	virtual bool CanUserAddOutput() const override { return true; }
#endif

protected:
	virtual void ExecuteInput(const FName& PinName) override;
	virtual void Cleanup() override;

#if WITH_EDITOR
	virtual FString GetNodeDescription() const override;
#endif
};


//MultiGate.cpp//
// Copyright https://github.com/MothCocoon/FlowGraph/graphs/contributors

#include "Nodes/Route/FlowNode_ExecutionMultiGate.h"

UFlowNode_ExecutionMultiGate::UFlowNode_ExecutionMultiGate(const FObjectInitializer& ObjectInitializer)
	: Super(ObjectInitializer)
	, StartIndex(INDEX_NONE)
{
#if WITH_EDITOR
	Category = TEXT("Route");
	NodeStyle = EFlowNodeStyle::Logic;
#endif

	FString ResetPinTooltip = TEXT("Finish work of this node.");
	ResetPinTooltip += LINE_TERMINATOR;
	ResetPinTooltip += TEXT("Calling In input will start triggering output pins once again.");
	
	InputPins.Add(FFlowPin(TEXT("Stop")));
	InputPins.Add(FFlowPin(TEXT("Reset"), ResetPinTooltip));
	
	AllowedSignalModes = {EFlowSignalMode::Enabled, EFlowSignalMode::Disabled};
	
	OutputPins.Empty();
	SetNumberedOutputPins(0, 1);
	OutputPins.Add(FFlowPin(TEXT("Completed")));
	OutputPins.Add(FFlowPin(TEXT("Stopped")));
}

void UFlowNode_ExecutionMultiGate::ExecuteInput(const FName& PinName)
{
	if (PinName == DefaultInputPin.PinName)
	{
		if (Completed.Num() == 0)
		{
			Completed.Init(false, OutputPins.Num());
		}

		if (!Completed.Contains(false))
		{
			return;
		}

		const bool bUseStartIndex = !Completed.Contains(true) && Completed.IsValidIndex(StartIndex);
		if (bParallel)
		{
			// Ejecutar todas las salidas en paralelo directamente
			for (const FFlowPin& Output : OutputPins)
			{
				TriggerOutput(Output.PinName, false);
			}

			// Llamar al output "Completed" cuando se completan todas las salidas en paralelo
			TriggerOutput(TEXT("Completed"), false);
		}
		if (bRandom)
		{
			int32 Index;
			if (bUseStartIndex)
			{
				Index = StartIndex;
			}
			else
			{
				TArray<int32> AvailableIndexes;
				AvailableIndexes.Reserve(Completed.Num()); // todo

				for (int32 i = 0; i < Completed.Num(); i++)
				{
					if (Completed[i] == false)
					{
						AvailableIndexes.Emplace(i);
					}
				}

				const int32 Random = FMath::RandRange(0, AvailableIndexes.Num() - 1);
				Index = AvailableIndexes[Random];
			}

			Completed[Index] = true;
			TriggerOutput(OutputPins[Index].PinName, false);
		}
		else
		{
			if (bUseStartIndex)
			{
				NextOutput = StartIndex;
			}

			const int32 CurrentOutput = NextOutput;
			// We have to calculate NextOutput before TriggerOutput(..)
			// TriggerOutput may call Reset and Cleanup
			NextOutput = ++NextOutput % OutputPins.Num();

			Completed[CurrentOutput] = true;
			TriggerOutput(OutputPins[CurrentOutput].PinName, false);
		}

		if (!Completed.Contains(false) && bLoop)
		{
			Finish();
		}
	}
	else if (PinName == TEXT("Reset"))
	{
		Finish();
	}
}

void UFlowNode_ExecutionMultiGate::Cleanup()
{
	NextOutput = 0;
	Completed.Reset();
}

#if WITH_EDITOR
FString UFlowNode_ExecutionMultiGate::GetNodeDescription() const
{
	FString Result;
	Result.Reserve(128);

	if (bRandom)
	{
		Result.Append(TEXT("Random"));
	}
	if (bParallel)
	{
		Result.Append(TEXT("Parallel"));
	}
	if (bRandom && bLoop)
	{
		Result.Append(TEXT(", "));
	}

	if (bLoop)
	{
		Result.Append(TEXT("Loop"));
	}

	if (StartIndex != INDEX_NONE)
	{
		if (bRandom || bLoop)
		{
			Result.Append(TEXT(", "));
		}

		if (OutputPins.IsValidIndex(StartIndex))
		{
			Result.Appendf(TEXT("Start Index: %d"), StartIndex);
		}
		else
		{
			Result.Append(TEXT("StartIndex: Invalid"));
		}
	}

	return Result;
}
#endif
Leave a Comment