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