Merge branch 'release/0.1.0'
This commit is contained in:
		
						commit
						df3c340779
					
				
							
								
								
									
										
											BIN
										
									
								
								Content/BPML_StateMacros.uasset
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										
											BIN
										
									
								
								Content/BPML_StateMacros.uasset
									
									
									
									
									
										Normal file
									
								
							
										
											Binary file not shown.
										
									
								
							@ -1,4 +1,4 @@
 | 
				
			|||||||
# UnrealFightingEngine
 | 
					# UnrealFightingFramework
 | 
				
			||||||
 | 
					
 | 
				
			||||||
This library provides actors, components, and other general data structures that are useful for developing character action or fighting games.
 | 
					This library provides actors, components, and other general data structures that are useful for developing character action or fighting games.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
				
			|||||||
@ -1,16 +0,0 @@
 | 
				
			|||||||
// Copyright Epic Games, Inc. All Rights Reserved.
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
#include "UnrealFightingEngineBPLibrary.h"
 | 
					 | 
				
			||||||
#include "UnrealFightingEngine.h"
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
UUnrealFightingEngineBPLibrary::UUnrealFightingEngineBPLibrary(const FObjectInitializer& ObjectInitializer)
 | 
					 | 
				
			||||||
: Super(ObjectInitializer)
 | 
					 | 
				
			||||||
{
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
float UUnrealFightingEngineBPLibrary::UnrealFightingEngineSampleFunction(float Param)
 | 
					 | 
				
			||||||
{
 | 
					 | 
				
			||||||
	return -1;
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
@ -0,0 +1,25 @@
 | 
				
			|||||||
 | 
					// Project Sword & Gun Copyright Kevin Poretti
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#include "GameplayFramework/FFGameState.h"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					void AFFGameState::OnFixedTick(float OneTick)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					void AFFGameState::Tick(float DeltaSeconds)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    Super::Tick(DeltaSeconds);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    // Run anything game logic related at a fixed tick rate
 | 
				
			||||||
 | 
					    // TODO: Interpolate between prev and current game state if there is time left in accumulator
 | 
				
			||||||
 | 
					    AccumulatedTime += DeltaSeconds;
 | 
				
			||||||
 | 
					    while(AccumulatedTime > ONE_TICK)
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        OnFixedTick(ONE_TICK);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        AccumulatedTime -= ONE_TICK;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        CurrentTick++;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
@ -0,0 +1,41 @@
 | 
				
			|||||||
 | 
					// Project Sword & Gun Copyright Kevin Poretti
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#pragma once
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#include "CoreMinimal.h"
 | 
				
			||||||
 | 
					#include "GameFramework/GameState.h"
 | 
				
			||||||
 | 
					#include "FFGameState.generated.h"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					constexpr float ONE_TICK = 0.0083333333;
 | 
				
			||||||
 | 
					constexpr int64 TICKS_PER_SECOND = 120;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/**
 | 
				
			||||||
 | 
					 * 
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					UCLASS()
 | 
				
			||||||
 | 
					class UNREALFIGHTINGFRAMEWORK_API AFFGameState : public AGameState
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						GENERATED_BODY()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					public:
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    UFUNCTION(BlueprintPure)
 | 
				
			||||||
 | 
						int64 GetCurrentTick() const { return CurrentTick; }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    virtual void OnFixedTick(float OneTick);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						// Begin AActor interface
 | 
				
			||||||
 | 
						virtual void Tick(float DeltaSeconds) override;
 | 
				
			||||||
 | 
						// End AActor interface
 | 
				
			||||||
 | 
					private:
 | 
				
			||||||
 | 
					    /**
 | 
				
			||||||
 | 
						 * Amount of time accumulated from ticks. When Tick is called the delta time since the
 | 
				
			||||||
 | 
						 * last Tick will be added to this variable.
 | 
				
			||||||
 | 
						 *
 | 
				
			||||||
 | 
						 * Once enough time has accumulated to simulate at least one frame (defined by the value ONE_TICK) then the
 | 
				
			||||||
 | 
						 * game logic will update/tick. ONE_TICK's worth of time will be subtracted from the this variable
 | 
				
			||||||
 | 
						 */
 | 
				
			||||||
 | 
						float AccumulatedTime = 0;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						int64 CurrentTick = 0;
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
							
								
								
									
										35
									
								
								Source/UnrealFightingFramework/IFFSystemInterface.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										35
									
								
								Source/UnrealFightingFramework/IFFSystemInterface.h
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,35 @@
 | 
				
			|||||||
 | 
					// Unreal Fighting Framework by Kevin Poretti
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#pragma once
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// UE includes
 | 
				
			||||||
 | 
					#include "CoreMinimal.h"
 | 
				
			||||||
 | 
					#include "UObject/Interface.h"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#include "IFFSystemInterface.generated.h"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// This class does not need to be modified.
 | 
				
			||||||
 | 
					UINTERFACE(MinimalAPI)
 | 
				
			||||||
 | 
					class UFFSystemInterface : public UInterface
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						GENERATED_BODY()
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/**
 | 
				
			||||||
 | 
					 *	This interface defines functions that need to be implemented for any objects that are "gameplay affecting".
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 *	This ensures all gameplay effecting objects can be assumed to have certain properties that enable serialization, networking and
 | 
				
			||||||
 | 
					 *	some form of determinism.
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					class UNREALFIGHTINGFRAMEWORK_API IFFSystemInterface
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						GENERATED_BODY()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					public:
 | 
				
			||||||
 | 
						/**
 | 
				
			||||||
 | 
						 *	Function to be called at a fixed interval/frame rate rather than using Unreal's variable Tick function
 | 
				
			||||||
 | 
						 *
 | 
				
			||||||
 | 
						 *	@param OneFrame the time that elapses during one fixed tick
 | 
				
			||||||
 | 
						 */
 | 
				
			||||||
 | 
					    virtual void FixedTick(float OneFrame) = 0;
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
@ -0,0 +1,86 @@
 | 
				
			|||||||
 | 
					// Unreal Fighting Framework by Kevin Poretti
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#include "FFInputBufferComponent.h"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					UFFInputBufferComponent::UFFInputBufferComponent()
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						PrimaryComponentTick.bCanEverTick = false;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					void UFFInputBufferComponent::AddInput(const FFFInputState& InputState)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						InputBuffer.ForcePush(InputState);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					bool UFFInputBufferComponent::CheckInputSequence(const FFFInputSequence& InputSequence)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    if(InputSequence.Sequence.IsEmpty())
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        UE_LOG(LogTemp, Error, 
 | 
				
			||||||
 | 
					            TEXT("FFInputBufferComponent :: CheckInputSequence - tried to check input sequence but it was empty"));
 | 
				
			||||||
 | 
					        return false;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    int CondIdx = InputSequence.Sequence.Num() - 1;
 | 
				
			||||||
 | 
					    int ElapsedFrames = 0;
 | 
				
			||||||
 | 
					    for(int InpIdx = InputBuffer.Num() - 1; InpIdx > 1; InpIdx--)
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        int32 RequiredButtons = InputSequence.Sequence[CondIdx].RequiredButtons;
 | 
				
			||||||
 | 
					        EFFButtonState RequiredButtonState = InputSequence.Sequence[CondIdx].RequiredButtonState;
 | 
				
			||||||
 | 
					        int32 PrevInput = InputBuffer[InpIdx - 1].Buttons;
 | 
				
			||||||
 | 
					        int32 CurrInput = InputBuffer[InpIdx].Buttons;
 | 
				
			||||||
 | 
					        int32 PrevDisable = InputBuffer[InpIdx - 1].DisabledButtons;
 | 
				
			||||||
 | 
					        int32 CurrDisable = InputBuffer[InpIdx].DisabledButtons;
 | 
				
			||||||
 | 
					        switch (RequiredButtonState)
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					            // TODO: should it be (PrevInput & RequiredButtons) == RequiredButtons or what we have now?
 | 
				
			||||||
 | 
					            case EFFButtonState::BTNS_Pressed:
 | 
				
			||||||
 | 
					                if(!(PrevInput & RequiredButtons | PrevDisable) && 
 | 
				
			||||||
 | 
					                   CurrInput & RequiredButtons & ~CurrDisable)
 | 
				
			||||||
 | 
					                {
 | 
				
			||||||
 | 
					                    CondIdx--;
 | 
				
			||||||
 | 
					                }
 | 
				
			||||||
 | 
					                break;
 | 
				
			||||||
 | 
					            case EFFButtonState::BTNS_Released:
 | 
				
			||||||
 | 
					                if(PrevInput & RequiredButtons & ~PrevDisable &&
 | 
				
			||||||
 | 
					                   !(CurrInput & RequiredButtons | CurrDisable))
 | 
				
			||||||
 | 
					                {
 | 
				
			||||||
 | 
					                    CondIdx--;
 | 
				
			||||||
 | 
					                }
 | 
				
			||||||
 | 
					                break;
 | 
				
			||||||
 | 
					            case EFFButtonState::BTNS_Down:
 | 
				
			||||||
 | 
					                if(CurrInput & RequiredButtons & ~CurrDisable)
 | 
				
			||||||
 | 
					                {
 | 
				
			||||||
 | 
					                    CondIdx--;
 | 
				
			||||||
 | 
					                }
 | 
				
			||||||
 | 
					                break;
 | 
				
			||||||
 | 
					            // TODO: implement button held condition
 | 
				
			||||||
 | 
					            /*
 | 
				
			||||||
 | 
					            case EFFButtonState::BTNS_Held:
 | 
				
			||||||
 | 
					                break;
 | 
				
			||||||
 | 
					            */
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        // All conditions were met
 | 
				
			||||||
 | 
					        if(CondIdx == -1)
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					            return true;
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        ElapsedFrames++;
 | 
				
			||||||
 | 
					        if(ElapsedFrames > InputSequence.MaxDuration)
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					            return false;
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						return false;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					void UFFInputBufferComponent::DisableMostRecentInput()
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    InputBuffer[InputBuffer.Num() - 1].DisabledButtons |= InputBuffer[InputBuffer.Num() - 1].Buttons;
 | 
				
			||||||
 | 
					    InputBuffer[InputBuffer.Num() - 2].DisabledButtons |= InputBuffer[InputBuffer.Num() - 2].Buttons;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
							
								
								
									
										102
									
								
								Source/UnrealFightingFramework/Input/FFInputBufferComponent.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										102
									
								
								Source/UnrealFightingFramework/Input/FFInputBufferComponent.h
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,102 @@
 | 
				
			|||||||
 | 
					// Unreal Fighting Framework by Kevin Poretti
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#pragma once
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// FF includes
 | 
				
			||||||
 | 
					#include "Utils/TCircleBuffer.h"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// UE includes
 | 
				
			||||||
 | 
					#include "CoreMinimal.h"
 | 
				
			||||||
 | 
					#include "Components/ActorComponent.h"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#include "FFInputBufferComponent.generated.h"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					UENUM(BlueprintType)
 | 
				
			||||||
 | 
					enum class EFFButtonState : uint8
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    BTNS_Pressed		UMETA(DisplayName="Pressed"),
 | 
				
			||||||
 | 
						BTNS_Released		UMETA(DisplayName="Released"),
 | 
				
			||||||
 | 
					    BTNS_Down			UMETA(DisplayName="Down"),    
 | 
				
			||||||
 | 
						//BTNS_Held			UMETA(DisplayName="Held"),
 | 
				
			||||||
 | 
						BTNS_MAX			UMETA(Hidden)
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/**
 | 
				
			||||||
 | 
					 *	Struct representing the state of a player's inputs for one frame
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					USTRUCT()
 | 
				
			||||||
 | 
					struct FFFInputState
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    GENERATED_BODY()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						FVector2D	MoveAxes;
 | 
				
			||||||
 | 
						FVector2D	LookAxes;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						UPROPERTY(EditAnywhere, Meta = (Bitmask))
 | 
				
			||||||
 | 
						int32		Buttons;
 | 
				
			||||||
 | 
						int32		DisabledButtons;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						FFFInputState()
 | 
				
			||||||
 | 
						    : MoveAxes(FVector2D::ZeroVector)
 | 
				
			||||||
 | 
						    , LookAxes(FVector2D::ZeroVector)
 | 
				
			||||||
 | 
						    , Buttons(0)
 | 
				
			||||||
 | 
						    , DisabledButtons(0)
 | 
				
			||||||
 | 
						{
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					USTRUCT(BlueprintType)
 | 
				
			||||||
 | 
					struct FFFInputCondition
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    GENERATED_BODY()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						// Buttons required for this specific condition to be valid
 | 
				
			||||||
 | 
						UPROPERTY(EditAnywhere, BlueprintReadWrite)
 | 
				
			||||||
 | 
						int32 RequiredButtons;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						// The button state required for condition to be valid i.e. pressed or released
 | 
				
			||||||
 | 
						UPROPERTY(EditAnywhere, BlueprintReadWrite)
 | 
				
			||||||
 | 
						EFFButtonState RequiredButtonState;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						FFFInputCondition()
 | 
				
			||||||
 | 
					        : RequiredButtons(0)
 | 
				
			||||||
 | 
					        , RequiredButtonState(EFFButtonState::BTNS_Pressed)
 | 
				
			||||||
 | 
						{
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					USTRUCT(BlueprintType)
 | 
				
			||||||
 | 
					struct FFFInputSequence
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    GENERATED_BODY()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    UPROPERTY(EditAnywhere, BlueprintReadWrite)
 | 
				
			||||||
 | 
						TArray<FFFInputCondition> Sequence;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						UPROPERTY(EditAnywhere, BlueprintReadWrite)
 | 
				
			||||||
 | 
						int32 MaxDuration;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						FFFInputSequence()
 | 
				
			||||||
 | 
						    : MaxDuration(0)
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					UCLASS( ClassGroup=(UnrealFightingFramework), meta=(BlueprintSpawnableComponent) )
 | 
				
			||||||
 | 
					class UNREALFIGHTINGFRAMEWORK_API UFFInputBufferComponent : public UActorComponent
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						GENERATED_BODY()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					public:	
 | 
				
			||||||
 | 
						UFFInputBufferComponent();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						void AddInput(const FFFInputState& InputState);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						bool CheckInputSequence(const FFFInputSequence& InputSequence);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						void DisableMostRecentInput();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					protected:
 | 
				
			||||||
 | 
						/** The underlying buffer data structure for holding past input states */
 | 
				
			||||||
 | 
						TCircleBuffer<FFFInputState, 120> InputBuffer;
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
							
								
								
									
										79
									
								
								Source/UnrealFightingFramework/Input/FFPlayerController.cpp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										79
									
								
								Source/UnrealFightingFramework/Input/FFPlayerController.cpp
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,79 @@
 | 
				
			|||||||
 | 
					// Unreal Fighting Framework by Kevin Poretti
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#include "FFPlayerController.h"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// FF includes
 | 
				
			||||||
 | 
					#include "FFInputBufferComponent.h"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// UE includes
 | 
				
			||||||
 | 
					#include "EnhancedInputSubsystems.h"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					AFFPlayerController::AFFPlayerController()
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    InputBuffer = CreateDefaultSubobject<UFFInputBufferComponent>(TEXT("InputBuffer"));
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					void AFFPlayerController::SendInputsToRemote() const
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					void AFFPlayerController::ModifyRawInput()
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    ModifiedInput = RawInput;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					void AFFPlayerController::FixedTick(float OneFrame)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    //UnacknowledgedInputs.Push(RawInput);
 | 
				
			||||||
 | 
					    InputBuffer->AddInput(ModifiedInput);
 | 
				
			||||||
 | 
					    //SendInputsToRemote();
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					bool AFFPlayerController::CheckInputSequence(const FFFInputSequence& InInputSequence)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    return InputBuffer->CheckInputSequence(InInputSequence);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					bool AFFPlayerController::CheckInputSequences(const TArray<FFFInputSequence>& InputSequences)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    // no input conditions to check
 | 
				
			||||||
 | 
					    if(InputSequences.IsEmpty())
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        return true;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    for(const FFFInputSequence& ThisInputSequence : InputSequences)
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        if(InputBuffer->CheckInputSequence(ThisInputSequence))
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					            return true;
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    return false;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					void AFFPlayerController::DisableMostRecentInput()
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    InputBuffer->DisableMostRecentInput();
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					void AFFPlayerController::SetupInputComponent()
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    Super::SetupInputComponent();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    if (ULocalPlayer* LocalPlayer = Cast<ULocalPlayer>(Player))
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        if (UEnhancedInputLocalPlayerSubsystem* InputSystem = LocalPlayer->GetSubsystem<UEnhancedInputLocalPlayerSubsystem>())
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					            if (!DefaultInputMapping.IsNull())
 | 
				
			||||||
 | 
					            {
 | 
				
			||||||
 | 
					                InputSystem->AddMappingContext(DefaultInputMapping.LoadSynchronous(), 0);
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
							
								
								
									
										92
									
								
								Source/UnrealFightingFramework/Input/FFPlayerController.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										92
									
								
								Source/UnrealFightingFramework/Input/FFPlayerController.h
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,92 @@
 | 
				
			|||||||
 | 
					// Unreal Fighting Framework by Kevin Poretti
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#pragma once
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// FF includes
 | 
				
			||||||
 | 
					#include "FFInputBufferComponent.h"
 | 
				
			||||||
 | 
					#include "IFFSystemInterface.h"
 | 
				
			||||||
 | 
					#include "Utils/TCircleBuffer.h"
 | 
				
			||||||
 | 
					#include "State/IFFStateOwnerInterface.h"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// UE includes
 | 
				
			||||||
 | 
					#include "CoreMinimal.h"
 | 
				
			||||||
 | 
					#include "GameFramework/PlayerController.h"
 | 
				
			||||||
 | 
					#include "InputMappingContext.h"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#include "FFPlayerController.generated.h"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/**
 | 
				
			||||||
 | 
					 *	A class that collects player inputs, stores them in an input buffer, and sends a rolling window of
 | 
				
			||||||
 | 
					 *	unacknowledged inputs to a remote client or server for processing.
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					UCLASS()
 | 
				
			||||||
 | 
					class UNREALFIGHTINGFRAMEWORK_API AFFPlayerController : public APlayerController, public IFFSystemInterface, public IFFStateOwnerInterface
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						GENERATED_BODY()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					public:
 | 
				
			||||||
 | 
						AFFPlayerController();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/**
 | 
				
			||||||
 | 
						 *	Sends all unacknowledged inputs to the remote
 | 
				
			||||||
 | 
						 */
 | 
				
			||||||
 | 
						virtual void SendInputsToRemote() const;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /**
 | 
				
			||||||
 | 
					     * @brief Gets the current input after cleaning/modifying the raw input state
 | 
				
			||||||
 | 
					     * @return the current input
 | 
				
			||||||
 | 
					     */
 | 
				
			||||||
 | 
					    virtual FFFInputState GetModifiedInput() const { return ModifiedInput; };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /**
 | 
				
			||||||
 | 
					     * @brief Function called before inputs are passed to the game logic to update the game state.
 | 
				
			||||||
 | 
					     * This is a chance for the application to mutate inputs before the game uses them to update game state.
 | 
				
			||||||
 | 
					     * Examples would include treating opposite directional inputs being held cancelling each other out or setting
 | 
				
			||||||
 | 
					     * a "neutral input" flag when no directional inputs are being held.
 | 
				
			||||||
 | 
					     * For stick/axis values this can be clamping those values or normalizing the Move and Look direction vectors.
 | 
				
			||||||
 | 
					     */
 | 
				
			||||||
 | 
					    virtual void ModifyRawInput();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						// IFFSystemInterface interface
 | 
				
			||||||
 | 
						virtual void FixedTick(float OneFrame) override;
 | 
				
			||||||
 | 
						// End of IFFSystemInterface
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						// IFFStateOwnerInterface
 | 
				
			||||||
 | 
						UFUNCTION()
 | 
				
			||||||
 | 
						virtual bool CheckInputSequence(const FFFInputSequence& InInputSequence) override;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						UFUNCTION()
 | 
				
			||||||
 | 
					    virtual bool CheckInputSequences(const TArray<FFFInputSequence>& InputSequences) override;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						virtual void DisableMostRecentInput() override;
 | 
				
			||||||
 | 
						// End of IFFStateOwnerInterface
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						// APlayerController interface
 | 
				
			||||||
 | 
						virtual void SetupInputComponent() override;
 | 
				
			||||||
 | 
						// End of APlayerController interface
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					protected:
 | 
				
			||||||
 | 
					    /** MappingContext */
 | 
				
			||||||
 | 
						UPROPERTY(EditAnywhere, BlueprintReadOnly, Category = "UFF|Input", meta = (AllowPrivateAccess = "true"))
 | 
				
			||||||
 | 
						TSoftObjectPtr<UInputMappingContext> DefaultInputMapping;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/** Input Buffer component */
 | 
				
			||||||
 | 
						UPROPERTY(VisibleAnywhere, BlueprintReadOnly, Category = "UFF|Input", meta = (AllowPrivateAccess = "true"))
 | 
				
			||||||
 | 
						UFFInputBufferComponent* InputBuffer;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/** Current state of the player's inputs */
 | 
				
			||||||
 | 
						FFFInputState RawInput;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/** Current state of the player's inputs after performing cleaning and modifications */
 | 
				
			||||||
 | 
						FFFInputState ModifiedInput;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/**
 | 
				
			||||||
 | 
						 *	Rolling window of the player's past inputs that have yet to be
 | 
				
			||||||
 | 
						 *	acknowledged and simulated by the remote machine
 | 
				
			||||||
 | 
						 *
 | 
				
			||||||
 | 
						 *	This ring buffer should be initialized to be the size of the past X frames
 | 
				
			||||||
 | 
						 *	you want the remote machine to re-simulate, where X is the oldest input you want to
 | 
				
			||||||
 | 
						 *	allow to be re-simulated.
 | 
				
			||||||
 | 
						 */
 | 
				
			||||||
 | 
						TCircleBuffer<FFFInputState, 20> UnacknowledgedInputs;
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
							
								
								
									
										240
									
								
								Source/UnrealFightingFramework/State/FFState.cpp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										240
									
								
								Source/UnrealFightingFramework/State/FFState.cpp
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,240 @@
 | 
				
			|||||||
 | 
					// Unreal Fighting Framework by Kevin Poretti
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#include "FFState.h"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// FF includes
 | 
				
			||||||
 | 
					#include "FFStateMachineComponent.h"
 | 
				
			||||||
 | 
					#include "IFFStateAvatarInterface.h"
 | 
				
			||||||
 | 
					#include "IFFStateOwnerInterface.h"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// UE includes
 | 
				
			||||||
 | 
					#include "Components/SkeletalMeshComponent.h"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					void UFFState::Init(const FFFStateContext& InStateContext)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    OnInit(InStateContext);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					bool UFFState::CanTransition(const FFFStateContext& InStateContext)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    /**
 | 
				
			||||||
 | 
					     *  Check to see if avatar implements StateAvatarInterface
 | 
				
			||||||
 | 
					     *  if so then
 | 
				
			||||||
 | 
					     *      Check if the avatar is in the correct stance to perform this action
 | 
				
			||||||
 | 
					     *      Check if the state is enabled
 | 
				
			||||||
 | 
					     *
 | 
				
			||||||
 | 
					     *  Check to see if the owner implements the StateOwnerInterface
 | 
				
			||||||
 | 
					     *      Check input conditions if there are any
 | 
				
			||||||
 | 
					     *
 | 
				
			||||||
 | 
					     *  If at least one input condition is good then we can transition
 | 
				
			||||||
 | 
					     *  so return true otherwise return false
 | 
				
			||||||
 | 
					     */
 | 
				
			||||||
 | 
					    IFFStateAvatarInterface* SAI = Cast<IFFStateAvatarInterface>(InStateContext.Avatar);
 | 
				
			||||||
 | 
					    if(SAI)
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        if(!(SAI->CheckStance(StanceRequired) && SAI->CheckStateEnabled(StateType)))
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					            return false;
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    else
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        UE_LOG(LogTemp, Error, TEXT("CanTransition :: Avatar of FFFStateContext does not implement IFFStateAvatarInterface"));
 | 
				
			||||||
 | 
					        return false;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    IFFStateOwnerInterface* SOI = Cast<IFFStateOwnerInterface>(InStateContext.Owner);
 | 
				
			||||||
 | 
					    if(SOI)
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        if(!SOI->CheckInputSequences(InputSequences))
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					            return false;
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    else
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        UE_LOG(LogTemp, Error, TEXT("CanTransition :: Owner of FFFStateContext does not implement IFFStateOwnerInterface"));
 | 
				
			||||||
 | 
					        return false;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    return OnCanTransition(InStateContext);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					void UFFState::Enter(const FFFStateContext& InStateContext)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    PlayMontage(InStateContext);
 | 
				
			||||||
 | 
					    
 | 
				
			||||||
 | 
					    OnEnter(InStateContext);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					void UFFState::Exit(const FFFStateContext& InStateContext, EFFStateFinishReason StateFinishReason)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    
 | 
				
			||||||
 | 
					    
 | 
				
			||||||
 | 
					    if(InStateContext.Avatar && 
 | 
				
			||||||
 | 
					      (bStopMontageOnStateEnd && StateFinishReason == EFFStateFinishReason::SFT_DurationMetOrExceeded || StateFinishReason == EFFStateFinishReason::SFT_Interrupted) || 
 | 
				
			||||||
 | 
					      (bStopMontageOnMovementModeChange && StateFinishReason == EFFStateFinishReason::SFT_NotInReqMovementMode))
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        StopCurrentAnimMontage(InStateContext);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    OnExit(InStateContext);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					void UFFState::Update(float OneFrame, const FFFStateContext& InStateContext)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    IFFStateOwnerInterface* SOI = Cast<IFFStateOwnerInterface>(InStateContext.Owner);
 | 
				
			||||||
 | 
					    // TODO: maybe a check/asset is better because I can't think of a reason that not having the Owner implement
 | 
				
			||||||
 | 
					    // IFFStateOwnerInterface is valid. Although there could be objects that have state that don't necessarily directly
 | 
				
			||||||
 | 
					    // respond to input and don't have an Owner/controller responsible for them. Or they do have an owner but are associated
 | 
				
			||||||
 | 
					    // with another Avatar like a character who is owned by a player/player controller.
 | 
				
			||||||
 | 
					    if(!SOI)
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        UE_LOG(LogTemp, Error, TEXT("Owner of FFFStateContext does not implement IFFStateOwnerInterface"));
 | 
				
			||||||
 | 
					        return;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    for(FFFInputEventHandler InputHandler : InputHandlers)
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        if(SOI->CheckInputSequence(InputHandler.RequiredSequence))
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					            if(InputHandler.Delegate.ExecuteIfBound(InStateContext))
 | 
				
			||||||
 | 
					            {
 | 
				
			||||||
 | 
					                UE_LOG(LogTemp, Error, 
 | 
				
			||||||
 | 
					                    TEXT("Trying to execute an input handler delegate on %s but it is not bound"), 
 | 
				
			||||||
 | 
					                    *Name.ToString()); 
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    OnUpdate(OneFrame, InStateContext);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    if(bStateHasDuration && InStateContext.Parent->GetTicksInState() >= StateDuration)
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        Finish(InStateContext, EFFStateFinishReason::SFT_DurationMetOrExceeded);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					void UFFState::Landed(const FHitResult& Hit, const FFFStateContext& InStateContext)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    OnLanded(Hit, InStateContext);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    // TODO: might want to also finish the state here by default and have the subclasses overwrite
 | 
				
			||||||
 | 
					    // that behavior in the few cases we don't want to finish the state when we land 
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					void UFFState::MovementModeChanged(EMovementMode PrevMovementMode, uint8 PreviousCustomMode,
 | 
				
			||||||
 | 
					    EMovementMode NewMovementMode, uint8 NewCustomMode, const FFFStateContext& InStateContext)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    OnMovementModeChanged(PrevMovementMode, PreviousCustomMode, 
 | 
				
			||||||
 | 
					        NewMovementMode, NewCustomMode, InStateContext);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    // TODO: Movement mode MOVE_None means movement is disabled but in this context it means no movement
 | 
				
			||||||
 | 
					    // mode is specifically required to stay in this state i.e. changing from falling to walking
 | 
				
			||||||
 | 
					    // will not exit out of this state. I think I want to use my own movement mode enum just so I
 | 
				
			||||||
 | 
					    // can explicitly document this is what is meant by none
 | 
				
			||||||
 | 
					    if((ReqMovementMode != EMovementMode::MOVE_None && NewMovementMode != ReqMovementMode) || 
 | 
				
			||||||
 | 
					      ((ReqMovementMode == MOVE_Custom) && NewCustomMode != RequiredCustomMode))
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        Finish(InStateContext, EFFStateFinishReason::SFT_NotInReqMovementMode);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					void UFFState::Hit(const FFFStateContext& InStateContext)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    OnHit(InStateContext);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					void UFFState::Block(const FFFStateContext& InStateContext)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    OnBlock(InStateContext);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					void UFFState::Finish(const FFFStateContext& InStateContext, EFFStateFinishReason StateFinishReason)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    // TODO: I really don't like having to pass this state finish reason into this GoToEntryState
 | 
				
			||||||
 | 
					    // function, which then passes it to GoToState, which then passes it back to the state through
 | 
				
			||||||
 | 
					    // it's "Exit" function all so we can stop the current anim montage when we exit from a state if
 | 
				
			||||||
 | 
					    // the appropriate flags are set. I think having this state finish reason is good but I may want
 | 
				
			||||||
 | 
					    // to rethink the way we handle logic for ending a state and which class is in charge of handling
 | 
				
			||||||
 | 
					    // what
 | 
				
			||||||
 | 
					    InStateContext.Parent->GoToEntryState(StateFinishReason);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					void UFFState::RegisterInputHandler(const FFFInputSequence& InRequiredSequence, FFFInputEventDelegate InDelegate)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    FFFInputEventHandler TempHandler;
 | 
				
			||||||
 | 
					    TempHandler.RequiredSequence = InRequiredSequence;
 | 
				
			||||||
 | 
					    TempHandler.Delegate = InDelegate;
 | 
				
			||||||
 | 
					    InputHandlers.Add(TempHandler);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					void UFFState::PlayMontage(const FFFStateContext& InStateContext)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    // TODO: think of a better way to handle optionally playing montages other than the one set as MontageToPlay
 | 
				
			||||||
 | 
					    OnPlayMontage(InStateContext);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					void UFFState::OnInit_Implementation(const FFFStateContext& InStateContext)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					bool UFFState::OnCanTransition_Implementation(const FFFStateContext& InStateContext)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    return true;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// TODO: think of a better way to handle optionally playing montages other than the one set as MontageToPlay
 | 
				
			||||||
 | 
					void UFFState::OnPlayMontage_Implementation(const FFFStateContext& InStateContext)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    if(InStateContext.Avatar)
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        USkeletalMeshComponent* SMC = InStateContext.Avatar->GetComponentByClass<USkeletalMeshComponent>();
 | 
				
			||||||
 | 
					        if(SMC && MontageToPlay)
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					            SMC->GetAnimInstance()->Montage_Play(MontageToPlay);
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					UWorld* UFFState::GetWorld() const
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						UFFStateMachineComponent* SMC = Cast<UFFStateMachineComponent>(GetOuter());
 | 
				
			||||||
 | 
						if(SMC)
 | 
				
			||||||
 | 
						{
 | 
				
			||||||
 | 
							return SMC->GetWorld();
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						
 | 
				
			||||||
 | 
						return nullptr;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					void UFFState::StopCurrentAnimMontage(const FFFStateContext& InStateContext)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    USkeletalMeshComponent* SMC = InStateContext.Avatar->GetComponentByClass<USkeletalMeshComponent>();
 | 
				
			||||||
 | 
					    if(SMC)
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        // TODO: Need a system for keeping track what anim montages were played during a state
 | 
				
			||||||
 | 
					        // so we can stop only those when the state ends (and if the bStopMontageOnStateEnd flag is set)
 | 
				
			||||||
 | 
					        // ALSO, this will be important for when we need to fast forward an animation when the game rollsback
 | 
				
			||||||
 | 
					        // and we have to resimulate to the current local tick
 | 
				
			||||||
 | 
					        // For now just stop all anim montages
 | 
				
			||||||
 | 
					        UAnimMontage* CurrAnim = SMC->GetAnimInstance()->GetCurrentActiveMontage();
 | 
				
			||||||
 | 
					        if(CurrAnim)
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					            SMC->GetAnimInstance()->Montage_Stop(CurrAnim->BlendOut.GetBlendTime());
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
							
								
								
									
										285
									
								
								Source/UnrealFightingFramework/State/FFState.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										285
									
								
								Source/UnrealFightingFramework/State/FFState.h
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,285 @@
 | 
				
			|||||||
 | 
					// Unreal Fighting Framework by Kevin Poretti
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#pragma once
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// FF includes
 | 
				
			||||||
 | 
					#include "Input/FFInputBufferComponent.h"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// UE includes
 | 
				
			||||||
 | 
					#include "CoreMinimal.h"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#include "FFState.generated.h"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					USTRUCT(BlueprintType)
 | 
				
			||||||
 | 
					struct FFFStateContext
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    GENERATED_BODY()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/** Actor that owns the avatar. Typically a player controller. */
 | 
				
			||||||
 | 
						UPROPERTY(BlueprintReadOnly)
 | 
				
			||||||
 | 
						AActor* Owner;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/**
 | 
				
			||||||
 | 
						 *	Actor that represents the player's avatar or an object associated with the player's avatar.
 | 
				
			||||||
 | 
						 *	This is typically a character or a weapon.
 | 
				
			||||||
 | 
						 */
 | 
				
			||||||
 | 
						UPROPERTY(BlueprintReadOnly)
 | 
				
			||||||
 | 
						AActor* Avatar;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /**
 | 
				
			||||||
 | 
					     * Parent state machine that controls this state
 | 
				
			||||||
 | 
					     */
 | 
				
			||||||
 | 
						UPROPERTY(BlueprintReadOnly)
 | 
				
			||||||
 | 
					    class UFFStateMachineComponent* Parent;
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					DECLARE_DYNAMIC_DELEGATE_OneParam(FFFInputEventDelegate, const FFFStateContext&, InStateContext);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					USTRUCT(BlueprintType)
 | 
				
			||||||
 | 
					struct FFFInputEventHandler
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    GENERATED_BODY()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						// TODO: document
 | 
				
			||||||
 | 
						UPROPERTY(EditDefaultsOnly, BlueprintReadOnly)
 | 
				
			||||||
 | 
						FFFInputSequence RequiredSequence;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						// TODO: document
 | 
				
			||||||
 | 
					    UPROPERTY(EditDefaultsOnly, BlueprintReadOnly)
 | 
				
			||||||
 | 
						FFFInputEventDelegate Delegate;
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					UENUM(BlueprintType)
 | 
				
			||||||
 | 
					enum class EFFStateFinishReason : uint8
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    // TODO: document
 | 
				
			||||||
 | 
						SFT_Interrupted				UMETA(DisplayName="Interrupted"),
 | 
				
			||||||
 | 
					    SFT_DurationMetOrExceeded			UMETA(DisplayName="Duration Reached"),
 | 
				
			||||||
 | 
					    SFT_NotInReqMovementMode	UMETA(DisplayName="Not In Required Movement Mode"),
 | 
				
			||||||
 | 
						SFT_MAX						UMETA(Hidden)
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/**
 | 
				
			||||||
 | 
					 *	A state is an object that provides rules and conditions for when a state can be transitioned into
 | 
				
			||||||
 | 
					 *	and logic to run when the state is entered, exited, and active.
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					UCLASS(Blueprintable)
 | 
				
			||||||
 | 
					class UNREALFIGHTINGFRAMEWORK_API UFFState : public UObject
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						GENERATED_BODY()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					public:
 | 
				
			||||||
 | 
						// State parameters (should be read-only)
 | 
				
			||||||
 | 
					    /** Name of this state behavior */
 | 
				
			||||||
 | 
						UPROPERTY(EditDefaultsOnly, BlueprintReadOnly, Category="UFF State Properties")
 | 
				
			||||||
 | 
						FName Name;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /**
 | 
				
			||||||
 | 
						 *	True if this state has some duration where it should return to the entry state
 | 
				
			||||||
 | 
						 *	if this state is not cancelled out of by other means.
 | 
				
			||||||
 | 
						 */
 | 
				
			||||||
 | 
					    UPROPERTY(EditDefaultsOnly, BlueprintReadOnly, Category="UFF State Properties")
 | 
				
			||||||
 | 
						bool bStateHasDuration;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						// TODO: this should only be editable if bStateHasDuration is true
 | 
				
			||||||
 | 
						/**
 | 
				
			||||||
 | 
						 *	How long this state will be active before finishing if this state is not cancelled out of
 | 
				
			||||||
 | 
						 *	by other means.
 | 
				
			||||||
 | 
						 */
 | 
				
			||||||
 | 
					    UPROPERTY(EditDefaultsOnly, BlueprintReadWrite, Category="UFF State Properties")
 | 
				
			||||||
 | 
						int64 StateDuration;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/**
 | 
				
			||||||
 | 
						 *	What stance the object this state represents must be in.
 | 
				
			||||||
 | 
						 *	For example this is usually an enumerated value that signifies if a character needs to be
 | 
				
			||||||
 | 
						 *	crouching, standing, or airborne for this state to be eligible for transitioning.
 | 
				
			||||||
 | 
						 */
 | 
				
			||||||
 | 
					    UPROPERTY(EditDefaultsOnly, BlueprintReadOnly, Category="UFF State Properties")
 | 
				
			||||||
 | 
						int32 StanceRequired;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/**
 | 
				
			||||||
 | 
						 *	What is this state's category.
 | 
				
			||||||
 | 
						 *	Used for determining what types of state can prematurely cancel this one.
 | 
				
			||||||
 | 
						 */
 | 
				
			||||||
 | 
					    UPROPERTY(EditDefaultsOnly, BlueprintReadOnly, Category="UFF State Properties")
 | 
				
			||||||
 | 
						int32 StateType;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/**
 | 
				
			||||||
 | 
						 *	Input sequences that needs to be present in the controlling player's input buffer for this
 | 
				
			||||||
 | 
						 *	state to be eligible for transitioning.
 | 
				
			||||||
 | 
						 */
 | 
				
			||||||
 | 
					    UPROPERTY(EditDefaultsOnly, BlueprintReadOnly, Category="UFF State Properties")
 | 
				
			||||||
 | 
						TArray<FFFInputSequence> InputSequences;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/**
 | 
				
			||||||
 | 
						 *	If true the state can transition from itself into itself without having to go through
 | 
				
			||||||
 | 
						 *	another state like Idle
 | 
				
			||||||
 | 
						 */
 | 
				
			||||||
 | 
					    UPROPERTY(EditDefaultsOnly, BlueprintReadOnly, Category="UFF State Properties")
 | 
				
			||||||
 | 
						bool bCanTransitionToSelf = false;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						UPROPERTY(EditDefaultsOnly, BlueprintReadOnly, Category="UFF State Properties")
 | 
				
			||||||
 | 
					    TEnumAsByte<EMovementMode> ReqMovementMode;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						UPROPERTY(EditDefaultsOnly, BlueprintReadOnly, Category="UFF State Properties")
 | 
				
			||||||
 | 
					    uint8 RequiredCustomMode;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/**
 | 
				
			||||||
 | 
						 *	Animation to begin playing when this state is entered
 | 
				
			||||||
 | 
						 */
 | 
				
			||||||
 | 
						UPROPERTY(EditDefaultsOnly, BlueprintReadOnly, Category="UFF State Properties")
 | 
				
			||||||
 | 
						UAnimMontage* MontageToPlay;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						UPROPERTY(EditDefaultsOnly, BlueprintReadOnly, Category="UFF State Properties")
 | 
				
			||||||
 | 
						bool bStopMontageOnStateEnd;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    UPROPERTY(EditDefaultsOnly, BlueprintReadOnly, Category="UFF State Properties")
 | 
				
			||||||
 | 
						bool bStopMontageOnMovementModeChange;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/**
 | 
				
			||||||
 | 
						 *	Event delegates to call when a certain input condition is detected in the Owner's input buffer
 | 
				
			||||||
 | 
						 */
 | 
				
			||||||
 | 
						UPROPERTY(BlueprintReadOnly, Category="UFF State Events")
 | 
				
			||||||
 | 
						TArray<FFFInputEventHandler> InputHandlers;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /**
 | 
				
			||||||
 | 
						 *	Called when state is first created.
 | 
				
			||||||
 | 
						 */
 | 
				
			||||||
 | 
						virtual void Init(const FFFStateContext& InStateContext);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/**
 | 
				
			||||||
 | 
						 *	Returns true if Avatar's is in the correct stance AND
 | 
				
			||||||
 | 
						 *	the state type is enabled (or the state can be hit or whiff cancelled from the current state) AND
 | 
				
			||||||
 | 
						 *	all state entry conditions were met AND
 | 
				
			||||||
 | 
						 *	at least one input sequence is present in the Owner's input buffer
 | 
				
			||||||
 | 
						 */ 
 | 
				
			||||||
 | 
						virtual bool CanTransition(const FFFStateContext& InStateContext);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /**
 | 
				
			||||||
 | 
						 *	Called whenever this state is transitioned into.
 | 
				
			||||||
 | 
						 *
 | 
				
			||||||
 | 
						 *	Calls appropriate Blueprint hooks.
 | 
				
			||||||
 | 
						 */
 | 
				
			||||||
 | 
						virtual void Enter(const FFFStateContext& InStateContext);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /**
 | 
				
			||||||
 | 
						 *	Called whenever this state is transitioned out of into a new state.
 | 
				
			||||||
 | 
						 *
 | 
				
			||||||
 | 
						 *	Calls appropriate Blueprint hooks.
 | 
				
			||||||
 | 
						 *
 | 
				
			||||||
 | 
						 *	TODO: document StateFinishReason
 | 
				
			||||||
 | 
						 */
 | 
				
			||||||
 | 
						virtual void Exit(const FFFStateContext& InStateContext, EFFStateFinishReason StateFinishReason);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /**
 | 
				
			||||||
 | 
						 *	Called whenever this state is active and the game logic ticks.
 | 
				
			||||||
 | 
						 *
 | 
				
			||||||
 | 
						 *	Calls appropriate Blueprint hooks.
 | 
				
			||||||
 | 
						 *
 | 
				
			||||||
 | 
						 *	@param OneFrame the time that elapses during one fixed tick
 | 
				
			||||||
 | 
						 */
 | 
				
			||||||
 | 
					    virtual void Update(float OneFrame, const FFFStateContext& InStateContext);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						// TODO: document
 | 
				
			||||||
 | 
						virtual void Landed(const FHitResult& Hit, const FFFStateContext& InStateContext);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						// TODO: document
 | 
				
			||||||
 | 
						virtual void MovementModeChanged(EMovementMode PrevMovementMode, uint8 PreviousCustomMode, 
 | 
				
			||||||
 | 
						    EMovementMode NewMovementMode, uint8 NewCustomMode, const FFFStateContext& InStateContext);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						// TODO: document
 | 
				
			||||||
 | 
						// TODO: pass in hitdata struct as well
 | 
				
			||||||
 | 
					    virtual void Hit(const FFFStateContext& InStateContext);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						// TODO: document
 | 
				
			||||||
 | 
						// TODO: pass in hitdata struct as well
 | 
				
			||||||
 | 
						virtual void Block(const FFFStateContext& InStateContext);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /**
 | 
				
			||||||
 | 
						 *	Called when you want to exit from this state but no eligible transitions exist to other states,
 | 
				
			||||||
 | 
						 *	usually due to a lack of player input.
 | 
				
			||||||
 | 
						 *
 | 
				
			||||||
 | 
						 *	By default this will transition to the owning state machine's entry state, which is usually
 | 
				
			||||||
 | 
						 *	an idle state.
 | 
				
			||||||
 | 
						 *
 | 
				
			||||||
 | 
						 *	This function will get called automatically when the ticks in this state reaches the
 | 
				
			||||||
 | 
						 *	threshold set by the StateDuration member, but you can call it whenever you wish to return
 | 
				
			||||||
 | 
						 *	to the entry state.
 | 
				
			||||||
 | 
						 *
 | 
				
			||||||
 | 
					     *	@param InStateContext 
 | 
				
			||||||
 | 
					     */
 | 
				
			||||||
 | 
					    UFUNCTION(BlueprintCallable)
 | 
				
			||||||
 | 
						virtual void Finish(const FFFStateContext& InStateContext, EFFStateFinishReason StateFinishReason);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						// TODO: document
 | 
				
			||||||
 | 
						UFUNCTION(BlueprintCallable)
 | 
				
			||||||
 | 
						virtual void RegisterInputHandler(
 | 
				
			||||||
 | 
						    const FFFInputSequence& InRequiredSequence, FFFInputEventDelegate InDelegate);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						// TODO: document
 | 
				
			||||||
 | 
						UFUNCTION(BlueprintNativeEvent, Category="UFF|State|Events")
 | 
				
			||||||
 | 
						void OnInit(const FFFStateContext& InStateContext);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/**
 | 
				
			||||||
 | 
						 *	Blueprint hook for overriding the CanTransition logic
 | 
				
			||||||
 | 
						 */
 | 
				
			||||||
 | 
					    UFUNCTION(BlueprintNativeEvent, Category="UFF|State|Events")
 | 
				
			||||||
 | 
						bool OnCanTransition(const FFFStateContext& InStateContext);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /**
 | 
				
			||||||
 | 
					     *	Blueprint hook for whenever this state is transitioned into
 | 
				
			||||||
 | 
					     */
 | 
				
			||||||
 | 
						UFUNCTION(BlueprintImplementableEvent, Category="UFF|State|Events")
 | 
				
			||||||
 | 
						void OnEnter(const FFFStateContext& InStateContext);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/**
 | 
				
			||||||
 | 
						 *	Blueprint hook for whenever this state is transitioned out of into a new state
 | 
				
			||||||
 | 
						 */
 | 
				
			||||||
 | 
						UFUNCTION(BlueprintImplementableEvent, Category="UFF|State|Events")
 | 
				
			||||||
 | 
						void OnExit(const FFFStateContext& InStateContext);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/**
 | 
				
			||||||
 | 
						 *	Blueprint hook for whenever this state is active and the game logic ticks.
 | 
				
			||||||
 | 
						 *
 | 
				
			||||||
 | 
						 *	@param OneFrame the time that elapses during one fixed tick
 | 
				
			||||||
 | 
						 */
 | 
				
			||||||
 | 
						UFUNCTION(BlueprintImplementableEvent, Category="UFF|State|Events")
 | 
				
			||||||
 | 
						void OnUpdate(float OneFrame, const FFFStateContext& InStateContext);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						UFUNCTION(BlueprintCallable, Category="UFF|State|Animations")
 | 
				
			||||||
 | 
						void PlayMontage(const FFFStateContext& InStateContext);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /**
 | 
				
			||||||
 | 
					     *	Blueprint hook for overriding the logic for when a anim montage plays at the start of a state
 | 
				
			||||||
 | 
					     *	@param InStateContext 
 | 
				
			||||||
 | 
					     */
 | 
				
			||||||
 | 
					    UFUNCTION(BlueprintNativeEvent, Category="UFF|State|Events")
 | 
				
			||||||
 | 
						void OnPlayMontage(const FFFStateContext& InStateContext);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						// TODO: document
 | 
				
			||||||
 | 
						UFUNCTION(BlueprintImplementableEvent, Category="UFF|State|Events")
 | 
				
			||||||
 | 
						void OnLanded(const FHitResult& Hit, const FFFStateContext& InStateContext);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						// TODO: document
 | 
				
			||||||
 | 
						UFUNCTION(BlueprintImplementableEvent, Category="UFF|State|Events")
 | 
				
			||||||
 | 
						void OnMovementModeChanged(EMovementMode PrevMovementMode, uint8 PreviousCustomMode, 
 | 
				
			||||||
 | 
						    EMovementMode NewMovementMode, uint8 NewCustomMode, const FFFStateContext& InStateContext);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						// TODO: document
 | 
				
			||||||
 | 
					    // TODO: pass in hitdata struct as well
 | 
				
			||||||
 | 
					    UFUNCTION(BlueprintImplementableEvent, Category="UFF|State|Events")
 | 
				
			||||||
 | 
						void OnHit(const FFFStateContext& InStateContext);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						// TODO: document
 | 
				
			||||||
 | 
					    // TODO: pass in hitdata struct as well
 | 
				
			||||||
 | 
					    UFUNCTION(BlueprintImplementableEvent, Category="UFF|State|Events")
 | 
				
			||||||
 | 
						void OnBlock(const FFFStateContext& InStateContext);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						// UObject interface
 | 
				
			||||||
 | 
						virtual UWorld* GetWorld() const override;
 | 
				
			||||||
 | 
						// End of UObject interface
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					private:
 | 
				
			||||||
 | 
						void StopCurrentAnimMontage(const FFFStateContext& InStateContext);
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
							
								
								
									
										28
									
								
								Source/UnrealFightingFramework/State/FFStateData.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										28
									
								
								Source/UnrealFightingFramework/State/FFStateData.h
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,28 @@
 | 
				
			|||||||
 | 
					// Unreal Fighting Framework by Kevin Poretti
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#pragma once
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// FF includes
 | 
				
			||||||
 | 
					#include "State/FFState.h"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// UE includes
 | 
				
			||||||
 | 
					#include "CoreMinimal.h"
 | 
				
			||||||
 | 
					#include "Engine/DataAsset.h"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#include "FFStateData.generated.h"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/**
 | 
				
			||||||
 | 
					 *	
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					UCLASS(BlueprintType)
 | 
				
			||||||
 | 
					class UNREALFIGHTINGFRAMEWORK_API UFFStateData : public UDataAsset
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						GENERATED_BODY()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					public:
 | 
				
			||||||
 | 
					    UPROPERTY(EditDefaultsOnly, BlueprintReadOnly)
 | 
				
			||||||
 | 
						TSubclassOf<UFFState> EntryState;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						UPROPERTY(EditDefaultsOnly, BlueprintReadOnly)
 | 
				
			||||||
 | 
						TArray<TSubclassOf<UFFState>> OtherStates;
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
							
								
								
									
										264
									
								
								Source/UnrealFightingFramework/State/FFStateMachineComponent.cpp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										264
									
								
								Source/UnrealFightingFramework/State/FFStateMachineComponent.cpp
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,264 @@
 | 
				
			|||||||
 | 
					// Unreal Fighting Framework by Kevin Poretti
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#include "FFStateMachineComponent.h"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// FF includes
 | 
				
			||||||
 | 
					#include "FFState.h"
 | 
				
			||||||
 | 
					#include "GameplayFramework/FFGameState.h"
 | 
				
			||||||
 | 
					#include "Input/FFPlayerController.h"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#if !UE_BUILD_SHIPPING
 | 
				
			||||||
 | 
					class ASNGGameState;
 | 
				
			||||||
 | 
					static int32 StateMachineDebug = 0;
 | 
				
			||||||
 | 
					FAutoConsoleVariableRef CVARStateMachineDebug(TEXT("ff.StateMachine.ShowDebug"),
 | 
				
			||||||
 | 
											StateMachineDebug, 
 | 
				
			||||||
 | 
											TEXT("Print state machine information for character"), 
 | 
				
			||||||
 | 
											ECVF_Cheat);
 | 
				
			||||||
 | 
					#endif
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					UFFStateMachineComponent::UFFStateMachineComponent()
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    // Don't use Unreal's tick instead use a fixed tick
 | 
				
			||||||
 | 
					#if !UE_BUILD_SHIPPING
 | 
				
			||||||
 | 
					    PrimaryComponentTick.bCanEverTick = true;
 | 
				
			||||||
 | 
					#else
 | 
				
			||||||
 | 
					    PrimaryComponentTick.bCanEverTick = false;
 | 
				
			||||||
 | 
					#endif
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					void UFFStateMachineComponent::Initialize(TSubclassOf<UFFState> EntryState, const TArray<TSubclassOf<UFFState>>& InitialStates)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    UFFState* EntryStateInstance = AddState(EntryState);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    for(const TSubclassOf<UFFState>& CurrState : InitialStates)
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        AddState(CurrState);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    // need an entry state or something went seriously wrong
 | 
				
			||||||
 | 
					    check(EntryStateInstance);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    CurrentState = EntryStateInstance;
 | 
				
			||||||
 | 
					    CurrentState->Enter(GetCurrentStateContext());
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					void UFFStateMachineComponent::InitActorInfo(AActor* InOwner, AActor* InAvatar)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    Owner = InOwner;
 | 
				
			||||||
 | 
						Avatar = InAvatar;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					UFFState* UFFStateMachineComponent::AddState(TSubclassOf<UFFState> StateClassToAdd)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    UFFState* TempState = NewObject<UFFState>(this, StateClassToAdd);
 | 
				
			||||||
 | 
					    if(TempState)
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        if(!FindStateWithName(TempState->Name))
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					            States.Add(TempState);
 | 
				
			||||||
 | 
					            TempState->Init(GetCurrentStateContext());
 | 
				
			||||||
 | 
					            return TempState;
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        UE_LOG(LogTemp, Error, TEXT("State with name %s already exists in state machine for %s"), 
 | 
				
			||||||
 | 
					            *TempState->Name.ToString(), *GetOwner()->GetFName().ToString());
 | 
				
			||||||
 | 
					        return nullptr;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    UE_LOG(LogTemp, Error, TEXT("Could not create instance of state class %s"), 
 | 
				
			||||||
 | 
					        *StateClassToAdd.GetDefaultObject()->Name.ToString());
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    return nullptr;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					void UFFStateMachineComponent::AddStates(const TArray<TSubclassOf<UFFState>>& StateClassesToAdd)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    for(const TSubclassOf<UFFState>& CurrState : StateClassesToAdd)
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        AddState(CurrState);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					void UFFStateMachineComponent::RemoveState(FName StateToRemove)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    UE_LOG(LogTemp, Error, TEXT("UFFStateMachineComponent::RemoveState is not yet implemented"));
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					void UFFStateMachineComponent::GoToState(FName NewStateName, EFFStateFinishReason StateFinishReason)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    UFFState* NewState = FindStateWithName(NewStateName);
 | 
				
			||||||
 | 
					    if(NewState)
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        GoToState(NewState, StateFinishReason);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					void UFFStateMachineComponent::GoToState(UFFState* NewState, EFFStateFinishReason StateFinishReason)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    check(CurrentState);
 | 
				
			||||||
 | 
					    check(NewState);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    // if state being transitioned into requires an input sequence we need to disable the most
 | 
				
			||||||
 | 
					    // recent input in the player controller input buffer to prevent unwanted "double firing" of
 | 
				
			||||||
 | 
					    // actions that have short durations but very lenient required input sequences
 | 
				
			||||||
 | 
					    if(NewState->InputSequences.Num() > 0)
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        IFFStateOwnerInterface* PC = Cast<IFFStateOwnerInterface>(Owner);
 | 
				
			||||||
 | 
					        if(PC)
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					            PC->DisableMostRecentInput();
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    CurrentState->Exit(GetCurrentStateContext(), StateFinishReason);
 | 
				
			||||||
 | 
					    TicksInState = 0;
 | 
				
			||||||
 | 
					    TickStateWasEntered = GetWorld()->GetGameState<AFFGameState>()->GetCurrentTick();
 | 
				
			||||||
 | 
					    CurrentSubStateLabel = NAME_None;
 | 
				
			||||||
 | 
					    NewState->Enter(GetCurrentStateContext());
 | 
				
			||||||
 | 
					    OnStateTransition.Broadcast(CurrentState, NewState);
 | 
				
			||||||
 | 
					    CurrentState = NewState;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					void UFFStateMachineComponent::GoToEntryState(EFFStateFinishReason StateFinishReason)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    // can't have an entry state if there are no states
 | 
				
			||||||
 | 
					    check(States.Num() > 0);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    GoToState(States[0], StateFinishReason);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					FName UFFStateMachineComponent::GetCurrentStateName() const
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    check(CurrentState)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    return CurrentState->Name;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					void UFFStateMachineComponent::SetSubStateLabel(FName InSubStateLabel)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    CurrentSubStateLabel = InSubStateLabel;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					FFFStateContext UFFStateMachineComponent::GetCurrentStateContext()
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    FFFStateContext CurrStateContext;
 | 
				
			||||||
 | 
					    CurrStateContext.Owner = Owner;
 | 
				
			||||||
 | 
					    CurrStateContext.Avatar = Avatar;
 | 
				
			||||||
 | 
					    CurrStateContext.Parent = this;
 | 
				
			||||||
 | 
					    return CurrStateContext;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					void UFFStateMachineComponent::Landed(const FHitResult& Hit)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    check(CurrentState)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    CurrentState->Landed(Hit, GetCurrentStateContext());
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					void UFFStateMachineComponent::MovementModeChanged(EMovementMode PrevMovementMode, uint8 PreviousCustomMode,
 | 
				
			||||||
 | 
					    EMovementMode NewMovementMode, uint8 NewCustomMode)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    // TODO: this check should be valid but isn't right now.
 | 
				
			||||||
 | 
					    // Movement mode changed seems to be called whenever the character is first created but before
 | 
				
			||||||
 | 
					    // any states are created and entered.
 | 
				
			||||||
 | 
					    // For now just check if CurrentState is null and don't call the MovementModeChanged callback if
 | 
				
			||||||
 | 
					    // so
 | 
				
			||||||
 | 
					    //check(CurrentState)
 | 
				
			||||||
 | 
					    if(!CurrentState)
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        return;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    CurrentState->MovementModeChanged(PrevMovementMode, PreviousCustomMode, 
 | 
				
			||||||
 | 
					        NewMovementMode, NewCustomMode, GetCurrentStateContext());
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					void UFFStateMachineComponent::FixedTick(float OneFrame)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    // CurrentState should never be null
 | 
				
			||||||
 | 
					    // TODO: Should probably assert or whatever UE's equivalent is
 | 
				
			||||||
 | 
					    //check(CurrentState);
 | 
				
			||||||
 | 
					    // TODO: yet another reason I want FULL CONTROL over when my game objects are created and initialized
 | 
				
			||||||
 | 
					    if(!CurrentState)
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        return;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    // Should we switch states?
 | 
				
			||||||
 | 
					    UFFState* StateToTransitionTo = nullptr;
 | 
				
			||||||
 | 
					    for(UFFState* ThisState : States)
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        // found a state 
 | 
				
			||||||
 | 
					        if(ThisState->CanTransition(GetCurrentStateContext()) && 
 | 
				
			||||||
 | 
					            (CurrentState->Name != ThisState->Name || ThisState->bCanTransitionToSelf))
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					            StateToTransitionTo = ThisState;
 | 
				
			||||||
 | 
					            break;
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    // Lastly just check if the state we're about to transition into isn't the current state.
 | 
				
			||||||
 | 
					    // It is OK to transition if state's "CanTransitionToSelf" is true
 | 
				
			||||||
 | 
					    if(StateToTransitionTo)
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        GoToState(StateToTransitionTo, EFFStateFinishReason::SFT_Interrupted);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    else
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        // Tick current state
 | 
				
			||||||
 | 
					        TicksInState++;
 | 
				
			||||||
 | 
					        CurrentState->Update(OneFrame, GetCurrentStateContext());   
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					UFFState* UFFStateMachineComponent::FindStateWithName(FName StateName)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    for (UFFState* CurrState : States)
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        if(CurrState->Name == StateName)
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					            return CurrState;
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						UE_LOG(LogTemp, Warning,
 | 
				
			||||||
 | 
								TEXT("Could not find state in state machine with name %s"), *StateName.ToString());
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						return nullptr;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#if !UE_BUILD_SHIPPING
 | 
				
			||||||
 | 
					void UFFStateMachineComponent::TickComponent(float DeltaTime, ELevelTick TickType,
 | 
				
			||||||
 | 
					    FActorComponentTickFunction* ThisTickFunction)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    Super::TickComponent(DeltaTime, TickType, ThisTickFunction);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    // Debug
 | 
				
			||||||
 | 
					    if(StateMachineDebug && CurrentState) 
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        FString SMDebugString = "---State Machine Info---\n";
 | 
				
			||||||
 | 
							SMDebugString.Append(FString::Printf(TEXT("Current State: %s\n"), *CurrentState->Name.ToString()));
 | 
				
			||||||
 | 
							SMDebugString.Append(FString::Printf(TEXT("Current SubState Label: %s\n"), *CurrentSubStateLabel.ToString()));
 | 
				
			||||||
 | 
							SMDebugString.Append(FString::Printf(TEXT("Ticks In State: %lld\n"), TicksInState));
 | 
				
			||||||
 | 
					        SMDebugString.Append(FString::Printf(TEXT("-- States added --\n")));
 | 
				
			||||||
 | 
					        for (auto TempState : States)
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					            SMDebugString.Append(FString::Printf(TEXT("%s\n"), *TempState->Name.ToString()));
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        GEngine->AddOnScreenDebugMessage(-1, 0.0f, FColor::Green, SMDebugString);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					#endif
 | 
				
			||||||
							
								
								
									
										188
									
								
								Source/UnrealFightingFramework/State/FFStateMachineComponent.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										188
									
								
								Source/UnrealFightingFramework/State/FFStateMachineComponent.h
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,188 @@
 | 
				
			|||||||
 | 
					// Unreal Fighting Framework by Kevin Poretti
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#pragma once
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// FF includes
 | 
				
			||||||
 | 
					#include "IFFSystemInterface.h"
 | 
				
			||||||
 | 
					#include "FFState.h"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// UE includes
 | 
				
			||||||
 | 
					#include "CoreMinimal.h"
 | 
				
			||||||
 | 
					#include "Components/ActorComponent.h"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#include "FFStateMachineComponent.generated.h"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					DECLARE_DYNAMIC_MULTICAST_DELEGATE_TwoParams(FOnStateTransitionSignature, 
 | 
				
			||||||
 | 
					    const UFFState*, PrevState, const UFFState*, NextState);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/**
 | 
				
			||||||
 | 
					 *	A state machine is a component that evaluates and controls the transitions for state objects that
 | 
				
			||||||
 | 
					 *	are a part of this state machine.
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 *	This component also calls the appropriate state logic when a state is changed or the component ticks.
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					UCLASS( ClassGroup=(UnrealFightingFramework), meta=(BlueprintSpawnableComponent) )
 | 
				
			||||||
 | 
					class UNREALFIGHTINGFRAMEWORK_API UFFStateMachineComponent : public UActorComponent, public IFFSystemInterface
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						GENERATED_BODY()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					public:	
 | 
				
			||||||
 | 
						UFFStateMachineComponent();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/**
 | 
				
			||||||
 | 
						 *	Creates and adds default states and enters the first state
 | 
				
			||||||
 | 
						 */
 | 
				
			||||||
 | 
						void Initialize(TSubclassOf<UFFState> EntryState, const TArray<TSubclassOf<UFFState>>& InitialStates);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /**
 | 
				
			||||||
 | 
						 *	Initializes pointers to what owns this state machine and what avatar this state represents.
 | 
				
			||||||
 | 
						 *
 | 
				
			||||||
 | 
						 *	These pointers will also be passed to the states owned by this state machine.
 | 
				
			||||||
 | 
						 *
 | 
				
			||||||
 | 
						 *	@param InOwner Actor that owns this state machine.
 | 
				
			||||||
 | 
						 *	@param InAvatar Actor that this state machine represents.
 | 
				
			||||||
 | 
						 */
 | 
				
			||||||
 | 
						virtual void InitActorInfo(AActor* InOwner, AActor* InAvatar);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /**
 | 
				
			||||||
 | 
						 *	Creates an instance of the state class and adds newly created state to this state machine.
 | 
				
			||||||
 | 
						 *
 | 
				
			||||||
 | 
						 *	@param StateClassToAdd State class type to be added to this state machine
 | 
				
			||||||
 | 
						 *
 | 
				
			||||||
 | 
						 *	@return A pointer to the state that was added or nullptr if there was an issue adding or creating the state
 | 
				
			||||||
 | 
						 */
 | 
				
			||||||
 | 
						// TODO: return should probably be a const pointer if this function is public. I don't want
 | 
				
			||||||
 | 
						// anything outside of the state machine modifying the state. Really, I want states in general to
 | 
				
			||||||
 | 
						// be read only objects that are only modified at edit time when creating state blueprints.
 | 
				
			||||||
 | 
						UFFState* AddState(TSubclassOf<UFFState> StateClassToAdd);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /**
 | 
				
			||||||
 | 
						 *	Creates an instance of the state classes and adds newly created states to this state machine.
 | 
				
			||||||
 | 
						 *
 | 
				
			||||||
 | 
						 *	@param StateClassesToAdd Array of state class types to be added to this state machine
 | 
				
			||||||
 | 
						 */
 | 
				
			||||||
 | 
						void AddStates(const TArray<TSubclassOf<UFFState>>& StateClassesToAdd);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /**
 | 
				
			||||||
 | 
						 *	Destroys the state with corresponding name and removes it from this state machine.
 | 
				
			||||||
 | 
						 */
 | 
				
			||||||
 | 
						void RemoveState(FName StateToRemove);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /**
 | 
				
			||||||
 | 
						 *	Transitions from CurrentState to the new state with the name passed to this function
 | 
				
			||||||
 | 
						 *
 | 
				
			||||||
 | 
						 *	Triggers the Exit callback on the CurrentState and the Enter callback on the new state
 | 
				
			||||||
 | 
						 *
 | 
				
			||||||
 | 
						 *	TODO: document StateFinishReason
 | 
				
			||||||
 | 
						 */
 | 
				
			||||||
 | 
						void GoToState(FName NewStateName, EFFStateFinishReason StateFinishReason);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/**
 | 
				
			||||||
 | 
						 *	Transitions from CurrentState to the new state passed to this function
 | 
				
			||||||
 | 
						 *
 | 
				
			||||||
 | 
						 *	Triggers the Exit callback on the CurrentState and the Enter callback on the new state
 | 
				
			||||||
 | 
						 *
 | 
				
			||||||
 | 
						 *	TODO: document StateFinishReason
 | 
				
			||||||
 | 
						 */
 | 
				
			||||||
 | 
						void GoToState(UFFState* NewState, EFFStateFinishReason StateFinishReason);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/**
 | 
				
			||||||
 | 
						 *	Transitions from CurrentState to the default entry state
 | 
				
			||||||
 | 
						 *
 | 
				
			||||||
 | 
						 *	TODO: document StateFinishReason
 | 
				
			||||||
 | 
						 */
 | 
				
			||||||
 | 
						void GoToEntryState(EFFStateFinishReason StateFinishReason);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    UFUNCTION(BlueprintPure)
 | 
				
			||||||
 | 
						FORCEINLINE int64 GetTicksInState() const { return TicksInState; }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/**
 | 
				
			||||||
 | 
						 *	Returns the tick number which corresponds to when this state was entered into.
 | 
				
			||||||
 | 
						 *
 | 
				
			||||||
 | 
						 *	The tick number represents the ticks that have elapsed since the game began.
 | 
				
			||||||
 | 
						 */
 | 
				
			||||||
 | 
						UFUNCTION(BlueprintPure)
 | 
				
			||||||
 | 
						FORCEINLINE int64 GetTickStateWasEntered() const { return TickStateWasEntered; }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						UFUNCTION(BlueprintPure)
 | 
				
			||||||
 | 
						const UFFState* GetCurrentState() const { return const_cast<UFFState*>(CurrentState); }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /**
 | 
				
			||||||
 | 
					     *	Returns the name of the current state
 | 
				
			||||||
 | 
					     */
 | 
				
			||||||
 | 
						UFUNCTION(BlueprintPure)
 | 
				
			||||||
 | 
						FORCEINLINE FName GetCurrentStateName() const;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /**
 | 
				
			||||||
 | 
					     *	Returns the name of the current sub state label
 | 
				
			||||||
 | 
					     */
 | 
				
			||||||
 | 
						UFUNCTION(BlueprintPure)
 | 
				
			||||||
 | 
						FORCEINLINE FName GetCurrentSubStateLabel() const { return CurrentSubStateLabel; }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						UFUNCTION(BlueprintCallable)
 | 
				
			||||||
 | 
						void SetSubStateLabel(FName InSubStateLabel);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /**
 | 
				
			||||||
 | 
						 *
 | 
				
			||||||
 | 
						 */
 | 
				
			||||||
 | 
						FFFStateContext GetCurrentStateContext();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						// Events
 | 
				
			||||||
 | 
						virtual void Landed(const FHitResult& Hit);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						virtual void MovementModeChanged(EMovementMode PrevMovementMode, uint8 PreviousCustomMode, 
 | 
				
			||||||
 | 
						    EMovementMode NewMovementMode, uint8 NewCustomMode);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						FOnStateTransitionSignature OnStateTransition;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						// IFFSystemInterface interface
 | 
				
			||||||
 | 
					    virtual void FixedTick(float OneFrame) override;
 | 
				
			||||||
 | 
						// End of IFFSystemInterface interface
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					protected:
 | 
				
			||||||
 | 
						/**
 | 
				
			||||||
 | 
						 *	Actor that owns this state machine.
 | 
				
			||||||
 | 
						 *	This will typically be a player controller that possesses the avatar.
 | 
				
			||||||
 | 
						 */
 | 
				
			||||||
 | 
						UPROPERTY()
 | 
				
			||||||
 | 
						AActor* Owner;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/**
 | 
				
			||||||
 | 
						 *	The avatar is an actor that this state machine represents.
 | 
				
			||||||
 | 
						 *	This will typically be a pawn or character the state machine is attached to.
 | 
				
			||||||
 | 
						 */
 | 
				
			||||||
 | 
						UPROPERTY()
 | 
				
			||||||
 | 
						AActor* Avatar;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /** How many ticks have elapsed since the currently active state was entered */
 | 
				
			||||||
 | 
						int64 TicksInState;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /**
 | 
				
			||||||
 | 
						 *	The tick number which corresponds to when this state was entered into.
 | 
				
			||||||
 | 
						 *
 | 
				
			||||||
 | 
						 *	The tick number represents the ticks that have elapsed since the game began.
 | 
				
			||||||
 | 
						 */
 | 
				
			||||||
 | 
						int64 TickStateWasEntered;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/** Current active state for this state machine */
 | 
				
			||||||
 | 
						UPROPERTY()
 | 
				
			||||||
 | 
						UFFState* CurrentState;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/** Current SubState label or NAME_None if there is no SubState label set for the current state*/
 | 
				
			||||||
 | 
						FName CurrentSubStateLabel;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						// States that have been added
 | 
				
			||||||
 | 
						UPROPERTY()
 | 
				
			||||||
 | 
						TArray<UFFState*> States;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /**
 | 
				
			||||||
 | 
						 *	Returns the state with corresponding name 
 | 
				
			||||||
 | 
						 */
 | 
				
			||||||
 | 
						UFFState* FindStateWithName(FName StateName);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#if !UE_BUILD_SHIPPING
 | 
				
			||||||
 | 
						// UActorComponent interface
 | 
				
			||||||
 | 
						virtual void TickComponent(float DeltaTime, ELevelTick TickType, FActorComponentTickFunction* ThisTickFunction) override;
 | 
				
			||||||
 | 
						// End of UActorComponent interface
 | 
				
			||||||
 | 
					#endif
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
@ -0,0 +1,27 @@
 | 
				
			|||||||
 | 
					// Unreal Fighting Framework by Kevin Poretti
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#pragma once
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#include "CoreMinimal.h"
 | 
				
			||||||
 | 
					#include "UObject/Interface.h"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#include "IFFStateAvatarInterface.generated.h"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					UINTERFACE(MinimalAPI)
 | 
				
			||||||
 | 
					class UFFStateAvatarInterface : public UInterface
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						GENERATED_BODY()
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/**
 | 
				
			||||||
 | 
					 * 
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					class UNREALFIGHTINGFRAMEWORK_API IFFStateAvatarInterface
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						GENERATED_BODY()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					public:
 | 
				
			||||||
 | 
						virtual bool CheckStance(int32 Stance) = 0;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    virtual bool CheckStateEnabled(int32 StateType) = 0;
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
@ -0,0 +1,31 @@
 | 
				
			|||||||
 | 
					// Unreal Fighting Framework by Kevin Poretti
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#pragma once
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#include "CoreMinimal.h"
 | 
				
			||||||
 | 
					#include "UObject/Interface.h"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#include "IFFStateOwnerInterface.generated.h"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					UINTERFACE(MinimalAPI, NotBlueprintable)
 | 
				
			||||||
 | 
					class UFFStateOwnerInterface : public UInterface
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						GENERATED_BODY()
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/**
 | 
				
			||||||
 | 
					 * 
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					class UNREALFIGHTINGFRAMEWORK_API IFFStateOwnerInterface
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						GENERATED_BODY()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					public:
 | 
				
			||||||
 | 
					    UFUNCTION(BlueprintCallable, Category="UFF State Owner Interface")
 | 
				
			||||||
 | 
					    virtual bool CheckInputSequence(const FFFInputSequence& InInputSequence) = 0;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    UFUNCTION(BlueprintCallable, Category="UFF State Owner Interface")
 | 
				
			||||||
 | 
					    virtual bool CheckInputSequences(const TArray<FFFInputSequence>& InInputSequences) = 0;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    virtual void DisableMostRecentInput() = 0;
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
@ -1,23 +1,22 @@
 | 
				
			|||||||
// Some copyright should be here...
 | 
					// Unreal Fighting Framework by Kevin Poretti
 | 
				
			||||||
 | 
					using System.IO;
 | 
				
			||||||
using UnrealBuildTool;
 | 
					using UnrealBuildTool;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
public class UnrealFightingEngine : ModuleRules
 | 
					public class UnrealFightingFramework : ModuleRules
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	public UnrealFightingEngine(ReadOnlyTargetRules Target) : base(Target)
 | 
						public UnrealFightingFramework(ReadOnlyTargetRules Target) : base(Target)
 | 
				
			||||||
	{
 | 
						{
 | 
				
			||||||
		PCHUsage = ModuleRules.PCHUsageMode.UseExplicitOrSharedPCHs;
 | 
							PCHUsage = ModuleRules.PCHUsageMode.UseExplicitOrSharedPCHs;
 | 
				
			||||||
		
 | 
							
 | 
				
			||||||
		PublicIncludePaths.AddRange(
 | 
							PublicIncludePaths.AddRange(
 | 
				
			||||||
			new string[] {
 | 
								new string[] {
 | 
				
			||||||
				// ... add public include paths required here ...
 | 
									Path.Combine(PluginDirectory,"Source/UnrealFightingFramework"),
 | 
				
			||||||
			}
 | 
								}
 | 
				
			||||||
			);
 | 
								);
 | 
				
			||||||
				
 | 
									
 | 
				
			||||||
		
 | 
							
 | 
				
			||||||
		PrivateIncludePaths.AddRange(
 | 
							PrivateIncludePaths.AddRange(
 | 
				
			||||||
			new string[] {
 | 
								new string[] {
 | 
				
			||||||
				// ... add other private include paths required here ...
 | 
					 | 
				
			||||||
			}
 | 
								}
 | 
				
			||||||
			);
 | 
								);
 | 
				
			||||||
			
 | 
								
 | 
				
			||||||
@ -26,6 +25,7 @@ public class UnrealFightingEngine : ModuleRules
 | 
				
			|||||||
			new string[]
 | 
								new string[]
 | 
				
			||||||
			{
 | 
								{
 | 
				
			||||||
				"Core",
 | 
									"Core",
 | 
				
			||||||
 | 
									"EnhancedInput",
 | 
				
			||||||
				// ... add other public dependencies that you statically link with here ...
 | 
									// ... add other public dependencies that you statically link with here ...
 | 
				
			||||||
			}
 | 
								}
 | 
				
			||||||
			);
 | 
								);
 | 
				
			||||||
@ -36,8 +36,6 @@ public class UnrealFightingEngine : ModuleRules
 | 
				
			|||||||
			{
 | 
								{
 | 
				
			||||||
				"CoreUObject",
 | 
									"CoreUObject",
 | 
				
			||||||
				"Engine",
 | 
									"Engine",
 | 
				
			||||||
				"Slate",
 | 
					 | 
				
			||||||
				"SlateCore",
 | 
					 | 
				
			||||||
				// ... add private dependencies that you statically link with here ...	
 | 
									// ... add private dependencies that you statically link with here ...	
 | 
				
			||||||
			}
 | 
								}
 | 
				
			||||||
			);
 | 
								);
 | 
				
			||||||
@ -0,0 +1,16 @@
 | 
				
			|||||||
 | 
					// Copyright Epic Games, Inc. All Rights Reserved.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#include "UnrealFightingFrameworkBPLibrary.h"
 | 
				
			||||||
 | 
					#include "UnrealFightingFrameworkModule.h"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					UUnrealFightingFrameworkBPLibrary::UUnrealFightingFrameworkBPLibrary(const FObjectInitializer& ObjectInitializer)
 | 
				
			||||||
 | 
					: Super(ObjectInitializer)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					float UUnrealFightingFrameworkBPLibrary::UnrealFightingFrameworkSampleFunction(float Param)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						return -1;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@ -3,7 +3,7 @@
 | 
				
			|||||||
#pragma once
 | 
					#pragma once
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#include "Kismet/BlueprintFunctionLibrary.h"
 | 
					#include "Kismet/BlueprintFunctionLibrary.h"
 | 
				
			||||||
#include "UnrealFightingEngineBPLibrary.generated.h"
 | 
					#include "UnrealFightingFrameworkBPLibrary.generated.h"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/* 
 | 
					/* 
 | 
				
			||||||
*	Function library class.
 | 
					*	Function library class.
 | 
				
			||||||
@ -23,10 +23,10 @@
 | 
				
			|||||||
*	https://wiki.unrealengine.com/Custom_Blueprint_Node_Creation
 | 
					*	https://wiki.unrealengine.com/Custom_Blueprint_Node_Creation
 | 
				
			||||||
*/
 | 
					*/
 | 
				
			||||||
UCLASS()
 | 
					UCLASS()
 | 
				
			||||||
class UUnrealFightingEngineBPLibrary : public UBlueprintFunctionLibrary
 | 
					class UUnrealFightingFrameworkBPLibrary : public UBlueprintFunctionLibrary
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	GENERATED_UCLASS_BODY()
 | 
						GENERATED_UCLASS_BODY()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	UFUNCTION(BlueprintCallable, meta = (DisplayName = "Execute Sample function", Keywords = "UnrealFightingEngine sample test testing"), Category = "UnrealFightingEngineTesting")
 | 
						UFUNCTION(BlueprintCallable, meta = (DisplayName = "Execute Sample function", Keywords = "UnrealFightingFramework sample test testing"), Category = "UnrealFightingFrameworkTesting")
 | 
				
			||||||
	static float UnrealFightingEngineSampleFunction(float Param);
 | 
						static float UnrealFightingFrameworkSampleFunction(float Param);
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
@ -1,16 +1,16 @@
 | 
				
			|||||||
// Copyright Epic Games, Inc. All Rights Reserved.
 | 
					// Copyright Epic Games, Inc. All Rights Reserved.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#include "UnrealFightingEngine.h"
 | 
					#include "UnrealFightingFrameworkModule.h"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#define LOCTEXT_NAMESPACE "FUnrealFightingEngineModule"
 | 
					#define LOCTEXT_NAMESPACE "FUnrealFightingFrameworkModule"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
void FUnrealFightingEngineModule::StartupModule()
 | 
					void FUnrealFightingFrameworkModule::StartupModule()
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	// This code will execute after your module is loaded into memory; the exact timing is specified in the .uplugin file per-module
 | 
						// This code will execute after your module is loaded into memory; the exact timing is specified in the .uplugin file per-module
 | 
				
			||||||
	
 | 
						
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
void FUnrealFightingEngineModule::ShutdownModule()
 | 
					void FUnrealFightingFrameworkModule::ShutdownModule()
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	// This function may be called during shutdown to clean up your module.  For modules that support dynamic reloading,
 | 
						// This function may be called during shutdown to clean up your module.  For modules that support dynamic reloading,
 | 
				
			||||||
	// we call this function before unloading the module.
 | 
						// we call this function before unloading the module.
 | 
				
			||||||
@ -19,4 +19,4 @@ void FUnrealFightingEngineModule::ShutdownModule()
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
#undef LOCTEXT_NAMESPACE
 | 
					#undef LOCTEXT_NAMESPACE
 | 
				
			||||||
	
 | 
						
 | 
				
			||||||
IMPLEMENT_MODULE(FUnrealFightingEngineModule, UnrealFightingEngine)
 | 
					IMPLEMENT_MODULE(FUnrealFightingFrameworkModule, UnrealFightingFramework)
 | 
				
			||||||
@ -4,7 +4,7 @@
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
#include "Modules/ModuleManager.h"
 | 
					#include "Modules/ModuleManager.h"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
class FUnrealFightingEngineModule : public IModuleInterface
 | 
					class FUnrealFightingFrameworkModule : public IModuleInterface
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
public:
 | 
					public:
 | 
				
			||||||
 | 
					
 | 
				
			||||||
							
								
								
									
										151
									
								
								Source/UnrealFightingFramework/Utils/TCircleBuffer.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										151
									
								
								Source/UnrealFightingFramework/Utils/TCircleBuffer.h
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,151 @@
 | 
				
			|||||||
 | 
					// Unreal Fighting Framework by Kevin Poretti
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#pragma once
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#include "CoreMinimal.h"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/**
 | 
				
			||||||
 | 
					 *	CircleBuffer is a templated array data structure allowing for FIFO, O(1) insertion and removal,
 | 
				
			||||||
 | 
					 *	and wraparound when iterating/accessing elements of the buffer.
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 *	The underlying container type is a statically allocated array. You can use the second
 | 
				
			||||||
 | 
					 *	template parameter to specify the static size of the buffer. Defaults to 64.
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					template<typename T, SIZE_T L = 64>
 | 
				
			||||||
 | 
					class UNREALFIGHTINGFRAMEWORK_API TCircleBuffer
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					public:
 | 
				
			||||||
 | 
						TCircleBuffer()
 | 
				
			||||||
 | 
						    : WriteIdx(0)
 | 
				
			||||||
 | 
							, ReadIdx(0)
 | 
				
			||||||
 | 
					        , _Num(0)
 | 
				
			||||||
 | 
						{
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /**
 | 
				
			||||||
 | 
					     * @brief Adds a new element to the buffer only if there is room.
 | 
				
			||||||
 | 
					     * @param Element to add to the buffer
 | 
				
			||||||
 | 
					     * @return true if there was room in the buffer and the element was added, false otherwise
 | 
				
			||||||
 | 
					     */
 | 
				
			||||||
 | 
					    bool Push(const T& Element)
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        if(_Num == L)
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					            // buffer full so can't add element
 | 
				
			||||||
 | 
					            return false;
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        Buffer[WriteIdx] = Element;
 | 
				
			||||||
 | 
					        WriteIdx = (WriteIdx + 1) % L;
 | 
				
			||||||
 | 
					        _Num++;
 | 
				
			||||||
 | 
					        return true;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /**
 | 
				
			||||||
 | 
					     * @brief Adds a new element to the buffer.
 | 
				
			||||||
 | 
					     * This function always adds an element. If the buffer is full the oldest element will be overwritten.
 | 
				
			||||||
 | 
					     * @param Element to add to the buffer
 | 
				
			||||||
 | 
					     */
 | 
				
			||||||
 | 
					    void ForcePush(const T& Element)
 | 
				
			||||||
 | 
						{
 | 
				
			||||||
 | 
						    if(_Num == L)
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					            // buffer is full so we need to overwrite the oldest element
 | 
				
			||||||
 | 
					            // and make the read index point to the next oldest element
 | 
				
			||||||
 | 
					            ReadIdx = (ReadIdx + 1) % L;
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        Buffer[WriteIdx] = Element;
 | 
				
			||||||
 | 
					        WriteIdx = (WriteIdx + 1) % L;
 | 
				
			||||||
 | 
					        _Num = FMath::Min(_Num + 1, L);
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /**
 | 
				
			||||||
 | 
					     * @brief Returns the oldest element in the buffer and removes that element from the buffer.
 | 
				
			||||||
 | 
					     * @param Result out parameter to be filled in with the popped element
 | 
				
			||||||
 | 
					     * @return true if there was an element in the buffer to pop, false otherwise
 | 
				
			||||||
 | 
					     */
 | 
				
			||||||
 | 
					    bool Pop(T* Result)
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        if(IsEmpty())
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					            return false;
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        *Result = Buffer[ReadIdx];
 | 
				
			||||||
 | 
					        ReadIdx = (ReadIdx + 1) % L;
 | 
				
			||||||
 | 
					        _Num--;
 | 
				
			||||||
 | 
					        return true;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /**
 | 
				
			||||||
 | 
					     * @brief Returns the newest element that was added to the buffer
 | 
				
			||||||
 | 
					     * @param Result out parameter to be filled in with the most recently added element
 | 
				
			||||||
 | 
					     * @return true if there was an element in the buffer to peak, false otherwise
 | 
				
			||||||
 | 
					     */
 | 
				
			||||||
 | 
					    bool PeakLast(T* Result)
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
						    if(IsEmpty())
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					            return false;
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        *Result = Buffer[((SSIZE_T)WriteIdx - 1) <= 0 ? L - 1 : (WriteIdx - 1)];
 | 
				
			||||||
 | 
					        return true;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /**
 | 
				
			||||||
 | 
					     * @brief Returns the oldest element that was added to the buffer
 | 
				
			||||||
 | 
					     * @param Result out parameter to be filled in with the oldest element
 | 
				
			||||||
 | 
					     * @return true if there was an element in the buffer to peak, false otherwise
 | 
				
			||||||
 | 
					     */
 | 
				
			||||||
 | 
					    bool PeakFirst(T* Result)
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
						    if(IsEmpty())
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					            return false;
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        *Result = Buffer[ReadIdx];
 | 
				
			||||||
 | 
					        return true;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /**
 | 
				
			||||||
 | 
					     * @brief Returns the element at an index supplied to the function.
 | 
				
			||||||
 | 
					     * This function will account for write index offset and wraparound of the supplied index.
 | 
				
			||||||
 | 
					     * i.e. Index 0 will be the oldest added element while index Num - 1 will be the newest added element
 | 
				
			||||||
 | 
					     * @param Index of the element to return
 | 
				
			||||||
 | 
					     * @return the element at the index supplied
 | 
				
			||||||
 | 
					     */
 | 
				
			||||||
 | 
					    T& operator[](SIZE_T Index)
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        return Buffer[(ReadIdx + Index) % L];
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    FORCEINLINE bool IsEmpty() const
 | 
				
			||||||
 | 
						{
 | 
				
			||||||
 | 
						    return _Num == 0;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /**
 | 
				
			||||||
 | 
					     * @brief Returns the max size of the underlying buffer
 | 
				
			||||||
 | 
					     * @return Max size of the underlying buffer
 | 
				
			||||||
 | 
					     */
 | 
				
			||||||
 | 
					    FORCEINLINE SIZE_T Max() const
 | 
				
			||||||
 | 
						{
 | 
				
			||||||
 | 
						    return L;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /**
 | 
				
			||||||
 | 
					     * @brief Returns the current number of elements of the underlying buffer
 | 
				
			||||||
 | 
					     * @return Max size of the underlying buffer
 | 
				
			||||||
 | 
					     */
 | 
				
			||||||
 | 
					    FORCEINLINE SIZE_T Num() const
 | 
				
			||||||
 | 
						{
 | 
				
			||||||
 | 
						    return _Num;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					private:
 | 
				
			||||||
 | 
					    T Buffer[L];
 | 
				
			||||||
 | 
						SIZE_T WriteIdx;
 | 
				
			||||||
 | 
						SIZE_T ReadIdx;
 | 
				
			||||||
 | 
					    SIZE_T _Num;
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
@ -2,7 +2,7 @@
 | 
				
			|||||||
	"FileVersion": 3,
 | 
						"FileVersion": 3,
 | 
				
			||||||
	"Version": 1,
 | 
						"Version": 1,
 | 
				
			||||||
	"VersionName": "1.0",
 | 
						"VersionName": "1.0",
 | 
				
			||||||
	"FriendlyName": "UnrealFightingEngine",
 | 
						"FriendlyName": "UnrealFightingFramework",
 | 
				
			||||||
	"Description": "This library provides actors, components, and other general data structures that are useful for developing character action or fighting games.",
 | 
						"Description": "This library provides actors, components, and other general data structures that are useful for developing character action or fighting games.",
 | 
				
			||||||
	"Category": "Other",
 | 
						"Category": "Other",
 | 
				
			||||||
	"CreatedBy": "Kevin Poretti",
 | 
						"CreatedBy": "Kevin Poretti",
 | 
				
			||||||
@ -16,9 +16,15 @@
 | 
				
			|||||||
	"Installed": false,
 | 
						"Installed": false,
 | 
				
			||||||
	"Modules": [
 | 
						"Modules": [
 | 
				
			||||||
		{
 | 
							{
 | 
				
			||||||
			"Name": "UnrealFightingEngine",
 | 
								"Name": "UnrealFightingFramework",
 | 
				
			||||||
			"Type": "Runtime",
 | 
								"Type": "Runtime",
 | 
				
			||||||
			"LoadingPhase": "PreLoadingScreen"
 | 
								"LoadingPhase": "PreLoadingScreen"
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
 | 
						],
 | 
				
			||||||
 | 
						"Plugins": [
 | 
				
			||||||
 | 
							{
 | 
				
			||||||
 | 
								"Name": "EnhancedInput",
 | 
				
			||||||
 | 
								"Enabled": true
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
	]
 | 
						]
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
		Loading…
	
		Reference in New Issue
	
	Block a user