Implemented AMyVICharacterBase

This commit is contained in:
Rafal Swierczek 2024-01-11 03:06:23 +00:00
parent e2a109255b
commit f6d54647aa
9 changed files with 442 additions and 8 deletions

View File

@ -1,3 +1,3 @@
version https://git-lfs.github.com/spec/v1
oid sha256:23f1d30713deb7b63e333e5bffd36f97365280f94c773c2b5a1128418a658c42
oid sha256:928263e4929943c3bca1c28ad56a4a5530a5a7e2318a11275415abcb276a0e15
size 679253

View File

@ -23,6 +23,11 @@
"TargetAllowList": [
"Editor"
]
},
{
"Name": "VaultIt",
"Enabled": true,
"MarketplaceURL": "com.epicgames.launcher://ue/marketplace/content/7d19b5622d6846edb9881e6c89bce05e"
}
]
}

View File

@ -12,7 +12,7 @@ public class EndlessVendetta : ModuleRules
{
"Core", "CoreUObject", "Engine", "InputCore", "HeadMountedDisplay", "EnhancedInput", "AIModule",
"GameplayTasks", "NavigationSystem", "UMG", "Slate", "SlateCore", "Niagara", "NiagaraCore", "NiagaraShader",
"HTTP", "Json", "JsonUtilities"
"HTTP", "Json", "JsonUtilities", "VaultIt", "MotionWarping", "GameplayAbilities"
});
}
}

View File

@ -9,6 +9,7 @@
#include "Components/ArrowComponent.h"
#include "GadgetSystem/GadgetManager.h"
#include "Inventory/InventoryComponent.h"
#include "Pawn/VICharacter.h"
#include "EndlessVendettaCharacter.generated.h"

View File

