// Fill out your copyright notice in the Description page of Project Settings.
#pragma once
#include "CoreMinimal.h"
#include "GameFramework/CharacterMovementComponent.h"
#include "[Link].h"
UENUM(BlueprintType)
enum ECustomMovementMode
{
CMOVE_None UMETA(Hidden),
CMOVE_Slide UMETA(DisplayName = "Slide"),
CMOVE_Prone UMETA(DisplayName = "Prone"),
CMOVE_WallRun UMETA(DisplayName = "Wall Run"),
CMOVE_Hang UMETA(DisplayName = "Hang"),
CMOVE_Climb UMETA(DisplayName = "Climb"),
CMOVE_MAX UMETA(Hidden),
};
UDELEGATE(BlueprintAuthorityOnly)
DECLARE_DYNAMIC_MULTICAST_DELEGATE(FWallRunningCooldownFinished);
DECLARE_DYNAMIC_MULTICAST_DELEGATE(FDashStartDelegate);
DECLARE_DYNAMIC_MULTICAST_DELEGATE_TwoParams(FMovementModeChanged, EMovementMode,
moveMode, ECustomMovementMode, custMode);
UCLASS()
class AUREISTAR_API UAureiCharacterMovementComponent : public
UCharacterMovementComponent
{
GENERATED_BODY()
class FSavedMove_Aurei : public FSavedMove_Character
{
public:
enum CompressedFlags
{
FLAG_Sprint = 0x10,
FLAG_Dash = 0x20,
FLAG_Custom_2 = 0x40,
FLAG_Custom_3 = 0x80,
};
// Flags
uint8 Saved_bPressedAureiJump : 1;
uint8 Saved_bWantsToSprint : 1;
uint8 Saved_bWantsToDash : 1;
// Other Variables
uint8 Saved_bHadAnimRootMotion : 1;
uint8 Saved_bTransitionFinished : 1;
uint8 Saved_bPrevWantsToCrouch : 1;
uint8 Saved_bWantsToProne : 1;
uint8 Saved_bWallRunIsRight : 1;
FSavedMove_Aurei();
virtual bool CanCombineWith(const FSavedMovePtr& NewMove, ACharacter*
InCharacter, float MaxDelta) const override;
virtual void Clear() override;
virtual uint8 GetCompressedFlags() const override;
virtual void SetMoveFor(ACharacter* C, float InDeltaTime, FVector
const& NewAccel, FNetworkPredictionData_Client_Character& ClientData) override;
virtual void PrepMoveFor(ACharacter* C) override;
};
class FNetworkPredictionData_Client_Aurei : public
FNetworkPredictionData_Client_Character
{
public:
FNetworkPredictionData_Client_Aurei(const UCharacterMovementComponent&
ClientMovement);
typedef FNetworkPredictionData_Client_Character Super;
virtual FSavedMovePtr AllocateNewMove() override;
};
// Parameters
UPROPERTY(EditDefaultsOnly) float MaxSprintSpeed = 750.f;
// Slide
UPROPERTY(EditDefaultsOnly) float MinSlideSpeed = 400.f;
UPROPERTY(EditDefaultsOnly) float MaxSlideSpeed = 400.f;
UPROPERTY(EditDefaultsOnly) float SlideEnterImpulse = 400.f;
UPROPERTY(EditDefaultsOnly) float SlideGravityForce = 4000.f;
UPROPERTY(EditDefaultsOnly) float SlideFrictionFactor = .06f;
UPROPERTY(EditDefaultsOnly) float BrakingDecelerationSliding = 1000.f;
// Prone
UPROPERTY(EditDefaultsOnly) float ProneEnterHoldDuration = .2f;
UPROPERTY(EditDefaultsOnly) float ProneSlideEnterImpulse = 300.f;
UPROPERTY(EditDefaultsOnly) float MaxProneSpeed = 300.f;
UPROPERTY(EditDefaultsOnly) float BrakingDecelerationProning = 2500.f;
// Dash
UPROPERTY(EditDefaultsOnly) float DashCooldownDuration = 1.f;
UPROPERTY(EditDefaultsOnly) float AuthDashCooldownDuration = .9f;
UPROPERTY(EditDefaultsOnly) UAnimMontage* DashMontage;
// Mantle
UPROPERTY(EditDefaultsOnly) float MantleMaxDistance = 200;
UPROPERTY(EditDefaultsOnly) float MantleReachHeight = 50;
UPROPERTY(EditDefaultsOnly) float MinMantleDepth = 30;
UPROPERTY(EditDefaultsOnly) float MantleMinWallSteepnessAngle = 75;
UPROPERTY(EditDefaultsOnly) float MantleMaxSurfaceAngle = 40;
UPROPERTY(EditDefaultsOnly) float MantleMaxAlignmentAngle = 45;
UPROPERTY(EditDefaultsOnly) UAnimMontage* TallMantleMontage;
UPROPERTY(EditDefaultsOnly) UAnimMontage* TransitionTallMantleMontage;
UPROPERTY(EditDefaultsOnly) UAnimMontage* ProxyTallMantleMontage;
UPROPERTY(EditDefaultsOnly) UAnimMontage* ShortMantleMontage;
UPROPERTY(EditDefaultsOnly) UAnimMontage* TransitionShortMantleMontage;
UPROPERTY(EditDefaultsOnly) UAnimMontage* ProxyShortMantleMontage;
// Wall Run
UPROPERTY(EditDefaultsOnly, Category = "Movement|WallRun|Start") float
WR_MinSpeedToStart = 200.f;
UPROPERTY(EditDefaultsOnly, Category = "Movement|WallRun|Start") float
WR_MinAngleToStart = 60.f;
UPROPERTY(EditDefaultsOnly, Category = "Movement|WallRun|Start") float
WR_MaxAngleToStart = 120.f;
UPROPERTY(EditDefaultsOnly, Category = "Movement|WallRun|Start") float
WR_LineTraceDistance = 5;
UPROPERTY(EditDefaultsOnly, Category = "Movement|WallRun|Start") float
WR_FloorLineTraceDistance = 10;
public:
UPROPERTY(BlueprintReadWrite, VisibleAnywhere, Category = "Movement|WallRun|
HorizontalSpeed") float WR_MinSpeed = 200.f;
UPROPERTY(BlueprintReadWrite, VisibleAnywhere, Category = "Movement|WallRun|
HorizontalSpeed") float WR_MaxSpeed = 800.f;
UPROPERTY(BlueprintReadWrite, VisibleAnywhere, Category = "Movement|WallRun|
HorizontalSpeed") float WR_minAngleHMultiplier = 1.f;
UPROPERTY(BlueprintReadWrite, VisibleAnywhere, Category = "Movement|WallRun|
HorizontalSpeed") float WR_maxAngleHMultiplier = 0.2f;
private:
/*This curve must go between 0 and 1. 0 means WR_MinSpeed, 1 means
WR_MaxSpeed.
Any intermediate value will be lerped between both.
The float used to calculate the curve value is the time since wall running
started
*/
UPROPERTY(EditDefaultsOnly, Category = "Movement|WallRun|HorizontalSpeed")
UCurveFloat* WR_HorizontalSpeedCurve;
UPROPERTY(EditDefaultsOnly, Category = "Movement|WallRun|VerticalSpeed")
float WR_MaxVerticalSpeed = 500.f;
UPROPERTY(EditDefaultsOnly, Category = "Movement|WallRun|VerticalSpeed")
float WR_MaxGravity = 200.f;
UPROPERTY(EditDefaultsOnly, Category = "Movement|WallRun|VerticalSpeed")
float bWR_wallAngleAffectsVerticalSpeed = false;
UPROPERTY(EditDefaultsOnly, Category = "Movement|WallRun|VerticalSpeed")
float WR_minAngleVMultiplier = 1.f;
UPROPERTY(EditDefaultsOnly, Category = "Movement|WallRun|VerticalSpeed")
float WR_maxAngleVMultiplier = 0.2f;
/*This curve must go between -1 and 1. -1 means -WR_MaxGravity, 1 means
WR_MaxVerticalSpeed.
Any intermediate value will be lerped between both.
The float used to calculate the curve value is the time since wall running
started
*/
UPROPERTY(EditDefaultsOnly, Category = "Movement|WallRun|VerticalSpeed")
UCurveFloat* WR_VerticalSpeedCurve;
UPROPERTY(EditDefaultsOnly, Category = "Movement|WallRun|EndJump") float
WR_Force = 1000;
UPROPERTY(EditDefaultsOnly, Category = "Movement|WallRun|EndJump") float
WR_HorizontalAngle = 45;
UPROPERTY(EditDefaultsOnly, Category = "Movement|WallRun|EndJump") float
WR_VerticalAngle = 45;
//When player starts wallRuning, instantly rotate the pawn to match the wall
surface
UPROPERTY(EditDefaultsOnly, Category = "Movement|WallRun|Rotation") bool
bWR_InstaRotation = false;
//If bInstaRotation == false, this value will be used as the interpolation
speed
UPROPERTY(EditDefaultsOnly, Category = "Movement|WallRun|Rotation") float
WR_RotationSpeed = 10.f;
UPROPERTY(EditDefaultsOnly, Category = "Movement|WallRun") float
WR_AttractionForce = 200.f;
UPROPERTY(EditDefaultsOnly, Category = "Movement|WallRun") float
WR_AttractionMinRange = 50.f;
UPROPERTY(EditDefaultsOnly, Category = "Movement|WallRun") float WR_Cooldown
= 2.f;
public:
UPROPERTY(BlueprintAssignable) FWallRunningCooldownFinished
WR_CooldownFinishedEvent;
private:
bool Safe_bWallRunIsRight;
bool canWallRun = true;
float WR_currentTimer;
FRotator targetRotation;
FTimerHandle WR_CooldownTimerHandle;
public:
// Hang
UPROPERTY(EditDefaultsOnly) UAnimMontage* TransitionHangMontage;
UPROPERTY(EditDefaultsOnly) UAnimMontage* WallJumpMontage;
UPROPERTY(EditDefaultsOnly) float WallJumpForce = 400.f;
// Climb
bool bWantsToClimb = false;
UPROPERTY(EditDefaultsOnly, Category = "Movement|Climb") float CL_MaxSpeed =
300.f;
UPROPERTY(EditDefaultsOnly, Category = "Movement|Climb") float
CL_BreakingDeaceleration = 1000.f;
UPROPERTY(EditDefaultsOnly, Category = "Movement|Climb") float CL_SnapRange =
200.f;
UPROPERTY(EditDefaultsOnly, Category = "Movement|Climb") float
CL_AttractionMinRange = 50.f;
UPROPERTY(EditDefaultsOnly, Category = "Movement|Climb") float
CL_AttractionForce = 200.f;
UPROPERTY(EditDefaultsOnly, Category = "Movement|Climb|Angle") float
CL_minWallAngle = 70.f;
UPROPERTY(EditDefaultsOnly, Category = "Movement|Climb|Angle") float
CL_maxWallAngle = 110.f;
//When player starts climbing, instantly rotate the pawn to match the wall
surface
UPROPERTY(EditDefaultsOnly, Category = "Movement|Climb|Rotation") bool
bCL_InstaRotation = false;
//If bCL_SnapRange == false, this value will be used as the interpolation
speed
UPROPERTY(EditDefaultsOnly, Category = "Movement|Climb|Rotation") float
CL_RotationSpeed = 10.f;
UPROPERTY(VisibleAnywhere, BlueprintReadWrite) float WR_WallAngle;
private:
float CL_currentTimer;
// Transient
UPROPERTY(Transient) class APlayerCharacter* AureiCharacterOwner;
// Debug
UPROPERTY(EditAnywhere, Category = "DebugFlags") bool ShowMovementMode =
false;
UPROPERTY(EditAnywhere, Category = "DebugFlags") bool ShowWallRiding = false;
// Flags
bool Safe_bWantsToSprint;
bool Safe_bWantsToProne;
bool Safe_bWantsToDash;
bool Safe_bHadAnimRootMotion;
bool Safe_bPrevWantsToCrouch;
float DashStartTime;
FTimerHandle TimerHandle_EnterProne;
FTimerHandle TimerHandle_DashCooldown;
bool Safe_bTransitionFinished;
TSharedPtr<FRootMotionSource_MoveToForce> TransitionRMS;
FString TransitionName;
UPROPERTY(Transient) UAnimMontage* TransitionQueuedMontage;
float TransitionQueuedMontageSpeed;
int TransitionRMS_ID;
float AccumulatedClientLocationError = 0.f;
int TickCount = 0;
int CorrectionCount = 0;
int TotalBitsSent = 0;
// Replication
UPROPERTY(ReplicatedUsing = OnRep_Dash) bool Proxy_bDash;
UPROPERTY(ReplicatedUsing = OnRep_ShortMantle) bool Proxy_bShortMantle;
UPROPERTY(ReplicatedUsing = OnRep_TallMantle) bool Proxy_bTallMantle;
// Delegates
public:
UPROPERTY(BlueprintAssignable) FDashStartDelegate DashStartDelegate;
UPROPERTY(BlueprintAssignable) FMovementModeChanged MovementModeChangedEvent;
public:
UAureiCharacterMovementComponent();
void TickComponent(float DeltaTime, ELevelTick TickType,
FActorComponentTickFunction* ThisTickFunction) override;
// Actor Component
protected:
virtual void InitializeComponent() override;
// Character Movement Component
public:
virtual FNetworkPredictionData_Client* GetPredictionData_Client() const
override;
virtual bool IsMovingOnGround() const override;
virtual bool CanCrouchInCurrentState() const override;
virtual float GetMaxSpeed() const override;
virtual float GetMaxBrakingDeceleration() const override;
virtual bool CanAttemptJump() const override;
virtual bool DoJump(bool bReplayingMoves) override;
protected:
virtual void UpdateFromCompressedFlags(uint8 Flags) override;
virtual void
OnClientCorrectionReceived(FNetworkPredictionData_Client_Character& ClientData,
float TimeStamp, FVector NewLocation, FVector NewVelocity, UPrimitiveComponent*
NewBase, FName NewBaseBoneName, bool bHasBase, bool bBaseRelativePosition, uint8
ServerMovementMode) override;
public:
virtual void UpdateCharacterStateBeforeMovement(float DeltaSeconds) override;
virtual void UpdateCharacterStateAfterMovement(float DeltaSeconds) override;
protected:
virtual void OnMovementUpdated(float DeltaSeconds, const FVector&
OldLocation, const FVector& OldVelocity) override;
virtual void PhysCustom(float deltaTime, int32 Iterations) override;
virtual void OnMovementModeChanged(EMovementMode PreviousMovementMode, uint8
PreviousCustomMode) override;
virtual bool ServerCheckClientError(float ClientTimeStamp, float DeltaTime,
const FVector& Accel, const FVector& ClientWorldLocation, const FVector&
RelativeClientLocation, UPrimitiveComponent* ClientMovementBase, FName
ClientBaseBoneName, uint8 ClientMovementMode) override;
FNetBitWriter AureiServerMoveBitWriter;
virtual void CallServerMovePacked(const FSavedMove_Character* NewMove, const
FSavedMove_Character* PendingMove, const FSavedMove_Character* OldMove) override;
// Slide
private:
void EnterSlide(EMovementMode PrevMode, ECustomMovementMode PrevCustomMode);
void ExitSlide();
bool CanSlide() const;
void PhysSlide(float deltaTime, int32 Iterations);
// Prone
private:
void OnTryEnterProne() { Safe_bWantsToProne = true; }
UFUNCTION(Server, Reliable) void Server_EnterProne();
void EnterProne(EMovementMode PrevMode, ECustomMovementMode PrevCustomMode);
void ExitProne();
bool CanProne() const;
void PhysProne(float deltaTime, int32 Iterations);
// Dash
private:
void OnDashCooldownFinished();
bool CanDash() const;
void PerformDash();
// Vault
private:
bool TryMantle();
FVector GetMantleStartLocation(FHitResult FrontHit, FHitResult SurfaceHit,
bool bTallMantle) const;
// Wall Run
public:
/// <summary>
/// Try to start a wallRun by checking if there is any runnable wall nearby
/// </summary>
/// <returns></returns>
bool TryWallRun();
void StopWallRuning();
void WallRuningCooldownFinished();
private:
void PhysWallRun(float deltaTime, int32 Iterations);
// Climb
public:
bool TryClimb();
private:
void PhysClimb(float deltaTime, int32 Iterations);
// Helpers
private:
bool IsServer() const;
float CapR() const;
float CapHH() const;
float GetWallAngle(FVector Normal);
// Interface
public:
UFUNCTION(BlueprintCallable) void SprintPressed();
UFUNCTION(BlueprintCallable) void SprintReleased();
UFUNCTION(BlueprintCallable) void CrouchPressed();
UFUNCTION(BlueprintCallable) void CrouchReleased();
UFUNCTION(BlueprintCallable) void DashPressed();
UFUNCTION(BlueprintCallable) void DashReleased();
UFUNCTION(BlueprintCallable) void ClimbPressed();
UFUNCTION(BlueprintCallable) void ClimbReleased();
UFUNCTION(BlueprintPure) bool IsCustomMovementMode(ECustomMovementMode
InCustomMovementMode) const;
UFUNCTION(BlueprintPure) bool IsMovementMode(EMovementMode InMovementMode)
const;
UFUNCTION(BlueprintPure) bool IsWallRunning() const { return
IsCustomMovementMode(CMOVE_WallRun); }
UFUNCTION(BlueprintPure) bool WallRunningIsRight() const { return
Safe_bWallRunIsRight; }
UFUNCTION(BlueprintPure) bool IsHanging() const { return
IsCustomMovementMode(CMOVE_Hang); }
UFUNCTION(BlueprintPure) bool IsClimbing() const { return
IsCustomMovementMode(CMOVE_Climb); }
// Proxy Replication
public:
virtual void GetLifetimeReplicatedProps(TArray<FLifetimeProperty>&
OutLifetimeProps) const override;
private:
UFUNCTION() void OnRep_Dash();
UFUNCTION() void OnRep_ShortMantle();
UFUNCTION() void OnRep_TallMantle();
//Debug
private:
FString GetMovementModeName(EMovementMode EnumValue);
};