Untested circle buffer implementation
This commit is contained in:
		
							parent
							
								
									ec6daa06fb
								
							
						
					
					
						commit
						2c5569b6d5
					
				@ -7,16 +7,18 @@ UFFInputBufferComponent::UFFInputBufferComponent()
 | 
			
		||||
	PrimaryComponentTick.bCanEverTick = false;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void UFFInputBufferComponent::Initialize(int32 BufferSize)
 | 
			
		||||
{
 | 
			
		||||
	Buffer.Reserve(BufferSize);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void UFFInputBufferComponent::AddInput(const FFFInputState& InputState)
 | 
			
		||||
{
 | 
			
		||||
	InputBuffer.ForcePush(InputState);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
bool UFFInputBufferComponent::CheckInputSequence(const FFFInputSequence& InputSequence)
 | 
			
		||||
{
 | 
			
		||||
    for(int InpIdx = 0; InpIdx < InputBuffer.Num(); InpIdx++)
 | 
			
		||||
    {
 | 
			
		||||
        // read input sequence
 | 
			
		||||
        FFFInputState CurrInput = InputBuffer[InpIdx];
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
	return true;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@ -2,14 +2,27 @@
 | 
			
		||||
 | 
			
		||||
#pragma once
 | 
			
		||||
 | 
			
		||||
// FF includes
 | 
			
		||||
#include "Utils/TCircleBuffer.h"
 | 
			
		||||
 | 
			
		||||
// UE includes
 | 
			
		||||
#include "CoreMinimal.h"
 | 
			
		||||
#include "Components/ActorComponent.h"
 | 
			
		||||
#include "Containers/RingBuffer.h"
 | 
			
		||||
 | 
			
		||||
#include "FFInputBufferComponent.generated.h"
 | 
			
		||||
 | 
			
		||||
struct FFFInputState;
 | 
			
		||||
/**
 | 
			
		||||
 *	Struct representing the state of a player's inputs for one frame
 | 
			
		||||
 */
 | 
			
		||||
USTRUCT()
 | 
			
		||||
struct FFFInputState
 | 
			
		||||
{
 | 
			
		||||
    GENERATED_BODY()
 | 
			
		||||
 | 
			
		||||
	FVector2D	MoveAxes;
 | 
			
		||||
	FVector2D	LookAxes;
 | 
			
		||||
	int32		Buttons;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
USTRUCT()
 | 
			
		||||
struct FFFInputSequence
 | 
			
		||||
@ -26,13 +39,11 @@ class UNREALFIGHTINGFRAMEWORK_API UFFInputBufferComponent : public UActorCompone
 | 
			
		||||
public:	
 | 
			
		||||
	UFFInputBufferComponent();
 | 
			
		||||
 | 
			
		||||
	void Initialize(int32 BufferSize = 120);
 | 
			
		||||
 | 
			
		||||
	void AddInput(const FFFInputState& InputState);
 | 
			
		||||
 | 
			
		||||
	bool CheckInputSequence(const FFFInputSequence& InputSequence);
 | 
			
		||||
 | 
			
		||||
protected:
 | 
			
		||||
	/** The underlying buffer data structure for holding past input states */
 | 
			
		||||
	TRingBuffer<FFFInputState> Buffer;
 | 
			
		||||
	TCircleBuffer<FFFInputState, 120> InputBuffer;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
@ -21,7 +21,7 @@ void AFFPlayerController::SendInputsToRemote() const
 | 
			
		||||
 | 
			
		||||
void AFFPlayerController::FixedTick(float OneFrame)
 | 
			
		||||
{
 | 
			
		||||
    UnacknowledgedInputs.Add(CurrInput);
 | 
			
		||||
    //UnacknowledgedInputs.Push(CurrInput);
 | 
			
		||||
    InputBuffer->AddInput(CurrInput);
 | 
			
		||||
 | 
			
		||||
    SendInputsToRemote();
 | 
			
		||||
 | 
			
		||||
@ -4,29 +4,16 @@
 | 
			
		||||
 | 
			
		||||
// FF includes
 | 
			
		||||
#include "FFInputBufferComponent.h"
 | 
			
		||||
#include "UnrealFightingFramework/IFFSystemInterface.h"
 | 
			
		||||
#include "IFFSystemInterface.h"
 | 
			
		||||
#include "Utils/TCircleBuffer.h"
 | 
			
		||||
 | 
			
		||||
// UE includes
 | 
			
		||||
#include "CoreMinimal.h"
 | 
			
		||||
#include "GameFramework/PlayerController.h"
 | 
			
		||||
#include "InputMappingContext.h"
 | 
			
		||||
#include "Containers/RingBuffer.h"
 | 
			
		||||
 | 
			
		||||
#include "FFPlayerController.generated.h"
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 *	Struct representing the state of a player's inputs for one frame
 | 
			
		||||
 */
 | 
			
		||||
USTRUCT()
 | 
			
		||||
struct FFFInputState
 | 
			
		||||
{
 | 
			
		||||
    GENERATED_BODY()
 | 
			
		||||
 | 
			
		||||
	FVector2D	MoveAxes;
 | 
			
		||||
	FVector2D	LookAxes;
 | 
			
		||||
	int32		Buttons;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 *	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.
 | 
			
		||||
@ -72,5 +59,5 @@ protected:
 | 
			
		||||
	 *	you want the remote machine to re-simulate, where X is the oldest input you want to
 | 
			
		||||
	 *	allow to be re-simulated.
 | 
			
		||||
	 */
 | 
			
		||||
	TRingBuffer<FFFInputState> UnacknowledgedInputs;
 | 
			
		||||
	TCircleBuffer<FFFInputState, 20> UnacknowledgedInputs;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
@ -1,5 +1,5 @@
 | 
			
		||||
// Unreal Fighting Framework by Kevin Poretti
 | 
			
		||||
 | 
			
		||||
using System.IO;
 | 
			
		||||
using UnrealBuildTool;
 | 
			
		||||
 | 
			
		||||
public class UnrealFightingFramework : ModuleRules
 | 
			
		||||
@ -10,14 +10,13 @@ public class UnrealFightingFramework : ModuleRules
 | 
			
		||||
		
 | 
			
		||||
		PublicIncludePaths.AddRange(
 | 
			
		||||
			new string[] {
 | 
			
		||||
				"UnrealFightingFramework"
 | 
			
		||||
				Path.Combine(PluginDirectory,"Source/UnrealFightingFramework"),
 | 
			
		||||
			}
 | 
			
		||||
			);
 | 
			
		||||
				
 | 
			
		||||
		
 | 
			
		||||
		PrivateIncludePaths.AddRange(
 | 
			
		||||
			new string[] {
 | 
			
		||||
				"UnrealFightingFramework"
 | 
			
		||||
			}
 | 
			
		||||
			);
 | 
			
		||||
			
 | 
			
		||||
 | 
			
		||||
@ -1,11 +0,0 @@
 | 
			
		||||
// Unreal Fighting Framework by Kevin Poretti
 | 
			
		||||
 | 
			
		||||
#include "Utils/TCircleBuffer.h"
 | 
			
		||||
 | 
			
		||||
TCircleBuffer::TCircleBuffer()
 | 
			
		||||
{
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
TCircleBuffer::~TCircleBuffer()
 | 
			
		||||
{
 | 
			
		||||
}
 | 
			
		||||
@ -5,11 +5,146 @@
 | 
			
		||||
#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();
 | 
			
		||||
	~TCircleBuffer();
 | 
			
		||||
};
 | 
			
		||||
	TCircleBuffer()
 | 
			
		||||
	    : WriteIdx(0)
 | 
			
		||||
		, ReadIdx(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[((SSIZE_T)WriteIdx - (SSIZE_T)Index) < 0 ? L - (Index - WriteIdx) : WriteIdx - Index];
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    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;
 | 
			
		||||
};
 | 
			
		||||
		Loading…
	
		Reference in New Issue
	
	Block a user