@ -0,0 +1,309 @@
// Copyright (c) 2019-2022 Drowning Dragons Limited. All Rights Reserved.
#include "EndlessVendetta/MyVICharacterBase.h"
#include "Pawn/VICharacterBase.h"
#include "Net/UnrealNetwork.h"
#include "GameFramework/CharacterMovementComponent.h"
#include "Pawn/VIPawnVaultComponent.h"
#include "MotionWarpingComponent.h"
#include "VIBlueprintFunctionLibrary.h"
void AMyVICharacterBase::BeginPlay()
{
Super::BeginPlay();
VaultComponent = IVIPawnInterface::Execute_GetPawnVaultComponent(this);
MotionWarpingComponent = IVIPawnInterface::Execute_GetMotionWarpingComponent(this);
}
void AMyVICharacterBase::CheckJumpInput(float DeltaTime)
{
const bool bIsVaulting = IsVaulting();
// Server update simulated proxies with correct vaulting state
if (GetLocalRole() == ROLE_Authority && GetNetMode() != NM_Standalone)
{
bRepIsVaulting = bIsVaulting;
}
// Try to vault from local input
if (IsLocallyControlled() && VaultComponent)
{
// Disable jump if vaulting
if (VaultComponent->bPressedVault)
{
bPressedJump = false;
}
// Possibly execute vault
if (GetCharacterMovement())
{
VaultComponent->CheckVaultInput(DeltaTime, GetCharacterMovement()->MovementMode);
}
else
{
VaultComponent->CheckVaultInput(DeltaTime);
}
}
// Pick up changes in vaulting state to change movement mode
// to something other than flying (required for root motion on Z)
if (bWasVaulting && !bIsVaulting)
{
StopVaultAbility();
}
// Call super so we actually jump if we're meant to
Super::CheckJumpInput(DeltaTime);
// Cache end of frame
bWasVaulting = bIsVaulting;
}
void AMyVICharacterBase::GetLifetimeReplicatedProps(TArray<FLifetimeProperty>& OutLifetimeProps) const
{
Super::GetLifetimeReplicatedProps(OutLifetimeProps);
DOREPLIFETIME_CONDITION(AMyVICharacterBase, bRepIsVaulting, COND_SimulatedOnly);
DOREPLIFETIME_CONDITION(AMyVICharacterBase, RepMotionMatch, COND_SimulatedOnly);
}
void AMyVICharacterBase::Jump()
{
// If missing critical components then jump and exit
if (!VaultComponent || !GetCharacterMovement())
{
Super::Jump();
return;
}
// Either jump or vault, determined by VaultComponent::EVIJumpKeyPriority
if (VaultComponent->Jump(GetCharacterMovement()->GetGravityZ(), CanJump(), GetCharacterMovement()->IsFalling()))
{
// Jump normally
Super::Jump();
}
else
{
// Jump key essentially presses the vault input
VaultComponent->Vault();
}
}
void AMyVICharacterBase::StopJumping()
{
Super::StopJumping();
// Release vault input if the jump key pressed vault instead
if (VaultComponent)
{
VaultComponent->StopJumping();
}
}
void AMyVICharacterBase::StartVaultAbility_Implementation()
{
// Called by GA_Vault
// Need to be in flying mode to have root motion on Z axis
if (GetCharacterMovement() && GetLocalRole() > ROLE_SimulatedProxy)
{
GetCharacterMovement()->SetMovementMode(MOVE_Flying);
}
}
void AMyVICharacterBase::StopVaultAbility()
{
// Called by CheckJumpInput()
// Exiting flying mode
// This may put is straight into falling if we aren't properly grounded, which is fine
if (GetCharacterMovement() && GetLocalRole() > ROLE_SimulatedProxy)
{
GetCharacterMovement()->SetMovementMode(GetCharacterMovement()->GetGroundMovementMode());
}
OnStopVaultAbility();
}
void AMyVICharacterBase::OnRep_MotionMatch()
{
// Simulated proxies update their sync points here, sent from the server during GA_Vault
MotionWarpingComponent->AddOrUpdateWarpTargetFromLocationAndRotation(TEXT("VaultSyncPoint"), RepMotionMatch.Location, RepMotionMatch.Direction.Rotation());
}
bool AMyVICharacterBase::IsVaulting() const
{
// Simulated proxies use the value provided by server
if (GetLocalRole() == ROLE_SimulatedProxy)
{
return bRepIsVaulting;
}
// Local and authority uses gameplay tags for a predicted result
if (VaultComponent)
{
return VaultComponent->IsVaulting();
}
return false;
}
// *********************************************** //
// ******** Begin Pawn Vaulting Interface ******** //
// *********************************************** //
UVIPawnVaultComponent* AMyVICharacterBase::GetPawnVaultComponent_Implementation() const
{
// You need to override this
UVIBlueprintFunctionLibrary::MessageLogError(FString::Printf(TEXT("AVICharacterBase::GetPawnVaultComponent not implemented for { %s }. Cannot Vault."), *GetName()));
return nullptr;
}
UMotionWarpingComponent* AMyVICharacterBase::GetMotionWarpingComponent_Implementation() const
{
// You need to override this
UVIBlueprintFunctionLibrary::MessageLogError(FString::Printf(TEXT("AVICharacterBase::GetMotionWarpingComponent not implemented for { %s }. Cannot Vault."), *GetName()));
return nullptr;
}
FVIAnimSet AMyVICharacterBase::GetVaultAnimSet_Implementation() const
{
// You need to override this
UVIBlueprintFunctionLibrary::MessageLogError(FString::Printf(TEXT("AVICharacterBase::GetVaultAnimSet not implemented for { %s }. Cannot Vault."), *GetName()));
return FVIAnimSet();
}
FVITraceSettings AMyVICharacterBase::GetVaultTraceSettings_Implementation() const
{
// You need to override this
UVIBlueprintFunctionLibrary::MessageLogError(FString::Printf(TEXT("AVICharacterBase::GetVaultTraceSettings not implemented for { %s }. Using default trace settings."), *GetName()), false);
return FVITraceSettings();
}
FVector AMyVICharacterBase::GetVaultDirection_Implementation() const
{
// Use input vector if available
if (GetCharacterMovement() && !GetCharacterMovement()->GetCurrentAcceleration().IsNearlyZero())
{
return GetCharacterMovement()->GetCurrentAcceleration();
}
// Use character facing direction if not providing input
return GetActorForwardVector();
}
bool AMyVICharacterBase::CanVault_Implementation() const
{
// Vaulting must finish before starting another vault attempt
if (IsVaulting())
{
return false;
}
// Invalid components
if (!VaultComponent || !GetCharacterMovement())
{
return false;
}
// Animation instance is required to play vault montage
if (!GetMesh() || !GetMesh()->GetAnimInstance())
{
return false;
}
// Authority not initialized (this isn't set on clients)
if (HasAuthority() && !VaultComponent->bVaultAbilityInitialized)
{
return false;
}
// Exit if character is in a state they cannot vault from
if (GetCharacterMovement()->IsMovingOnGround() || GetCharacterMovement()->IsFalling() || GetCharacterMovement()->IsSwimming())
{
if (GetCharacterMovement()->IsMovingOnGround() && !VaultComponent->bCanVaultFromGround)
{
return false;
}
if (GetCharacterMovement()->IsFalling() && !VaultComponent->bCanVaultFromFalling)
{
return false;
}
if (GetCharacterMovement()->IsSwimming() && !VaultComponent->bCanVaultFromSwimming)
{
return false;
}
}
else
{
return false;
}
// Can't vault while crouching
if (!VaultComponent->bCanVaultFromCrouching && GetCharacterMovement()->IsCrouching())
{
return false;
}
// Passed all conditions
return true;
}
void AMyVICharacterBase::OnLocalPlayerVault_Implementation(const FVector& Location, const FVector& Direction)
{
// LocalPlayer just stores the data in the same place for convenience, ease of use, memory reduction, etc
RepMotionMatch = FVIRepMotionMatch(Location, Direction);
}
void AMyVICharacterBase::GetVaultLocationAndDirection_Implementation(FVector& OutLocation, FVector& OutDirection) const
{
// Because LocalPlayer stores in the same place, no need for any testing as they all use RepMotionMatch to store this
// This is only currently used for FBIK tracing
OutLocation = RepMotionMatch.Location;
OutDirection = RepMotionMatch.Direction;
}
void AMyVICharacterBase::ReplicateMotionMatch_Implementation(const FVIRepMotionMatch& MotionMatch)
{
// GA_Vault has directed server to update it's RepMotionMatch property so that it will
// be replicated to simulated proxies with 1 decimal point of precision (net quantization)
RepMotionMatch = MotionMatch;
}
bool AMyVICharacterBase::IsWalkable_Implementation(const FHitResult& HitResult) const
{
// Surface we hit can be walked on or not
return GetCharacterMovement() && GetCharacterMovement()->IsWalkable(HitResult);
}
bool AMyVICharacterBase::CanAutoVaultInCustomMovementMode_Implementation() const
{
return true;
// Example usage commented out
/*
if (GetCharacterMovement())
{
switch (GetCharacterMovement()->CustomMovementMode)
{
case 0:
return false;
case 1: // Some example custom mode where auto vault can work
return true;
case 2:
return false;
default:
return true;
}
}
*/
}
// *********************************************** //
// ********* End Pawn Vaulting Interface ********* //
// *********************************************** //

View File

@ -0,0 +1,119 @@
// Copyright (c) 2019-2022 Drowning Dragons Limited. All Rights Reserved.
#pragma once
#include "CoreMinimal.h"
#include "EndlessVendettaCharacter.h"
#include "VITypes.h"
#include "Pawn/VIPawnInterface.h"
#include "MyVICharacterBase.generated.h"
class UMotionWarpingComponent;
class UVIPawnVaultComponent;
/**
* An incomplete character base class
* Needs to inherit from IAbilitySystemInterface and implement a UVIAbilitySystemComponent
* @see: AVICharacterAbilityBase where this is done for you
*
* Requires multiple overrides which will cause errors if not correctly performed
*/
UCLASS(abstract)
class ENDLESSVENDETTA_API AMyVICharacterBase : public AEndlessVendettaCharacter, public IVIPawnInterface
{
GENERATED_BODY()
public:
/**
* Motion Warping Component used for vaulting
*/
UPROPERTY(VisibleAnywhere, BlueprintReadOnly, Category = Character)
UMotionWarpingComponent* MotionWarpingComponent;
/**
* Pawn Vault Component used for core vaulting logic
*
* This is added in Blueprint and must be returned via
* the IVIPawnInterface::GetPawnVaultComponent function
*/
UPROPERTY(VisibleAnywhere, BlueprintReadOnly, Category = Character)
UVIPawnVaultComponent* VaultComponent;
protected:
/** Simulated proxies use this to update their vaulting state based on server values */
UPROPERTY(Replicated, BlueprintReadWrite, Category = Vault)
bool bRepIsVaulting;
/** Used to detect changes in vaulting state and call StopVaultAbility() */
UPROPERTY()
bool bWasVaulting;
/**
* Simulated proxies use this to reproduce motion matching results provided
* by server in the GA_Vault gameplay ability
*
* Local players use this as a cache for FBIK testing (returned via GetVaultLocationAndDirection)
*
* Net Serialized to one decimal point of precision
*/
UPROPERTY(ReplicatedUsing="OnRep_MotionMatch", BlueprintReadWrite, Category = Vault)
FVIRepMotionMatch RepMotionMatch;
public:
virtual void BeginPlay() override;
virtual void CheckJumpInput(float DeltaTime) override;
virtual void GetLifetimeReplicatedProps(TArray<FLifetimeProperty>& OutLifetimeProps) const override;
public:
virtual void Jump() override;
virtual void StopJumping() override;
/** Called from gameplay ability when vault stops */
UFUNCTION(BlueprintCallable, Category = Vault)
void StopVaultAbility();
UFUNCTION(BlueprintImplementableEvent, Category = Vault)
void OnStopVaultAbility();
protected:
UFUNCTION()
void OnRep_MotionMatch();
public:
/**
* @return True if vaulting
* Correct value must be returned based on net role here
* Simulated proxies return bRepIsVaulting
* Server & Authority must return CMC bIsVaulting
*/
UFUNCTION(BlueprintPure, Category = Vault)
virtual bool IsVaulting() const;
// *********************************************** //
// *********** Begin IVIPawnInterface ************ //
// *********************************************** //
// Read VIPawnInterface.h for detailed descriptions of these functions or look
// inside their functions themselves
virtual UVIPawnVaultComponent* GetPawnVaultComponent_Implementation() const override;
virtual UMotionWarpingComponent* GetMotionWarpingComponent_Implementation() const override;
virtual USkeletalMeshComponent* GetMeshForVaultMontage_Implementation() const override { return GetMesh(); }
virtual FVIAnimSet GetVaultAnimSet_Implementation() const override;
virtual FVITraceSettings GetVaultTraceSettings_Implementation() const override;
virtual FVector GetVaultDirection_Implementation() const override;
virtual bool CanVault_Implementation() const override;
virtual void StartVaultAbility_Implementation() override;
virtual void OnLocalPlayerVault_Implementation(const FVector& Location, const FVector& Direction) override;
virtual void GetVaultLocationAndDirection_Implementation(FVector& OutLocation, FVector& OutDirection) const override;
virtual void ReplicateMotionMatch_Implementation(const FVIRepMotionMatch& MotionMatch) override;
virtual bool IsWalkable_Implementation(const FHitResult& HitResult) const override;
virtual bool CanAutoVaultInCustomMovementMode_Implementation() const override;
// *********************************************** //
// ************* End IVIPawnInterface ************ //
// *********************************************** //
};