From 3852db1e1b805b1b0d8606236e6c05e39bdd33a6 Mon Sep 17 00:00:00 2001 From: Helcio Laurentino do Carmo Junior Date: Sun, 26 Mar 2023 15:17:04 -0300 Subject: [PATCH 01/17] Add TopDown Camera Mode --- .../Private/Character/ALSBaseCharacter.cpp | 79 +++++++++++++++++-- .../Private/Character/ALSCharacter.cpp | 72 ++++++++++++++++- .../Character/ALSPlayerCameraManager.cpp | 7 +- .../Animation/ALSCharacterAnimInstance.cpp | 5 +- .../Notify/ALSAnimNotifyCameraShake.cpp | 6 +- .../Public/Character/ALSBaseCharacter.h | 24 +++++- .../ALSV4_CPP/Public/Character/ALSCharacter.h | 10 +++ .../Public/Library/ALSCharacterEnumLibrary.h | 3 +- 8 files changed, 189 insertions(+), 17 deletions(-) diff --git a/Source/ALSV4_CPP/Private/Character/ALSBaseCharacter.cpp b/Source/ALSV4_CPP/Private/Character/ALSBaseCharacter.cpp index 899f7fdc..65cc49d8 100644 --- a/Source/ALSV4_CPP/Private/Character/ALSBaseCharacter.cpp +++ b/Source/ALSV4_CPP/Private/Character/ALSBaseCharacter.cpp @@ -638,6 +638,35 @@ FTransform AALSBaseCharacter::GetThirdPersonPivotTarget() return GetActorTransform(); } +FTransform AALSBaseCharacter::GetTopDownPivotTarget() +{ + return GetActorTransform(); +} + +FTransform AALSBaseCharacter::GetCurrentPivotTarget() +{ + if (ViewMode == EALSViewMode::ThirdPerson) + { + return GetThirdPersonPivotTarget(); + } + if (ViewMode == EALSViewMode::TopDown) + { + return GetTopDownPivotTarget(); + } + + return GetActorTransform(); +} + +FRotator AALSBaseCharacter::GetCurrentCameraControlRotation() const +{ + if (ViewMode == EALSViewMode::TopDown) + { + return TopDownCameraRotation; + } + + return GetControlRotation(); +} + FVector AALSBaseCharacter::GetFirstPersonCameraTarget() { return GetMesh()->GetSocketLocation(NAME_FP_Camera); @@ -650,6 +679,11 @@ void AALSBaseCharacter::GetCameraParameters(float& TPFOVOut, float& FPFOVOut, bo bRightShoulderOut = bRightShoulder; } +bool AALSBaseCharacter::CanPlayCameraShake() const +{ + return ViewMode != EALSViewMode::TopDown; +} + void AALSBaseCharacter::RagdollUpdate(float DeltaTime) { GetMesh()->bOnlyAllowAutonomousTickPose = false; @@ -854,7 +888,7 @@ void AALSBaseCharacter::OnGaitChanged(const EALSGait PreviousGait) void AALSBaseCharacter::OnViewModeChanged(const EALSViewMode PreviousViewMode) { - if (ViewMode == EALSViewMode::ThirdPerson) + if (ViewMode == EALSViewMode::ThirdPerson || ViewMode == EALSViewMode::TopDown) { if (RotationMode == EALSRotationMode::VelocityDirection || RotationMode == EALSRotationMode::LookingDirection) { @@ -1089,7 +1123,13 @@ void AALSBaseCharacter::UpdateGroundedRotation(float DeltaTime) // Rolling Rotation (Not allowed on networked games) if (!bEnableNetworkOptimizations && bHasMovementInput) { - SmoothCharacterRotation({0.0f, LastMovementInputRotation.Yaw, 0.0f}, 0.0f, 2.0f, DeltaTime); + /*UE_LOG(LogTemp, Warning, TEXT("Yaw: %f Pitch %f | Forward %s Right %s"), + MovementInputYaw, MovementInputPitch, *InputForwardVector.ToString(), *InputRightVector.ToString());*/ + + SmoothCharacterRotation( + {0.0f, LastMovementInputRotation.Yaw, 0.0f}, + 0.0f, 2.0f, DeltaTime + ); } } @@ -1207,8 +1247,13 @@ void AALSBaseCharacter::ForwardMovementAction_Implementation(float Value) { if (MovementState == EALSMovementState::Grounded || MovementState == EALSMovementState::InAir) { + // Get the Yaw Rotation based on the View Mode + const float YawRotation = ViewMode == EALSViewMode::TopDown ? 1.0f : AimingRotation.Yaw; + // Default camera relative movement behavior - const FRotator DirRotator(0.0f, AimingRotation.Yaw, 0.0f); + LastForwardInput = Value; + UE_LOG(LogTemp, Warning, TEXT("ForwardMovementAction_Implementation: %f"), Value); + const FRotator DirRotator(0.0f, YawRotation, 0.0f); AddMovementInput(UKismetMathLibrary::GetForwardVector(DirRotator), Value); } } @@ -1217,20 +1262,29 @@ void AALSBaseCharacter::RightMovementAction_Implementation(float Value) { if (MovementState == EALSMovementState::Grounded || MovementState == EALSMovementState::InAir) { + const float YawRotation = ViewMode == EALSViewMode::TopDown ? -1.0f : AimingRotation.Yaw; + // Default camera relative movement behavior - const FRotator DirRotator(0.0f, AimingRotation.Yaw, 0.0f); + LastRightInput = Value; + const FRotator DirRotator(0.0f, YawRotation, 0.0f); AddMovementInput(UKismetMathLibrary::GetRightVector(DirRotator), Value); } } void AALSBaseCharacter::CameraUpAction_Implementation(float Value) { - AddControllerPitchInput(LookUpDownRate * Value); + if (GetViewMode() != EALSViewMode::TopDown) + { + AddControllerPitchInput(LookUpDownRate * Value); + } } void AALSBaseCharacter::CameraRightAction_Implementation(float Value) { - AddControllerYawInput(LookLeftRightRate * Value); + if (GetViewMode() != EALSViewMode::TopDown) + { + AddControllerYawInput(LookLeftRightRate * Value); + } } void AALSBaseCharacter::JumpAction_Implementation(bool bValue) @@ -1343,6 +1397,19 @@ void AALSBaseCharacter::StanceAction_Implementation() if (LastStanceInputTime - PrevStanceInputTime <= RollDoubleTapTimeout) { // Roll + if (bHasMovementInput) + { + float MovementInputYaw, MovementInputPitch; + const FVector InputForwardVector = UKismetMathLibrary::GetForwardVector(GetControlRotation()) * LastForwardInput; + const FVector InputRightVector = UKismetMathLibrary::GetRightVector(GetControlRotation()) * LastRightInput; + UKismetMathLibrary::GetYawPitchFromVector( + GetCharacterMovement()->GetLastInputVector(), MovementInputYaw,MovementInputPitch + ); + FRotator RollRotator = GetActorRotation(); + RollRotator.Yaw = MovementInputYaw; + SetActorRotation(RollRotator); + } + Replicated_PlayMontage(GetRollAnimation(), 1.15f); if (Stance == EALSStance::Standing) diff --git a/Source/ALSV4_CPP/Private/Character/ALSCharacter.cpp b/Source/ALSV4_CPP/Private/Character/ALSCharacter.cpp index 6b962691..b58d0f1b 100644 --- a/Source/ALSV4_CPP/Private/Character/ALSCharacter.cpp +++ b/Source/ALSV4_CPP/Private/Character/ALSCharacter.cpp @@ -84,12 +84,19 @@ ECollisionChannel AALSCharacter::GetThirdPersonTraceParams(FVector& TraceOrigin, } FTransform AALSCharacter::GetThirdPersonPivotTarget() -{ +{ return FTransform(GetActorRotation(), (GetMesh()->GetSocketLocation(TEXT("Head")) + GetMesh()->GetSocketLocation(TEXT("root"))) / 2.0f, FVector::OneVector); } +FTransform AALSCharacter::GetTopDownPivotTarget() +{ + return FTransform(GetActorRotation(), + (GetMesh()->GetSocketLocation(TEXT("Head")) + TopDownPivotOffset), + FVector::OneVector); +} + FVector AALSCharacter::GetFirstPersonCameraTarget() { return GetMesh()->GetSocketLocation(TEXT("FP_Camera")); @@ -101,8 +108,64 @@ void AALSCharacter::OnOverlayStateChanged(EALSOverlayState PreviousState) UpdateHeldObject(); } +void AALSCharacter::OnViewModeChanged(EALSViewMode PreviousViewMode) +{ + Super::OnViewModeChanged(PreviousViewMode); + + if (ViewMode == EALSViewMode::TopDown) + { + EnableCursor(true); + } + else + { + EnableCursor(false); + } +} + +void AALSCharacter::EnableCursor(bool bEnable) +{ + if (!PlayerController) + { + return; + } + UE_LOG(LogTemp, Warning, TEXT("EanbleCursor: %s"), bEnable ? TEXT("true") : TEXT("false")); + + PlayerController->bShowMouseCursor = bEnable; + PlayerController->bEnableClickEvents = bEnable; + PlayerController->bEnableMouseOverEvents = bEnable; +} + +void AALSCharacter::UpdateAimMovement(float DeltaTime) +{ + if (!PlayerController || GetViewMode() != EALSViewMode::TopDown) + { + return; + } + + FVector MouseWorldLocation, MouseWorldDirection; + const bool SuccessConvert = PlayerController->DeprojectMousePositionToWorld(MouseWorldLocation, MouseWorldDirection); + + if (SuccessConvert) + { + // Find intersect point with plane originating on actor + FVector ActorLocation = GetActorLocation(); + FVector AimTargetLocation = FMath::LinePlaneIntersection( + MouseWorldLocation, + MouseWorldLocation + (MouseWorldDirection * 10000.f), + ActorLocation, + FVector{ 0.f, 0.f, 1.f }); + + // Change actor's yaw rotation + FRotator ActorRotation = GetActorRotation(); + ActorRotation.Yaw = (AimTargetLocation - ActorLocation).Rotation().Yaw; + PlayerController->SetControlRotation(ActorRotation); + } +} + void AALSCharacter::Tick(float DeltaTime) { + UpdateAimMovement(DeltaTime); + Super::Tick(DeltaTime); UpdateHeldObjectAnimations(); @@ -111,6 +174,13 @@ void AALSCharacter::Tick(float DeltaTime) void AALSCharacter::BeginPlay() { Super::BeginPlay(); + + PlayerController = Cast(GetController()); + + if (ViewMode == EALSViewMode::TopDown) + { + EnableCursor(true); + } UpdateHeldObject(); } diff --git a/Source/ALSV4_CPP/Private/Character/ALSPlayerCameraManager.cpp b/Source/ALSV4_CPP/Private/Character/ALSPlayerCameraManager.cpp index ad7b3f1f..d0022649 100644 --- a/Source/ALSV4_CPP/Private/Character/ALSPlayerCameraManager.cpp +++ b/Source/ALSV4_CPP/Private/Character/ALSPlayerCameraManager.cpp @@ -56,7 +56,7 @@ void AALSPlayerCameraManager::OnPossess(AALSBaseCharacter* NewCharacter) } // Initial position - const FVector& TPSLoc = ControlledCharacter->GetThirdPersonPivotTarget().GetLocation(); + const FVector& TPSLoc = ControlledCharacter->GetCurrentPivotTarget().GetLocation(); SetActorLocation(TPSLoc); SmoothedPivotTarget.SetLocation(TPSLoc); @@ -127,8 +127,7 @@ bool AALSPlayerCameraManager::CustomCameraBehavior(float DeltaTime, FVector& Loc return false; } - // Step 1: Get Camera Parameters from CharacterBP via the Camera Interface - const FTransform& PivotTarget = ControlledCharacter->GetThirdPersonPivotTarget(); + const FTransform& PivotTarget = ControlledCharacter->GetCurrentPivotTarget(); const FVector& FPTarget = ControlledCharacter->GetFirstPersonCameraTarget(); float TPFOV = 90.0f; float FPFOV = 90.0f; @@ -137,7 +136,7 @@ bool AALSPlayerCameraManager::CustomCameraBehavior(float DeltaTime, FVector& Loc // Step 2: Calculate Target Camera Rotation. Use the Control Rotation and interpolate for smooth camera rotation. const FRotator& InterpResult = FMath::RInterpTo(GetCameraRotation(), - GetOwningPlayerController()->GetControlRotation(), DeltaTime, + ControlledCharacter->GetCurrentCameraControlRotation(), DeltaTime, GetCameraBehaviorParam(NAME_RotationLagSpeed)); TargetCameraRotation = UKismetMathLibrary::RLerp(InterpResult, DebugViewRotation, diff --git a/Source/ALSV4_CPP/Private/Character/Animation/ALSCharacterAnimInstance.cpp b/Source/ALSV4_CPP/Private/Character/Animation/ALSCharacterAnimInstance.cpp index 11a44ff6..97776d01 100644 --- a/Source/ALSV4_CPP/Private/Character/Animation/ALSCharacterAnimInstance.cpp +++ b/Source/ALSV4_CPP/Private/Character/Animation/ALSCharacterAnimInstance.cpp @@ -196,13 +196,14 @@ bool UALSCharacterAnimInstance::ShouldMoveCheck() const bool UALSCharacterAnimInstance::CanRotateInPlace() const { return RotationMode.Aiming() || - CharacterInformation.ViewMode == EALSViewMode::FirstPerson; + CharacterInformation.ViewMode == EALSViewMode::FirstPerson || + CharacterInformation.ViewMode == EALSViewMode::TopDown; } bool UALSCharacterAnimInstance::CanTurnInPlace() const { return RotationMode.LookingDirection() && - CharacterInformation.ViewMode == EALSViewMode::ThirdPerson && + (CharacterInformation.ViewMode == EALSViewMode::ThirdPerson) && GetCurveValue(NAME_Enable_Transition) >= 0.99f; } diff --git a/Source/ALSV4_CPP/Private/Character/Animation/Notify/ALSAnimNotifyCameraShake.cpp b/Source/ALSV4_CPP/Private/Character/Animation/Notify/ALSAnimNotifyCameraShake.cpp index 9bfc50ba..e1713eb6 100644 --- a/Source/ALSV4_CPP/Private/Character/Animation/Notify/ALSAnimNotifyCameraShake.cpp +++ b/Source/ALSV4_CPP/Private/Character/Animation/Notify/ALSAnimNotifyCameraShake.cpp @@ -4,13 +4,15 @@ #include "Character/Animation/Notify/ALSAnimNotifyCameraShake.h" +#include "Character/ALSBaseCharacter.h" + void UALSAnimNotifyCameraShake::Notify(USkeletalMeshComponent* MeshComp, UAnimSequenceBase* Animation, const FAnimNotifyEventReference& EventReference) { Super::Notify(MeshComp, Animation, EventReference); - APawn* OwnerPawn = Cast(MeshComp->GetOwner()); - if (OwnerPawn) + AALSBaseCharacter* OwnerPawn = Cast(MeshComp->GetOwner()); + if (IsValid(OwnerPawn) && OwnerPawn->CanPlayCameraShake()) { APlayerController* OwnerController = Cast(OwnerPawn->GetController()); if (OwnerController) diff --git a/Source/ALSV4_CPP/Public/Character/ALSBaseCharacter.h b/Source/ALSV4_CPP/Public/Character/ALSBaseCharacter.h index 372f146d..5148c0aa 100644 --- a/Source/ALSV4_CPP/Public/Character/ALSBaseCharacter.h +++ b/Source/ALSV4_CPP/Public/Character/ALSBaseCharacter.h @@ -39,7 +39,7 @@ class ALSV4_CPP_API AALSBaseCharacter : public ACharacter { return MyCharacterMovementComponent; } - + virtual void Tick(float DeltaTime) override; virtual void BeginPlay() override; @@ -271,6 +271,13 @@ class ALSV4_CPP_API AALSBaseCharacter : public ACharacter UFUNCTION(BlueprintCallable, Category = "ALS|Camera System") virtual FTransform GetThirdPersonPivotTarget(); + UFUNCTION(BlueprintCallable, Category="ALS|Camera System") + virtual FTransform GetTopDownPivotTarget(); + + UFUNCTION(BlueprintCallable, Category = "ALS|Camera System") + virtual FTransform GetCurrentPivotTarget(); + FRotator GetCurrentCameraControlRotation() const; + UFUNCTION(BlueprintCallable, Category = "ALS|Camera System") virtual FVector GetFirstPersonCameraTarget(); @@ -280,6 +287,9 @@ class ALSV4_CPP_API AALSBaseCharacter : public ACharacter UFUNCTION(BlueprintCallable, Category = "ALS|Camera System") void SetCameraBehavior(UALSPlayerCameraBehavior* CamBeh) { CameraBehavior = CamBeh; } + UFUNCTION(BlueprintCallable, Category = "ALS|Camera System") + bool CanPlayCameraShake() const; + /** Essential Information Getters/Setters */ UFUNCTION(BlueprintGetter, Category = "ALS|Essential Information") @@ -456,6 +466,12 @@ class ALSV4_CPP_API AALSBaseCharacter : public ACharacter UPROPERTY(EditDefaultsOnly, BlueprintReadWrite, Category = "ALS|Camera System") float FirstPersonFOV = 90.0f; + UPROPERTY(EditDefaultsOnly, BlueprintReadWrite, Category = "ALS|Camera System") + FVector TopDownPivotOffset = FVector::ZeroVector; + + UPROPERTY(EditDefaultsOnly, BlueprintReadWrite, Category = "ALS|Camera System") + FRotator TopDownCameraRotation = FRotator::ZeroRotator; + UPROPERTY(EditDefaultsOnly, BlueprintReadWrite, Category = "ALS|Camera System") bool bRightShoulder = false; @@ -609,6 +625,12 @@ class ALSV4_CPP_API AALSBaseCharacter : public ACharacter /** Last time the 'first' crouch/roll button is pressed */ float LastStanceInputTime = 0.0f; + /** Last forward input action pressed */ + float LastForwardInput = 0.0f; + + /** Last right input action pressed */ + float LastRightInput = 0.0f; + /* Timer to manage reset of braking friction factor after on landed event */ FTimerHandle OnLandedFrictionResetTimer; diff --git a/Source/ALSV4_CPP/Public/Character/ALSCharacter.h b/Source/ALSV4_CPP/Public/Character/ALSCharacter.h index 2483ec67..eef2aecb 100644 --- a/Source/ALSV4_CPP/Public/Character/ALSCharacter.h +++ b/Source/ALSV4_CPP/Public/Character/ALSCharacter.h @@ -38,6 +38,8 @@ class ALSV4_CPP_API AALSCharacter : public AALSBaseCharacter virtual FTransform GetThirdPersonPivotTarget() override; + virtual FTransform GetTopDownPivotTarget() override; + virtual FVector GetFirstPersonCameraTarget() override; protected: @@ -47,6 +49,11 @@ class ALSV4_CPP_API AALSCharacter : public AALSBaseCharacter virtual void OnOverlayStateChanged(EALSOverlayState PreviousState) override; + virtual void OnViewModeChanged(EALSViewMode PreviousViewMode) override; + + void EnableCursor(bool bEnable); + void UpdateAimMovement(float DeltaTime); + /** Implement on BP to update animation states of held objects */ UFUNCTION(BlueprintImplementableEvent, BlueprintCallable, Category = "ALS|HeldObject") void UpdateHeldObjectAnimations(); @@ -63,4 +70,7 @@ class ALSV4_CPP_API AALSCharacter : public AALSBaseCharacter private: bool bNeedsColorReset = false; + + UPROPERTY() + APlayerController* PlayerController; }; diff --git a/Source/ALSV4_CPP/Public/Library/ALSCharacterEnumLibrary.h b/Source/ALSV4_CPP/Public/Library/ALSCharacterEnumLibrary.h index 8e79ba2b..832e3332 100644 --- a/Source/ALSV4_CPP/Public/Library/ALSCharacterEnumLibrary.h +++ b/Source/ALSV4_CPP/Public/Library/ALSCharacterEnumLibrary.h @@ -107,7 +107,8 @@ UENUM(BlueprintType) enum class EALSViewMode : uint8 { ThirdPerson, - FirstPerson + FirstPerson, + TopDown }; UENUM(BlueprintType) From c31a37ed2e4f3b656a528f4056db8dc99b1a2681 Mon Sep 17 00:00:00 2001 From: Helcio Laurentino do Carmo Junior Date: Mon, 1 May 2023 18:19:16 -0300 Subject: [PATCH 02/17] refactor(input): Move input actions to game feature plugin --- .../DebugFocusedCharacterCycleAction.uasset | Bin 1854 -> 0 bytes .../Debug/DebugOpenOverlayMenuAction.uasset | Bin 1883 -> 0 bytes .../Debug/DebugOverlayMenuCycleAction.uasset | Bin 1834 -> 0 bytes .../Debug/DebugToggleCharacterInfoAction.uasset | Bin 1698 -> 0 bytes .../Debug/DebugToggleDebugMeshAction.uasset | Bin 1682 -> 0 bytes .../Debug/DebugToggleDebugViewAction.uasset | Bin 1682 -> 0 bytes .../Input/Debug/DebugToggleHudAction.uasset | Bin 1658 -> 0 bytes .../Debug/DebugToggleLayerColorsAction.uasset | Bin 1690 -> 0 bytes .../Input/Debug/DebugToggleShapesAction.uasset | Bin 1670 -> 0 bytes .../Input/Debug/DebugToggleSlomoAction.uasset | Bin 1666 -> 0 bytes .../Input/Debug/DebugToggleTracesAction.uasset | Bin 1670 -> 0 bytes .../Blueprints/Input/Default/AimAction.uasset | Bin 1748 -> 0 bytes .../Input/Default/CameraHeldAction.uasset | Bin 1763 -> 0 bytes .../Input/Default/CameraRightAction.uasset | Bin 1802 -> 0 bytes .../Input/Default/CameraTapAction.uasset | Bin 1636 -> 0 bytes .../Input/Default/CameraUpAction.uasset | Bin 1790 -> 0 bytes .../Input/Default/ForwardMovementAction.uasset | Bin 1818 -> 0 bytes .../Blueprints/Input/Default/JumpAction.uasset | Bin 1752 -> 0 bytes .../Input/Default/LookingDirectionAction.uasset | Bin 1599 -> 0 bytes .../Input/Default/RagdollAction.uasset | Bin 1563 -> 0 bytes .../Input/Default/RightMovementAction.uasset | Bin 1774 -> 0 bytes .../Input/Default/SprintAction.uasset | Bin 1760 -> 0 bytes .../Input/Default/StanceAction.uasset | Bin 1559 -> 0 bytes .../Default/VelocityDirectionAction.uasset | Bin 1603 -> 0 bytes .../Blueprints/Input/Default/WalkAction.uasset | Bin 1551 -> 0 bytes .../Blueprints/Input/IMC_Debug.uasset | Bin 9346 -> 0 bytes .../Blueprints/Input/IMC_Default.uasset | Bin 25582 -> 0 bytes 27 files changed, 0 insertions(+), 0 deletions(-) delete mode 100644 Content/AdvancedLocomotionV4/Blueprints/Input/Debug/DebugFocusedCharacterCycleAction.uasset delete mode 100644 Content/AdvancedLocomotionV4/Blueprints/Input/Debug/DebugOpenOverlayMenuAction.uasset delete mode 100644 Content/AdvancedLocomotionV4/Blueprints/Input/Debug/DebugOverlayMenuCycleAction.uasset delete mode 100644 Content/AdvancedLocomotionV4/Blueprints/Input/Debug/DebugToggleCharacterInfoAction.uasset delete mode 100644 Content/AdvancedLocomotionV4/Blueprints/Input/Debug/DebugToggleDebugMeshAction.uasset delete mode 100644 Content/AdvancedLocomotionV4/Blueprints/Input/Debug/DebugToggleDebugViewAction.uasset delete mode 100644 Content/AdvancedLocomotionV4/Blueprints/Input/Debug/DebugToggleHudAction.uasset delete mode 100644 Content/AdvancedLocomotionV4/Blueprints/Input/Debug/DebugToggleLayerColorsAction.uasset delete mode 100644 Content/AdvancedLocomotionV4/Blueprints/Input/Debug/DebugToggleShapesAction.uasset delete mode 100644 Content/AdvancedLocomotionV4/Blueprints/Input/Debug/DebugToggleSlomoAction.uasset delete mode 100644 Content/AdvancedLocomotionV4/Blueprints/Input/Debug/DebugToggleTracesAction.uasset delete mode 100644 Content/AdvancedLocomotionV4/Blueprints/Input/Default/AimAction.uasset delete mode 100644 Content/AdvancedLocomotionV4/Blueprints/Input/Default/CameraHeldAction.uasset delete mode 100644 Content/AdvancedLocomotionV4/Blueprints/Input/Default/CameraRightAction.uasset delete mode 100644 Content/AdvancedLocomotionV4/Blueprints/Input/Default/CameraTapAction.uasset delete mode 100644 Content/AdvancedLocomotionV4/Blueprints/Input/Default/CameraUpAction.uasset delete mode 100644 Content/AdvancedLocomotionV4/Blueprints/Input/Default/ForwardMovementAction.uasset delete mode 100644 Content/AdvancedLocomotionV4/Blueprints/Input/Default/JumpAction.uasset delete mode 100644 Content/AdvancedLocomotionV4/Blueprints/Input/Default/LookingDirectionAction.uasset delete mode 100644 Content/AdvancedLocomotionV4/Blueprints/Input/Default/RagdollAction.uasset delete mode 100644 Content/AdvancedLocomotionV4/Blueprints/Input/Default/RightMovementAction.uasset delete mode 100644 Content/AdvancedLocomotionV4/Blueprints/Input/Default/SprintAction.uasset delete mode 100644 Content/AdvancedLocomotionV4/Blueprints/Input/Default/StanceAction.uasset delete mode 100644 Content/AdvancedLocomotionV4/Blueprints/Input/Default/VelocityDirectionAction.uasset delete mode 100644 Content/AdvancedLocomotionV4/Blueprints/Input/Default/WalkAction.uasset delete mode 100644 Content/AdvancedLocomotionV4/Blueprints/Input/IMC_Debug.uasset delete mode 100644 Content/AdvancedLocomotionV4/Blueprints/Input/IMC_Default.uasset diff --git a/Content/AdvancedLocomotionV4/Blueprints/Input/Debug/DebugFocusedCharacterCycleAction.uasset b/Content/AdvancedLocomotionV4/Blueprints/Input/Debug/DebugFocusedCharacterCycleAction.uasset deleted file mode 100644 index 6839deb23ae5159650ff81d1b5b431c484fc7efb..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 1854 zcma)7O-vI(6drz5#6Lta9{dR=ii*${L4N`1RuSS!S(ZszZM)6x7O4kg;)UqR zs23B_7%zHIqTGxJ4jzm#F;PO)Xrf{aDi>ze2 z)o!uYv(;O*t$KTn=xMC-dOcfx)t)+Ejc2=CsH+vgXD7)6oHXWJO6Z?~B;gX(C^xCx z9tmE3_%+-zc=g%q`VBkRx8xQk3a&igdt=YU{JOD;i--_92*8?t_|m$ZV(OKbxA|(y z5AYC|bY4+Y=}wN{ANtNRkJBU*pC-=TLE{4n*3YwS_Lnv(fz>Y{1KPl1Y73es#RHle z<(d&^O#|-~SUW{EqQ}C#DH4qt?8}pe+(l$l=dUDy%xj3)CQELuXHeVs?SY@|5C z%ex;}lQ|&C$D|-{R%I!qoRAQMUkY4VS2Dyve+(sgDW?>&bUHQmnSa8Gzu`$8f*4uuu3>{y5(Oj~j@0vgvTX!iL1&a>E~7H&vh z$&lFSsloFFWJvBT(|7lk6#ea|c$c?a=WqldV}PHOQ^-&NvD--J{U9DRf!TOVEm}t2 zvg8;l+eaonClBccIC;M*9?NQdk#GR+O0U_nUXEmQ#tQcu1t8gfbYc7Duz`p5p~fND zYZ!M1NA_&6{a`$kuXG!d0HBAG31*A2Zw_D3b803j)2eh`5HJtA*?@7Z&zYE|)Soq@ z`{^xEl0ib`zb2)7vc3E1iRj_ho!UfVW~(gY4XkuTT4p}MYiR-iF<|;~@wfoigU%Q( p5`c%^1pPEj;Iy5viK#~$KA`V7ovdvLfp3eHQhU~a*%19X{{WWRcJlxL diff --git a/Content/AdvancedLocomotionV4/Blueprints/Input/Debug/DebugOpenOverlayMenuAction.uasset b/Content/AdvancedLocomotionV4/Blueprints/Input/Debug/DebugOpenOverlayMenuAction.uasset deleted file mode 100644 index de0cf70951e033d604b1d44264bc982fd056f400..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 1883 zcmb7FT}TvB6u#z9w*F+I5=9UFfSKvKwu||q&CaSU=(=bc1f}EdW!>7H*=A<9HVTAZ zq=blqz_1{C=#LO8dXOH3dWZ;ms2A%Y%7Vls$Oo}>J7?yOjpM@F2Y1fB=YIE`bI;s! z@8pGjHy2W=RDU)hwhe^Lf<$CN`!P5^{oQ?SzF^96o118@-3z)0d4%MG^hqKGK}adI zCSdOb$vgOi^#|%2ob{ZOZ*+Sa9PY+Co^v~#uEy3Dmk0S|4|vD{Sq2|4rj1{qNx(;t z*k++UJ^$?0(XqR&BO?#<&K*m<3r_X<=DrQJ4NaWNAI+^Q#t6|42B0rLKDsLlN7dCm zEw1V=8li$hYh1N;Z2tM=qQ+i34~sPXyzbQGZV2qiMy6x}l9a;TqZ<2&V(4?SEF}H1 z6r-}5B;N5aVbl)rlBmR^)GNl~D*5%+y`c!SZb^!)P)l;gFJj=fDXX zP**tIhsQHJK&Q1o6G zDC}H&cdxUL_xtT!Fd>Km8UzbcRKoSWPP;o2r!hG!s)}8U)9#@I@sR%Qj8U;OLFI^$ z?4V+t3*Z`ZKX`dt8CvcR$l;i3=Ovl;=rNN8Z%tE$X|6>a)LiN*c>n12EdFjjA}9(` zPoKH69Y&hN^seS^%yxn+)>fgrJsbS`0v zI;bjm1XUo@Lr<>egMuZNC~d>#CI7}Nys`avDDn_CU69}K=kZ@5Sh;9@D{m2axC2Bc z9-aYEZ@`Ep6AzPuF!PonZe6Q?3)lc=nRLj* zJfOt5jNC2%hc8&BA)T*37GIc4t1p|S>Y2GU!q^i|r1NFfZDAJRiX|NDSD1XEJ+nSm*W#wVr+Z-PKi^Oby z-SGDQ`umql5>HC%#}B<2AA0!ZsqkR7ee-$GXe&kt9Sp$ge&Xh~1w~XVD{B+IWvx8I zC7ti}mRF?OpAUX#ncJz8iTsgGBXHgz{}L-^e`%5CF#AFZzz0^6FKC*S3}|YMYetea z42*{n?ewdP9*^<{B^Ec>*HPcX6%_TUY9vivoj-7C0|iBsBgjTrRobOUoF7ldIQupB z>ci%2tp^SWJz>4FmQAb?`yebT@n~B3*z5kISP^rNX7YwstfERw=P525X^!yz(dQBh z2PFBl6ylAlEJea+C5)k2igGSTS^$IbByR?~I46Z%cw}5h>ZkmAF4C zN4T{VEHW`&ybjVqSqsMumtWO*n>7vgtzqwBtexE^D&1yIYq`fB4o}feF@HqTb!MFD zxmHXyGh>!qHNnX%%ZcOI3RbkSV>$AhvD6X-G_LEsi@lsY(ub94;)YZ!84{bg@c8;t z3Z&MP>Gi$qSO2M}dHs9tawGz9PJo|ul5j2o4BN(h-VfqI6UfC|W6?75)~4EE>>Qc& zoID&dz{#7X@mNvoi(>}hhV+=8^MbL`Nz!H1p)n_n+<5k{G10f*I~Xvm%lAFKJ?GU zpRaG{Y^LWR!L3WQi*!t{G~<;kcZ{#pd~UZ;2LNKgzmvp60$7hXW4Jy59(5D+gD`Ey-hBUH_+$`ihj38Z1A}JVxV!K8+=wq8Ia^9JrD`=%}@w6Br*2W$P>oj zU7LQ`I#TegzDj%R+p%+Q;?7u4@alN=fu5FqqAD8O<*etmmR1)|h+1w1uJd5lXs zul3Z`+v^XezO&`m$;m`vhm=IpU~|vCxusBtMRZ|z{&ef z^;lNxS!_=r+ie}qoDFc%FaQd>Bra^f95(Qx3i{@tqM98E^LA@j`{J>UvAXXmY?!v}nO=h^))rs(hV2MpOp A%>V!Z diff --git a/Content/AdvancedLocomotionV4/Blueprints/Input/Debug/DebugToggleDebugMeshAction.uasset b/Content/AdvancedLocomotionV4/Blueprints/Input/Debug/DebugToggleDebugMeshAction.uasset deleted file mode 100644 index 3093b6ab040c881c9c44c58e591f292c9223932d..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 1682 zcma)7OH30{6n%UYd%Ci*OnPz5+;!2|nqKU!a zMx!pog(k+3s0*Vmh|!HPuyKQNqiCXmXp{xZiWH6SU&e$ArP#TT-{)yR7p34h4GnF^R$4AQdlJ46Y#^_-_Mdrj9+eo9H(8a{v zRbp+OPjtgUvty>*pdksgmAR0y?If~N*}mPHW|WQrzu!nz0o(H`O$ZW_nO$6qvE z8S|Z)aet|r9OB zth&6y+J8FvgC*Z5BZF>_J}QDRKn^diHFfq(MT+C}S)_mr+CZ|Xs?xAuRia$ghgtK) z`w+CfUPabo5#B6EV>YL;aXG*a8{@fkE|z9ry2?dxvH^uha-2|N#PP(I=Y2p zUccWZ_68F&RCjq5m3Nsrv&H7J`Yn#VM!DYzX_nyiy_a*Ss5dNW8q-glytJKGhX3TD zo_w93$|Z&ryq>1BZXBvrZtUh zF8H@z!d*XbivtJBHW~Y6y<9BOWHu$@ei9Bzf>Pno0H9wn^yUQM=g;>DFX7>~3142L(Zj zf*|TeXb(~l6-q#F)@H*dc8GjHB(vX>6e zuH^Iiu?j+J%L!Qmj#LI?c|5cDiM^Std);w|d3@4-5OiOw2!S67N+JbD$Tk=~fNlZq z>tb0?7wd9$`?}lRu1@z+XS;{(_IG$(olcLRK|HB}2pHrAOy~*M+fe}84;+URM)tw% z+Y4%S@4{g7v6))~p+NM@WqUH$H&<;tA6)L6#|+UACZL<2y1lQg307@wBYt<=AdOQ_ zp*FX@-PnJU{XvTFgONt}zuWMTWC9#stJZbq3`NT0>1#lNGSU{18CmAiVOdI2Sxu8b z=DmR0h*uJoRDuS?WJ)F9Ub5v4pk*Z~z6x!u%v{05wNmCPo;GZSMJO^sd36=Tym|O} z52(W&e};?Eeu?Me!Z}VABr(V(sFLJ(N}AO4^kx7J%R($hWre&uk+?Sq3J23aH0nC- z4Tl{}bdnQ!8U+thLPGmdmxGO`Xi^qLRdHx}I(#&eis|#P6pO{FrWh6I6vLwpiDasB z&FFcEmxZM2@Jccr(Q_s%0b9>b%bs5x*Fx$gcs2iQ2`lQ2bBaRLsk7I2!%FjCJk){E z*xh=7Xy!)vrd?z87+%vE#|_I=QD~Gr|8V>&R$+juoR3pEvUu^)jZL61YDbjb=^c&# z)~mRgBXbmSNVPg6zl_VpB{rE!g}9%9!z7VP;jjUaisA6;O)_JY!r@_&thhgrkFM3{ zI%9!6WXRaW|3mn|a3F!(HGWa|+oD4po)0Ec9pfX+YMoLca(=JM_B|;eKIbmgwbHDEUXD>}XyBUg+J77=(vEN%a?W2;68= ztN9k!yf?e$*|cikzrDtJ&>7PDBUQ6J$qHn_B(Gt@NVqOR0ca0!9JMe8Rs)VZ zGpB-6!w0#{^zm1z&cM6n>#H3T6Y8_ickAY`LX3k2=tmiZB{dDrhGdrx(6>&QOjcZx#vIj zgE}OL!$O1xWKoDkuL@dJmV!c@stG})q*5Cl+X|pwB^rrPMI~R_=Bh{LUVd$h4$&ylBKSOw%rz+Um9Y`^yX)#-Y?)@dSimB67BMpdsVPvsq9Ir@88~8 z21e#+B(B^$P=<+_&S){DP*tU2^5NTwTiE$&stG@jlq>kH&_hV_u*=qM0QK7kq^3_oWU3FsatO zd24Q0qvfj9viDrI(E|oUTHlss<iye8p@96S|_C^_1n4(FgJ70jmLd!|y;EzB+#a D3@JOu diff --git a/Content/AdvancedLocomotionV4/Blueprints/Input/Debug/DebugToggleLayerColorsAction.uasset b/Content/AdvancedLocomotionV4/Blueprints/Input/Debug/DebugToggleLayerColorsAction.uasset deleted file mode 100644 index fa93946d6abf4fe5de66df719bc6b290ac9b170a..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 1690 zcma)7OH30{6nzN(_$VUySr~(fsaT4a)L>EL? zMB{=)O^k_gqa?aB#B|}p7!woYM&m|t0YNviAfVQJ=7U2isW*M^-gn=*pLgfJ*VMIx z_ZHIWbbmf$h3gobBM!==@qK7=dd72mzUX7!1K~w$%>mLau4jyXtX+ndVgJAy}RD$u5E5S>~VYiexJ}J_>R=Nn_C-zXGIhNLEh5@Pgw7SK;$5f(M03= znHg!jW5o0H^kR9{?$L_G{+H*j+)tgDs_dH>KeeQ12tP=`Fz=h#msdtBr?bc3=9tZa1R+ii?`$x1)=Wi8lEiK@!9OC#er znI3YjV4aUfXNw7>J1`R{+tpu;1azHwaa2OQ1^j=Zdz1TroXZDl1Z4mPvJ%GBXI zg6P#^f-W)EV~YiUcAq9>70dJs0PNs*Ey8|gW9IB;Cl&pNS$H_eX^z!R}fYz3yH3b ztV|@)xWJ9UXxtDNEL^BDvN0yG&Ar4bjDD{607 zF3DHps;zR>)HO;C&g!aKx5w$Mb9)+`zG_dM4}6wE5fJ1Rb?}6F0S1H;l4upwW(I~w z9gFXp$M1Jc<~$iYojBR|>Bh(BE#tGVz1gl0E7&3YU;~Ev#k+?yifC3|-r3+TKQAJJ ztD?ePS!J%jnEJ`mual9EX)%5f15OUFZ#Q&SPf1GR^f{!!7}!N)Nm2NqUy9Ijx_u9 zdkLxiJkZC3qFD~`NO*{AVL8^yqe6}IfM7-1;K)uQbtvIrP$(+4xxLGE z$?Nw!q~3lW3y5CwAV+1`cexy%NJ7Mwa7`p#TraH3a)@UMr?3FAJ%>U&O;EfvtGBdLSJSmu|s|u@w)81?;>(v>!uj z^m*n4614!JeE$b{T4(^dUE>$J6`Kw`oDUNFvU1{1c|Nq17FHZAri+!T!#x7@tzwcs zB58{Se|DcHWt~X%3j*xmcOzguwJR<{pd#!CWh7I^unU&Ib%m0Ka`Um<8 DD^WmD diff --git a/Content/AdvancedLocomotionV4/Blueprints/Input/Debug/DebugToggleSlomoAction.uasset b/Content/AdvancedLocomotionV4/Blueprints/Input/Debug/DebugToggleSlomoAction.uasset deleted file mode 100644 index 3c60407a2be4310254a19d592831fa1b61f3d7f3..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 1666 zcma)7OH30{6n%U|`3W}oNsJ-50j*GK+H@s2(~lvkrIF7P8OpO%+fFkxMKQ*Z7!B&m zNQ^OoL}Oyy7!uhT7c7hmG`i7+?gU~mxRM2a>pksVXUH`!U?AiR1>L~29A!b0moy;~HBmA_&_#p%-wQ4p5$FgLJKkA*=+lpqjiYd z6;l!!&E=OB-ec^St#mZE?XlT{=^;IxQU1FpvrFivKPjmy)6QSGwU;D4+4?jU;;Zs1 zGV88pYRA6*Dx}tRW|>iit12I4uNT^HqWY6ulLC?^vH8*I+dD{M_Kc|~#&*~KlUH#Q zM;>zEKo!Qqewl{~(R>NIB_H>baM&bhD;y3UR0xM7x5&z|6%NIM?6^O)A46-*m8O8T z)8uh^|A+9fFhCS`OcC?r}Y}`@Pw6xNZW?k7{L#&_f^Q#;Z9*A#|?MdVg!) zSc~nsH0s~Gdb17$1FbL3);AqtUBFUZq6w~Wv){Chc=!NsU9tw^xBNetp?{yh!B9V4 diff --git a/Content/AdvancedLocomotionV4/Blueprints/Input/Debug/DebugToggleTracesAction.uasset b/Content/AdvancedLocomotionV4/Blueprints/Input/Debug/DebugToggleTracesAction.uasset deleted file mode 100644 index ffae55a5b0dcc075f34b55fa346006dfca6d9ffa..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 1670 zcma)7O-vI(6dr#3<42LGAtuD&1r=$*lv-kf?v|F2@Y6`)h%9ANs%^K~-J*CfMq(uB z#YohcV2pax60MrrqcP>y zlj((~5%1*-H@{yy@<8mq68w6sb<}q+b$j&v3+xbnumQuo`_BHHQkqp&b^7Y6PVy+1 zR9;=@s4>@HPX1uo*U3o7?B1yu1`;{EwAs*EJtZlP({CXK#=v$O3yLBQ1{68L6>X3; zPke|#+v}C%YBI)~V`eGHDA16k7u0!?c?crq|+OfRF!FG&s{I0nI0`m zoYZ)#vWV7oTQhcPSx*sS>pJtG0fnn7?_+O19>0q7w{lHtlr)LWU3_+9D=EyZF|}!U zcger`GH>kgLk=ELUFOnT5GtAy-hoXUv?#c0F#UUn^D{J@x@^Je-5%LmyRI zPjJOEbJ!kCrT)#^XPyMkfYpbyWlm>UC77?zsDmlY?6tPm7&hQrWmZAs4gV7+=^yAX Dx$Q!S diff --git a/Content/AdvancedLocomotionV4/Blueprints/Input/Default/AimAction.uasset b/Content/AdvancedLocomotionV4/Blueprints/Input/Default/AimAction.uasset deleted file mode 100644 index 8af43bb172a4c5f179d2e546ae31e38ce47e0d9c..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 1748 zcmb_dOH33&5N*T{@==50=U@zaKt-69EU;V_XP3p0@Y#rPGD*axhC$=F z38Q{)i~7A~GWbB-wRofB`PHZWBX2)f9g&AF%x!BMpW28SA`d2z+J5xP&YWVHm6vyf zs>=_tD5EB;sIK(b>yIWDNal6e#ARS?M*$j7fbbP2=MX4TQk))bly$H!8wO2;4L!~b zD?yq@KdP7wug`4m;Dq#@^t>{epZ14{EFv3g%eH ztyJ^c=CTTT1vk*9@#4lshYxWW12xuAoV8yZ27Jqjh=Z6+v3|N@A-_A;z<-M6j*q>I z0xuSkxkbo%M=Z?4nZFJBOSyRwfSfq&_ZD3l1^L|_mEM7u;k~J{vqE(Gs(Y{CYlZiw zkEObH5A5PrnRpS>y1vrU&1Jk{>g`nV{dJ1?_;@fb&Qm%o^)EIOAWl@M6zr^jmp(5MD1H>d}h{nYd-x$@qOtNJWo%(=Gs#9JDo8N4n_4+}=aDRy z+>+!iDe?G@`8^(YnZMLsRVw+4OFUkWr@F)qf99nONU}s9FrhC&A)F$K#;J9;AARUf zIbJg{_5J<8zFE2EvM;Hk=}G0)>>pJ_Z$?KkL-1e%X876L2a>X>S5VMe?JYPhWWhC2 z=q++v<1Z(FvBcvPWFR-a?5{7Q{(!2)gsS(my74bz zSUdenRO^X|x@fFNXFuQiHl@Q_r!_@Ib4bzIn13QQlT1EEkyoO#QpRr}x<*#GzG7W` z^l1t6u2tl&mT*M0gjAu0sKd&qZTXfYlXEL-m%+(u3ws2ZEDj6ALYB?~s;f$z=RLCS@)NhpYlYk;1>wu4+v}gy#F4Zda-=h$ z2sI#wdf2e@%9F(yQWPHdDsogPTAZ~%_!?Y6R(E?O8q>&)e7bljCOYF$!KUB6{k-O1 zquaJgCxU9Ni;b1I&lQ6eiG@?bd*2T=AzW)n=32`7>+Yv%tc$)=lld=-mr!R<_fg?X zbEJ%{Hn8BbsW{7s2KdM|dox*;*)? z!aIWgKyqQ&#E8FpIVAV_lwgz?vLf~y>9eW!sz$7&Ip&T8^jNwkdw2iUIJP-k^TNe% zF4{rX65^`Lw7wIAMbxuw2P<89xTwUmB`55X`y#CT*^Xyegxx~pF0OGlcKXq!g=9!B z9aGx|%9f`4Dc;cLI|5Mv>;Ukajt(*ekdKK>-Y?=o6PS&MtbtrS98(i!jM;cNWq_48 zL-`n1ce&;WJ~Ky<()rruZ#z{|4A h;OQ`4_jD9i@Vn&M zXlaOKKE}w}ACM(AmEaL6nbP3rYkz(zTK%#dUxJnwW-d|UdMW1$UX+&MptJuZ7qumf z@b2-KU1*Ln@e~{6?Xt+?v9nBz$x;VPa5c$94wYJZWD|nAmDu1QS5)|LAaO5(2Di}O z)$2PRh(_JQz%Y|UK7b5zLZKDR%f;z=bYX{uY#(;eg|SSqf$1IVqgZk7~8g2H&& ze(zQy>=Kn&68*BmdyG_JKGM*--R28PLwY1*!AV%;!IURJALMA z36AtRX3WYReI+zgx0y@BjNn@BOGc|b$Tb#Z8iSeh z`*c|UN9ZC^BSG3_ykz@hvk{KgN1F1oYO=*~Sdau^HX3MUU x%XT?x^%t$m%$&$bRxZX?DIH-QIrF*wR|EUmTCGnE6v{eQ)!1M2#h=3em%p$mGo}Cl diff --git a/Content/AdvancedLocomotionV4/Blueprints/Input/Default/CameraUpAction.uasset b/Content/AdvancedLocomotionV4/Blueprints/Input/Default/CameraUpAction.uasset deleted file mode 100644 index 78edb9d4ae389a5e2679afe1fd2bd8c41b2ca902..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 1790 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 C5IEle diff --git a/Content/AdvancedLocomotionV4/Blueprints/Input/Default/LookingDirectionAction.uasset b/Content/AdvancedLocomotionV4/Blueprints/Input/Default/LookingDirectionAction.uasset deleted file mode 100644 index e0e83408487c554799183c4e725de605fc2a5634..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 1599 zcmb7FT}TvB6h3Ny{#7jfK}ZyVmASK`2^&kX6 zKSBlh5E&FCM!ksm;6qR0Lk~&io7qEQ1tMW)ZRgC+*t)Dg9roUH?>XQ7&N+APy*qmK zP~TiU9&gG5$jJnlMop4|?Q6^6)Mx3=Z0-mDLvdK~9zfgBdI0=Et*&uY09&w?BYH1t zzgSu(OC|n*9FTpAq$o%HeqX65OQKYwlvPTEhjENTLHe*GCYn#KBM-m~YHFG2D1M%^ zzyC^i-Q9ur1#f1@uk|XI-i<8GRNd(Bymk5MkU|*}4<$f60H^Qo%kZEsDr%?<7M{%YFR4m&QRPJi5WPCNyqR+^wF*B%9GC8V2hM8G4KxRu@zc zepD$Ndw*uLUgcAIb!X4>u(gO0CtiFhKy!$NTUmtH=wTLBFEUHjwOZE3%@_-F@K{|v z*$6sisF4UaOqe|0_9TP`L9D5744jceAwg{JU|N_rBZJOar zc0ijL-VVH;rcIKg%rwF3yl^uQXSUDb_UvlPBW~N~R1z|{Y4Tb zWHnq)0+tq+@Ayc$G1BoR<2I(@`-Ax;Q9-UVAsuwabSBp#6yMDOX_xTQ`rk=5!cl#s zX+PY(`}QBPaG5RXVx`*X9+BWv0HQqtm`{pDc~DzTQh5na>xg$bA%E(*UEy5*z~||i zlNv2u0h-F{MykcD-oX>M<{(noqeA!oExBXfq}xlP4W8}byS$JP_>qX7V4w(D4x<*( zTR;Z`AzzI@81mNmGbmv;paPoBdnxX5{UAQQfiF2D#OA3)=n zg7I?m{S5=nRdtWIjRoANDn{;fDWfNi{gImkEyl#7sX@#Tc`yOwA>`oItpzU7Zg*SQ z=WbydqZX_5d8&B)>F{@wKkiJ2$2;}eU9{H&;o3#Qo6@jJNl`u8D9a!una`wn+8#h%5;V-F@af;&o;qcqN%b%ko`32Li)B0{^FWl)6? zm)+OD6hH?|H6CZCMLyPb-);nlBsaIVdk=-8QAv*V(uBfdz@T^QIKSO11+^Y#m} zVbI5H*=)u^4&%dCxhlYcI2DJ+&zr zKmG915^(U{AXa1l>J@+AXK~jmZZX{N%rXjHS0wSFkOk!@e3_Dz>6~M3l5E@$z+oyV zc$$Rd!xi&jJ{*=WM9lpcZZV&bj{6Py2p-f}Eeh7+bF5VVadTdUyn-8OGk9_0uQVUx zus+ndAEKU-R9k^(ei7>+D&Jb!zA{b+jZb85zfD^U`O-N#Bu8cQA^_(h?_7fM?Bkky zs>b2|ImRn#~8oZ|L>w6hQEbBQh6pi diff --git a/Content/AdvancedLocomotionV4/Blueprints/Input/Default/RightMovementAction.uasset b/Content/AdvancedLocomotionV4/Blueprints/Input/Default/RightMovementAction.uasset deleted file mode 100644 index e6b5d1302292efe24f395976d9b75c4cc0cc20f8..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 1774 zcma)7TSyd97(QuNFO`-eL4_4)H&=196bffAhT*Q)q=zV{^|U*+JG0HsdI8qP>!{5J2B&^F9?YeGE_o;nRTUMIY~M!4Hc;R_273Ym!$4$IULn! z8|`TpgHhhp8Rl$peC*qv)mAGigbpcE;$l--?%SDQ$x~9mN~+g7t^~*TqpXjihf?B_{5-eU5~~qhIk|_`Z&whI(xPd zsY#Xmey&E?WM$}C8VQ!2PaW$i_K?IT)HF8RFFNb$Y(i_BDEoLT=~P0B9;@BvplHLY zBx@0yo&=kVUlyZ5&DJ3K1DZ!^;~_4`Q^W3@A9%eJN*jHu6xM7`MdfFW0N8x>(NoB! zx#pGwx;0%Z8-MpSv@!`oz$On>a1fCm5$3iw6W2Oa>{o0iC1ARbN* zSc?b0fMmREV@dy-HrC?drU6#oZ}P{G8ehZ=pe!!vBjW*x5C7SrJkbDB`LL* z^~4*y+TG$*Z5|BbyZ}kpaT7c-)s2G@EQR0T_l(e=?hp1B BSDpX> diff --git a/Content/AdvancedLocomotionV4/Blueprints/Input/Default/SprintAction.uasset b/Content/AdvancedLocomotionV4/Blueprints/Input/Default/SprintAction.uasset deleted file mode 100644 index 69a3e5d128ddf5850c886ec8b5d4c750ed56ea66..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 1760 zcmb_dO-vI(6duH1e$)^#UOZr8P!X1&Lahhtc4-xZrOMAy8MgxzOSjowzL}OySm?m;V492L2G?)x5&kOi=aJZL|AlXE|OHx~;()ZCM20#ygVcXBf!o4^LO7z0DdPH2t5 zE(7a!RVyB)uHNO6{WVI!6L5R#+zqng3wT_$KG~0a@&%%71p5XeffyfOMoGXVSZoiV z9sOK1{^D66IC<@~duD8|oeV#z_3GUx?l!n--}O`zW{5hNKxX;bTl?}#U{q1j;jgba z!=j8Dtg^nU+M0hlyG(M=!y=C4^pR5RyamBen4Aqzq_o&Q_7U4*Ue1Kj7 zC%;878(yEq{O83xV9r1IXp;XDhq>x*016EPM7414zRc$iJ6Af z9E%T_QWNW@15s0I<6c=s9@+nL=*lisYg6?|+>{heXC0Y5$x?G=<8IrWKi12`a5?h+ z(W?b4jS{7XLCm3x6GbrMbC!0=o~|O)<~}R`kj@N)g~{vh-Z3n(ea`w)VNx*On!-Jw zVkT{(CM9#j(>Jz)!>SZ9j*ph&_qN6>yxWKGvtsaPZE?as|4w{E6hZugkA~?Y@Bj%o zdCS1VOc3kw3No~Hd4+56FnIxyORl(f-WF?to%aXw7CLD0^dT^|hxam9*y^rnP*-S! zY?dxAOxb+M!#beFx``T(h|Pd+Er>YC$rbCjBNpz*8SCnQisg)tmmC4_7Lj?6kSSX% z%)_3)MOkH>x=27xY}TubuAD%9=QUe(;HTi>X|xi<1*-^71)&;*w`Y)LF7!cI$b04D wX~??%Rkn*>&fjmZl`y`=c8DW@+vBkB)n2cE>7xMhM4if@zwX~=7XEF20ky|E)c^nh diff --git a/Content/AdvancedLocomotionV4/Blueprints/Input/Default/StanceAction.uasset b/Content/AdvancedLocomotionV4/Blueprints/Input/Default/StanceAction.uasset deleted file mode 100644 index e4dba4332a014af0ba5bab361677a66c31fe7819..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 1559 zcma)7O-vI}5FW%|e$?Ra#i%3(73osbf?j|}X|)MrV}+yg+&*cw?KZm$f+rJWLi8X6 z6C*|rgbNpg(VNi(h{nX|!RSR34~Pd18lxnjsC8z$58G1EN#D-w%s1bgdHde$=*7JQ zv&m$#H6Ng08Nd{3k~|!r!XuL(>aR@~zIG0>`##5R^!2U)z#lYeae)e89gZ4A??mlw zU`{uya=NO0ZdP4cwf}&}#k|br^i>^n`kajLFov_xB$x3)O!WSIIYj{8qNec~$F9wKvbP}NhLzHr(zr-T**)1LYca%hop%LvEg^KX3;ZMR zB2?} zLC|qM($*$)119QX!#;EaaDwnL5pdW-{Mm0qwON0N8+ZT_~VIo zQ)v*Vd3)4Uf+m5PN;ptDzkl6GY(Z6zBuvGl>7qGRC(QaQYBs0Eyz#I#jYS8qZaxeLU12;KLUbxq{8Xfjx zfN`jM)B3;f^SE34hD0&?GrG7r6B?ACiAYF(;&&-bnbt10O~}U0A&x2`p}iy}7p}k# z=E70;Qe^JGaI5Tublh*ONAi%Sy+uO3xGgJn`fPJaMZA(5X)|~!@mHFUaMT}ZS`XRJ z$=@I;Ra;pt5-hKzYQwm{2@>w=URJ6L|St zvJ0Yw1%PY@$=ZZRxI?7Q#U4zwtTK7RGER{r?Yxv(*VA^pW}G}jkol8Rfm9Ds8(|oP_#pkboilr{t=qbF*qL+gIp6v2Id|^8JAQV@ z_1Q!s(U}X7zXV_kHAxOWUwiJyC$$SR1#c>EtE0h+ZRi_Y3V=UowIUo9z-oNz5xohu zRu%N=HFW{MT2mKPb)UbwDxmpl1JyyjvPSo5gog>7g(kU)FJhu`JdYv(GpOmw!@#|* z_VbcUL2Y>G*5&xOx;y#ro=o4!`K&&Db@lz=mczTLLgJwUhzH=vmCZTDsLRUQn*wDA zd6+YYmj^0#iTK#~cgP&~((%=Jd+sBa&B*?{g4GfuE>-eMUnY@TMWX+>IDA9te6;85(w z23I2JkZpE%bK8Lrd;0DkK!>8Xv~~E8Hiklq+BLu;2Jb=!tIwkR4!@#>`+3whBd((~ zN22|%qVwadKkOb(KcT=IzOnVYa!vetk-; zDbnN3=rP0Vkrz|6N{wOWIN+Wl$ z%w-Ti^XU8vbcl5UXYb&;HGjtQxNAFyc?tR#YiM+&<)Zv}#7FWIzg9ug^!BzeAszPv zaa0ru?Jy~saQPyb2}cVdMdtnsw_GHo;^wd($wQiU90~Oj@T}yS6lPXMypkJf7w}Tz zuM{8Qs6W!Q9Vc?@aLmuNc# diff --git a/Content/AdvancedLocomotionV4/Blueprints/Input/Default/WalkAction.uasset b/Content/AdvancedLocomotionV4/Blueprints/Input/Default/WalkAction.uasset deleted file mode 100644 index b9505168a2e3b01730b55adcab5d6ef65a4d490f..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 1551 zcma)7T}TvB6h3D5<7z)r(nA^bVr4q6uI`&P>+Y8Lw`5vR>TSH~>bkScjFv$Z1!43Q z1wm9qB+)}56uyKDKKNopLjiq9#eh=WEB{^k?7AIoE{yf&3y^v=41pGXU@hb!wEO0@#dC1)}$$ z_PT??lG1X&Cr}!2yS;LGaf!Rw=PM0*{5bWv2@i3MLP4(JiJ4Md$hj!$TfY|QZD}$nT%c>_T&hDP63c*Qg4MgwHV}tVZitH`ilK;gDnW z^>0MbaV^~5&NUrA9`1hZM}s8SG&FfyDnlVjZtG=Hg|{Jt+O5+1CXeKc^zfJ#jvBgD z6^->6lAoVuJrP4X!6IFU0WS;9h9VMVUZ7l?M4K}<4u z_w?l~ZA@i^={gu^&R);Lnd!5*b9S_55w~fxvJYuo*LfSf`gG_T6;;a(=4S?j>5I>A zY(Rsx6`&vK-@fI~dN6F5!hN~*#72HU>jF%QJ+H8cQ`bg7$ zh&z^W9r{tU0(rznX482UmkzOiE)JIy#N@Mbq O&$`V2?{Xf&zk=U9l_S#t diff --git a/Content/AdvancedLocomotionV4/Blueprints/Input/IMC_Debug.uasset b/Content/AdvancedLocomotionV4/Blueprints/Input/IMC_Debug.uasset deleted file mode 100644 index bf447f341557ade8e7e662a70d8c9775b05785f6..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 9346 zcmeHNd2kd(7jG35gGj^+6-DrfiX@w4lPn^^-OVDaHf`oJ@38l_j-1FZ@*~Gz5@piEIf*_q9YmGMK$OMDt(cjtvh@V_mAFK{*?EvS)~_H zpLGIbBdKoCM2v^1*)dZvxOOC(O`zOmiE*_`L{NU`_qI#U|867Z>$E{&#-A#s`;D*)Bf<0TJ5ZM+q zn_^lwH|n)SLTih0Hnpqj`7t!&)Ad*qUOb}b?xU&GuXl84Y}K-(zk*upcw1+9mLBRf zdAmQN8CuBVhQB)$<5KqQjtQ+aV^$Y66C}m2Sv;&8-E7sz+x8xp>Tl3GI9u|_cHe2# z7l=o+c!;;#EUx6;m{~L)W{<9!?j}cILDqHab03YM77emjXI%a8D7!7#ENf1T0IHs? z-MfFmv1r-Pn{0D$=OVHxtJmA3i=x~x*`)6xHsn6`zJz&A zJJa(m^a1Wkecbljs4J4*)_>H8W5A`c?Is?wk{Iu%S9YFB-A!8PW-ZL;=pii@U82D# z;AJMX5NG48?iDar6E~uII~)5=(NZWO(6z(05$rV`TbnH{8g;y z^-XVJPR*9lnKmaEdwf3tEo{@~9hXCgEm|9U@W+=uc*Pdpm74wsmsoE=eJw^b9EP%f zxU6G6o}I^H@85GaTCME0?QQp?bqyPJo%;#2u4P{?-RQcST4mlj&8_YQ{-&lfZ~J0l zQ__Lnq2oA)h z`^K(#ynvirqx=@hxvghp|D1woWOk?AELc&|{Pisb;W-C;qF;~chAHP;yW{%JjRoP| z9MKY7v7Nr;hSM4f!!|~1OHTHanV(k_X0k1`t0yOWyKD7((+_2`!FvA!;acq8nMWp0 z0*mI55lvWSe%;{n?46VC3r?-Y=BCC}C=lBN`})OCc8M4i(@c|Dw{)#UlonibFX!El z?F>#xLUON5PxH3>CMwL}3+(&i4Zftb+$-hnU-~}J1xa)H^BWhgJ2_KW%6BI|c<+e_ z7vhC%5d)oY?z-hW$7g~vyeYD!c=@SW<7sYDlJSG#cPq%iBwLg=V0LhK%`(uP^!zTyzZLna(8uQ<*XV{Wrfe< z_Evjqs(e-M>Oh^3EhW&9<5W^RrKy%mGA<~0U0AAaN;AW_jMAkt8xrXX$BY`+1Iw9=`w437?T8hia^*Dk?VwjB z2Y_6%virP}6OJ0HJtIvP_@(od@BvjeUjQ)o|Iol*Dt}V>Hx+z>_=C#7sPt3$jmmy1 zkpDZ?crF)V4yib3pFmZN%#5(FP{fN!%iyWZ(ZP5CiTO6rd2%uLi|2J^GbbS@0S%C;WC`sN0NEx8D!rE9EG$!v;{A7}NmR;tOX0wd|GHVFM^l3~B(x*TNYWBHo#B~fCFve z44{q|YUle$1z~j@Rc9@6jDrT0Hl%kBJPQ=o2>6)+q{KQm!khMkhj1EJ-;1+P!!44d zU5Rt;Bx>jVI1fdR651^sj^6&m-Lun*kJK1gA!{_iN4FqlG{XbAI H{rl+uK*Q7N diff --git a/Content/AdvancedLocomotionV4/Blueprints/Input/IMC_Default.uasset b/Content/AdvancedLocomotionV4/Blueprints/Input/IMC_Default.uasset deleted file mode 100644 index 862be8025fbb62c31181ee03c8bdc022c3eea12c..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 25582 zcmeHQ36K@V8Ey`vg6o0ND4vTV2)aA>yiqyk#N}LBP8H#?jLVbv_HEw21=dsrFu_<> zEN@M`s-!$iLyTHwyfq$GIgHUV6{Eo@UWgb2DxQ)2|4jGW+2OsNcP?w;Up3n^-GBGr z{eS)c-P7G~_UWIEyXA{ryLK%ZLddYeglvNlX%Ji=Ex+%b4~%O*9sU}>L4VX~7z=Ta zjU!|q2xq3-T?mGfCGdA5aMwd<*qrU?iXbV5qgcA^aJnHlnyBi$V>*sX4g{vZ96-py z5Uv?T$O#bcdki6yPKFzxk0Hcs7hG37d-WAlzP_pHj@N#C@nJ8$dHJ}F3${OV)vzg# z*KIs@rTJ6>Yl!76feULy$ay!68Z-jJ@#E*(^7z?q(v5ezr^*c+O@I99uSouMFFX8^ zZ@KnTyl;e7Zf#|;eh5n1g{?Q?5$};eVMHfSrK~si#k%*FORpky0nVZ+-_`TqP>k=cgyJ#R(1+x?T9a1Y&FB5>F)Vi zvR=C9_Cv!dUTaAFg5!3L3?w=6R@dmtX4CD9jWh%)^1!&4B$UgF4RH8HXx5-HKMF9Q z$T`cqQcF9tiPjb5$oTOu{V<%INwl@O88ULsN54lLS=pF%0U3VAzHT^nA$hER>EOcy zyq@ru<>{{EGAL=EIgf5SBAgni#r^B#jfe}Ac>n6# zu;q}H4B*%ojMdm%F~w6E6}hc(kcy4+TBscp`zKl#KIE+Hq8tIs7tcEf92aShx2}k{xzp3F@nqt{I643A2KC*7bu!`^a@r#|{S6h+(veBDGY@g4 zz4a9@GK=O)W!?DsvJI$+mTaagpa_oK^bPXPaaZ?f=h@S;522Vj8P8Zc$>zzayHQ

!9F zSD&~O6Bm#towL3`SKO#iZwoZ|3Bs9` z7nmC}uD@#9v{{vuM@<=RH|6H~<)Ssu>sBSj2K?TV`g@;iuB5C29_^i@Uf6$1CFSRZ_P?zU0*pl8;o> zc>=CypQEQ;KcSpTHq9^>Q>R1b?D%#I&Mq2TS~H1`Y@?aZxO4qshJ4X<>O>q2SQ?u- zd2WmRedC|Eq1!i;@y=fTlECDYt9 z-8Ps$l8e_bwY~A*&Bm>GHcsAI`{30$%b;T^>6~)OVK|D@=NXLe=2LESu~0hJ^>Pzi zU%qw|Bzg1u-RA|Ef5?Z^%2`H_$1zH%Eag^dhXdrWm})IWftWq2em9aVBrbx+ciHAE5Ds%F6Zx-Dv)BRGy@sz!|vQ7UQ}+JK@t znrf-C#4C;>D~4cdqU~scVe^t+JL6R=t~k#-lE%rJ#Mzq8$9Tn7VzOk2vaH2)gXe3c z@mR$bHyuND6w#J!(7T{Xx}rP0852z1;S@#IYE*HpqKac*$M+V0VxF6#Vl*xrVNbF| z#S|>bkOa-(M9a}dC#D%-)P`l4lA(}wz*PNVfafc2SpF3rsBNxovf`Nj5C{Iswk?Mf zRMF5SL*)#?wqmtvTV+E9wg4TM4_eQQ3dS?kbV-j1il9o4ZYnA-8kT7rcFf>xOR-c- zt5wS?^IX`1ybE^0ra53za?DmG+2&=FhrVdVEFJuv4L+Gy^;$KpGT(+R=)Kq(Y?G`? z8mtD}lFacMUGmMp5Aqr==%5gb#h6;?v!PNR>t#$W?Q zO_MFdh=IqKc^J)%7%#Q z99t0-J;v9pXIAb)c3PwEq8e-# zr|FVn>M@BIG+ot20p{YC3?cMKS&_LKbx5&tM-p0<4K_-Imgu@-!mE-gnSy4Uq9#k4 z!~WgnH@ZnMoQeS)@03WXLAoaz!1^96KfYcY?`@lEXXX}&i zJ>bJ_8Kl0-dl&dl^x694dk6T$BKY10zQslGZ3ezr5qxg}pH>9lo4_}z2)=&?GAD`v3Me^B2^5J?iQj}a=X-A6U!_5t(C_da(L5kwTEh3~SKHT_0 zisGB@vqkdFD3Whxk$kvGgA`Ri+$lkd;$wXyijVo6Am6vpFMTQg-+A-_2N;_g3Ld&B zhVUH`FC-|oSGgGXzd#)Fp+CkD{S>Z@BMoZx!>GSZ4)PT%3->L9vg&FmYe-1eku{Vx zG$duV@0+&8YQp)B0Z4EDpDt0XJzkIw@+NZ3Dg?~ahW1G2D>;uS^V za*_XNxITk~?Qr23f--PEi{n=vTtnd6328XD#&=xA65EZ7(|GI>=h95)pTqN)aD4^W zr*Qoju210l4_rIo`WUW{;DRhwBW!oiKCOQ;kL>_^yTyUM>rYN5^Dp>i1S zOgJ62()IVRdC2eGjmf*)-H>NTdW?5k6xyGAQ5j9ufJ#O>f=(Dt^B)Nr1viX|MZT^2 zsfa*cVqKwurXpk>Am+o{4n2A9z+sZ(%xvcZe-gVGdT-89t-e)A5$IgQ?F;KB*WcR$@T_ z(8!pgnKH@;;CNamCYDuvuK<8`!yHP?NSQVYf>2#6m{>Llchj7uTLJ4bb+iQ5$8GxT z2c81z;ogWkFERp{c0Y15AT6l6;NiME66-U?TTs7&7kOr8kARog`f%#NG}%wqr+D!7 zh#i0cMxGrSH~`|jub%_|-P0E92{%-|k?kEtp5;t;wOVOOAk9n+#b+iOF=Iu|Py`Vo8xVIT}Yn*Q|^P!A80r*!k2@?|P6j4^9)S!-8lxkxz#(S%TSY+aX? zUJylG_^qBfjls$QF|oy?nDR4{(otlx>SzgtRb68+^7=H4WHsz35Jpl(FtNphQ2tT~ zYkL@k0_#|jhr;ni%s+b_{M~7d0c6GJtO@-g4&>;WnKlc8h+8Jrvm`WNBqp|a5L14} z@3JMa#^!(sYN8+jxL@@>0H7*w?!Y=uS>sB1094lk@M8r?tRbvUwVYYADOjB^I=AIi zU^yc47a%x3hkruCyiDP7inX{Op{uU#ln>oqRPm)x190Ao6o$_7qv>DIdDO#0DkQ%$i>SiIS#XwK5HW3s~7F>~|^?vFPj*4WYpp6UXCAJ0Kz zN?~=1_ItPb8Os>?aiW711^~Y?&_g-niTo)QzFGBr(_}ze4W4SLp4HHU9A$u(qWazI ztfsmE;0ps%=~lDB&sc`lu*3aftC>hk^n;w$ME+I}mw^Lch#8P(g9pK?XErBLO_h$? zUTZeh1pv>fYf?_$nJ_s}*4F^w8R?l!6sjf=L zEk$$gb>mHS0bnbyr30|BYyeKAIkCedu{X%6{v-XHGn~lZ7~`3#0$&jukS2tOkE>@w zY;IdRf_tqARTlt!!$v9{fZzHV%NTnm(VSrunnvUOAZJ36KVm-uG8FpY+kmtoJiK2$ z8)7?Ur9-&a+E8@?IGXm`(gC=g<}7_4z0fsmp1M<)lQ<={_V zs%JU%R9U41x7S)ubpbfEYyirC^I^ZD4_nS;S{FaaSx)3PIk23T;Kxe`q~YN2#HwdF zqo}UFHyqY!m?pe_1Cea;nk^iY>H>gM9wa7~iHTmHE`Oy>_eJiuK0T4f`$5idBES2B lD{X<#>F!ChVQR!Cd>8Mr-l%vEZ-DCIiu~UjPs4xu_&<|gvyA`% From 6b207e9c17ab267f285544d33413ed092525b408 Mon Sep 17 00:00:00 2001 From: Helcio Laurentino do Carmo Junior Date: Mon, 1 May 2023 18:20:14 -0300 Subject: [PATCH 03/17] feat: Add Lyra dependencies --- ALSV4_CPP.uplugin | 39 ++++++++++++++++++++++++++- Source/ALSV4_CPP/ALSV4_CPP.Build.cs | 42 ++++++++++++++++++++++++++--- 2 files changed, 76 insertions(+), 5 deletions(-) diff --git a/ALSV4_CPP.uplugin b/ALSV4_CPP.uplugin index f5b1bb8b..cfe17347 100644 --- a/ALSV4_CPP.uplugin +++ b/ALSV4_CPP.uplugin @@ -9,7 +9,7 @@ "CreatedByURL": "https://github.com/dyanikoglu", "DocsURL": "https://github.com/dyanikoglu/ALS-Community", "SupportURL": "https://github.com/dyanikoglu/ALS-Community/issues", - "EngineVersion": "5.1", + "EngineAssociation": "5.1", "EnabledByDefault": true, "CanContainContent": true, "IsBetaVersion": false, @@ -24,6 +24,7 @@ "Engine", "AIModule", "GameplayTasks", + "GameplayAbilities", "PhysicsCore" ] } @@ -36,6 +37,42 @@ { "Name": "EnhancedInput", "Enabled": true + }, + { + "Name": "GameplayMessageRouter", + "Enabled": true + }, + { + "Name": "GameFeatures", + "Enabled": true + }, + { + "Name": "CommonLoadingScreen", + "Enabled": true + }, + { + "Name": "CommonUI", + "Enabled": true + }, + { + "Name": "CommonUser", + "Enabled": true + }, + { + "Name": "CommonGame", + "Enabled": true + }, + { + "Name": "GameplayAbilities", + "Enabled": true + }, + { + "Name": "ModularGameplay", + "Enabled": true + }, + { + "Name": "ModularGameplayActors", + "Enabled": true } ] } diff --git a/Source/ALSV4_CPP/ALSV4_CPP.Build.cs b/Source/ALSV4_CPP/ALSV4_CPP.Build.cs index 90a5d820..8d0e3730 100644 --- a/Source/ALSV4_CPP/ALSV4_CPP.Build.cs +++ b/Source/ALSV4_CPP/ALSV4_CPP.Build.cs @@ -8,11 +8,45 @@ public class ALSV4_CPP : ModuleRules public ALSV4_CPP(ReadOnlyTargetRules Target) : base(Target) { PCHUsage = PCHUsageMode.UseExplicitOrSharedPCHs; - + PublicDependencyModuleNames.AddRange(new[] - {"Core", "CoreUObject", "Engine", "InputCore", "NavigationSystem", "AIModule", "GameplayTasks","PhysicsCore", "Niagara", "EnhancedInput" - }); + { + "GameplayAbilities", + "GameplayTags", + "GameplayTasks", + "Core", + "CoreUObject", + "Engine", + "InputCore", + "NavigationSystem", + "AIModule", + "ModularGameplay", + "ModularGameplayActors", + "GameplayTasks", + "GameFeatures", + "PhysicsCore", + "Niagara", + "CommonLoadingScreen", + "EnhancedInput" + } + ); - PrivateDependencyModuleNames.AddRange(new[] {"Slate", "SlateCore"}); + PrivateDependencyModuleNames.AddRange( + new string[] + { + "InputCore", + "AudioMixer", + "AudioModulation", + "EnhancedInput", + "NetCore", + "CommonInput", + "CommonGame", + "CommonUser", + "CommonUI", + "GameplayMessageRuntime", + "Slate", + "SlateCore" + } + ); } } \ No newline at end of file From a1cad43d1eb7c09f0214c323f1166ad0d57f546f Mon Sep 17 00:00:00 2001 From: Helcio Laurentino do Carmo Junior Date: Mon, 1 May 2023 18:25:50 -0300 Subject: [PATCH 04/17] feat: Add AbilitySystem classes --- .../Private/AbilitySystem/ALSAbilitySet.cpp | 145 +++++ .../ALSAbilitySourceInterface.cpp | 8 + .../ALSAbilitySystemComponent.cpp | 515 +++++++++++++++++ .../ALSAbilityTagRelationshipMapping.cpp | 60 ++ .../ALSGameplayEffectContext.cpp | 44 ++ .../AbilitySystem/ALSGlobalAbilitySystem.cpp | 151 +++++ .../Abilities/ALSGameplayAbility.cpp | 546 ++++++++++++++++++ .../Public/AbilitySystem/ALSAbilitySet.h | 146 +++++ .../AbilitySystem/ALSAbilitySourceInterface.h | 40 ++ .../AbilitySystem/ALSAbilitySystemComponent.h | 104 ++++ .../ALSAbilityTagRelationshipMapping.h | 60 ++ .../AbilitySystem/ALSGameplayEffectContext.h | 76 +++ .../AbilitySystem/ALSGlobalAbilitySystem.h | 78 +++ .../AbilitySystem/Abilities/ALSAbilityCost.h | 60 ++ .../ALSAbilitySimpleFailureMessage.h | 26 + .../Abilities/ALSGameplayAbility.h | 195 +++++++ 16 files changed, 2254 insertions(+) create mode 100644 Source/ALSV4_CPP/Private/AbilitySystem/ALSAbilitySet.cpp create mode 100644 Source/ALSV4_CPP/Private/AbilitySystem/ALSAbilitySourceInterface.cpp create mode 100644 Source/ALSV4_CPP/Private/AbilitySystem/ALSAbilitySystemComponent.cpp create mode 100644 Source/ALSV4_CPP/Private/AbilitySystem/ALSAbilityTagRelationshipMapping.cpp create mode 100644 Source/ALSV4_CPP/Private/AbilitySystem/ALSGameplayEffectContext.cpp create mode 100644 Source/ALSV4_CPP/Private/AbilitySystem/ALSGlobalAbilitySystem.cpp create mode 100644 Source/ALSV4_CPP/Private/AbilitySystem/Abilities/ALSGameplayAbility.cpp create mode 100644 Source/ALSV4_CPP/Public/AbilitySystem/ALSAbilitySet.h create mode 100644 Source/ALSV4_CPP/Public/AbilitySystem/ALSAbilitySourceInterface.h create mode 100644 Source/ALSV4_CPP/Public/AbilitySystem/ALSAbilitySystemComponent.h create mode 100644 Source/ALSV4_CPP/Public/AbilitySystem/ALSAbilityTagRelationshipMapping.h create mode 100644 Source/ALSV4_CPP/Public/AbilitySystem/ALSGameplayEffectContext.h create mode 100644 Source/ALSV4_CPP/Public/AbilitySystem/ALSGlobalAbilitySystem.h create mode 100644 Source/ALSV4_CPP/Public/AbilitySystem/Abilities/ALSAbilityCost.h create mode 100644 Source/ALSV4_CPP/Public/AbilitySystem/Abilities/ALSAbilitySimpleFailureMessage.h create mode 100644 Source/ALSV4_CPP/Public/AbilitySystem/Abilities/ALSGameplayAbility.h diff --git a/Source/ALSV4_CPP/Private/AbilitySystem/ALSAbilitySet.cpp b/Source/ALSV4_CPP/Private/AbilitySystem/ALSAbilitySet.cpp new file mode 100644 index 00000000..7f469644 --- /dev/null +++ b/Source/ALSV4_CPP/Private/AbilitySystem/ALSAbilitySet.cpp @@ -0,0 +1,145 @@ +// Fill out your copyright notice in the Description page of Project Settings. + + +#include "AbilitySystem/ALSAbilitySet.h" +#include "ALSLogChannels.h" +#include "AbilitySystem/ALSAbilitySystemComponent.h" +#include "AbilitySystem/Abilities/ALSGameplayAbility.h" + +void FALSAbilitySet_GrantedHandles::AddAbilitySpecHandle(const FGameplayAbilitySpecHandle& Handle) +{ + if (Handle.IsValid()) + { + AbilitySpecHandles.Add(Handle); + } +} + +void FALSAbilitySet_GrantedHandles::AddGameplayEffectHandle(const FActiveGameplayEffectHandle& Handle) +{ + if (Handle.IsValid()) + { + GameplayEffectHandles.Add(Handle); + } +} + +void FALSAbilitySet_GrantedHandles::AddAttributeSet(UAttributeSet* Set) +{ + GrantedAttributeSets.Add(Set); +} + +void FALSAbilitySet_GrantedHandles::TakeFromAbilitySystem(UALSAbilitySystemComponent* ALSASC) +{ + check(ALSASC); + + if (!ALSASC->IsOwnerActorAuthoritative()) + { + // Must be authoritative to give or take ability sets. + return; + } + + for (const FGameplayAbilitySpecHandle& Handle : AbilitySpecHandles) + { + if (Handle.IsValid()) + { + ALSASC->ClearAbility(Handle); + } + } + + for (const FActiveGameplayEffectHandle& Handle : GameplayEffectHandles) + { + if (Handle.IsValid()) + { + ALSASC->RemoveActiveGameplayEffect(Handle); + } + } + + for (UAttributeSet* Set : GrantedAttributeSets) + { + ALSASC->GetSpawnedAttributes_Mutable().Remove(Set); + } + + AbilitySpecHandles.Reset(); + GameplayEffectHandles.Reset(); + GrantedAttributeSets.Reset(); +} + +UALSAbilitySet::UALSAbilitySet(const FObjectInitializer& ObjectInitializer) + : Super(ObjectInitializer) +{ +} + +void UALSAbilitySet::GiveToAbilitySystem(UALSAbilitySystemComponent* ALSASC, FALSAbilitySet_GrantedHandles* OutGrantedHandles, UObject* SourceObject) const +{ + check(ALSASC); + + if (!ALSASC->IsOwnerActorAuthoritative()) + { + // Must be authoritative to give or take ability sets. + return; + } + + // Grant the gameplay abilities. + for (int32 AbilityIndex = 0; AbilityIndex < GrantedGameplayAbilities.Num(); ++AbilityIndex) + { + const FALSAbilitySet_GameplayAbility& AbilityToGrant = GrantedGameplayAbilities[AbilityIndex]; + + if (!IsValid(AbilityToGrant.Ability)) + { + UE_LOG(LogALSAbilitySystem, Error, TEXT("GrantedGameplayAbilities[%d] on ability set [%s] is not valid."), AbilityIndex, *GetNameSafe(this)); + continue; + } + + UALSGameplayAbility* AbilityCDO = AbilityToGrant.Ability->GetDefaultObject(); + + FGameplayAbilitySpec AbilitySpec(AbilityCDO, AbilityToGrant.AbilityLevel); + AbilitySpec.SourceObject = SourceObject; + AbilitySpec.DynamicAbilityTags.AddTag(AbilityToGrant.InputTag); + + const FGameplayAbilitySpecHandle AbilitySpecHandle = ALSASC->GiveAbility(AbilitySpec); + + if (OutGrantedHandles) + { + OutGrantedHandles->AddAbilitySpecHandle(AbilitySpecHandle); + } + } + + // Grant the gameplay effects. + for (int32 EffectIndex = 0; EffectIndex < GrantedGameplayEffects.Num(); ++EffectIndex) + { + const FALSAbilitySet_GameplayEffect& EffectToGrant = GrantedGameplayEffects[EffectIndex]; + + if (!IsValid(EffectToGrant.GameplayEffect)) + { + UE_LOG(LogALSAbilitySystem, Error, TEXT("GrantedGameplayEffects[%d] on ability set [%s] is not valid"), EffectIndex, *GetNameSafe(this)); + continue; + } + + const UGameplayEffect* GameplayEffect = EffectToGrant.GameplayEffect->GetDefaultObject(); + const FActiveGameplayEffectHandle GameplayEffectHandle = ALSASC->ApplyGameplayEffectToSelf(GameplayEffect, EffectToGrant.EffectLevel, ALSASC->MakeEffectContext()); + + if (OutGrantedHandles) + { + OutGrantedHandles->AddGameplayEffectHandle(GameplayEffectHandle); + } + } + + // Grant the attribute sets. + for (int32 SetIndex = 0; SetIndex < GrantedAttributes.Num(); ++SetIndex) + { + const FALSAbilitySet_AttributeSet& SetToGrant = GrantedAttributes[SetIndex]; + + if (!IsValid(SetToGrant.AttributeSet)) + { + UE_LOG(LogALSAbilitySystem, Error, TEXT("GrantedAttributes[%d] on ability set [%s] is not valid"), SetIndex, *GetNameSafe(this)); + continue; + } + + UAttributeSet* NewSet = NewObject(ALSASC->GetOwner(), SetToGrant.AttributeSet); + ALSASC->AddAttributeSetSubobject(NewSet); + + if (OutGrantedHandles) + { + OutGrantedHandles->AddAttributeSet(NewSet); + } + } +} \ No newline at end of file diff --git a/Source/ALSV4_CPP/Private/AbilitySystem/ALSAbilitySourceInterface.cpp b/Source/ALSV4_CPP/Private/AbilitySystem/ALSAbilitySourceInterface.cpp new file mode 100644 index 00000000..f3fffb95 --- /dev/null +++ b/Source/ALSV4_CPP/Private/AbilitySystem/ALSAbilitySourceInterface.cpp @@ -0,0 +1,8 @@ +// Fill out your copyright notice in the Description page of Project Settings. + + +#include "AbilitySystem/ALSAbilitySourceInterface.h" + +UALSAbilitySourceInterface::UALSAbilitySourceInterface(const FObjectInitializer& ObjectInitializer) + : Super(ObjectInitializer) +{} diff --git a/Source/ALSV4_CPP/Private/AbilitySystem/ALSAbilitySystemComponent.cpp b/Source/ALSV4_CPP/Private/AbilitySystem/ALSAbilitySystemComponent.cpp new file mode 100644 index 00000000..c5fc41ff --- /dev/null +++ b/Source/ALSV4_CPP/Private/AbilitySystem/ALSAbilitySystemComponent.cpp @@ -0,0 +1,515 @@ +// Fill out your copyright notice in the Description page of Project Settings. + + +#include "AbilitySystem/ALSAbilitySystemComponent.h" +#include "ALSLogChannels.h" +#include "System/ALSGameData.h" +#include "System/ALSAssetManager.h" +#include "AbilitySystem/ALSGlobalAbilitySystem.h" +#include "GameplayTagContainer.h" +#include "GameplayAbilitySpec.h" +#include "AbilitySystem/Abilities/ALSGameplayAbility.h" +#include "Character/Animation/ALSCharacterAnimInstance.h" +#include "AbilitySystem/ALSAbilityTagRelationshipMapping.h" + +UE_DEFINE_GAMEPLAY_TAG(TAG_Gameplay_AbilityInputBlocked, "Gameplay.AbilityInputBlocked"); + +UALSAbilitySystemComponent::UALSAbilitySystemComponent(const FObjectInitializer& ObjectInitializer) + : Super(ObjectInitializer) +{ + InputPressedSpecHandles.Reset(); + InputReleasedSpecHandles.Reset(); + InputHeldSpecHandles.Reset(); + + FMemory::Memset(ActivationGroupCounts, 0, sizeof(ActivationGroupCounts)); +} + +void UALSAbilitySystemComponent::EndPlay(const EEndPlayReason::Type EndPlayReason) +{ + if (UALSGlobalAbilitySystem* GlobalAbilitySystem = UWorld::GetSubsystem(GetWorld())) + { + GlobalAbilitySystem->UnregisterASC(this); + } +} + +void UALSAbilitySystemComponent::InitAbilityActorInfo(AActor* InOwnerActor, AActor* InAvatarActor) +{ + FGameplayAbilityActorInfo* ActorInfo = AbilityActorInfo.Get(); + check(ActorInfo); + check(InOwnerActor); + + const bool bHasNewPawnAvatar = Cast(InAvatarActor) && (InAvatarActor != ActorInfo->AvatarActor); + + Super::InitAbilityActorInfo(InOwnerActor, InAvatarActor); + + if (bHasNewPawnAvatar) + { + // Notify all abilities that a new pawn avatar has been set + for (const FGameplayAbilitySpec& AbilitySpec : ActivatableAbilities.Items) + { + UALSGameplayAbility* ALSAbilityCDO = CastChecked(AbilitySpec.Ability); + + if (ALSAbilityCDO->GetInstancingPolicy() != EGameplayAbilityInstancingPolicy::NonInstanced) + { + TArray Instances = AbilitySpec.GetAbilityInstances(); + for (UGameplayAbility* AbilityInstance : Instances) + { + UALSGameplayAbility* ALSAbilityInstance = CastChecked(AbilityInstance); + ALSAbilityInstance->OnPawnAvatarSet(); + } + } + else + { + ALSAbilityCDO->OnPawnAvatarSet(); + } + } + + // Register with the global system once we actually have a pawn avatar. We wait until this time since some globally-applied effects may require an avatar. + if (UALSGlobalAbilitySystem* GlobalAbilitySystem = UWorld::GetSubsystem(GetWorld())) + { + GlobalAbilitySystem->RegisterASC(this); + } + + if (UALSCharacterAnimInstance* ALSAnimInst = Cast(ActorInfo->GetAnimInstance())) + { + ALSAnimInst->InitializeWithAbilitySystem(this); + } + + TryActivateAbilitiesOnSpawn(); + } +} + +void UALSAbilitySystemComponent::TryActivateAbilitiesOnSpawn() +{ + ABILITYLIST_SCOPE_LOCK(); + for (const FGameplayAbilitySpec& AbilitySpec : ActivatableAbilities.Items) + { + const UALSGameplayAbility* ALSAbilityCDO = CastChecked(AbilitySpec.Ability); + ALSAbilityCDO->TryActivateAbilityOnSpawn(AbilityActorInfo.Get(), AbilitySpec); + } +} + +void UALSAbilitySystemComponent::CancelAbilitiesByFunc(TShouldCancelAbilityFunc ShouldCancelFunc, bool bReplicateCancelAbility) +{ + ABILITYLIST_SCOPE_LOCK(); + for (const FGameplayAbilitySpec& AbilitySpec : ActivatableAbilities.Items) + { + if (!AbilitySpec.IsActive()) + { + continue; + } + + UALSGameplayAbility* ALSAbilityCDO = CastChecked(AbilitySpec.Ability); + + if (ALSAbilityCDO->GetInstancingPolicy() != EGameplayAbilityInstancingPolicy::NonInstanced) + { + // Cancel all the spawned instances, not the CDO. + TArray Instances = AbilitySpec.GetAbilityInstances(); + for (UGameplayAbility* AbilityInstance : Instances) + { + UALSGameplayAbility* ALSAbilityInstance = CastChecked(AbilityInstance); + + if (ShouldCancelFunc(ALSAbilityInstance, AbilitySpec.Handle)) + { + if (ALSAbilityInstance->CanBeCanceled()) + { + ALSAbilityInstance->CancelAbility(AbilitySpec.Handle, AbilityActorInfo.Get(), ALSAbilityInstance->GetCurrentActivationInfo(), bReplicateCancelAbility); + } + else + { + UE_LOG(LogALSAbilitySystem, Error, TEXT("CancelAbilitiesByFunc: Can't cancel ability [%s] because CanBeCanceled is false."), *ALSAbilityInstance->GetName()); + } + } + } + } + else + { + // Cancel the non-instanced ability CDO. + if (ShouldCancelFunc(ALSAbilityCDO, AbilitySpec.Handle)) + { + // Non-instanced abilities can always be canceled. + check(ALSAbilityCDO->CanBeCanceled()); + ALSAbilityCDO->CancelAbility(AbilitySpec.Handle, AbilityActorInfo.Get(), FGameplayAbilityActivationInfo(), bReplicateCancelAbility); + } + } + } +} + +void UALSAbilitySystemComponent::CancelInputActivatedAbilities(bool bReplicateCancelAbility) +{ + TShouldCancelAbilityFunc ShouldCancelFunc = [this](const UALSGameplayAbility* ALSAbility, FGameplayAbilitySpecHandle Handle) + { + const EALSAbilityActivationPolicy ActivationPolicy = ALSAbility->GetActivationPolicy(); + return ((ActivationPolicy == EALSAbilityActivationPolicy::OnInputTriggered) || (ActivationPolicy == EALSAbilityActivationPolicy::WhileInputActive)); + }; + + CancelAbilitiesByFunc(ShouldCancelFunc, bReplicateCancelAbility); +} + +void UALSAbilitySystemComponent::AbilitySpecInputPressed(FGameplayAbilitySpec& Spec) +{ + Super::AbilitySpecInputPressed(Spec); + + // We don't support UGameplayAbility::bReplicateInputDirectly. + // Use replicated events instead so that the WaitInputPress ability task works. + if (Spec.IsActive()) + { + // Invoke the InputPressed event. This is not replicated here. If someone is listening, they may replicate the InputPressed event to the server. + InvokeReplicatedEvent(EAbilityGenericReplicatedEvent::InputPressed, Spec.Handle, Spec.ActivationInfo.GetActivationPredictionKey()); + } +} + +void UALSAbilitySystemComponent::AbilitySpecInputReleased(FGameplayAbilitySpec& Spec) +{ + Super::AbilitySpecInputReleased(Spec); + + // We don't support UGameplayAbility::bReplicateInputDirectly. + // Use replicated events instead so that the WaitInputRelease ability task works. + if (Spec.IsActive()) + { + // Invoke the InputReleased event. This is not replicated here. If someone is listening, they may replicate the InputReleased event to the server. + InvokeReplicatedEvent(EAbilityGenericReplicatedEvent::InputReleased, Spec.Handle, Spec.ActivationInfo.GetActivationPredictionKey()); + } +} + +void UALSAbilitySystemComponent::AbilityInputTagPressed(const FGameplayTag& InputTag) +{ + if (InputTag.IsValid()) + { + for (const FGameplayAbilitySpec& AbilitySpec : ActivatableAbilities.Items) + { + if (AbilitySpec.Ability && (AbilitySpec.DynamicAbilityTags.HasTagExact(InputTag))) + { + InputPressedSpecHandles.AddUnique(AbilitySpec.Handle); + InputHeldSpecHandles.AddUnique(AbilitySpec.Handle); + } + } + } +} + +void UALSAbilitySystemComponent::AbilityInputTagReleased(const FGameplayTag& InputTag) +{ + if (InputTag.IsValid()) + { + for (const FGameplayAbilitySpec& AbilitySpec : ActivatableAbilities.Items) + { + if (AbilitySpec.Ability && (AbilitySpec.DynamicAbilityTags.HasTagExact(InputTag))) + { + InputReleasedSpecHandles.AddUnique(AbilitySpec.Handle); + InputHeldSpecHandles.Remove(AbilitySpec.Handle); + } + } + } +} + +void UALSAbilitySystemComponent::ProcessAbilityInput(float DeltaTime, bool bGamePaused) +{ + if (HasMatchingGameplayTag(TAG_Gameplay_AbilityInputBlocked)) + { + ClearAbilityInput(); + return; + } + + static TArray AbilitiesToActivate; + AbilitiesToActivate.Reset(); + + //@TODO: See if we can use FScopedServerAbilityRPCBatcher ScopedRPCBatcher in some of these loops + + // + // Process all abilities that activate when the input is held. + // + for (const FGameplayAbilitySpecHandle& SpecHandle : InputHeldSpecHandles) + { + if (const FGameplayAbilitySpec* AbilitySpec = FindAbilitySpecFromHandle(SpecHandle)) + { + if (AbilitySpec->Ability && !AbilitySpec->IsActive()) + { + const UALSGameplayAbility* ALSAbilityCDO = CastChecked(AbilitySpec->Ability); + + if (ALSAbilityCDO->GetActivationPolicy() == EALSAbilityActivationPolicy::WhileInputActive) + { + AbilitiesToActivate.AddUnique(AbilitySpec->Handle); + } + } + } + } + + // + // Process all abilities that had their input pressed this frame. + // + for (const FGameplayAbilitySpecHandle& SpecHandle : InputPressedSpecHandles) + { + if (FGameplayAbilitySpec* AbilitySpec = FindAbilitySpecFromHandle(SpecHandle)) + { + if (AbilitySpec->Ability) + { + AbilitySpec->InputPressed = true; + + if (AbilitySpec->IsActive()) + { + // Ability is active so pass along the input event. + AbilitySpecInputPressed(*AbilitySpec); + } + else + { + const UALSGameplayAbility* ALSAbilityCDO = CastChecked(AbilitySpec->Ability); + + if (ALSAbilityCDO->GetActivationPolicy() == EALSAbilityActivationPolicy::OnInputTriggered) + { + AbilitiesToActivate.AddUnique(AbilitySpec->Handle); + } + } + } + } + } + + // + // Try to activate all the abilities that are from presses and holds. + // We do it all at once so that held inputs don't activate the ability + // and then also send a input event to the ability because of the press. + // + for (const FGameplayAbilitySpecHandle& AbilitySpecHandle : AbilitiesToActivate) + { + TryActivateAbility(AbilitySpecHandle); + } + + // + // Process all abilities that had their input released this frame. + // + for (const FGameplayAbilitySpecHandle& SpecHandle : InputReleasedSpecHandles) + { + if (FGameplayAbilitySpec* AbilitySpec = FindAbilitySpecFromHandle(SpecHandle)) + { + if (AbilitySpec->Ability) + { + AbilitySpec->InputPressed = false; + + if (AbilitySpec->IsActive()) + { + // Ability is active so pass along the input event. + AbilitySpecInputReleased(*AbilitySpec); + } + } + } + } + + // + // Clear the cached ability handles. + // + InputPressedSpecHandles.Reset(); + InputReleasedSpecHandles.Reset(); +} + +void UALSAbilitySystemComponent::ClearAbilityInput() +{ + InputPressedSpecHandles.Reset(); + InputReleasedSpecHandles.Reset(); + InputHeldSpecHandles.Reset(); +} + +void UALSAbilitySystemComponent::NotifyAbilityActivated(const FGameplayAbilitySpecHandle Handle, UGameplayAbility* Ability) +{ + Super::NotifyAbilityActivated(Handle, Ability); + + UALSGameplayAbility* ALSAbility = CastChecked(Ability); + + AddAbilityToActivationGroup(ALSAbility->GetActivationGroup(), ALSAbility); +} + +void UALSAbilitySystemComponent::NotifyAbilityFailed(const FGameplayAbilitySpecHandle Handle, UGameplayAbility* Ability, const FGameplayTagContainer& FailureReason) +{ + Super::NotifyAbilityFailed(Handle, Ability, FailureReason); + + if (APawn* Avatar = Cast(GetAvatarActor())) + { + if (!Avatar->IsLocallyControlled() && Ability->IsSupportedForNetworking()) + { + ClientNotifyAbilityFailed(Ability, FailureReason); + return; + } + } + + HandleAbilityFailed(Ability, FailureReason); +} + +void UALSAbilitySystemComponent::NotifyAbilityEnded(FGameplayAbilitySpecHandle Handle, UGameplayAbility* Ability, bool bWasCancelled) +{ + Super::NotifyAbilityEnded(Handle, Ability, bWasCancelled); + + UALSGameplayAbility* ALSAbility = CastChecked(Ability); + + RemoveAbilityFromActivationGroup(ALSAbility->GetActivationGroup(), ALSAbility); +} + +void UALSAbilitySystemComponent::ApplyAbilityBlockAndCancelTags(const FGameplayTagContainer& AbilityTags, UGameplayAbility* RequestingAbility, bool bEnableBlockTags, const FGameplayTagContainer& BlockTags, bool bExecuteCancelTags, const FGameplayTagContainer& CancelTags) +{ + FGameplayTagContainer ModifiedBlockTags = BlockTags; + FGameplayTagContainer ModifiedCancelTags = CancelTags; + + if (TagRelationshipMapping) + { + // Use the mapping to expand the ability tags into block and cancel tag + TagRelationshipMapping->GetAbilityTagsToBlockAndCancel(AbilityTags, &ModifiedBlockTags, &ModifiedCancelTags); + } + + Super::ApplyAbilityBlockAndCancelTags(AbilityTags, RequestingAbility, bEnableBlockTags, ModifiedBlockTags, bExecuteCancelTags, ModifiedCancelTags); + + //@TODO: Apply any special logic like blocking input or movement +} + +void UALSAbilitySystemComponent::HandleChangeAbilityCanBeCanceled(const FGameplayTagContainer& AbilityTags, UGameplayAbility* RequestingAbility, bool bCanBeCanceled) +{ + Super::HandleChangeAbilityCanBeCanceled(AbilityTags, RequestingAbility, bCanBeCanceled); + + //@TODO: Apply any special logic like blocking input or movement +} + +void UALSAbilitySystemComponent::GetAdditionalActivationTagRequirements(const FGameplayTagContainer& AbilityTags, FGameplayTagContainer& OutActivationRequired, FGameplayTagContainer& OutActivationBlocked) const +{ + if (TagRelationshipMapping) + { + TagRelationshipMapping->GetRequiredAndBlockedActivationTags(AbilityTags, &OutActivationRequired, &OutActivationBlocked); + } +} + +void UALSAbilitySystemComponent::SetTagRelationshipMapping(UALSAbilityTagRelationshipMapping* NewMapping) +{ + TagRelationshipMapping = NewMapping; +} + +void UALSAbilitySystemComponent::ClientNotifyAbilityFailed_Implementation(const UGameplayAbility* Ability, const FGameplayTagContainer& FailureReason) +{ + HandleAbilityFailed(Ability, FailureReason); +} + +void UALSAbilitySystemComponent::HandleAbilityFailed(const UGameplayAbility* Ability, const FGameplayTagContainer& FailureReason) +{ + //UE_LOG(LogALSAbilitySystem, Warning, TEXT("Ability %s failed to activate (tags: %s)"), *GetPathNameSafe(Ability), *FailureReason.ToString()); + + if (const UALSGameplayAbility* ALSAbility = Cast(Ability)) + { + ALSAbility->OnAbilityFailedToActivate(FailureReason); + } +} + +bool UALSAbilitySystemComponent::IsActivationGroupBlocked(EALSAbilityActivationGroup Group) const +{ + bool bBlocked = false; + + switch (Group) + { + case EALSAbilityActivationGroup::Independent: + // Independent abilities are never blocked. + bBlocked = false; + break; + + case EALSAbilityActivationGroup::Exclusive_Replaceable: + case EALSAbilityActivationGroup::Exclusive_Blocking: + // Exclusive abilities can activate if nothing is blocking. + bBlocked = (ActivationGroupCounts[(uint8)EALSAbilityActivationGroup::Exclusive_Blocking] > 0); + break; + + default: + checkf(false, TEXT("IsActivationGroupBlocked: Invalid ActivationGroup [%d]\n"), (uint8)Group); + break; + } + + return bBlocked; +} + +void UALSAbilitySystemComponent::AddAbilityToActivationGroup(EALSAbilityActivationGroup Group, UALSGameplayAbility* ALSAbility) +{ + check(ALSAbility); + check(ActivationGroupCounts[(uint8)Group] < INT32_MAX); + + ActivationGroupCounts[(uint8)Group]++; + + const bool bReplicateCancelAbility = false; + + switch (Group) + { + case EALSAbilityActivationGroup::Independent: + // Independent abilities do not cancel any other abilities. + break; + + case EALSAbilityActivationGroup::Exclusive_Replaceable: + case EALSAbilityActivationGroup::Exclusive_Blocking: + CancelActivationGroupAbilities(EALSAbilityActivationGroup::Exclusive_Replaceable, ALSAbility, bReplicateCancelAbility); + break; + + default: + checkf(false, TEXT("AddAbilityToActivationGroup: Invalid ActivationGroup [%d]\n"), (uint8)Group); + break; + } + + const int32 ExclusiveCount = ActivationGroupCounts[(uint8)EALSAbilityActivationGroup::Exclusive_Replaceable] + ActivationGroupCounts[(uint8)EALSAbilityActivationGroup::Exclusive_Blocking]; + if (!ensure(ExclusiveCount <= 1)) + { + UE_LOG(LogALSAbilitySystem, Error, TEXT("AddAbilityToActivationGroup: Multiple exclusive abilities are running.")); + } +} + +void UALSAbilitySystemComponent::RemoveAbilityFromActivationGroup(EALSAbilityActivationGroup Group, UALSGameplayAbility* ALSAbility) +{ + check(ALSAbility); + check(ActivationGroupCounts[(uint8)Group] > 0); + + ActivationGroupCounts[(uint8)Group]--; +} + +void UALSAbilitySystemComponent::CancelActivationGroupAbilities(EALSAbilityActivationGroup Group, UALSGameplayAbility* IgnoreALSAbility, bool bReplicateCancelAbility) +{ + TShouldCancelAbilityFunc ShouldCancelFunc = [this, Group, IgnoreALSAbility](const UALSGameplayAbility* ALSAbility, FGameplayAbilitySpecHandle Handle) + { + return ((ALSAbility->GetActivationGroup() == Group) && (ALSAbility != IgnoreALSAbility)); + }; + + CancelAbilitiesByFunc(ShouldCancelFunc, bReplicateCancelAbility); +} + +void UALSAbilitySystemComponent::AddDynamicTagGameplayEffect(const FGameplayTag& Tag) +{ + const TSubclassOf DynamicTagGE = UALSAssetManager::GetSubclass(UALSGameData::Get().DynamicTagGameplayEffect); + if (!DynamicTagGE) + { + UE_LOG(LogALSAbilitySystem, Warning, TEXT("AddDynamicTagGameplayEffect: Unable to find DynamicTagGameplayEffect [%s]."), *UALSGameData::Get().DynamicTagGameplayEffect.GetAssetName()); + return; + } + + const FGameplayEffectSpecHandle SpecHandle = MakeOutgoingSpec(DynamicTagGE, 1.0f, MakeEffectContext()); + FGameplayEffectSpec* Spec = SpecHandle.Data.Get(); + + if (!Spec) + { + UE_LOG(LogALSAbilitySystem, Warning, TEXT("AddDynamicTagGameplayEffect: Unable to make outgoing spec for [%s]."), *GetNameSafe(DynamicTagGE)); + return; + } + + Spec->DynamicGrantedTags.AddTag(Tag); + + ApplyGameplayEffectSpecToSelf(*Spec); +} + +void UALSAbilitySystemComponent::RemoveDynamicTagGameplayEffect(const FGameplayTag& Tag) +{ + const TSubclassOf DynamicTagGE = UALSAssetManager::GetSubclass(UALSGameData::Get().DynamicTagGameplayEffect); + if (!DynamicTagGE) + { + UE_LOG(LogALSAbilitySystem, Warning, TEXT("RemoveDynamicTagGameplayEffect: Unable to find gameplay effect [%s]."), *UALSGameData::Get().DynamicTagGameplayEffect.GetAssetName()); + return; + } + + FGameplayEffectQuery Query = FGameplayEffectQuery::MakeQuery_MatchAnyOwningTags(FGameplayTagContainer(Tag)); + Query.EffectDefinition = DynamicTagGE; + + RemoveActiveEffects(Query); +} + +void UALSAbilitySystemComponent::GetAbilityTargetData(const FGameplayAbilitySpecHandle AbilityHandle, FGameplayAbilityActivationInfo ActivationInfo, FGameplayAbilityTargetDataHandle& OutTargetDataHandle) +{ + TSharedPtr ReplicatedData = AbilityTargetDataMap.Find(FGameplayAbilitySpecHandleAndPredictionKey(AbilityHandle, ActivationInfo.GetActivationPredictionKey())); + if (ReplicatedData.IsValid()) + { + OutTargetDataHandle = ReplicatedData->TargetData; + } +} diff --git a/Source/ALSV4_CPP/Private/AbilitySystem/ALSAbilityTagRelationshipMapping.cpp b/Source/ALSV4_CPP/Private/AbilitySystem/ALSAbilityTagRelationshipMapping.cpp new file mode 100644 index 00000000..76db9632 --- /dev/null +++ b/Source/ALSV4_CPP/Private/AbilitySystem/ALSAbilityTagRelationshipMapping.cpp @@ -0,0 +1,60 @@ +// Fill out your copyright notice in the Description page of Project Settings. + + +#include "AbilitySystem/ALSAbilityTagRelationshipMapping.h" + +void UALSAbilityTagRelationshipMapping::GetAbilityTagsToBlockAndCancel(const FGameplayTagContainer& AbilityTags, FGameplayTagContainer* OutTagsToBlock, FGameplayTagContainer* OutTagsToCancel) const +{ + // Simple iteration for now + for (int32 i = 0; i < AbilityTagRelationships.Num(); i++) + { + const FALSAbilityTagRelationship& Tags = AbilityTagRelationships[i]; + if (AbilityTags.HasTag(Tags.AbilityTag)) + { + if (OutTagsToBlock) + { + OutTagsToBlock->AppendTags(Tags.AbilityTagsToBlock); + } + if (OutTagsToCancel) + { + OutTagsToCancel->AppendTags(Tags.AbilityTagsToCancel); + } + } + } +} + +void UALSAbilityTagRelationshipMapping::GetRequiredAndBlockedActivationTags(const FGameplayTagContainer& AbilityTags, FGameplayTagContainer* OutActivationRequired, FGameplayTagContainer* OutActivationBlocked) const +{ + // Simple iteration for now + for (int32 i = 0; i < AbilityTagRelationships.Num(); i++) + { + const FALSAbilityTagRelationship& Tags = AbilityTagRelationships[i]; + if (AbilityTags.HasTag(Tags.AbilityTag)) + { + if (OutActivationRequired) + { + OutActivationRequired->AppendTags(Tags.ActivationRequiredTags); + } + if (OutActivationBlocked) + { + OutActivationBlocked->AppendTags(Tags.ActivationBlockedTags); + } + } + } +} + +bool UALSAbilityTagRelationshipMapping::IsAbilityCancelledByTag(const FGameplayTagContainer& AbilityTags, const FGameplayTag& ActionTag) const +{ + // Simple iteration for now + for (int32 i = 0; i < AbilityTagRelationships.Num(); i++) + { + const FALSAbilityTagRelationship& Tags = AbilityTagRelationships[i]; + + if (Tags.AbilityTag == ActionTag && Tags.AbilityTagsToCancel.HasAny(AbilityTags)) + { + return true; + } + } + + return false; +} \ No newline at end of file diff --git a/Source/ALSV4_CPP/Private/AbilitySystem/ALSGameplayEffectContext.cpp b/Source/ALSV4_CPP/Private/AbilitySystem/ALSGameplayEffectContext.cpp new file mode 100644 index 00000000..b39ed823 --- /dev/null +++ b/Source/ALSV4_CPP/Private/AbilitySystem/ALSGameplayEffectContext.cpp @@ -0,0 +1,44 @@ +#include "AbilitySystem/ALSGameplayEffectContext.h" +#include "Components/PrimitiveComponent.h" +#include "AbilitySystem/ALSAbilitySourceInterface.h" + +FALSGameplayEffectContext* FALSGameplayEffectContext::ExtractEffectContext(struct FGameplayEffectContextHandle Handle) +{ + FGameplayEffectContext* BaseEffectContext = Handle.Get(); + if ((BaseEffectContext != nullptr) && BaseEffectContext->GetScriptStruct()->IsChildOf(FALSGameplayEffectContext::StaticStruct())) + { + return (FALSGameplayEffectContext*)BaseEffectContext; + } + + return nullptr; +} + +bool FALSGameplayEffectContext::NetSerialize(FArchive& Ar, class UPackageMap* Map, bool& bOutSuccess) +{ + FGameplayEffectContext::NetSerialize(Ar, Map, bOutSuccess); + + // Not serialized for post-activation use: + // CartridgeID + + return true; +} + +void FALSGameplayEffectContext::SetAbilitySource(const IALSAbilitySourceInterface* InObject, float InSourceLevel) +{ + AbilitySourceObject = MakeWeakObjectPtr(Cast(InObject)); + //SourceLevel = InSourceLevel; +} + +const IALSAbilitySourceInterface* FALSGameplayEffectContext::GetAbilitySource() const +{ + return Cast(AbilitySourceObject.Get()); +} + +const UPhysicalMaterial* FALSGameplayEffectContext::GetPhysicalMaterial() const +{ + if (const FHitResult* HitResultPtr = GetHitResult()) + { + return HitResultPtr->PhysMaterial.Get(); + } + return nullptr; +} \ No newline at end of file diff --git a/Source/ALSV4_CPP/Private/AbilitySystem/ALSGlobalAbilitySystem.cpp b/Source/ALSV4_CPP/Private/AbilitySystem/ALSGlobalAbilitySystem.cpp new file mode 100644 index 00000000..97a4e0d9 --- /dev/null +++ b/Source/ALSV4_CPP/Private/AbilitySystem/ALSGlobalAbilitySystem.cpp @@ -0,0 +1,151 @@ +#include "AbilitySystem/ALSGlobalAbilitySystem.h" +#include "Net/UnrealNetwork.h" +#include "AbilitySystem/ALSAbilitySystemComponent.h" + +void FGlobalAppliedAbilityList::AddToASC(TSubclassOf Ability, UALSAbilitySystemComponent* ASC) +{ + if (FGameplayAbilitySpecHandle* SpecHandle = Handles.Find(ASC)) + { + RemoveFromASC(ASC); + } + + UGameplayAbility* AbilityCDO = Ability->GetDefaultObject(); + FGameplayAbilitySpec AbilitySpec(AbilityCDO); + const FGameplayAbilitySpecHandle AbilitySpecHandle = ASC->GiveAbility(AbilitySpec); + Handles.Add(ASC, AbilitySpecHandle); +} + +void FGlobalAppliedAbilityList::RemoveFromASC(UALSAbilitySystemComponent* ASC) +{ + if (FGameplayAbilitySpecHandle* SpecHandle = Handles.Find(ASC)) + { + ASC->ClearAbility(*SpecHandle); + Handles.Remove(ASC); + } +} + +void FGlobalAppliedAbilityList::RemoveFromAll() +{ + for (auto& KVP : Handles) + { + if (KVP.Key != nullptr) + { + KVP.Key->ClearAbility(KVP.Value); + } + } + Handles.Empty(); +} + + + +void FGlobalAppliedEffectList::AddToASC(TSubclassOf Effect, UALSAbilitySystemComponent* ASC) +{ + if (FActiveGameplayEffectHandle* EffectHandle = Handles.Find(ASC)) + { + RemoveFromASC(ASC); + } + + const UGameplayEffect* GameplayEffectCDO = Effect->GetDefaultObject(); + const FActiveGameplayEffectHandle GameplayEffectHandle = ASC->ApplyGameplayEffectToSelf(GameplayEffectCDO, /*Level=*/ 1, ASC->MakeEffectContext()); + Handles.Add(ASC, GameplayEffectHandle); +} + +void FGlobalAppliedEffectList::RemoveFromASC(UALSAbilitySystemComponent* ASC) +{ + if (FActiveGameplayEffectHandle* EffectHandle = Handles.Find(ASC)) + { + ASC->RemoveActiveGameplayEffect(*EffectHandle); + Handles.Remove(ASC); + } +} + +void FGlobalAppliedEffectList::RemoveFromAll() +{ + for (auto& KVP : Handles) + { + if (KVP.Key != nullptr) + { + KVP.Key->RemoveActiveGameplayEffect(KVP.Value); + } + } + Handles.Empty(); +} + +UALSGlobalAbilitySystem::UALSGlobalAbilitySystem() +{ +} + +void UALSGlobalAbilitySystem::ApplyAbilityToAll(TSubclassOf Ability) +{ + if ((Ability.Get() != nullptr) && (!AppliedAbilities.Contains(Ability))) + { + FGlobalAppliedAbilityList& Entry = AppliedAbilities.Add(Ability); + for (UALSAbilitySystemComponent* ASC : RegisteredASCs) + { + Entry.AddToASC(Ability, ASC); + } + } +} + +void UALSGlobalAbilitySystem::ApplyEffectToAll(TSubclassOf Effect) +{ + if ((Effect.Get() != nullptr) && (!AppliedEffects.Contains(Effect))) + { + FGlobalAppliedEffectList& Entry = AppliedEffects.Add(Effect); + for (UALSAbilitySystemComponent* ASC : RegisteredASCs) + { + Entry.AddToASC(Effect, ASC); + } + } +} + +void UALSGlobalAbilitySystem::RemoveAbilityFromAll(TSubclassOf Ability) +{ + if ((Ability.Get() != nullptr) && AppliedAbilities.Contains(Ability)) + { + FGlobalAppliedAbilityList& Entry = AppliedAbilities[Ability]; + Entry.RemoveFromAll(); + AppliedAbilities.Remove(Ability); + } +} + +void UALSGlobalAbilitySystem::RemoveEffectFromAll(TSubclassOf Effect) +{ + if ((Effect.Get() != nullptr) && AppliedEffects.Contains(Effect)) + { + FGlobalAppliedEffectList& Entry = AppliedEffects[Effect]; + Entry.RemoveFromAll(); + AppliedEffects.Remove(Effect); + } +} + +void UALSGlobalAbilitySystem::RegisterASC(UALSAbilitySystemComponent* ASC) +{ + check(ASC); + + for (auto& Entry : AppliedAbilities) + { + Entry.Value.AddToASC(Entry.Key, ASC); + } + for (auto& Entry : AppliedEffects) + { + Entry.Value.AddToASC(Entry.Key, ASC); + } + + RegisteredASCs.AddUnique(ASC); +} + +void UALSGlobalAbilitySystem::UnregisterASC(UALSAbilitySystemComponent* ASC) +{ + check(ASC); + for (auto& Entry : AppliedAbilities) + { + Entry.Value.RemoveFromASC(ASC); + } + for (auto& Entry : AppliedEffects) + { + Entry.Value.RemoveFromASC(ASC); + } + + RegisteredASCs.Remove(ASC); +} diff --git a/Source/ALSV4_CPP/Private/AbilitySystem/Abilities/ALSGameplayAbility.cpp b/Source/ALSV4_CPP/Private/AbilitySystem/Abilities/ALSGameplayAbility.cpp new file mode 100644 index 00000000..f992d490 --- /dev/null +++ b/Source/ALSV4_CPP/Private/AbilitySystem/Abilities/ALSGameplayAbility.cpp @@ -0,0 +1,546 @@ +// Fill out your copyright notice in the Description page of Project Settings. + + +#include "AbilitySystem/Abilities/ALSGameplayAbility.h" +#include "ALSLogChannels.h" +#include "AbilitySystem/ALSAbilitySystemComponent.h" +#include "Camera/ALSCameraMode.h" +#include "Player/ALSPlayerController2.h" +#include "Character/ALSCharacter.h" +#include "ALSGameplayTags.h" +#include "AbilitySystem/Abilities/ALSAbilityCost.h" +#include "Character/ALSHeroComponent.h" +#include "AbilitySystemBlueprintLibrary.h" +#include "AbilitySystemGlobals.h" +#include "AbilitySystemLog.h" +#include "AbilitySystem/Abilities/ALSAbilitySimpleFailureMessage.h" +#include "GameFramework/GameplayMessageSubsystem.h" +#include "AbilitySystem/ALSAbilitySourceInterface.h" +#include "AbilitySystem/ALSGameplayEffectContext.h" +#include "Physics/PhysicalMaterialWithTags.h" + +#include UE_INLINE_GENERATED_CPP_BY_NAME(ALSGameplayAbility) + +#define ENSURE_ABILITY_IS_INSTANTIATED_OR_RETURN(FunctionName, ReturnValue) \ +{ \ +if (!ensure(IsInstantiated())) \ +{ \ +ABILITY_LOG(Error, TEXT("%s: " #FunctionName " cannot be called on a non-instanced ability. Check the instancing policy."), *GetPathName()); \ +return ReturnValue; \ +} \ +} + +UE_DEFINE_GAMEPLAY_TAG(TAG_ABILITY_SIMPLE_FAILURE_MESSAGE, "Ability.UserFacingSimpleActivateFail.Message"); +UE_DEFINE_GAMEPLAY_TAG(TAG_ABILITY_PLAY_MONTAGE_FAILURE_MESSAGE, "Ability.PlayMontageOnActivateFail.Message"); + +UALSGameplayAbility::UALSGameplayAbility(const FObjectInitializer& ObjectInitializer) + : Super(ObjectInitializer) +{ + ReplicationPolicy = EGameplayAbilityReplicationPolicy::ReplicateNo; + InstancingPolicy = EGameplayAbilityInstancingPolicy::InstancedPerActor; + NetExecutionPolicy = EGameplayAbilityNetExecutionPolicy::LocalPredicted; + NetSecurityPolicy = EGameplayAbilityNetSecurityPolicy::ClientOrServer; + + ActivationPolicy = EALSAbilityActivationPolicy::OnInputTriggered; + ActivationGroup = EALSAbilityActivationGroup::Independent; + + ActiveCameraMode = nullptr; +} + +UALSAbilitySystemComponent* UALSGameplayAbility::GetALSAbilitySystemComponentFromActorInfo() const +{ + return (CurrentActorInfo ? Cast(CurrentActorInfo->AbilitySystemComponent.Get()) : nullptr); +} + +AALSPlayerController2* UALSGameplayAbility::GetALSPlayerControllerFromActorInfo() const +{ + return (CurrentActorInfo ? Cast(CurrentActorInfo->PlayerController.Get()) : nullptr); +} + +AController* UALSGameplayAbility::GetControllerFromActorInfo() const +{ + if (CurrentActorInfo) + { + if (AController* PC = CurrentActorInfo->PlayerController.Get()) + { + return PC; + } + + // Look for a player controller or pawn in the owner chain. + AActor* TestActor = CurrentActorInfo->OwnerActor.Get(); + while (TestActor) + { + if (AController* C = Cast(TestActor)) + { + return C; + } + + if (APawn* Pawn = Cast(TestActor)) + { + return Pawn->GetController(); + } + + TestActor = TestActor->GetOwner(); + } + } + + return nullptr; +} + +AALSCharacter* UALSGameplayAbility::GetALSCharacterFromActorInfo() const +{ + return (CurrentActorInfo ? Cast(CurrentActorInfo->AvatarActor.Get()) : nullptr); +} + +UALSHeroComponent* UALSGameplayAbility::GetHeroComponentFromActorInfo() const +{ + return (CurrentActorInfo ? UALSHeroComponent::FindHeroComponent(CurrentActorInfo->AvatarActor.Get()) : nullptr); +} + +void UALSGameplayAbility::NativeOnAbilityFailedToActivate(const FGameplayTagContainer& FailedReason) const +{ + bool bSimpleFailureFound = false; + for (FGameplayTag Reason : FailedReason) + { + if (!bSimpleFailureFound) + { + if (const FText* pUserFacingMessage = FailureTagToUserFacingMessages.Find(Reason)) + { + FALSAbilitySimpleFailureMessage Message; + Message.PlayerController = GetActorInfo().PlayerController.Get(); + Message.FailureTags = FailedReason; + Message.UserFacingReason = *pUserFacingMessage; + + UGameplayMessageSubsystem& MessageSystem = UGameplayMessageSubsystem::Get(GetWorld()); + MessageSystem.BroadcastMessage(TAG_ABILITY_SIMPLE_FAILURE_MESSAGE, Message); + bSimpleFailureFound = true; + } + } + + if (UAnimMontage* pMontage = FailureTagToAnimMontage.FindRef(Reason)) + { + FALSAbilityMontageFailureMessage Message; + Message.PlayerController = GetActorInfo().PlayerController.Get(); + Message.FailureTags = FailedReason; + Message.FailureMontage = pMontage; + + UGameplayMessageSubsystem& MessageSystem = UGameplayMessageSubsystem::Get(GetWorld()); + MessageSystem.BroadcastMessage(TAG_ABILITY_PLAY_MONTAGE_FAILURE_MESSAGE, Message); + } + } +} + +bool UALSGameplayAbility::CanActivateAbility(const FGameplayAbilitySpecHandle Handle, const FGameplayAbilityActorInfo* ActorInfo, const FGameplayTagContainer* SourceTags, const FGameplayTagContainer* TargetTags, FGameplayTagContainer* OptionalRelevantTags) const +{ + if (!ActorInfo || !ActorInfo->AbilitySystemComponent.IsValid()) + { + return false; + } + + UALSAbilitySystemComponent* ALSASC = CastChecked(ActorInfo->AbilitySystemComponent.Get()); + const FALSGameplayTags& GameplayTags = FALSGameplayTags::Get(); + + if (!Super::CanActivateAbility(Handle, ActorInfo, SourceTags, TargetTags, OptionalRelevantTags)) + { + return false; + } + + //@TODO Possibly remove after setting up tag relationships + if (ALSASC->IsActivationGroupBlocked(ActivationGroup)) + { + if (OptionalRelevantTags) + { + OptionalRelevantTags->AddTag(GameplayTags.Ability_ActivateFail_ActivationGroup); + } + return false; + } + + return true; +} + +void UALSGameplayAbility::SetCanBeCanceled(bool bCanBeCanceled) +{ + // The ability can not block canceling if it's replaceable. + if (!bCanBeCanceled && (ActivationGroup == EALSAbilityActivationGroup::Exclusive_Replaceable)) + { + UE_LOG(LogALSAbilitySystem, Error, TEXT("SetCanBeCanceled: Ability [%s] can not block canceling because its activation group is replaceable."), *GetName()); + return; + } + + Super::SetCanBeCanceled(bCanBeCanceled); +} + +void UALSGameplayAbility::OnGiveAbility(const FGameplayAbilityActorInfo* ActorInfo, const FGameplayAbilitySpec& Spec) +{ + Super::OnGiveAbility(ActorInfo, Spec); + + K2_OnAbilityAdded(); + + TryActivateAbilityOnSpawn(ActorInfo, Spec); +} + +void UALSGameplayAbility::OnRemoveAbility(const FGameplayAbilityActorInfo* ActorInfo, const FGameplayAbilitySpec& Spec) +{ + K2_OnAbilityRemoved(); + + Super::OnRemoveAbility(ActorInfo, Spec); +} + +void UALSGameplayAbility::ActivateAbility(const FGameplayAbilitySpecHandle Handle, const FGameplayAbilityActorInfo* ActorInfo, const FGameplayAbilityActivationInfo ActivationInfo, const FGameplayEventData* TriggerEventData) +{ + Super::ActivateAbility(Handle, ActorInfo, ActivationInfo, TriggerEventData); +} + +void UALSGameplayAbility::EndAbility(const FGameplayAbilitySpecHandle Handle, const FGameplayAbilityActorInfo* ActorInfo, const FGameplayAbilityActivationInfo ActivationInfo, bool bReplicateEndAbility, bool bWasCancelled) +{ + ClearCameraMode(); + + Super::EndAbility(Handle, ActorInfo, ActivationInfo, bReplicateEndAbility, bWasCancelled); +} + +bool UALSGameplayAbility::CheckCost(const FGameplayAbilitySpecHandle Handle, const FGameplayAbilityActorInfo* ActorInfo, OUT FGameplayTagContainer* OptionalRelevantTags) const +{ + if (!Super::CheckCost(Handle, ActorInfo, OptionalRelevantTags) || !ActorInfo) + { + return false; + } + + // Verify we can afford any additional costs + for (TObjectPtr AdditionalCost : AdditionalCosts) + { + if (AdditionalCost != nullptr) + { + if (!AdditionalCost->CheckCost(this, Handle, ActorInfo, /*inout*/ OptionalRelevantTags)) + { + return false; + } + } + } + + return true; +} + +void UALSGameplayAbility::ApplyCost(const FGameplayAbilitySpecHandle Handle, const FGameplayAbilityActorInfo* ActorInfo, const FGameplayAbilityActivationInfo ActivationInfo) const +{ + Super::ApplyCost(Handle, ActorInfo, ActivationInfo); + + check(ActorInfo); + + // Used to determine if the ability actually hit a target (as some costs are only spent on successful attempts) + auto DetermineIfAbilityHitTarget = [&]() + { + if (ActorInfo->IsNetAuthority()) + { + if (UALSAbilitySystemComponent* ASC = Cast(ActorInfo->AbilitySystemComponent.Get())) + { + FGameplayAbilityTargetDataHandle TargetData; + ASC->GetAbilityTargetData(Handle, ActivationInfo, TargetData); + for (int32 TargetDataIdx = 0; TargetDataIdx < TargetData.Data.Num(); ++TargetDataIdx) + { + if (UAbilitySystemBlueprintLibrary::TargetDataHasHitResult(TargetData, TargetDataIdx)) + { + return true; + } + } + } + } + + return false; + }; + + // Pay any additional costs + bool bAbilityHitTarget = false; + bool bHasDeterminedIfAbilityHitTarget = false; + for (TObjectPtr AdditionalCost : AdditionalCosts) + { + if (AdditionalCost != nullptr) + { + if (AdditionalCost->ShouldOnlyApplyCostOnHit()) + { + if (!bHasDeterminedIfAbilityHitTarget) + { + bAbilityHitTarget = DetermineIfAbilityHitTarget(); + bHasDeterminedIfAbilityHitTarget = true; + } + + if (!bAbilityHitTarget) + { + continue; + } + } + + AdditionalCost->ApplyCost(this, Handle, ActorInfo, ActivationInfo); + } + } +} + +FGameplayEffectContextHandle UALSGameplayAbility::MakeEffectContext(const FGameplayAbilitySpecHandle Handle, const FGameplayAbilityActorInfo* ActorInfo) const +{ + FGameplayEffectContextHandle ContextHandle = Super::MakeEffectContext(Handle, ActorInfo); + + FALSGameplayEffectContext* EffectContext = FALSGameplayEffectContext::ExtractEffectContext(ContextHandle); + check(EffectContext); + + check(ActorInfo); + + AActor* EffectCauser = nullptr; + const IALSAbilitySourceInterface* AbilitySource = nullptr; + float SourceLevel = 0.0f; + GetAbilitySource(Handle, ActorInfo, /*out*/ SourceLevel, /*out*/ AbilitySource, /*out*/ EffectCauser); + + UObject* SourceObject = GetSourceObject(Handle, ActorInfo); + + AActor* Instigator = ActorInfo ? ActorInfo->OwnerActor.Get() : nullptr; + + EffectContext->SetAbilitySource(AbilitySource, SourceLevel); + EffectContext->AddInstigator(Instigator, EffectCauser); + EffectContext->AddSourceObject(SourceObject); + + return ContextHandle; +} + +void UALSGameplayAbility::ApplyAbilityTagsToGameplayEffectSpec(FGameplayEffectSpec& Spec, FGameplayAbilitySpec* AbilitySpec) const +{ + Super::ApplyAbilityTagsToGameplayEffectSpec(Spec, AbilitySpec); + + if (const FHitResult* HitResult = Spec.GetContext().GetHitResult()) + { + if (const UPhysicalMaterialWithTags* PhysMatWithTags = Cast(HitResult->PhysMaterial.Get())) + { + Spec.CapturedTargetTags.GetSpecTags().AppendTags(PhysMatWithTags->Tags); + } + } +} + +bool UALSGameplayAbility::DoesAbilitySatisfyTagRequirements(const UAbilitySystemComponent& AbilitySystemComponent, const FGameplayTagContainer* SourceTags, const FGameplayTagContainer* TargetTags, OUT FGameplayTagContainer* OptionalRelevantTags) const +{ + // Specialized version to handle death exclusion and AbilityTags expansion via ASC + + bool bBlocked = false; + bool bMissing = false; + + UAbilitySystemGlobals& AbilitySystemGlobals = UAbilitySystemGlobals::Get(); + const FGameplayTag& BlockedTag = AbilitySystemGlobals.ActivateFailTagsBlockedTag; + const FGameplayTag& MissingTag = AbilitySystemGlobals.ActivateFailTagsMissingTag; + + // Check if any of this ability's tags are currently blocked + if (AbilitySystemComponent.AreAbilityTagsBlocked(AbilityTags)) + { + bBlocked = true; + } + + const UALSAbilitySystemComponent* ALSASC = Cast(&AbilitySystemComponent); + static FGameplayTagContainer AllRequiredTags; + static FGameplayTagContainer AllBlockedTags; + + AllRequiredTags = ActivationRequiredTags; + AllBlockedTags = ActivationBlockedTags; + + // Expand our ability tags to add additional required/blocked tags + if (ALSASC) + { + ALSASC->GetAdditionalActivationTagRequirements(AbilityTags, AllRequiredTags, AllBlockedTags); + } + + // Check to see the required/blocked tags for this ability + if (AllBlockedTags.Num() || AllRequiredTags.Num()) + { + static FGameplayTagContainer AbilitySystemComponentTags; + + AbilitySystemComponentTags.Reset(); + AbilitySystemComponent.GetOwnedGameplayTags(AbilitySystemComponentTags); + + if (AbilitySystemComponentTags.HasAny(AllBlockedTags)) + { + const FALSGameplayTags& GameplayTags = FALSGameplayTags::Get(); + if (OptionalRelevantTags && AbilitySystemComponentTags.HasTag(GameplayTags.Status_Death)) + { + // If player is dead and was rejected due to blocking tags, give that feedback + OptionalRelevantTags->AddTag(GameplayTags.Ability_ActivateFail_IsDead); + } + + bBlocked = true; + } + + if (!AbilitySystemComponentTags.HasAll(AllRequiredTags)) + { + bMissing = true; + } + } + + if (SourceTags != nullptr) + { + if (SourceBlockedTags.Num() || SourceRequiredTags.Num()) + { + if (SourceTags->HasAny(SourceBlockedTags)) + { + bBlocked = true; + } + + if (!SourceTags->HasAll(SourceRequiredTags)) + { + bMissing = true; + } + } + } + + if (TargetTags != nullptr) + { + if (TargetBlockedTags.Num() || TargetRequiredTags.Num()) + { + if (TargetTags->HasAny(TargetBlockedTags)) + { + bBlocked = true; + } + + if (!TargetTags->HasAll(TargetRequiredTags)) + { + bMissing = true; + } + } + } + + if (bBlocked) + { + if (OptionalRelevantTags && BlockedTag.IsValid()) + { + OptionalRelevantTags->AddTag(BlockedTag); + } + return false; + } + if (bMissing) + { + if (OptionalRelevantTags && MissingTag.IsValid()) + { + OptionalRelevantTags->AddTag(MissingTag); + } + return false; + } + + return true; +} + +void UALSGameplayAbility::OnPawnAvatarSet() +{ + K2_OnPawnAvatarSet(); +} + +void UALSGameplayAbility::GetAbilitySource(FGameplayAbilitySpecHandle Handle, const FGameplayAbilityActorInfo* ActorInfo, float& OutSourceLevel, const IALSAbilitySourceInterface*& OutAbilitySource, AActor*& OutEffectCauser) const +{ + OutSourceLevel = 0.0f; + OutAbilitySource = nullptr; + OutEffectCauser = nullptr; + + OutEffectCauser = ActorInfo->AvatarActor.Get(); + + // If we were added by something that's an ability info source, use it + UObject* SourceObject = GetSourceObject(Handle, ActorInfo); + + OutAbilitySource = Cast(SourceObject); +} + +void UALSGameplayAbility::TryActivateAbilityOnSpawn(const FGameplayAbilityActorInfo* ActorInfo, const FGameplayAbilitySpec& Spec) const +{ + const bool bIsPredicting = (Spec.ActivationInfo.ActivationMode == EGameplayAbilityActivationMode::Predicting); + + // Try to activate if activation policy is on spawn. + if (ActorInfo && !Spec.IsActive() && !bIsPredicting && (ActivationPolicy == EALSAbilityActivationPolicy::OnSpawn)) + { + UAbilitySystemComponent* ASC = ActorInfo->AbilitySystemComponent.Get(); + const AActor* AvatarActor = ActorInfo->AvatarActor.Get(); + + // If avatar actor is torn off or about to die, don't try to activate until we get the new one. + if (ASC && AvatarActor && !AvatarActor->GetTearOff() && (AvatarActor->GetLifeSpan() <= 0.0f)) + { + const bool bIsLocalExecution = (NetExecutionPolicy == EGameplayAbilityNetExecutionPolicy::LocalPredicted) || (NetExecutionPolicy == EGameplayAbilityNetExecutionPolicy::LocalOnly); + const bool bIsServerExecution = (NetExecutionPolicy == EGameplayAbilityNetExecutionPolicy::ServerOnly) || (NetExecutionPolicy == EGameplayAbilityNetExecutionPolicy::ServerInitiated); + + const bool bClientShouldActivate = ActorInfo->IsLocallyControlled() && bIsLocalExecution; + const bool bServerShouldActivate = ActorInfo->IsNetAuthority() && bIsServerExecution; + + if (bClientShouldActivate || bServerShouldActivate) + { + ASC->TryActivateAbility(Spec.Handle); + } + } + } +} + +bool UALSGameplayAbility::CanChangeActivationGroup(EALSAbilityActivationGroup NewGroup) const +{ + if (!IsInstantiated() || !IsActive()) + { + return false; + } + + if (ActivationGroup == NewGroup) + { + return true; + } + + UALSAbilitySystemComponent* ALSASC = GetALSAbilitySystemComponentFromActorInfo(); + check(ALSASC); + + if ((ActivationGroup != EALSAbilityActivationGroup::Exclusive_Blocking) && ALSASC->IsActivationGroupBlocked(NewGroup)) + { + // This ability can't change groups if it's blocked (unless it is the one doing the blocking). + return false; + } + + if ((NewGroup == EALSAbilityActivationGroup::Exclusive_Replaceable) && !CanBeCanceled()) + { + // This ability can't become replaceable if it can't be canceled. + return false; + } + + return true; +} + +bool UALSGameplayAbility::ChangeActivationGroup(EALSAbilityActivationGroup NewGroup) +{ + ENSURE_ABILITY_IS_INSTANTIATED_OR_RETURN(ChangeActivationGroup, false); + + if (!CanChangeActivationGroup(NewGroup)) + { + return false; + } + + if (ActivationGroup != NewGroup) + { + UALSAbilitySystemComponent* ALSASC = GetALSAbilitySystemComponentFromActorInfo(); + check(ALSASC); + + ALSASC->RemoveAbilityFromActivationGroup(ActivationGroup, this); + ALSASC->AddAbilityToActivationGroup(NewGroup, this); + + ActivationGroup = NewGroup; + } + + return true; +} + +void UALSGameplayAbility::SetCameraMode(TSubclassOf CameraMode) +{ + ENSURE_ABILITY_IS_INSTANTIATED_OR_RETURN(SetCameraMode, ); + + if (UALSHeroComponent* HeroComponent = GetHeroComponentFromActorInfo()) + { + HeroComponent->SetAbilityCameraMode(CameraMode, CurrentSpecHandle); + ActiveCameraMode = CameraMode; + } +} + +void UALSGameplayAbility::ClearCameraMode() +{ + ENSURE_ABILITY_IS_INSTANTIATED_OR_RETURN(ClearCameraMode, ); + + if (ActiveCameraMode) + { + if (UALSHeroComponent* HeroComponent = GetHeroComponentFromActorInfo()) + { + HeroComponent->ClearAbilityCameraMode(CurrentSpecHandle); + } + + ActiveCameraMode = nullptr; + } +} diff --git a/Source/ALSV4_CPP/Public/AbilitySystem/ALSAbilitySet.h b/Source/ALSV4_CPP/Public/AbilitySystem/ALSAbilitySet.h new file mode 100644 index 00000000..fcaa4aef --- /dev/null +++ b/Source/ALSV4_CPP/Public/AbilitySystem/ALSAbilitySet.h @@ -0,0 +1,146 @@ +// Fill out your copyright notice in the Description page of Project Settings. + +#pragma once + +#include "CoreMinimal.h" +#include "GameplayTagContainer.h" +#include "GameplayAbilitySpec.h" +#include "GameplayEffectTypes.h" +#include "Engine/DataAsset.h" +#include "ALSAbilitySet.generated.h" + +class UALSAbilitySystemComponent; +class UALSGameplayAbility; +class UGameplayEffect; + + +/** + * FALSAbilitySet_GameplayAbility + * + * Data used by the ability set to grant gameplay abilities. + */ +USTRUCT(BlueprintType) +struct FALSAbilitySet_GameplayAbility +{ + GENERATED_BODY() + +public: + + // Gameplay ability to grant. + UPROPERTY(EditDefaultsOnly) + TSubclassOf Ability = nullptr; + + // Level of ability to grant. + UPROPERTY(EditDefaultsOnly) + int32 AbilityLevel = 1; + + // Tag used to process input for the ability. + UPROPERTY(EditDefaultsOnly, Meta = (Categories = "InputTag")) + FGameplayTag InputTag; +}; + + +/** + * FALSAbilitySet_GameplayEffect + * + * Data used by the ability set to grant gameplay effects. + */ +USTRUCT(BlueprintType) +struct FALSAbilitySet_GameplayEffect +{ + GENERATED_BODY() + +public: + + // Gameplay effect to grant. + UPROPERTY(EditDefaultsOnly) + TSubclassOf GameplayEffect = nullptr; + + // Level of gameplay effect to grant. + UPROPERTY(EditDefaultsOnly) + float EffectLevel = 1.0f; +}; + +/** + * FALSAbilitySet_AttributeSet + * + * Data used by the ability set to grant attribute sets. + */ +USTRUCT(BlueprintType) +struct FALSAbilitySet_AttributeSet +{ + GENERATED_BODY() + +public: + // Gameplay effect to grant. + UPROPERTY(EditDefaultsOnly) + TSubclassOf AttributeSet; + +}; + +/** + * FALSAbilitySet_GrantedHandles + * + * Data used to store handles to what has been granted by the ability set. + */ +USTRUCT(BlueprintType) +struct ALSV4_CPP_API FALSAbilitySet_GrantedHandles +{ + GENERATED_BODY() + +public: + + void AddAbilitySpecHandle(const FGameplayAbilitySpecHandle& Handle); + void AddGameplayEffectHandle(const FActiveGameplayEffectHandle& Handle); + void AddAttributeSet(UAttributeSet* Set); + + void TakeFromAbilitySystem(UALSAbilitySystemComponent* ALSASC); + +protected: + + // Handles to the granted abilities. + UPROPERTY() + TArray AbilitySpecHandles; + + // Handles to the granted gameplay effects. + UPROPERTY() + TArray GameplayEffectHandles; + + // Pointers to the granted attribute sets + UPROPERTY() + TArray> GrantedAttributeSets; +}; + + +/** + * UALSAbilitySet + * + * Non-mutable data asset used to grant gameplay abilities and gameplay effects. + */ +UCLASS(BlueprintType, Const) +class ALSV4_CPP_API UALSAbilitySet : public UPrimaryDataAsset +{ + GENERATED_BODY() + +public: + + UALSAbilitySet(const FObjectInitializer& ObjectInitializer = FObjectInitializer::Get()); + + // Grants the ability set to the specified ability system component. + // The returned handles can be used later to take away anything that was granted. + void GiveToAbilitySystem(UALSAbilitySystemComponent* ALSASC, FALSAbilitySet_GrantedHandles* OutGrantedHandles, UObject* SourceObject = nullptr) const; + +protected: + + // Gameplay abilities to grant when this ability set is granted. + UPROPERTY(EditDefaultsOnly, Category = "Gameplay Abilities", meta=(TitleProperty=Ability)) + TArray GrantedGameplayAbilities; + + // Gameplay effects to grant when this ability set is granted. + UPROPERTY(EditDefaultsOnly, Category = "Gameplay Effects", meta=(TitleProperty=GameplayEffect)) + TArray GrantedGameplayEffects; + + // Attribute sets to grant when this ability set is granted. + UPROPERTY(EditDefaultsOnly, Category = "Attribute Sets", meta=(TitleProperty=AttributeSet)) + TArray GrantedAttributes; +}; diff --git a/Source/ALSV4_CPP/Public/AbilitySystem/ALSAbilitySourceInterface.h b/Source/ALSV4_CPP/Public/AbilitySystem/ALSAbilitySourceInterface.h new file mode 100644 index 00000000..2cfbe81a --- /dev/null +++ b/Source/ALSV4_CPP/Public/AbilitySystem/ALSAbilitySourceInterface.h @@ -0,0 +1,40 @@ +// Fill out your copyright notice in the Description page of Project Settings. + +#pragma once + +#include "CoreMinimal.h" +#include "UObject/ObjectMacros.h" +#include "UObject/Interface.h" +#include "ALSAbilitySourceInterface.generated.h" + +class AActor; +struct FGameplayTagContainer; +class UPhysicalMaterial; + +// This class does not need to be modified. +UINTERFACE() +class UALSAbilitySourceInterface : public UInterface +{ + GENERATED_UINTERFACE_BODY() +}; + +/** + * + */ +class IALSAbilitySourceInterface +{ + GENERATED_IINTERFACE_BODY() + + /** + * Compute the multiplier for effect falloff with distance + * + * @param Distance Distance from source to target for ability calculations (distance bullet traveled for a gun, etc...) + * @param SourceTags Aggregated Tags from the source + * @param TargetTags Aggregated Tags currently on the target + * + * @return Multiplier to apply to the base attribute value due to distance + */ + virtual float GetDistanceAttenuation(float Distance, const FGameplayTagContainer* SourceTags = nullptr, const FGameplayTagContainer* TargetTags = nullptr) const = 0; + + virtual float GetPhysicalMaterialAttenuation(const UPhysicalMaterial* PhysicalMaterial, const FGameplayTagContainer* SourceTags = nullptr, const FGameplayTagContainer* TargetTags = nullptr) const = 0; +}; diff --git a/Source/ALSV4_CPP/Public/AbilitySystem/ALSAbilitySystemComponent.h b/Source/ALSV4_CPP/Public/AbilitySystem/ALSAbilitySystemComponent.h new file mode 100644 index 00000000..7d080a22 --- /dev/null +++ b/Source/ALSV4_CPP/Public/AbilitySystem/ALSAbilitySystemComponent.h @@ -0,0 +1,104 @@ +// Fill out your copyright notice in the Description page of Project Settings. + +#pragma once + +#include "CoreMinimal.h" +#include "AbilitySystemComponent.h" +#include "NativeGameplayTags.h" +#include "Abilities/ALSGameplayAbility.h" +#include "ALSAbilitySystemComponent.generated.h" + +class UALSGameplayAbility; +class UALSAbilityTagRelationshipMapping; +struct FGameplayTag; +struct FGameplayAbilitySpec; + +ALSV4_CPP_API UE_DECLARE_GAMEPLAY_TAG_EXTERN(TAG_Gameplay_AbilityInputBlocked); + +/** + * UALSAbilitySystemComponent + * + * Base ability system component class used by this project. + */ +UCLASS() +class ALSV4_CPP_API UALSAbilitySystemComponent : public UAbilitySystemComponent +{ + GENERATED_BODY() + +public: + + UALSAbilitySystemComponent(const FObjectInitializer& ObjectInitializer = FObjectInitializer::Get()); + + //~UActorComponent interface + virtual void EndPlay(const EEndPlayReason::Type EndPlayReason) override; + //~End of UActorComponent interface + + virtual void InitAbilityActorInfo(AActor* InOwnerActor, AActor* InAvatarActor) override; + + typedef TFunctionRef TShouldCancelAbilityFunc; + void CancelAbilitiesByFunc(TShouldCancelAbilityFunc ShouldCancelFunc, bool bReplicateCancelAbility); + + void CancelInputActivatedAbilities(bool bReplicateCancelAbility); + + void AbilityInputTagPressed(const FGameplayTag& InputTag); + void AbilityInputTagReleased(const FGameplayTag& InputTag); + + void ProcessAbilityInput(float DeltaTime, bool bGamePaused); + void ClearAbilityInput(); + + bool IsActivationGroupBlocked(EALSAbilityActivationGroup Group) const; + void AddAbilityToActivationGroup(EALSAbilityActivationGroup Group, UALSGameplayAbility* ALSAbility); + void RemoveAbilityFromActivationGroup(EALSAbilityActivationGroup Group, UALSGameplayAbility* ALSAbility); + void CancelActivationGroupAbilities(EALSAbilityActivationGroup Group, UALSGameplayAbility* IgnoreALSAbility, bool bReplicateCancelAbility); + + // Uses a gameplay effect to add the specified dynamic granted tag. + void AddDynamicTagGameplayEffect(const FGameplayTag& Tag); + + // Removes all active instances of the gameplay effect that was used to add the specified dynamic granted tag. + void RemoveDynamicTagGameplayEffect(const FGameplayTag& Tag); + + /** Gets the ability target data associated with the given ability handle and activation info */ + void GetAbilityTargetData(const FGameplayAbilitySpecHandle AbilityHandle, FGameplayAbilityActivationInfo ActivationInfo, FGameplayAbilityTargetDataHandle& OutTargetDataHandle); + + /** Sets the current tag relationship mapping, if null it will clear it out */ + void SetTagRelationshipMapping(UALSAbilityTagRelationshipMapping* NewMapping); + + /** Looks at ability tags and gathers additional required and blocking tags */ + void GetAdditionalActivationTagRequirements(const FGameplayTagContainer& AbilityTags, FGameplayTagContainer& OutActivationRequired, FGameplayTagContainer& OutActivationBlocked) const; + +protected: + + void TryActivateAbilitiesOnSpawn(); + + virtual void AbilitySpecInputPressed(FGameplayAbilitySpec& Spec) override; + virtual void AbilitySpecInputReleased(FGameplayAbilitySpec& Spec) override; + + virtual void NotifyAbilityActivated(const FGameplayAbilitySpecHandle Handle, UGameplayAbility* Ability) override; + virtual void NotifyAbilityFailed(const FGameplayAbilitySpecHandle Handle, UGameplayAbility* Ability, const FGameplayTagContainer& FailureReason) override; + virtual void NotifyAbilityEnded(FGameplayAbilitySpecHandle Handle, UGameplayAbility* Ability, bool bWasCancelled) override; + virtual void ApplyAbilityBlockAndCancelTags(const FGameplayTagContainer& AbilityTags, UGameplayAbility* RequestingAbility, bool bEnableBlockTags, const FGameplayTagContainer& BlockTags, bool bExecuteCancelTags, const FGameplayTagContainer& CancelTags) override; + virtual void HandleChangeAbilityCanBeCanceled(const FGameplayTagContainer& AbilityTags, UGameplayAbility* RequestingAbility, bool bCanBeCanceled) override; + + /** Notify client that an ability failed to activate */ + UFUNCTION(Client, Unreliable) + void ClientNotifyAbilityFailed(const UGameplayAbility* Ability, const FGameplayTagContainer& FailureReason); + + void HandleAbilityFailed(const UGameplayAbility* Ability, const FGameplayTagContainer& FailureReason); +protected: + + // If set, this table is used to look up tag relationships for activate and cancel + UPROPERTY() + UALSAbilityTagRelationshipMapping* TagRelationshipMapping; + + // Handles to abilities that had their input pressed this frame. + TArray InputPressedSpecHandles; + + // Handles to abilities that had their input released this frame. + TArray InputReleasedSpecHandles; + + // Handles to abilities that have their input held. + TArray InputHeldSpecHandles; + + // Number of abilities running in each activation group. + int32 ActivationGroupCounts[(uint8)EALSAbilityActivationGroup::MAX]; +}; diff --git a/Source/ALSV4_CPP/Public/AbilitySystem/ALSAbilityTagRelationshipMapping.h b/Source/ALSV4_CPP/Public/AbilitySystem/ALSAbilityTagRelationshipMapping.h new file mode 100644 index 00000000..af6a0b07 --- /dev/null +++ b/Source/ALSV4_CPP/Public/AbilitySystem/ALSAbilityTagRelationshipMapping.h @@ -0,0 +1,60 @@ +// Fill out your copyright notice in the Description page of Project Settings. + +#pragma once + +#include "CoreMinimal.h" +#include "UObject/ObjectMacros.h" +#include "GameplayTagContainer.h" +#include "Engine/DataAsset.h" + +#include "ALSAbilityTagRelationshipMapping.generated.h" + +/** Struct that defines the relationship between different ability tags */ +USTRUCT() +struct FALSAbilityTagRelationship +{ + GENERATED_BODY() + + /** The tag that this container relationship is about. Single tag, but abilities can have multiple of these */ + UPROPERTY(EditAnywhere, Category = Ability, meta = (Categories = "Gameplay.Action")) + FGameplayTag AbilityTag; + + /** The other ability tags that will be blocked by any ability using this tag */ + UPROPERTY(EditAnywhere, Category = Ability) + FGameplayTagContainer AbilityTagsToBlock; + + /** The other ability tags that will be canceled by any ability using this tag */ + UPROPERTY(EditAnywhere, Category = Ability) + FGameplayTagContainer AbilityTagsToCancel; + + /** If an ability has the tag, this is implicitly added to the activation required tags of the ability */ + UPROPERTY(EditAnywhere, Category = Ability) + FGameplayTagContainer ActivationRequiredTags; + + /** If an ability has the tag, this is implicitly added to the activation blocked tags of the ability */ + UPROPERTY(EditAnywhere, Category = Ability) + FGameplayTagContainer ActivationBlockedTags; +}; + + +/** Mapping of how ability tags block or cancel other abilities */ +UCLASS() +class UALSAbilityTagRelationshipMapping : public UDataAsset +{ + GENERATED_BODY() + +private: + /** The list of relationships between different gameplay tags (which ones block or cancel others) */ + UPROPERTY(EditAnywhere, Category = Ability, meta=(TitleProperty="AbilityTag")) + TArray AbilityTagRelationships; + +public: + /** Given a set of ability tags, parse the tag relationship and fill out tags to block and cancel */ + void GetAbilityTagsToBlockAndCancel(const FGameplayTagContainer& AbilityTags, FGameplayTagContainer* OutTagsToBlock, FGameplayTagContainer* OutTagsToCancel) const; + + /** Given a set of ability tags, add additional required and blocking tags */ + void GetRequiredAndBlockedActivationTags(const FGameplayTagContainer& AbilityTags, FGameplayTagContainer* OutActivationRequired, FGameplayTagContainer* OutActivationBlocked) const; + + /** Returns true if the specified ability tags are canceled by the passed in action tag */ + bool IsAbilityCancelledByTag(const FGameplayTagContainer& AbilityTags, const FGameplayTag& ActionTag) const; +}; diff --git a/Source/ALSV4_CPP/Public/AbilitySystem/ALSGameplayEffectContext.h b/Source/ALSV4_CPP/Public/AbilitySystem/ALSGameplayEffectContext.h new file mode 100644 index 00000000..0d89334d --- /dev/null +++ b/Source/ALSV4_CPP/Public/AbilitySystem/ALSGameplayEffectContext.h @@ -0,0 +1,76 @@ +#pragma once + +#include "GameplayEffectTypes.h" +#include "ALSGameplayEffectContext.generated.h" + +class UAbilitySystemComponent; +class IALSAbilitySourceInterface; +class UPhysicalMaterial; + +USTRUCT() +struct FALSGameplayEffectContext : public FGameplayEffectContext +{ + GENERATED_BODY() + + FALSGameplayEffectContext() + : FGameplayEffectContext() + { + } + + FALSGameplayEffectContext(AActor* InInstigator, AActor* InEffectCauser) + : FGameplayEffectContext(InInstigator, InEffectCauser) + { + } + + /** Returns the wrapped FALSGameplayEffectContext from the handle, or nullptr if it doesn't exist or is the wrong type */ + static ALSV4_CPP_API FALSGameplayEffectContext* ExtractEffectContext(struct FGameplayEffectContextHandle Handle); + + /** Sets the object used as the ability source */ + void SetAbilitySource(const IALSAbilitySourceInterface* InObject, float InSourceLevel); + + /** Returns the ability source interface associated with the source object. Only valid on the authority. */ + const IALSAbilitySourceInterface* GetAbilitySource() const; + + virtual FGameplayEffectContext* Duplicate() const override + { + FALSGameplayEffectContext* NewContext = new FALSGameplayEffectContext(); + *NewContext = *this; + if (GetHitResult()) + { + // Does a deep copy of the hit result + NewContext->AddHitResult(*GetHitResult(), true); + } + return NewContext; + } + + virtual UScriptStruct* GetScriptStruct() const override + { + return FALSGameplayEffectContext::StaticStruct(); + } + + /** Overridden to serialize new fields */ + virtual bool NetSerialize(FArchive& Ar, class UPackageMap* Map, bool& bOutSuccess) override; + + /** Returns the physical material from the hit result if there is one */ + const UPhysicalMaterial* GetPhysicalMaterial() const; + +public: + /** ID to allow the identification of multiple bullets that were part of the same cartridge */ + UPROPERTY() + int32 CartridgeID = -1; + +protected: + /** Ability Source object (should implement IALSAbilitySourceInterface). NOT replicated currently */ + UPROPERTY() + TWeakObjectPtr AbilitySourceObject; +}; + +template<> +struct TStructOpsTypeTraits : public TStructOpsTypeTraitsBase2 +{ + enum + { + WithNetSerializer = true, + WithCopy = true + }; +}; \ No newline at end of file diff --git a/Source/ALSV4_CPP/Public/AbilitySystem/ALSGlobalAbilitySystem.h b/Source/ALSV4_CPP/Public/AbilitySystem/ALSGlobalAbilitySystem.h new file mode 100644 index 00000000..79244820 --- /dev/null +++ b/Source/ALSV4_CPP/Public/AbilitySystem/ALSGlobalAbilitySystem.h @@ -0,0 +1,78 @@ +#pragma once + +#include "CoreMinimal.h" +#include "Subsystems/WorldSubsystem.h" +#include "AbilitySystemInterface.h" +#include "GameplayTagContainer.h" +#include "GameplayAbilitySpec.h" +#include "GameplayEffectTypes.h" + +#include "ALSGlobalAbilitySystem.generated.h" + +class UALSAbilitySystemComponent; +class UAbilitySystemComponent; +class UGameplayEffect; +class UGameplayAbility; + +USTRUCT() +struct FGlobalAppliedAbilityList +{ + GENERATED_BODY() + + UPROPERTY() + TMap Handles; + + void AddToASC(TSubclassOf Ability, UALSAbilitySystemComponent* ASC); + void RemoveFromASC(UALSAbilitySystemComponent* ASC); + void RemoveFromAll(); +}; + +USTRUCT() +struct FGlobalAppliedEffectList +{ + GENERATED_BODY() + + UPROPERTY() + TMap Handles; + + void AddToASC(TSubclassOf Effect, UALSAbilitySystemComponent* ASC); + void RemoveFromASC(UALSAbilitySystemComponent* ASC); + void RemoveFromAll(); +}; + +UCLASS() +class UALSGlobalAbilitySystem : public UWorldSubsystem +{ + GENERATED_BODY() + +public: + UALSGlobalAbilitySystem(); + + UFUNCTION(BlueprintCallable, BlueprintAuthorityOnly, Category="ALS") + void ApplyAbilityToAll(TSubclassOf Ability); + + UFUNCTION(BlueprintCallable, BlueprintAuthorityOnly, Category="ALS") + void ApplyEffectToAll(TSubclassOf Effect); + + UFUNCTION(BlueprintCallable, BlueprintAuthorityOnly, Category = "ALS") + void RemoveAbilityFromAll(TSubclassOf Ability); + + UFUNCTION(BlueprintCallable, BlueprintAuthorityOnly, Category = "ALS") + void RemoveEffectFromAll(TSubclassOf Effect); + + /** Register an ASC with global system and apply any active global effects/abilities. */ + void RegisterASC(UALSAbilitySystemComponent* ASC); + + /** Removes an ASC from the global system, along with any active global effects/abilities. */ + void UnregisterASC(UALSAbilitySystemComponent* ASC); + +private: + UPROPERTY() + TMap, FGlobalAppliedAbilityList> AppliedAbilities; + + UPROPERTY() + TMap, FGlobalAppliedEffectList> AppliedEffects; + + UPROPERTY() + TArray RegisteredASCs; +}; diff --git a/Source/ALSV4_CPP/Public/AbilitySystem/Abilities/ALSAbilityCost.h b/Source/ALSV4_CPP/Public/AbilitySystem/Abilities/ALSAbilityCost.h new file mode 100644 index 00000000..2d283e0c --- /dev/null +++ b/Source/ALSV4_CPP/Public/AbilitySystem/Abilities/ALSAbilityCost.h @@ -0,0 +1,60 @@ +// Fill out your copyright notice in the Description page of Project Settings. + +#pragma once + +#include "CoreMinimal.h" +#include "GameplayAbilitySpec.h" +#include "Abilities/GameplayAbility.h" +#include "ALSAbilityCost.generated.h" + +class UALSGameplayAbility; + +/** + * UALSAbilityCost + * + * Base class for costs that a ALSGameplayAbility has (e.g., ammo or charges) + */ +UCLASS(DefaultToInstanced, EditInlineNew, Abstract) +class UALSAbilityCost : public UObject +{ + GENERATED_BODY() + +public: + UALSAbilityCost() + { + } + + /** + * Checks if we can afford this cost. + * + * A failure reason tag can be added to OptionalRelevantTags (if non-null), which can be queried + * elsewhere to determine how to provide user feedback (e.g., a clicking noise if a weapon is out of ammo) + * + * Ability and ActorInfo are guaranteed to be non-null on entry, but OptionalRelevantTags can be nullptr. + * + * @return true if we can pay for the ability, false otherwise. + */ + virtual bool CheckCost(const UALSGameplayAbility* Ability, const FGameplayAbilitySpecHandle Handle, const FGameplayAbilityActorInfo* ActorInfo, FGameplayTagContainer* OptionalRelevantTags) const + { + return true; + } + + /** + * Applies the ability's cost to the target + * + * Notes: + * - Your implementation don't need to check ShouldOnlyApplyCostOnHit(), the caller does that for you. + * - Ability and ActorInfo are guaranteed to be non-null on entry. + */ + virtual void ApplyCost(const UALSGameplayAbility* Ability, const FGameplayAbilitySpecHandle Handle, const FGameplayAbilityActorInfo* ActorInfo, const FGameplayAbilityActivationInfo ActivationInfo) + { + } + + /** If true, this cost should only be applied if this ability hits successfully */ + bool ShouldOnlyApplyCostOnHit() const { return bOnlyApplyCostOnHit; } + +protected: + /** If true, this cost should only be applied if this ability hits successfully */ + UPROPERTY(EditAnywhere, BlueprintReadOnly, Category=Costs) + bool bOnlyApplyCostOnHit = false; +}; diff --git a/Source/ALSV4_CPP/Public/AbilitySystem/Abilities/ALSAbilitySimpleFailureMessage.h b/Source/ALSV4_CPP/Public/AbilitySystem/Abilities/ALSAbilitySimpleFailureMessage.h new file mode 100644 index 00000000..1859d04a --- /dev/null +++ b/Source/ALSV4_CPP/Public/AbilitySystem/Abilities/ALSAbilitySimpleFailureMessage.h @@ -0,0 +1,26 @@ +#pragma once + +#include "CoreMinimal.h" +#include "GameplayTagContainer.h" +#include "NativeGameplayTags.h" + +#include "ALSAbilitySimpleFailureMessage.generated.h" + +UE_DECLARE_GAMEPLAY_TAG_EXTERN(TAG_ABILITY_SIMPLE_FAILURE_MESSAGE); + +USTRUCT(BlueprintType) +struct FALSAbilitySimpleFailureMessage +{ + GENERATED_BODY() + +public: + UPROPERTY(BlueprintReadWrite) + APlayerController* PlayerController = nullptr; + + UPROPERTY(BlueprintReadWrite) + FGameplayTagContainer FailureTags; + + UPROPERTY(BlueprintReadWrite) + FText UserFacingReason; +}; + diff --git a/Source/ALSV4_CPP/Public/AbilitySystem/Abilities/ALSGameplayAbility.h b/Source/ALSV4_CPP/Public/AbilitySystem/Abilities/ALSGameplayAbility.h new file mode 100644 index 00000000..82938921 --- /dev/null +++ b/Source/ALSV4_CPP/Public/AbilitySystem/Abilities/ALSGameplayAbility.h @@ -0,0 +1,195 @@ +// Fill out your copyright notice in the Description page of Project Settings. + +#pragma once + +#include "CoreMinimal.h" +#include "Abilities/GameplayAbility.h" +#include "ALSGameplayAbility.generated.h" + +class UALSAbilitySystemComponent; +class AALSPlayerController2; +class AALSCharacter; +class UALSHeroComponent; +class UALSCameraMode; +class UALSAbilityCost; +class IALSAbilitySourceInterface; + +/** + * EALSAbilityActivationPolicy + * + * Defines how an ability is meant to activate. + */ +UENUM(BlueprintType) +enum class EALSAbilityActivationPolicy : uint8 +{ + // Try to activate the ability when the input is triggered. + OnInputTriggered, + + // Continually try to activate the ability while the input is active. + WhileInputActive, + + // Try to activate the ability when an avatar is assigned. + OnSpawn +}; + + +/** + * EALSAbilityActivationGroup + * + * Defines how an ability activates in relation to other abilities. + */ +UENUM(BlueprintType) +enum class EALSAbilityActivationGroup : uint8 +{ + // Ability runs independently of all other abilities. + Independent, + + // Ability is canceled and replaced by other exclusive abilities. + Exclusive_Replaceable, + + // Ability blocks all other exclusive abilities from activating. + Exclusive_Blocking, + + MAX UMETA(Hidden) +}; + +/** Failure reason that can be used to play an animation montage when a failure occurs */ +USTRUCT(BlueprintType) +struct FALSAbilityMontageFailureMessage +{ + GENERATED_BODY() + +public: + + UPROPERTY(BlueprintReadWrite) + APlayerController* PlayerController = nullptr; + + // All the reasons why this ability has failed + UPROPERTY(BlueprintReadWrite) + FGameplayTagContainer FailureTags; + + UPROPERTY(BlueprintReadWrite) + UAnimMontage* FailureMontage = nullptr; +}; + +/** + * UALSGameplayAbility + * + * The base gameplay ability class used by this project. + */ +UCLASS(Abstract, HideCategories = Input, Meta = (ShortTooltip = "The base gameplay ability class used by this project.")) +class ALSV4_CPP_API UALSGameplayAbility : public UGameplayAbility +{ + GENERATED_BODY() + friend class UALSAbilitySystemComponent; + +public: + + UALSGameplayAbility(const FObjectInitializer& ObjectInitializer = FObjectInitializer::Get()); + + UFUNCTION(BlueprintCallable, Category = "ALS|Ability") + UALSAbilitySystemComponent* GetALSAbilitySystemComponentFromActorInfo() const; + + UFUNCTION(BlueprintCallable, Category = "ALS|Ability") + AALSPlayerController2* GetALSPlayerControllerFromActorInfo() const; + + UFUNCTION(BlueprintCallable, Category = "ALS|Ability") + AController* GetControllerFromActorInfo() const; + + UFUNCTION(BlueprintCallable, Category = "ALS|Ability") + AALSCharacter* GetALSCharacterFromActorInfo() const; + + UFUNCTION(BlueprintCallable, Category = "ALS|Ability") + UALSHeroComponent* GetHeroComponentFromActorInfo() const; + + EALSAbilityActivationPolicy GetActivationPolicy() const { return ActivationPolicy; } + EALSAbilityActivationGroup GetActivationGroup() const { return ActivationGroup; } + + void TryActivateAbilityOnSpawn(const FGameplayAbilityActorInfo* ActorInfo, const FGameplayAbilitySpec& Spec) const; + + // Returns true if the requested activation group is a valid transition. + UFUNCTION(BlueprintCallable, BlueprintPure = false, Category = "ALS|Ability", Meta = (ExpandBoolAsExecs = "ReturnValue")) + bool CanChangeActivationGroup(EALSAbilityActivationGroup NewGroup) const; + + // Tries to change the activation group. Returns true if it successfully changed. + UFUNCTION(BlueprintCallable, BlueprintPure = false, Category = "ALS|Ability", Meta = (ExpandBoolAsExecs = "ReturnValue")) + bool ChangeActivationGroup(EALSAbilityActivationGroup NewGroup); + + // Sets the ability's camera mode. + UFUNCTION(BlueprintCallable, Category = "ALS|Ability") + void SetCameraMode(TSubclassOf CameraMode); + + // Clears the ability's camera mode. Automatically called if needed when the ability ends. + UFUNCTION(BlueprintCallable, Category = "ALS|Ability") + void ClearCameraMode(); + + void OnAbilityFailedToActivate(const FGameplayTagContainer& FailedReason) const + { + NativeOnAbilityFailedToActivate(FailedReason); + ScriptOnAbilityFailedToActivate(FailedReason); + } + +protected: + + // Called when the ability fails to activate + virtual void NativeOnAbilityFailedToActivate(const FGameplayTagContainer& FailedReason) const; + + // Called when the ability fails to activate + UFUNCTION(BlueprintImplementableEvent) + void ScriptOnAbilityFailedToActivate(const FGameplayTagContainer& FailedReason) const; + + //~UGameplayAbility interface + virtual bool CanActivateAbility(const FGameplayAbilitySpecHandle Handle, const FGameplayAbilityActorInfo* ActorInfo, const FGameplayTagContainer* SourceTags, const FGameplayTagContainer* TargetTags, FGameplayTagContainer* OptionalRelevantTags) const override; + virtual void SetCanBeCanceled(bool bCanBeCanceled) override; + virtual void OnGiveAbility(const FGameplayAbilityActorInfo* ActorInfo, const FGameplayAbilitySpec& Spec) override; + virtual void OnRemoveAbility(const FGameplayAbilityActorInfo* ActorInfo, const FGameplayAbilitySpec& Spec) override; + virtual void ActivateAbility(const FGameplayAbilitySpecHandle Handle, const FGameplayAbilityActorInfo* ActorInfo, const FGameplayAbilityActivationInfo ActivationInfo, const FGameplayEventData* TriggerEventData) override; + virtual void EndAbility(const FGameplayAbilitySpecHandle Handle, const FGameplayAbilityActorInfo* ActorInfo, const FGameplayAbilityActivationInfo ActivationInfo, bool bReplicateEndAbility, bool bWasCancelled) override; + virtual bool CheckCost(const FGameplayAbilitySpecHandle Handle, const FGameplayAbilityActorInfo* ActorInfo, OUT FGameplayTagContainer* OptionalRelevantTags = nullptr) const override; + virtual void ApplyCost(const FGameplayAbilitySpecHandle Handle, const FGameplayAbilityActorInfo* ActorInfo, const FGameplayAbilityActivationInfo ActivationInfo) const override; + virtual FGameplayEffectContextHandle MakeEffectContext(const FGameplayAbilitySpecHandle Handle, const FGameplayAbilityActorInfo* ActorInfo) const override; + virtual void ApplyAbilityTagsToGameplayEffectSpec(FGameplayEffectSpec& Spec, FGameplayAbilitySpec* AbilitySpec) const override; + virtual bool DoesAbilitySatisfyTagRequirements(const UAbilitySystemComponent& AbilitySystemComponent, const FGameplayTagContainer* SourceTags, const FGameplayTagContainer* TargetTags, OUT FGameplayTagContainer* OptionalRelevantTags) const override; + //~End of UGameplayAbility interface + + virtual void OnPawnAvatarSet(); + + virtual void GetAbilitySource(FGameplayAbilitySpecHandle Handle, const FGameplayAbilityActorInfo* ActorInfo, float& OutSourceLevel, const IALSAbilitySourceInterface*& OutAbilitySource, AActor*& OutEffectCauser) const; + + /** Called when this ability is granted to the ability system component. */ + UFUNCTION(BlueprintImplementableEvent, Category = Ability, DisplayName = "OnAbilityAdded") + void K2_OnAbilityAdded(); + + /** Called when this ability is removed from the ability system component. */ + UFUNCTION(BlueprintImplementableEvent, Category = Ability, DisplayName = "OnAbilityRemoved") + void K2_OnAbilityRemoved(); + + /** Called when the ability system is initialized with a pawn avatar. */ + UFUNCTION(BlueprintImplementableEvent, Category = Ability, DisplayName = "OnPawnAvatarSet") + void K2_OnPawnAvatarSet(); + +protected: + + // Defines how this ability is meant to activate. + UPROPERTY(EditDefaultsOnly, BlueprintReadOnly, Category = "ALS|Ability Activation") + EALSAbilityActivationPolicy ActivationPolicy; + + // Defines the relationship between this ability activating and other abilities activating. + UPROPERTY(EditDefaultsOnly, BlueprintReadOnly, Category = "ALS|Ability Activation") + EALSAbilityActivationGroup ActivationGroup; + + // Additional costs that must be paid to activate this ability + UPROPERTY(EditDefaultsOnly, Instanced, Category = Costs) + TArray> AdditionalCosts; + + // Map of failure tags to simple error messages + UPROPERTY(EditDefaultsOnly, Category = "Advanced") + TMap FailureTagToUserFacingMessages; + + // Map of failure tags to anim montages that should be played with them + UPROPERTY(EditDefaultsOnly, Category = "Advanced") + TMap FailureTagToAnimMontage; + + // Current camera mode set by the ability. + TSubclassOf ActiveCameraMode; +}; From 56ca87ff1898e1d15e04f2f1790420697d18355b Mon Sep 17 00:00:00 2001 From: Helcio Laurentino do Carmo Junior Date: Mon, 1 May 2023 18:26:38 -0300 Subject: [PATCH 05/17] feat: Add GameplayTags class --- Source/ALSV4_CPP/Private/ALSGameplayTags.cpp | 100 +++++++++++++++++++ Source/ALSV4_CPP/Public/ALSGameplayTags.h | 91 +++++++++++++++++ 2 files changed, 191 insertions(+) create mode 100644 Source/ALSV4_CPP/Private/ALSGameplayTags.cpp create mode 100644 Source/ALSV4_CPP/Public/ALSGameplayTags.h diff --git a/Source/ALSV4_CPP/Private/ALSGameplayTags.cpp b/Source/ALSV4_CPP/Private/ALSGameplayTags.cpp new file mode 100644 index 00000000..71de6d73 --- /dev/null +++ b/Source/ALSV4_CPP/Private/ALSGameplayTags.cpp @@ -0,0 +1,100 @@ +#include "ALSGameplayTags.h" +#include "ALSLogChannels.h" +#include "GameplayTagsManager.h" +#include "Engine/EngineTypes.h" + +FALSGameplayTags FALSGameplayTags::GameplayTags; + +void FALSGameplayTags::InitializeNativeTags() +{ + UE_LOG(LogTemp, Warning, TEXT("FALSGameplayTags::InitializeNativeTags")) + UGameplayTagsManager& Manager = UGameplayTagsManager::Get(); + + GameplayTags.AddAllTags(Manager); + + // Notify manager that we are done adding native tags. + Manager.DoneAddingNativeTags(); +} + +void FALSGameplayTags::AddAllTags(UGameplayTagsManager& Manager) +{ + AddTag(Ability_ActivateFail_IsDead, "Ability.ActivateFail.IsDead", "Ability failed to activate because its owner is dead."); + AddTag(Ability_ActivateFail_Cooldown, "Ability.ActivateFail.Cooldown", "Ability failed to activate because it is on cool down."); + AddTag(Ability_ActivateFail_Cost, "Ability.ActivateFail.Cost", "Ability failed to activate because it did not pass the cost checks."); + AddTag(Ability_ActivateFail_TagsBlocked, "Ability.ActivateFail.TagsBlocked", "Ability failed to activate because tags are blocking it."); + AddTag(Ability_ActivateFail_TagsMissing, "Ability.ActivateFail.TagsMissing", "Ability failed to activate because tags are missing."); + AddTag(Ability_ActivateFail_Networking, "Ability.ActivateFail.Networking", "Ability failed to activate because it did not pass the network checks."); + AddTag(Ability_ActivateFail_ActivationGroup, "Ability.ActivateFail.ActivationGroup", "Ability failed to activate because of its activation group."); + + AddTag(Ability_Behavior_SurvivesDeath, "Ability.Behavior.SurvivesDeath", "An ability with this type tag should not be canceled due to death."); + + AddTag(InputTag_Move, "InputTag.Move", "Move input."); + AddTag(InputTag_Look_Mouse, "InputTag.Look.Mouse", "Look (mouse) input."); + AddTag(InputTag_Look_Stick, "InputTag.Look.Stick", "Look (stick) input."); + AddTag(InputTag_Crouch, "InputTag.Crouch", "Crouch input."); + AddTag(InputTag_AutoRun, "InputTag.AutoRun", "Auto-run input."); + + AddTag(GameplayEvent_Death, "GameplayEvent.Death", "Event that fires on death. This event only fires on the server."); + AddTag(GameplayEvent_Reset, "GameplayEvent.Reset", "Event that fires once a player reset is executed."); + AddTag(GameplayEvent_RequestReset, "GameplayEvent.RequestReset", "Event to request a player's pawn to be instantly replaced with a new one at a valid spawn location."); + + AddTag(SetByCaller_Damage, "SetByCaller.Damage", "SetByCaller tag used by damage gameplay effects."); + AddTag(SetByCaller_Heal, "SetByCaller.Heal", "SetByCaller tag used by healing gameplay effects."); + + AddTag(Cheat_GodMode, "Cheat.GodMode", "GodMode cheat is active on the owner."); + AddTag(Cheat_UnlimitedHealth, "Cheat.UnlimitedHealth", "UnlimitedHealth cheat is active on the owner."); + + AddTag(Status_Crouching, "Status.Crouching", "Target is crouching."); + AddTag(Status_AutoRunning, "Status.AutoRunning", "Target is auto-running."); + AddTag(Status_Death, "Status.Death", "Target has the death status."); + AddTag(Status_Death_Dying, "Status.Death.Dying", "Target has begun the death process."); + AddTag(Status_Death_Dead, "Status.Death.Dead", "Target has finished the death process."); + + AddMovementModeTag(Movement_Mode_Walking, "Movement.Mode.Walking", MOVE_Walking); + AddMovementModeTag(Movement_Mode_NavWalking, "Movement.Mode.NavWalking", MOVE_NavWalking); + AddMovementModeTag(Movement_Mode_Falling, "Movement.Mode.Falling", MOVE_Falling); + AddMovementModeTag(Movement_Mode_Swimming, "Movement.Mode.Swimming", MOVE_Swimming); + AddMovementModeTag(Movement_Mode_Flying, "Movement.Mode.Flying", MOVE_Flying); + AddMovementModeTag(Movement_Mode_Custom, "Movement.Mode.Custom", MOVE_Custom); +} + +void FALSGameplayTags::AddTag(FGameplayTag& OutTag, const ANSICHAR* TagName, const ANSICHAR* TagComment) +{ + OutTag = UGameplayTagsManager::Get().AddNativeGameplayTag(FName(TagName), FString(TEXT("(Native) ")) + FString(TagComment)); +} + +void FALSGameplayTags::AddMovementModeTag(FGameplayTag& OutTag, const ANSICHAR* TagName, uint8 MovementMode) +{ + AddTag(OutTag, TagName, "Character movement mode tag."); + GameplayTags.MovementModeTagMap.Add(MovementMode, OutTag); +} + +void FALSGameplayTags::AddCustomMovementModeTag(FGameplayTag& OutTag, const ANSICHAR* TagName, uint8 CustomMovementMode) +{ + AddTag(OutTag, TagName, "Character custom movement mode tag."); + GameplayTags.CustomMovementModeTagMap.Add(CustomMovementMode, OutTag); +} + +FGameplayTag FALSGameplayTags::FindTagByString(FString TagString, bool bMatchPartialString) +{ + const UGameplayTagsManager& Manager = UGameplayTagsManager::Get(); + FGameplayTag Tag = Manager.RequestGameplayTag(FName(*TagString), false); + + if (!Tag.IsValid() && bMatchPartialString) + { + FGameplayTagContainer AllTags; + Manager.RequestAllGameplayTags(AllTags, true); + + for (const FGameplayTag TestTag : AllTags) + { + if (TestTag.ToString().Contains(TagString)) + { + UE_LOG(LogALS, Display, TEXT("Could not find exact match for tag [%s] but found partial match on tag [%s]."), *TagString, *TestTag.ToString()); + Tag = TestTag; + break; + } + } + } + + return Tag; +} diff --git a/Source/ALSV4_CPP/Public/ALSGameplayTags.h b/Source/ALSV4_CPP/Public/ALSGameplayTags.h new file mode 100644 index 00000000..c034a75f --- /dev/null +++ b/Source/ALSV4_CPP/Public/ALSGameplayTags.h @@ -0,0 +1,91 @@ +#pragma once + +#include "CoreMinimal.h" +#include "GameplayTagContainer.h" + +class UGameplayTagsManager; + +/** + * FALSGameplayTags + * + * Singleton containing native gameplay tags. + */ +struct ALSV4_CPP_API FALSGameplayTags +{ +public: + + static const FALSGameplayTags& Get() { return GameplayTags; } + + static void InitializeNativeTags(); + + static FGameplayTag FindTagByString(FString TagString, bool bMatchPartialString = false); + +public: + + FGameplayTag Ability_ActivateFail_IsDead; + FGameplayTag Ability_ActivateFail_Cooldown; + FGameplayTag Ability_ActivateFail_Cost; + FGameplayTag Ability_ActivateFail_TagsBlocked; + FGameplayTag Ability_ActivateFail_TagsMissing; + FGameplayTag Ability_ActivateFail_Networking; + FGameplayTag Ability_ActivateFail_ActivationGroup; + + FGameplayTag Ability_Behavior_SurvivesDeath; + + FGameplayTag InputTag_Move; + FGameplayTag InputTag_Look_Mouse; + FGameplayTag InputTag_Look_Stick; + FGameplayTag InputTag_Crouch; + FGameplayTag InputTag_AutoRun; + + // Initialization states for the GameFrameworkComponentManager, these are registered in order by LyraGameInstance and some actors will skip right to GameplayReady + + /** Actor/component has initially spawned and can be extended */ + FGameplayTag InitState_Spawned; + + /** All required data has been loaded/replicated and is ready for initialization */ + FGameplayTag InitState_DataAvailable; + + /** The available data has been initialized for this actor/component, but it is not ready for full gameplay */ + FGameplayTag InitState_DataInitialized; + + /** The actor/component is fully ready for active gameplay */ + FGameplayTag InitState_GameplayReady; + + FGameplayTag GameplayEvent_Death; + FGameplayTag GameplayEvent_Reset; + FGameplayTag GameplayEvent_RequestReset; + + FGameplayTag SetByCaller_Damage; + FGameplayTag SetByCaller_Heal; + + FGameplayTag Cheat_GodMode; + FGameplayTag Cheat_UnlimitedHealth; + + FGameplayTag Status_Crouching; + FGameplayTag Status_AutoRunning; + FGameplayTag Status_Death; + FGameplayTag Status_Death_Dying; + FGameplayTag Status_Death_Dead; + + FGameplayTag Movement_Mode_Walking; + FGameplayTag Movement_Mode_NavWalking; + FGameplayTag Movement_Mode_Falling; + FGameplayTag Movement_Mode_Swimming; + FGameplayTag Movement_Mode_Flying; + FGameplayTag Movement_Mode_Custom; + + TMap MovementModeTagMap; + TMap CustomMovementModeTagMap; + +protected: + + void AddAllTags(UGameplayTagsManager& Manager); + void AddTag(FGameplayTag& OutTag, const ANSICHAR* TagName, const ANSICHAR* TagComment); + void AddMovementModeTag(FGameplayTag& OutTag, const ANSICHAR* TagName, uint8 MovementMode); + void AddCustomMovementModeTag(FGameplayTag& OutTag, const ANSICHAR* TagName, uint8 CustomMovementMode); + +private: + + static FALSGameplayTags GameplayTags; +}; \ No newline at end of file From 006e784da232d0e98c47639d8600d5095e0dbf14 Mon Sep 17 00:00:00 2001 From: Helcio Laurentino do Carmo Junior Date: Mon, 1 May 2023 18:26:52 -0300 Subject: [PATCH 06/17] feat: Add LogChannel class --- Source/ALSV4_CPP/Private/ALSLogChannels.cpp | 37 +++++++++++++++++++++ Source/ALSV4_CPP/Public/ALSLogChannels.h | 10 ++++++ 2 files changed, 47 insertions(+) create mode 100644 Source/ALSV4_CPP/Private/ALSLogChannels.cpp create mode 100644 Source/ALSV4_CPP/Public/ALSLogChannels.h diff --git a/Source/ALSV4_CPP/Private/ALSLogChannels.cpp b/Source/ALSV4_CPP/Private/ALSLogChannels.cpp new file mode 100644 index 00000000..020029c3 --- /dev/null +++ b/Source/ALSV4_CPP/Private/ALSLogChannels.cpp @@ -0,0 +1,37 @@ +#include "ALSLogChannels.h" +#include "GameFramework/Actor.h" + +DEFINE_LOG_CATEGORY(LogALS); +DEFINE_LOG_CATEGORY(LogALSAbilitySystem); +DEFINE_LOG_CATEGORY(LogALSExperience); + +FString GetClientServerContextString(UObject* ContextObject) +{ + ENetRole Role = ROLE_None; + + if (AActor* Actor = Cast(ContextObject)) + { + Role = Actor->GetLocalRole(); + } + else if (UActorComponent* Component = Cast(ContextObject)) + { + Role = Component->GetOwnerRole(); + } + + if (Role != ROLE_None) + { + return (Role == ROLE_Authority) ? TEXT("Server") : TEXT("Client"); + } + else + { +#if WITH_EDITOR + if (GIsEditor) + { + extern ENGINE_API FString GPlayInEditorContextString; + return GPlayInEditorContextString; + } +#endif + } + + return TEXT("[]"); +} diff --git a/Source/ALSV4_CPP/Public/ALSLogChannels.h b/Source/ALSV4_CPP/Public/ALSLogChannels.h new file mode 100644 index 00000000..af6cec6a --- /dev/null +++ b/Source/ALSV4_CPP/Public/ALSLogChannels.h @@ -0,0 +1,10 @@ +#pragma once + +#include "CoreMinimal.h" +#include "Logging/LogMacros.h" + +ALSV4_CPP_API DECLARE_LOG_CATEGORY_EXTERN(LogALS, Log, All); +ALSV4_CPP_API DECLARE_LOG_CATEGORY_EXTERN(LogALSAbilitySystem, Log, All); +ALSV4_CPP_API DECLARE_LOG_CATEGORY_EXTERN(LogALSExperience, Log, All); + +ALSV4_CPP_API FString GetClientServerContextString(UObject* ContextObject = nullptr); From f9c458c438058a4698d6e733936346d0cacd76bb Mon Sep 17 00:00:00 2001 From: Helcio Laurentino do Carmo Junior Date: Mon, 1 May 2023 18:27:49 -0300 Subject: [PATCH 07/17] feat: Add Camera classes --- .../Private/Camera/ALSCameraComponent.cpp | 8 +++++ .../Private/Camera/ALSCameraMode.cpp | 4 +++ .../Public/Camera/ALSCameraComponent.h | 30 +++++++++++++++++++ .../ALSV4_CPP/Public/Camera/ALSCameraMode.h | 16 ++++++++++ 4 files changed, 58 insertions(+) create mode 100644 Source/ALSV4_CPP/Private/Camera/ALSCameraComponent.cpp create mode 100644 Source/ALSV4_CPP/Private/Camera/ALSCameraMode.cpp create mode 100644 Source/ALSV4_CPP/Public/Camera/ALSCameraComponent.h create mode 100644 Source/ALSV4_CPP/Public/Camera/ALSCameraMode.h diff --git a/Source/ALSV4_CPP/Private/Camera/ALSCameraComponent.cpp b/Source/ALSV4_CPP/Private/Camera/ALSCameraComponent.cpp new file mode 100644 index 00000000..bd94bf57 --- /dev/null +++ b/Source/ALSV4_CPP/Private/Camera/ALSCameraComponent.cpp @@ -0,0 +1,8 @@ +// Fill out your copyright notice in the Description page of Project Settings. + + +#include "Camera/ALSCameraComponent.h" + +UALSCameraComponent::UALSCameraComponent(const FObjectInitializer& ObjectInitializer) +{ +} diff --git a/Source/ALSV4_CPP/Private/Camera/ALSCameraMode.cpp b/Source/ALSV4_CPP/Private/Camera/ALSCameraMode.cpp new file mode 100644 index 00000000..4d0829ba --- /dev/null +++ b/Source/ALSV4_CPP/Private/Camera/ALSCameraMode.cpp @@ -0,0 +1,4 @@ +// Fill out your copyright notice in the Description page of Project Settings. + + +#include "Camera/ALSCameraMode.h" diff --git a/Source/ALSV4_CPP/Public/Camera/ALSCameraComponent.h b/Source/ALSV4_CPP/Public/Camera/ALSCameraComponent.h new file mode 100644 index 00000000..2ff04834 --- /dev/null +++ b/Source/ALSV4_CPP/Public/Camera/ALSCameraComponent.h @@ -0,0 +1,30 @@ +// Fill out your copyright notice in the Description page of Project Settings. + +#pragma once + +#include "CoreMinimal.h" +#include "Camera/CameraComponent.h" +#include "ALSCameraComponent.generated.h" + +class UALSCameraMode; + +DECLARE_DELEGATE_RetVal(TSubclassOf, FALSCameraModeDelegate); + +/** + * + */ +UCLASS() +class ALSV4_CPP_API UALSCameraComponent : public UCameraComponent +{ + GENERATED_BODY() + +public: + UALSCameraComponent(const FObjectInitializer& ObjectInitializer); + + // Returns the camera component if one exists on the specified actor. + UFUNCTION(BlueprintPure, Category = "ALS|Camera") + static UALSCameraComponent* FindCameraComponent(const AActor* Actor) { return (Actor ? Actor->FindComponentByClass() : nullptr); } + + // Delegate used to query for the best camera mode. + FALSCameraModeDelegate DetermineCameraModeDelegate; +}; diff --git a/Source/ALSV4_CPP/Public/Camera/ALSCameraMode.h b/Source/ALSV4_CPP/Public/Camera/ALSCameraMode.h new file mode 100644 index 00000000..7fa58c73 --- /dev/null +++ b/Source/ALSV4_CPP/Public/Camera/ALSCameraMode.h @@ -0,0 +1,16 @@ +// Fill out your copyright notice in the Description page of Project Settings. + +#pragma once + +#include "CoreMinimal.h" +#include "UObject/Object.h" +#include "ALSCameraMode.generated.h" + +/** + * + */ +UCLASS() +class ALSV4_CPP_API UALSCameraMode : public UObject +{ + GENERATED_BODY() +}; From 73e4be935d16273f2672bb6ba117aa9dbeb45d4d Mon Sep 17 00:00:00 2001 From: Helcio Laurentino do Carmo Junior Date: Mon, 1 May 2023 18:28:21 -0300 Subject: [PATCH 08/17] feat: Add Input classes --- .../Private/Input/ALSInputComponent.cpp | 104 ++++++++++++++++++ .../Private/Input/ALSInputConfig.cpp | 46 ++++++++ .../Private/Input/ALSMappableConfigPair.cpp | 90 +++++++++++++++ .../Public/Input/ALSInputComponent.h | 73 ++++++++++++ .../ALSV4_CPP/Public/Input/ALSInputConfig.h | 56 ++++++++++ .../Public/Input/ALSMappableConfigPair.h | 94 ++++++++++++++++ 6 files changed, 463 insertions(+) create mode 100644 Source/ALSV4_CPP/Private/Input/ALSInputComponent.cpp create mode 100644 Source/ALSV4_CPP/Private/Input/ALSInputConfig.cpp create mode 100644 Source/ALSV4_CPP/Private/Input/ALSMappableConfigPair.cpp create mode 100644 Source/ALSV4_CPP/Public/Input/ALSInputComponent.h create mode 100644 Source/ALSV4_CPP/Public/Input/ALSInputConfig.h create mode 100644 Source/ALSV4_CPP/Public/Input/ALSMappableConfigPair.h diff --git a/Source/ALSV4_CPP/Private/Input/ALSInputComponent.cpp b/Source/ALSV4_CPP/Private/Input/ALSInputComponent.cpp new file mode 100644 index 00000000..0a657903 --- /dev/null +++ b/Source/ALSV4_CPP/Private/Input/ALSInputComponent.cpp @@ -0,0 +1,104 @@ +// Fill out your copyright notice in the Description page of Project Settings. + + +#include "Input/ALSInputComponent.h" +#include "Player/ALSLocalPlayer.h" +#include "EnhancedInputSubsystems.h" +#include "Settings/ALSSettingsLocal.h" +#include "PlayerMappableInputConfig.h" + +UALSInputComponent::UALSInputComponent(const FObjectInitializer& ObjectInitializer) +{ +} + +void UALSInputComponent::AddInputMappings(const UALSInputConfig* InputConfig, UEnhancedInputLocalPlayerSubsystem* InputSubsystem) const +{ + check(InputConfig); + check(InputSubsystem); + + UALSLocalPlayer* LocalPlayer = InputSubsystem->GetLocalPlayer(); + check(LocalPlayer); + + // Add any registered input mappings from the settings! + if (UALSSettingsLocal* LocalSettings = UALSSettingsLocal::Get()) + { + // We don't want to ignore keys that were "Down" when we add the mapping context + // This allows you to die holding a movement key, keep holding while waiting for respawn, + // and have it be applied after you respawn immediately. Leaving bIgnoreAllPressedKeysUntilRelease + // to it's default "true" state would require the player to release the movement key, + // and press it again when they respawn + FModifyContextOptions Options = {}; + Options.bIgnoreAllPressedKeysUntilRelease = false; + + // Add all registered configs, which will add every input mapping context that is in it + const TArray& Configs = LocalSettings->GetAllRegisteredInputConfigs(); + for (const FLoadedMappableConfigPair& Pair : Configs) + { + if (Pair.bIsActive) + { + InputSubsystem->AddPlayerMappableConfig(Pair.Config, Options); + } + } + + // Tell enhanced input about any custom keymappings that we have set + for (const TPair& Pair : LocalSettings->GetCustomPlayerInputConfig()) + { + if (Pair.Key != NAME_None && Pair.Value.IsValid()) + { + InputSubsystem->AddPlayerMappedKey(Pair.Key, Pair.Value); + } + } + } +} + +void UALSInputComponent::RemoveInputMappings(const UALSInputConfig* InputConfig, UEnhancedInputLocalPlayerSubsystem* InputSubsystem) const +{ + check(InputConfig); + check(InputSubsystem); + + UALSLocalPlayer* LocalPlayer = InputSubsystem->GetLocalPlayer(); + check(LocalPlayer); + + if (UALSSettingsLocal* LocalSettings = UALSSettingsLocal::Get()) + { + // Remove any registered input contexts + const TArray& Configs = LocalSettings->GetAllRegisteredInputConfigs(); + for (const FLoadedMappableConfigPair& Pair : Configs) + { + InputSubsystem->RemovePlayerMappableConfig(Pair.Config); + } + + // Clear any player mapped keys from enhanced input + for (const TPair& Pair : LocalSettings->GetCustomPlayerInputConfig()) + { + InputSubsystem->RemovePlayerMappedKey(Pair.Key); + } + } +} + +void UALSInputComponent::RemoveBinds(TArray& BindHandles) +{ + for (uint32 Handle : BindHandles) + { + RemoveBindingByHandle(Handle); + } + BindHandles.Reset(); +} + +void UALSInputComponent::AddInputConfig(const FLoadedMappableConfigPair& ConfigPair, UEnhancedInputLocalPlayerSubsystem* InputSubsystem) +{ + check(InputSubsystem); + if (ensure(ConfigPair.bIsActive)) + { + InputSubsystem->AddPlayerMappableConfig(ConfigPair.Config); + } +} + +void UALSInputComponent::RemoveInputConfig(const FLoadedMappableConfigPair& ConfigPair, UEnhancedInputLocalPlayerSubsystem* InputSubsystem) +{ + check(InputSubsystem); + if (!ConfigPair.bIsActive) + { + InputSubsystem->AddPlayerMappableConfig(ConfigPair.Config); + } +} diff --git a/Source/ALSV4_CPP/Private/Input/ALSInputConfig.cpp b/Source/ALSV4_CPP/Private/Input/ALSInputConfig.cpp new file mode 100644 index 00000000..9b0b9b7e --- /dev/null +++ b/Source/ALSV4_CPP/Private/Input/ALSInputConfig.cpp @@ -0,0 +1,46 @@ +// Fill out your copyright notice in the Description page of Project Settings. + + +#include "Input/ALSInputConfig.h" + +#include "ALSLogChannels.h" + +UALSInputConfig::UALSInputConfig(const FObjectInitializer& ObjectInitializer) +{ +} + +const UInputAction* UALSInputConfig::FindNativeInputActionForTag(const FGameplayTag& InputTag, bool bLogNotFound) const +{ + for (const FALSInputAction& Action : NativeInputActions) + { + if (Action.InputAction && (Action.InputTag == InputTag)) + { + return Action.InputAction; + } + } + + if (bLogNotFound) + { + UE_LOG(LogALS, Error, TEXT("Can't find NativeInputAction for InputTag [%s] on InputConfig [%s]."), *InputTag.ToString(), *GetNameSafe(this)); + } + + return nullptr; +} + +const UInputAction* UALSInputConfig::FindAbilityInputActionForTag(const FGameplayTag& InputTag, bool bLogNotFound) const +{ + for (const FALSInputAction& Action : AbilityInputActions) + { + if (Action.InputAction && (Action.InputTag == InputTag)) + { + return Action.InputAction; + } + } + + if (bLogNotFound) + { + UE_LOG(LogALS, Error, TEXT("Can't find AbilityInputAction for InputTag [%s] on InputConfig [%s]."), *InputTag.ToString(), *GetNameSafe(this)); + } + + return nullptr; +} \ No newline at end of file diff --git a/Source/ALSV4_CPP/Private/Input/ALSMappableConfigPair.cpp b/Source/ALSV4_CPP/Private/Input/ALSMappableConfigPair.cpp new file mode 100644 index 00000000..7aefc7c2 --- /dev/null +++ b/Source/ALSV4_CPP/Private/Input/ALSMappableConfigPair.cpp @@ -0,0 +1,90 @@ +#include "Input/ALSMappableConfigPair.h" + +#include "System/ALSAssetManager.h" +#include "Settings/ALSSettingsLocal.h" +#include "ICommonUIModule.h" +#include "CommonUISettings.h" +#include "PlayerMappableInputConfig.h" + +#include UE_INLINE_GENERATED_CPP_BY_NAME(ALSMappableConfigPair) + +bool FMappableConfigPair::CanBeActivated() const +{ + const FGameplayTagContainer& PlatformTraits = ICommonUIModule::GetSettings().GetPlatformTraits(); + + // If the current platform does NOT have all the dependent traits, then don't activate it + if (!DependentPlatformTraits.IsEmpty() && !PlatformTraits.HasAll(DependentPlatformTraits)) + { + return false; + } + + // If the platform has any of the excluded traits, then we shouldn't activate this config. + if (!ExcludedPlatformTraits.IsEmpty() && PlatformTraits.HasAny(ExcludedPlatformTraits)) + { + return false; + } + + return true; +} + +bool FMappableConfigPair::RegisterPair(const FMappableConfigPair& Pair) +{ + UALSAssetManager& AssetManager = UALSAssetManager::Get(); + + if (UALSSettingsLocal* Settings = UALSSettingsLocal::Get()) + { + // Register the pair with the settings, but do not activate it yet + if (const UPlayerMappableInputConfig* LoadedConfig = AssetManager.GetAsset(Pair.Config)) + { + Settings->RegisterInputConfig(Pair.Type, LoadedConfig, false); + return true; + } + } + + return false; +} + +bool FMappableConfigPair::ActivatePair(const FMappableConfigPair& Pair) +{ + UALSAssetManager& AssetManager = UALSAssetManager::Get(); + // Only activate a pair that has been successfully registered + if (FMappableConfigPair::RegisterPair(Pair) && Pair.CanBeActivated()) + { + if (UALSSettingsLocal* Settings = UALSSettingsLocal::Get()) + { + if (const UPlayerMappableInputConfig* LoadedConfig = AssetManager.GetAsset(Pair.Config)) + { + Settings->ActivateInputConfig(LoadedConfig); + return true; + } + } + } + return false; +} + +void FMappableConfigPair::DeactivatePair(const FMappableConfigPair& Pair) +{ + UALSAssetManager& AssetManager = UALSAssetManager::Get(); + + if (UALSSettingsLocal* Settings = UALSSettingsLocal::Get()) + { + if (const UPlayerMappableInputConfig* LoadedConfig = AssetManager.GetAsset(Pair.Config)) + { + Settings->DeactivateInputConfig(LoadedConfig); + } + } +} + +void FMappableConfigPair::UnregisterPair(const FMappableConfigPair& Pair) +{ + UALSAssetManager& AssetManager = UALSAssetManager::Get(); + + if (UALSSettingsLocal* Settings = UALSSettingsLocal::Get()) + { + if (const UPlayerMappableInputConfig* LoadedConfig = AssetManager.GetAsset(Pair.Config)) + { + Settings->UnregisterInputConfig(LoadedConfig); + } + } +} + diff --git a/Source/ALSV4_CPP/Public/Input/ALSInputComponent.h b/Source/ALSV4_CPP/Public/Input/ALSInputComponent.h new file mode 100644 index 00000000..429601b7 --- /dev/null +++ b/Source/ALSV4_CPP/Public/Input/ALSInputComponent.h @@ -0,0 +1,73 @@ +// Fill out your copyright notice in the Description page of Project Settings. + +#pragma once + +#include "CoreMinimal.h" +#include "EnhancedInputComponent.h" +#include "EnhancedInputSubsystems.h" +#include "ALSInputConfig.h" +#include "GameplayTagContainer.h" +#include "Input/ALSMappableConfigPair.h" +#include "ALSInputComponent.generated.h" + +/** + * UALSInputComponent + * + * Component used to manage input mappings and bindings using an input config data asset. + */ +UCLASS(Config = Input) +class ALSV4_CPP_API UALSInputComponent : public UEnhancedInputComponent +{ + GENERATED_BODY() + +public: + + UALSInputComponent(const FObjectInitializer& ObjectInitializer); + + void AddInputMappings(const UALSInputConfig* InputConfig, UEnhancedInputLocalPlayerSubsystem* InputSubsystem) const; + void RemoveInputMappings(const UALSInputConfig* InputConfig, UEnhancedInputLocalPlayerSubsystem* InputSubsystem) const; + + template + void BindNativeAction(const UALSInputConfig* InputConfig, const FGameplayTag& InputTag, ETriggerEvent TriggerEvent, UserClass* Object, FuncType Func, bool bLogIfNotFound); + + template + void BindAbilityActions(const UALSInputConfig* InputConfig, UserClass* Object, PressedFuncType PressedFunc, ReleasedFuncType ReleasedFunc, TArray& BindHandles); + + void RemoveBinds(TArray& BindHandles); + + void AddInputConfig(const FLoadedMappableConfigPair& ConfigPair, UEnhancedInputLocalPlayerSubsystem* InputSubsystem); + void RemoveInputConfig(const FLoadedMappableConfigPair& ConfigPair, UEnhancedInputLocalPlayerSubsystem* InputSubsystem); +}; + + +template +void UALSInputComponent::BindNativeAction(const UALSInputConfig* InputConfig, const FGameplayTag& InputTag, ETriggerEvent TriggerEvent, UserClass* Object, FuncType Func, bool bLogIfNotFound) +{ + check(InputConfig); + if (const UInputAction* IA = InputConfig->FindNativeInputActionForTag(InputTag, bLogIfNotFound)) + { + BindAction(IA, TriggerEvent, Object, Func); + } +} + +template +void UALSInputComponent::BindAbilityActions(const UALSInputConfig* InputConfig, UserClass* Object, PressedFuncType PressedFunc, ReleasedFuncType ReleasedFunc, TArray& BindHandles) +{ + check(InputConfig); + + for (const FALSInputAction& Action : InputConfig->AbilityInputActions) + { + if (Action.InputAction && Action.InputTag.IsValid()) + { + if (PressedFunc) + { + BindHandles.Add(BindAction(Action.InputAction, ETriggerEvent::Triggered, Object, PressedFunc, Action.InputTag).GetHandle()); + } + + if (ReleasedFunc) + { + BindHandles.Add(BindAction(Action.InputAction, ETriggerEvent::Completed, Object, ReleasedFunc, Action.InputTag).GetHandle()); + } + } + } +} diff --git a/Source/ALSV4_CPP/Public/Input/ALSInputConfig.h b/Source/ALSV4_CPP/Public/Input/ALSInputConfig.h new file mode 100644 index 00000000..c161d60a --- /dev/null +++ b/Source/ALSV4_CPP/Public/Input/ALSInputConfig.h @@ -0,0 +1,56 @@ +// Fill out your copyright notice in the Description page of Project Settings. + +#pragma once + +#include "CoreMinimal.h" +#include "Engine/DataAsset.h" +#include "GameplayTagContainer.h" +#include "ALSInputConfig.generated.h" + +class UInputAction; +class UInputMappingContext; +class UALSLocalPlayer; + +/** + * FALSInputAction + * + * Struct used to map a input action to a gameplay input tag. + */ +USTRUCT(BlueprintType) +struct FALSInputAction +{ + GENERATED_BODY() + +public: + + UPROPERTY(EditDefaultsOnly) + const UInputAction* InputAction = nullptr; + + UPROPERTY(EditDefaultsOnly, Meta = (Categories = "InputTag")) + FGameplayTag InputTag; +}; + + +/** + * + */ +UCLASS() +class ALSV4_CPP_API UALSInputConfig : public UDataAsset +{ + GENERATED_BODY() +public: + + UALSInputConfig(const FObjectInitializer& ObjectInitializer); + + const UInputAction* FindNativeInputActionForTag(const FGameplayTag& InputTag, bool bLogNotFound = true) const; + const UInputAction* FindAbilityInputActionForTag(const FGameplayTag& InputTag, bool bLogNotFound = true) const; + +public: + // List of input actions used by the owner. These input actions are mapped to a gameplay tag and must be manually bound. + UPROPERTY(EditDefaultsOnly, BlueprintReadOnly, Meta = (TitleProperty = "InputAction")) + TArray NativeInputActions; + + // List of input actions used by the owner. These input actions are mapped to a gameplay tag and are automatically bound to abilities with matching input tags. + UPROPERTY(EditDefaultsOnly, BlueprintReadOnly, Meta = (TitleProperty = "InputAction")) + TArray AbilityInputActions; +}; diff --git a/Source/ALSV4_CPP/Public/Input/ALSMappableConfigPair.h b/Source/ALSV4_CPP/Public/Input/ALSMappableConfigPair.h new file mode 100644 index 00000000..a178cf26 --- /dev/null +++ b/Source/ALSV4_CPP/Public/Input/ALSMappableConfigPair.h @@ -0,0 +1,94 @@ +#pragma once + +#include "CommonInputBaseTypes.h" +#include "GameplayTagContainer.h" + +#include "ALSMappableConfigPair.generated.h" + +class UPlayerMappableInputConfig; + +/** A container to organize loaded player mappable configs to their CommonUI input type */ +USTRUCT(BlueprintType) +struct FLoadedMappableConfigPair +{ + GENERATED_BODY() + + FLoadedMappableConfigPair() = default; + FLoadedMappableConfigPair(const UPlayerMappableInputConfig* InConfig, ECommonInputType InType, const bool InIsActive) + : Config(InConfig) + , Type(InType) + , bIsActive(InIsActive) + {} + + /** The player mappable input config that should be applied to the Enhanced Input subsystem */ + UPROPERTY(BlueprintReadOnly, VisibleAnywhere) + const UPlayerMappableInputConfig* Config = nullptr; + + /** The type of device that this mapping config should be applied to */ + UPROPERTY(BlueprintReadOnly, VisibleAnywhere) + ECommonInputType Type = ECommonInputType::Count; + + /** If this config is currently active. A config is marked as active when it's owning GFA is active */ + UPROPERTY(BlueprintReadOnly, VisibleAnywhere) + bool bIsActive = false; +}; + +/** A container to organize potentially unloaded player mappable configs to their CommonUI input type */ +USTRUCT() +struct ALSV4_CPP_API FMappableConfigPair +{ + GENERATED_BODY() + +public: + FMappableConfigPair() = default; + + UPROPERTY(EditAnywhere) + TSoftObjectPtr Config; + + /** + * The type of config that this is. Useful for filtering out configs by the current input device + * for things like the settings screen, or if you only want to apply this config when a certain + * input type is being used. + */ + UPROPERTY(EditAnywhere) + ECommonInputType Type = ECommonInputType::Count; + + /** + * Container of platform traits that must be set in order for this input to be activated. + * + * If the platform does not have one of the traits specified it can still be registered, but cannot + * be activated. + */ + UPROPERTY(EditAnywhere) + FGameplayTagContainer DependentPlatformTraits; + + /** + * If the current platform has any of these traits, then this config will not be actived. + */ + UPROPERTY(EditAnywhere) + FGameplayTagContainer ExcludedPlatformTraits; + + /** If true, then this input config will be activated when it's associated Game Feature is activated. + * This is normally the desirable behavior + */ + UPROPERTY(EditAnywhere) + bool bShouldActivateAutomatically = true; + + /** Returns true if this config pair can be activated based on the current platform traits and settings. */ + bool CanBeActivated() const; + + /** + * Registers the given config mapping with the settings + */ + static bool RegisterPair(const FMappableConfigPair& Pair); + + /** + * Activates the given config mapping in the settings. This will also register the mapping + * if it hasn't been yet. + */ + static bool ActivatePair(const FMappableConfigPair& Pair); + + static void DeactivatePair(const FMappableConfigPair& Pair); + + static void UnregisterPair(const FMappableConfigPair& Pair); +}; \ No newline at end of file From 4286abe2aab28a72b3cbb372ce139db818fe4c0b Mon Sep 17 00:00:00 2001 From: Helcio Laurentino do Carmo Junior Date: Mon, 1 May 2023 18:28:52 -0300 Subject: [PATCH 09/17] feat: Add GameMode classes --- .../GameModes/ALSExperienceActionSet.cpp | 57 +++ .../GameModes/ALSExperienceDefinition.cpp | 80 ++++ .../GameModes/ALSExperienceManager.cpp | 57 +++ .../ALSExperienceManagerComponent.cpp | 453 ++++++++++++++++++ .../Private/GameModes/ALSGameMode.cpp | 376 +++++++++++++++ .../Private/GameModes/ALSGameState.cpp | 101 ++++ .../Private/GameModes/ALSWorldSettings.cpp | 54 +++ .../Public/GameModes/ALSExperienceActionSet.h | 42 ++ .../GameModes/ALSExperienceDefinition.h | 53 ++ .../Public/GameModes/ALSExperienceManager.h | 32 ++ .../GameModes/ALSExperienceManagerComponent.h | 103 ++++ .../ALSV4_CPP/Public/GameModes/ALSGameMode.h | 87 ++++ .../ALSV4_CPP/Public/GameModes/ALSGameState.h | 80 ++++ .../Public/GameModes/ALSWorldSettings.h | 42 ++ 14 files changed, 1617 insertions(+) create mode 100644 Source/ALSV4_CPP/Private/GameModes/ALSExperienceActionSet.cpp create mode 100644 Source/ALSV4_CPP/Private/GameModes/ALSExperienceDefinition.cpp create mode 100644 Source/ALSV4_CPP/Private/GameModes/ALSExperienceManager.cpp create mode 100644 Source/ALSV4_CPP/Private/GameModes/ALSExperienceManagerComponent.cpp create mode 100644 Source/ALSV4_CPP/Private/GameModes/ALSGameMode.cpp create mode 100644 Source/ALSV4_CPP/Private/GameModes/ALSGameState.cpp create mode 100644 Source/ALSV4_CPP/Private/GameModes/ALSWorldSettings.cpp create mode 100644 Source/ALSV4_CPP/Public/GameModes/ALSExperienceActionSet.h create mode 100644 Source/ALSV4_CPP/Public/GameModes/ALSExperienceDefinition.h create mode 100644 Source/ALSV4_CPP/Public/GameModes/ALSExperienceManager.h create mode 100644 Source/ALSV4_CPP/Public/GameModes/ALSExperienceManagerComponent.h create mode 100644 Source/ALSV4_CPP/Public/GameModes/ALSGameMode.h create mode 100644 Source/ALSV4_CPP/Public/GameModes/ALSGameState.h create mode 100644 Source/ALSV4_CPP/Public/GameModes/ALSWorldSettings.h diff --git a/Source/ALSV4_CPP/Private/GameModes/ALSExperienceActionSet.cpp b/Source/ALSV4_CPP/Private/GameModes/ALSExperienceActionSet.cpp new file mode 100644 index 00000000..65dbdbd6 --- /dev/null +++ b/Source/ALSV4_CPP/Private/GameModes/ALSExperienceActionSet.cpp @@ -0,0 +1,57 @@ +// Fill out your copyright notice in the Description page of Project Settings. + + +#include "GameModes/ALSExperienceActionSet.h" +#include "GameFeatureAction.h" + +#include UE_INLINE_GENERATED_CPP_BY_NAME(ALSExperienceActionSet) + +#define LOCTEXT_NAMESPACE "ALSSystem" + +UALSExperienceActionSet::UALSExperienceActionSet() +{ +} + +#if WITH_EDITOR +EDataValidationResult UALSExperienceActionSet::IsDataValid(TArray& ValidationErrors) +{ + EDataValidationResult Result = CombineDataValidationResults(Super::IsDataValid(ValidationErrors), EDataValidationResult::Valid); + + int32 EntryIndex = 0; + for (UGameFeatureAction* Action : Actions) + { + if (Action) + { + EDataValidationResult ChildResult = Action->IsDataValid(ValidationErrors); + Result = CombineDataValidationResults(Result, ChildResult); + } + else + { + Result = EDataValidationResult::Invalid; + ValidationErrors.Add(FText::Format(LOCTEXT("ActionEntryIsNull", "Null entry at index {0} in Actions"), FText::AsNumber(EntryIndex))); + } + + ++EntryIndex; + } + + return Result; +} +#endif + +#if WITH_EDITORONLY_DATA +void UALSExperienceActionSet::UpdateAssetBundleData() +{ + Super::UpdateAssetBundleData(); + + for (UGameFeatureAction* Action : Actions) + { + if (Action) + { + Action->AddAdditionalAssetBundleData(AssetBundleData); + } + } +} +#endif // WITH_EDITORONLY_DATA + +#undef LOCTEXT_NAMESPACE + diff --git a/Source/ALSV4_CPP/Private/GameModes/ALSExperienceDefinition.cpp b/Source/ALSV4_CPP/Private/GameModes/ALSExperienceDefinition.cpp new file mode 100644 index 00000000..cfd08788 --- /dev/null +++ b/Source/ALSV4_CPP/Private/GameModes/ALSExperienceDefinition.cpp @@ -0,0 +1,80 @@ +// Fill out your copyright notice in the Description page of Project Settings. + + +#include "GameModes/ALSExperienceDefinition.h" +#include "GameFeatureAction.h" + +#include UE_INLINE_GENERATED_CPP_BY_NAME(ALSExperienceDefinition) + +#define LOCTEXT_NAMESPACE "ALSSystem" + +UALSExperienceDefinition::UALSExperienceDefinition() +{ +} + +#if WITH_EDITOR +EDataValidationResult UALSExperienceDefinition::IsDataValid(TArray& ValidationErrors) +{ + EDataValidationResult Result = CombineDataValidationResults(Super::IsDataValid(ValidationErrors), EDataValidationResult::Valid); + + int32 EntryIndex = 0; + for (UGameFeatureAction* Action : Actions) + { + if (Action) + { + EDataValidationResult ChildResult = Action->IsDataValid(ValidationErrors); + Result = CombineDataValidationResults(Result, ChildResult); + } + else + { + Result = EDataValidationResult::Invalid; + ValidationErrors.Add(FText::Format(LOCTEXT("ActionEntryIsNull", "Null entry at index {0} in Actions"), FText::AsNumber(EntryIndex))); + } + + ++EntryIndex; + } + + // Make sure users didn't subclass from a BP of this (it's fine and expected to subclass once in BP, just not twice) + if (!GetClass()->IsNative()) + { + UClass* ParentClass = GetClass()->GetSuperClass(); + + // Find the native parent + UClass* FirstNativeParent = ParentClass; + while ((FirstNativeParent != nullptr) && !FirstNativeParent->IsNative()) + { + FirstNativeParent = FirstNativeParent->GetSuperClass(); + } + + if (FirstNativeParent != ParentClass) + { + ValidationErrors.Add(FText::Format(LOCTEXT("ExperienceInheritenceIsUnsupported", "Blueprint subclasses of Blueprint experiences is not currently supported (use composition via ActionSets instead). Parent class was {0} but should be {1}."), + FText::AsCultureInvariant(GetPathNameSafe(ParentClass)), + FText::AsCultureInvariant(GetPathNameSafe(FirstNativeParent)) + )); + Result = EDataValidationResult::Invalid; + } + } + + return Result; +} +#endif + +#if WITH_EDITORONLY_DATA +void UALSExperienceDefinition::UpdateAssetBundleData() +{ + Super::UpdateAssetBundleData(); + + for (UGameFeatureAction* Action : Actions) + { + if (Action) + { + Action->AddAdditionalAssetBundleData(AssetBundleData); + } + } +} +#endif // WITH_EDITORONLY_DATA + +#undef LOCTEXT_NAMESPACE + + diff --git a/Source/ALSV4_CPP/Private/GameModes/ALSExperienceManager.cpp b/Source/ALSV4_CPP/Private/GameModes/ALSExperienceManager.cpp new file mode 100644 index 00000000..48dc734b --- /dev/null +++ b/Source/ALSV4_CPP/Private/GameModes/ALSExperienceManager.cpp @@ -0,0 +1,57 @@ +// Fill out your copyright notice in the Description page of Project Settings. + +// Copyright Epic Games, Inc. All Rights Reserved. + +#include "GameModes/ALSExperienceManager.h" +#include "Engine/AssetManager.h" +#include "GameModes/ALSExperienceDefinition.h" +#include "GameModes/ALSExperienceManager.h" +#include "Engine/Engine.h" + +#include UE_INLINE_GENERATED_CPP_BY_NAME(ALSExperienceManager) + +#if WITH_EDITOR + +void UALSExperienceManager::OnPlayInEditorBegun() +{ + ensure(GameFeaturePluginRequestCountMap.IsEmpty()); + GameFeaturePluginRequestCountMap.Empty(); +} + +void UALSExperienceManager::NotifyOfPluginActivation(const FString PluginURL) +{ + if (GIsEditor) + { + UALSExperienceManager* ExperienceManagerSubsystem = GEngine->GetEngineSubsystem(); + check(ExperienceManagerSubsystem); + + // Track the number of requesters who activate this plugin. Multiple load/activation requests are always allowed because concurrent requests are handled. + int32& Count = ExperienceManagerSubsystem->GameFeaturePluginRequestCountMap.FindOrAdd(PluginURL); + ++Count; + } +} + +bool UALSExperienceManager::RequestToDeactivatePlugin(const FString PluginURL) +{ + if (GIsEditor) + { + UALSExperienceManager* ExperienceManagerSubsystem = GEngine->GetEngineSubsystem(); + check(ExperienceManagerSubsystem); + + // Only let the last requester to get this far deactivate the plugin + int32& Count = ExperienceManagerSubsystem->GameFeaturePluginRequestCountMap.FindChecked(PluginURL); + --Count; + + if (Count == 0) + { + ExperienceManagerSubsystem->GameFeaturePluginRequestCountMap.Remove(PluginURL); + return true; + } + + return false; + } + + return true; +} + +#endif diff --git a/Source/ALSV4_CPP/Private/GameModes/ALSExperienceManagerComponent.cpp b/Source/ALSV4_CPP/Private/GameModes/ALSExperienceManagerComponent.cpp new file mode 100644 index 00000000..b9b6679f --- /dev/null +++ b/Source/ALSV4_CPP/Private/GameModes/ALSExperienceManagerComponent.cpp @@ -0,0 +1,453 @@ +// Copyright Epic Games, Inc. All Rights Reserved. + +#include "GameModes/ALSExperienceManagerComponent.h" +#include "Net/UnrealNetwork.h" +#include "GameModes/ALSExperienceDefinition.h" +#include "GameModes/ALSExperienceActionSet.h" +#include "GameModes/ALSExperienceManager.h" +#include "GameFeaturesSubsystem.h" +#include "System/ALSAssetManager.h" +#include "GameFeatureAction.h" +#include "GameFeaturesSubsystemSettings.h" +#include "TimerManager.h" +#include "ALSLogChannels.h" + +#include UE_INLINE_GENERATED_CPP_BY_NAME(ALSExperienceManagerComponent) + +//@TODO: Async load the experience definition itself +//@TODO: Handle failures explicitly (go into a 'completed but failed' state rather than check()-ing) +//@TODO: Do the action phases at the appropriate times instead of all at once +//@TODO: Support deactivating an experience and do the unloading actions +//@TODO: Think about what deactivation/cleanup means for preloaded assets +//@TODO: Handle deactivating game features, right now we 'leak' them enabled +// (for a client moving from experience to experience we actually want to diff the requirements and only unload some, not unload everything for them to just be immediately reloaded) +//@TODO: Handle both built-in and URL-based plugins (search for colon?) + +namespace ALSConsoleVariables +{ + static float ExperienceLoadRandomDelayMin = 0.0f; + static FAutoConsoleVariableRef CVarExperienceLoadRandomDelayMin( + TEXT("lyra.chaos.ExperienceDelayLoad.MinSecs"), + ExperienceLoadRandomDelayMin, + TEXT("This value (in seconds) will be added as a delay of load completion of the experience (along with the random value lyra.chaos.ExperienceDelayLoad.RandomSecs)"), + ECVF_Default); + + static float ExperienceLoadRandomDelayRange = 0.0f; + static FAutoConsoleVariableRef CVarExperienceLoadRandomDelayRange( + TEXT("lyra.chaos.ExperienceDelayLoad.RandomSecs"), + ExperienceLoadRandomDelayRange, + TEXT("A random amount of time between 0 and this value (in seconds) will be added as a delay of load completion of the experience (along with the fixed value lyra.chaos.ExperienceDelayLoad.MinSecs)"), + ECVF_Default); + + float GetExperienceLoadDelayDuration() + { + return FMath::Max(0.0f, ExperienceLoadRandomDelayMin + FMath::FRand() * ExperienceLoadRandomDelayRange); + } +} + +UALSExperienceManagerComponent::UALSExperienceManagerComponent(const FObjectInitializer& ObjectInitializer) + : Super(ObjectInitializer) +{ + SetIsReplicatedByDefault(true); +} + +#if WITH_SERVER_CODE +void UALSExperienceManagerComponent::ServerSetCurrentExperience(FPrimaryAssetId ExperienceId) +{ + UALSAssetManager& AssetManager = UALSAssetManager::Get(); + FSoftObjectPath AssetPath = AssetManager.GetPrimaryAssetPath(ExperienceId); + TSubclassOf AssetClass = Cast(AssetPath.TryLoad()); + check(AssetClass); + const UALSExperienceDefinition* Experience = GetDefault(AssetClass); + + check(Experience != nullptr); + check(CurrentExperience == nullptr); + CurrentExperience = Experience; + StartExperienceLoad(); +} +#endif + +void UALSExperienceManagerComponent::CallOrRegister_OnExperienceLoaded_HighPriority(FOnALSExperienceLoaded::FDelegate&& Delegate) +{ + if (IsExperienceLoaded()) + { + Delegate.Execute(CurrentExperience); + } + else + { + OnExperienceLoaded_HighPriority.Add(MoveTemp(Delegate)); + } +} + +void UALSExperienceManagerComponent::CallOrRegister_OnExperienceLoaded(FOnALSExperienceLoaded::FDelegate&& Delegate) +{ + if (IsExperienceLoaded()) + { + Delegate.Execute(CurrentExperience); + } + else + { + OnExperienceLoaded.Add(MoveTemp(Delegate)); + } +} + +void UALSExperienceManagerComponent::CallOrRegister_OnExperienceLoaded_LowPriority(FOnALSExperienceLoaded::FDelegate&& Delegate) +{ + if (IsExperienceLoaded()) + { + Delegate.Execute(CurrentExperience); + } + else + { + OnExperienceLoaded_LowPriority.Add(MoveTemp(Delegate)); + } +} + +const UALSExperienceDefinition* UALSExperienceManagerComponent::GetCurrentExperienceChecked() const +{ + check(LoadState == EALSExperienceLoadState::Loaded); + check(CurrentExperience != nullptr); + return CurrentExperience; +} + +bool UALSExperienceManagerComponent::IsExperienceLoaded() const +{ + return (LoadState == EALSExperienceLoadState::Loaded) && (CurrentExperience != nullptr); +} + +void UALSExperienceManagerComponent::OnRep_CurrentExperience() +{ + StartExperienceLoad(); +} + +void UALSExperienceManagerComponent::StartExperienceLoad() +{ + check(CurrentExperience != nullptr); + check(LoadState == EALSExperienceLoadState::Unloaded); + + UE_LOG(LogALSExperience, Log, TEXT("EXPERIENCE: StartExperienceLoad(CurrentExperience = %s, %s)"), + *CurrentExperience->GetPrimaryAssetId().ToString(), + *GetClientServerContextString(this)); + + LoadState = EALSExperienceLoadState::Loading; + + UALSAssetManager& AssetManager = UALSAssetManager::Get(); + + TSet BundleAssetList; + TSet RawAssetList; + + BundleAssetList.Add(CurrentExperience->GetPrimaryAssetId()); + for (const TObjectPtr& ActionSet : CurrentExperience->ActionSets) + { + if (ActionSet != nullptr) + { + BundleAssetList.Add(ActionSet->GetPrimaryAssetId()); + } + } + + // Load assets associated with the experience + + TArray BundlesToLoad; + BundlesToLoad.Add(FALSBundles::Equipped); + + //@TODO: Centralize this client/server stuff into the ALSAssetManager + const ENetMode OwnerNetMode = GetOwner()->GetNetMode(); + const bool bLoadClient = GIsEditor || (OwnerNetMode != NM_DedicatedServer); + const bool bLoadServer = GIsEditor || (OwnerNetMode != NM_Client); + if (bLoadClient) + { + BundlesToLoad.Add(UGameFeaturesSubsystemSettings::LoadStateClient); + } + if (bLoadServer) + { + BundlesToLoad.Add(UGameFeaturesSubsystemSettings::LoadStateServer); + } + + const TSharedPtr BundleLoadHandle = AssetManager.ChangeBundleStateForPrimaryAssets(BundleAssetList.Array(), BundlesToLoad, {}, false, FStreamableDelegate(), FStreamableManager::AsyncLoadHighPriority); + const TSharedPtr RawLoadHandle = AssetManager.LoadAssetList(RawAssetList.Array(), FStreamableDelegate(), FStreamableManager::AsyncLoadHighPriority, TEXT("StartExperienceLoad()")); + + // If both async loads are running, combine them + TSharedPtr Handle = nullptr; + if (BundleLoadHandle.IsValid() && RawLoadHandle.IsValid()) + { + Handle = AssetManager.GetStreamableManager().CreateCombinedHandle({ BundleLoadHandle, RawLoadHandle }); + } + else + { + Handle = BundleLoadHandle.IsValid() ? BundleLoadHandle : RawLoadHandle; + } + + FStreamableDelegate OnAssetsLoadedDelegate = FStreamableDelegate::CreateUObject(this, &ThisClass::OnExperienceLoadComplete); + if (!Handle.IsValid() || Handle->HasLoadCompleted()) + { + // Assets were already loaded, call the delegate now + FStreamableHandle::ExecuteDelegate(OnAssetsLoadedDelegate); + } + else + { + Handle->BindCompleteDelegate(OnAssetsLoadedDelegate); + + Handle->BindCancelDelegate(FStreamableDelegate::CreateLambda([OnAssetsLoadedDelegate]() + { + OnAssetsLoadedDelegate.ExecuteIfBound(); + })); + } + + // This set of assets gets preloaded, but we don't block the start of the experience based on it + TSet PreloadAssetList; + //@TODO: Determine assets to preload (but not blocking-ly) + if (PreloadAssetList.Num() > 0) + { + AssetManager.ChangeBundleStateForPrimaryAssets(PreloadAssetList.Array(), BundlesToLoad, {}); + } +} + +void UALSExperienceManagerComponent::OnExperienceLoadComplete() +{ + check(LoadState == EALSExperienceLoadState::Loading); + check(CurrentExperience != nullptr); + + UE_LOG(LogALSExperience, Log, TEXT("EXPERIENCE: OnExperienceLoadComplete(CurrentExperience = %s, %s)"), + *CurrentExperience->GetPrimaryAssetId().ToString(), + *GetClientServerContextString(this)); + + // find the URLs for our GameFeaturePlugins - filtering out dupes and ones that don't have a valid mapping + GameFeaturePluginURLs.Reset(); + + auto CollectGameFeaturePluginURLs = [This=this](const UPrimaryDataAsset* Context, const TArray& FeaturePluginList) + { + for (const FString& PluginName : FeaturePluginList) + { + FString PluginURL; + if (UGameFeaturesSubsystem::Get().GetPluginURLByName(PluginName, /*out*/ PluginURL)) + { + This->GameFeaturePluginURLs.AddUnique(PluginURL); + } + else + { + ensureMsgf(false, TEXT("OnExperienceLoadComplete failed to find plugin URL from PluginName %s for experience %s - fix data, ignoring for this run"), *PluginName, *Context->GetPrimaryAssetId().ToString()); + } + } + + // // Add in our extra plugin + // if (!CurrentPlaylistData->GameFeaturePluginToActivateUntilDownloadedContentIsPresent.IsEmpty()) + // { + // FString PluginURL; + // if (UGameFeaturesSubsystem::Get().GetPluginURLByName(CurrentPlaylistData->GameFeaturePluginToActivateUntilDownloadedContentIsPresent, PluginURL)) + // { + // GameFeaturePluginURLs.AddUnique(PluginURL); + // } + // } + }; + + CollectGameFeaturePluginURLs(CurrentExperience, CurrentExperience->GameFeaturesToEnable); + for (const TObjectPtr& ActionSet : CurrentExperience->ActionSets) + { + if (ActionSet != nullptr) + { + CollectGameFeaturePluginURLs(ActionSet, ActionSet->GameFeaturesToEnable); + } + } + + // Load and activate the features + NumGameFeaturePluginsLoading = GameFeaturePluginURLs.Num(); + if (NumGameFeaturePluginsLoading > 0) + { + LoadState = EALSExperienceLoadState::LoadingGameFeatures; + for (const FString& PluginURL : GameFeaturePluginURLs) + { + UALSExperienceManager::NotifyOfPluginActivation(PluginURL); + UGameFeaturesSubsystem::Get().LoadAndActivateGameFeaturePlugin(PluginURL, FGameFeaturePluginLoadComplete::CreateUObject(this, &ThisClass::OnGameFeaturePluginLoadComplete)); + } + } + else + { + OnExperienceFullLoadCompleted(); + } +} + +void UALSExperienceManagerComponent::OnGameFeaturePluginLoadComplete(const UE::GameFeatures::FResult& Result) +{ + // decrement the number of plugins that are loading + NumGameFeaturePluginsLoading--; + + if (NumGameFeaturePluginsLoading == 0) + { + OnExperienceFullLoadCompleted(); + } +} + +void UALSExperienceManagerComponent::OnExperienceFullLoadCompleted() +{ + check(LoadState != EALSExperienceLoadState::Loaded); + + // Insert a random delay for testing (if configured) + if (LoadState != EALSExperienceLoadState::LoadingChaosTestingDelay) + { + const float DelaySecs = ALSConsoleVariables::GetExperienceLoadDelayDuration(); + if (DelaySecs > 0.0f) + { + FTimerHandle DummyHandle; + + LoadState = EALSExperienceLoadState::LoadingChaosTestingDelay; + GetWorld()->GetTimerManager().SetTimer(DummyHandle, this, &ThisClass::OnExperienceFullLoadCompleted, DelaySecs, /*bLooping=*/ false); + + return; + } + } + + LoadState = EALSExperienceLoadState::ExecutingActions; + + // Execute the actions + FGameFeatureActivatingContext Context; + + // Only apply to our specific world context if set + const FWorldContext* ExistingWorldContext = GEngine->GetWorldContextFromWorld(GetWorld()); + if (ExistingWorldContext) + { + Context.SetRequiredWorldContextHandle(ExistingWorldContext->ContextHandle); + } + + auto ActivateListOfActions = [&Context](const TArray& ActionList) + { + for (UGameFeatureAction* Action : ActionList) + { + if (Action != nullptr) + { + //@TODO: The fact that these don't take a world are potentially problematic in client-server PIE + // The current behavior matches systems like gameplay tags where loading and registering apply to the entire process, + // but actually applying the results to actors is restricted to a specific world + Action->OnGameFeatureRegistering(); + Action->OnGameFeatureLoading(); + Action->OnGameFeatureActivating(Context); + } + } + }; + + ActivateListOfActions(CurrentExperience->Actions); + for (const TObjectPtr& ActionSet : CurrentExperience->ActionSets) + { + if (ActionSet != nullptr) + { + ActivateListOfActions(ActionSet->Actions); + } + } + + LoadState = EALSExperienceLoadState::Loaded; + + OnExperienceLoaded_HighPriority.Broadcast(CurrentExperience); + OnExperienceLoaded_HighPriority.Clear(); + + OnExperienceLoaded.Broadcast(CurrentExperience); + OnExperienceLoaded.Clear(); + + OnExperienceLoaded_LowPriority.Broadcast(CurrentExperience); + OnExperienceLoaded_LowPriority.Clear(); +} + +void UALSExperienceManagerComponent::OnActionDeactivationCompleted() +{ + check(IsInGameThread()); + ++NumObservedPausers; + + if (NumObservedPausers == NumExpectedPausers) + { + OnAllActionsDeactivated(); + } +} + +void UALSExperienceManagerComponent::GetLifetimeReplicatedProps(TArray& OutLifetimeProps) const +{ + Super::GetLifetimeReplicatedProps(OutLifetimeProps); + + DOREPLIFETIME(ThisClass, CurrentExperience); +} + +void UALSExperienceManagerComponent::EndPlay(const EEndPlayReason::Type EndPlayReason) +{ + Super::EndPlay(EndPlayReason); + + // deactivate any features this experience loaded + //@TODO: This should be handled FILO as well + for (const FString& PluginURL : GameFeaturePluginURLs) + { + if (UALSExperienceManager::RequestToDeactivatePlugin(PluginURL)) + { + UGameFeaturesSubsystem::Get().DeactivateGameFeaturePlugin(PluginURL); + } + } + + //@TODO: Ensure proper handling of a partially-loaded state too + if (LoadState == EALSExperienceLoadState::Loaded) + { + LoadState = EALSExperienceLoadState::Deactivating; + + // Make sure we won't complete the transition prematurely if someone registers as a pauser but fires immediately + NumExpectedPausers = INDEX_NONE; + NumObservedPausers = 0; + + // Deactivate and unload the actions + FGameFeatureDeactivatingContext Context(FSimpleDelegate::CreateUObject(this, &ThisClass::OnActionDeactivationCompleted)); + + const FWorldContext* ExistingWorldContext = GEngine->GetWorldContextFromWorld(GetWorld()); + if (ExistingWorldContext) + { + Context.SetRequiredWorldContextHandle(ExistingWorldContext->ContextHandle); + } + + auto DeactivateListOfActions = [&Context](const TArray& ActionList) + { + for (UGameFeatureAction* Action : ActionList) + { + if (Action) + { + Action->OnGameFeatureDeactivating(Context); + Action->OnGameFeatureUnregistering(); + } + } + }; + + DeactivateListOfActions(CurrentExperience->Actions); + for (const TObjectPtr& ActionSet : CurrentExperience->ActionSets) + { + if (ActionSet != nullptr) + { + DeactivateListOfActions(ActionSet->Actions); + } + } + + NumExpectedPausers = Context.GetNumPausers(); + + if (NumExpectedPausers > 0) + { + UE_LOG(LogALSExperience, Error, TEXT("Actions that have asynchronous deactivation aren't fully supported yet in ALS experiences")); + } + + if (NumExpectedPausers == NumObservedPausers) + { + OnAllActionsDeactivated(); + } + } +} + +bool UALSExperienceManagerComponent::ShouldShowLoadingScreen(FString& OutReason) const +{ + if (LoadState != EALSExperienceLoadState::Loaded) + { + OutReason = TEXT("Experience still loading"); + return false; + } + else + { + return false; + } +} + +void UALSExperienceManagerComponent::OnAllActionsDeactivated() +{ + //@TODO: We actually only deactivated and didn't fully unload... + LoadState = EALSExperienceLoadState::Unloaded; + CurrentExperience = nullptr; + //@TODO: GEngine->ForceGarbageCollection(true); +} + diff --git a/Source/ALSV4_CPP/Private/GameModes/ALSGameMode.cpp b/Source/ALSV4_CPP/Private/GameModes/ALSGameMode.cpp new file mode 100644 index 00000000..a062ab9e --- /dev/null +++ b/Source/ALSV4_CPP/Private/GameModes/ALSGameMode.cpp @@ -0,0 +1,376 @@ +// Fill out your copyright notice in the Description page of Project Settings. + + +#include "GameModes/ALSGameMode.h" + +#include "Character/ALSCharacter.h" +#include "Character/ALSPawnData.h" +#include "Character/ALSPawnExtensionComponent.h" +#include "Character/ALSPlayerController.h" +#include "GameModes/ALSExperienceManagerComponent.h" +#include "GameModes/ALSExperienceDefinition.h" +#include "Kismet/GameplayStatics.h" +#include "Player/ALSPlayerState.h" +#include "System/ALSAssetManager.h" +#include "ALSLogChannels.h" +#include "GameModes/ALSWorldSettings.h" + +#include UE_INLINE_GENERATED_CPP_BY_NAME(ALSGameMode) + +AALSGameMode::AALSGameMode(const FObjectInitializer& ObjectInitializer) + : Super(ObjectInitializer) +{ + // Session And Game State + PlayerControllerClass = AALSPlayerController::StaticClass(); + PlayerStateClass = AALSPlayerState::StaticClass(); + DefaultPawnClass = AALSCharacter::StaticClass(); +} + +const UALSPawnData* AALSGameMode::GetPawnDataForController(const AController* InController) const +{ + // See if pawn data is already set on the player state + if (InController != nullptr) + { + if (const AALSPlayerState* ALSPS = InController->GetPlayerState()) + { + if (const UALSPawnData* PawnData = ALSPS->GetPawnData()) + { + return PawnData; + } + } + } + + // If not, fall back to the the default for the current experience + check(GameState); + UALSExperienceManagerComponent* ExperienceComponent = GameState->FindComponentByClass(); + check(ExperienceComponent); + + if (ExperienceComponent->IsExperienceLoaded()) + { + const UALSExperienceDefinition* Experience = ExperienceComponent->GetCurrentExperienceChecked(); + if (Experience->DefaultPawnData != nullptr) + { + return Experience->DefaultPawnData; + } + + // Experience is loaded and there's still no pawn data, fall back to the default for now + return UALSAssetManager::Get().GetDefaultPawnData(); + } + + // Experience not loaded yet, so there is no pawn data to be had + return nullptr; +} + +void AALSGameMode::InitGame(const FString& MapName, const FString& Options, FString& ErrorMessage) +{ + Super::InitGame(MapName, Options, ErrorMessage); + + //@TODO: Eventually only do this for PIE/auto + GetWorld()->GetTimerManager().SetTimerForNextTick(this, &ThisClass::HandleMatchAssignmentIfNotExpectingOne); +} + +void AALSGameMode::HandleMatchAssignmentIfNotExpectingOne() +{ + FPrimaryAssetId ExperienceId; + FString ExperienceIdSource; + + // Precedence order (highest wins) + // - Matchmaking assignment (if present) + // - URL Options override + // - Developer Settings (PIE only) + // - Command Line override + // - World Settings + // - Default experience + + UWorld* World = GetWorld(); + + if (!ExperienceId.IsValid() && UGameplayStatics::HasOption(OptionsString, TEXT("Experience"))) + { + const FString ExperienceFromOptions = UGameplayStatics::ParseOption(OptionsString, TEXT("Experience")); + ExperienceId = FPrimaryAssetId(FPrimaryAssetType(UALSExperienceDefinition::StaticClass()->GetFName()), FName(*ExperienceFromOptions)); + ExperienceIdSource = TEXT("OptionsString"); + } + + /*if (!ExperienceId.IsValid() && World->IsPlayInEditor()) + { + ExperienceId = GetDefault()->ExperienceOverride; + ExperienceIdSource = TEXT("DeveloperSettings"); + }*/ + + // see if the command line wants to set the experience + if (!ExperienceId.IsValid()) + { + FString ExperienceFromCommandLine; + if (FParse::Value(FCommandLine::Get(), TEXT("Experience="), ExperienceFromCommandLine)) + { + ExperienceId = FPrimaryAssetId::ParseTypeAndName(ExperienceFromCommandLine); + ExperienceIdSource = TEXT("CommandLine"); + } + } + + // see if the world settings has a default experience + if (!ExperienceId.IsValid()) + { + if (AALSWorldSettings* TypedWorldSettings = Cast(GetWorldSettings())) + { + ExperienceId = TypedWorldSettings->GetDefaultGameplayExperience(); + ExperienceIdSource = TEXT("WorldSettings"); + } + } + + UALSAssetManager& AssetManager = UALSAssetManager::Get(); + FAssetData Dummy; + if (ExperienceId.IsValid() && !AssetManager.GetPrimaryAssetData(ExperienceId, /*out*/ Dummy)) + { + UE_LOG(LogALSExperience, Error, TEXT("EXPERIENCE: Wanted to use %s but couldn't find it, falling back to the default)"), *ExperienceId.ToString()); + ExperienceId = FPrimaryAssetId(); + } + + // Final fallback to the default experience + if (!ExperienceId.IsValid()) + { + //@TODO: Pull this from a config setting or something + ExperienceId = FPrimaryAssetId(FPrimaryAssetType("ALSExperienceDefinition"), FName("BP_DungeonCrawler_DefaultExperience")); + ExperienceIdSource = TEXT("DungeonCrawlerCore"); + } + + UE_LOG(LogTemp, Warning, TEXT("ExperienceID: %s, ExperienceSource %s"), *ExperienceId.ToString(), *ExperienceIdSource); + OnMatchAssignmentGiven(ExperienceId, ExperienceIdSource); +} + +void AALSGameMode::OnMatchAssignmentGiven(FPrimaryAssetId ExperienceId, const FString& ExperienceIdSource) +{ +#if WITH_SERVER_CODE + if (ExperienceId.IsValid()) + { + UE_LOG(LogALSExperience, Log, TEXT("Identified experience %s (Source: %s)"), *ExperienceId.ToString(), *ExperienceIdSource); + + UALSExperienceManagerComponent* ExperienceComponent = GameState->FindComponentByClass(); + check(ExperienceComponent); + ExperienceComponent->ServerSetCurrentExperience(ExperienceId); + } + else + { + UE_LOG(LogALSExperience, Error, TEXT("Failed to identify experience, loading screen will stay up forever")); + } +#endif +} + +void AALSGameMode::OnExperienceLoaded(const UALSExperienceDefinition* CurrentExperience) +{ + // Spawn any players that are already attached + //@TODO: Here we're handling only *player* controllers, but in GetDefaultPawnClassForController_Implementation we skipped all controllers + // GetDefaultPawnClassForController_Implementation might only be getting called for players anyways + for (FConstPlayerControllerIterator Iterator = GetWorld()->GetPlayerControllerIterator(); Iterator; ++Iterator) + { + APlayerController* PC = Cast(*Iterator); + if ((PC != nullptr) && (PC->GetPawn() == nullptr)) + { + if (PlayerCanRestart(PC)) + { + RestartPlayer(PC); + } + } + } +} + +bool AALSGameMode::IsExperienceLoaded() const +{ + check(GameState); + UALSExperienceManagerComponent* ExperienceComponent = GameState->FindComponentByClass(); + check(ExperienceComponent); + + return ExperienceComponent->IsExperienceLoaded(); +} + +UClass* AALSGameMode::GetDefaultPawnClassForController_Implementation(AController* InController) +{ + if (const UALSPawnData* PawnData = GetPawnDataForController(InController)) + { + if (PawnData->PawnClass) + { + return PawnData->PawnClass; + } + } + + return Super::GetDefaultPawnClassForController_Implementation(InController); +} + +APawn* AALSGameMode::SpawnDefaultPawnAtTransform_Implementation(AController* NewPlayer, const FTransform& SpawnTransform) +{ + FActorSpawnParameters SpawnInfo; + SpawnInfo.Instigator = GetInstigator(); + SpawnInfo.ObjectFlags |= RF_Transient; // Never save the default player pawns into a map. + SpawnInfo.bDeferConstruction = true; + + if (UClass* PawnClass = GetDefaultPawnClassForController(NewPlayer)) + { + if (APawn* SpawnedPawn = GetWorld()->SpawnActor(PawnClass, SpawnTransform, SpawnInfo)) + { + if (UALSPawnExtensionComponent* PawnExtComp = UALSPawnExtensionComponent::FindPawnExtensionComponent(SpawnedPawn)) + { + if (const UALSPawnData* PawnData = GetPawnDataForController(NewPlayer)) + { + PawnExtComp->SetPawnData(PawnData); + } + else + { + UE_LOG(LogALS, Error, TEXT("Game mode was unable to set PawnData on the spawned pawn [%s]."), *GetNameSafe(SpawnedPawn)); + } + } + + SpawnedPawn->FinishSpawning(SpawnTransform); + + return SpawnedPawn; + } + else + { + UE_LOG(LogALS, Error, TEXT("Game mode was unable to spawn Pawn of class [%s] at [%s]."), *GetNameSafe(PawnClass), *SpawnTransform.ToHumanReadableString()); + } + } + else + { + UE_LOG(LogALS, Error, TEXT("Game mode was unable to spawn Pawn due to NULL pawn class.")); + } + + return nullptr; +} + +bool AALSGameMode::ShouldSpawnAtStartSpot(AController* Player) +{ + // We never want to use the start spot, always use the spawn management component. + return false; +} + +void AALSGameMode::HandleStartingNewPlayer_Implementation(APlayerController* NewPlayer) +{ + // Delay starting new players until the experience has been loaded + // (players who log in prior to that will be started by OnExperienceLoaded) + if (IsExperienceLoaded()) + { + Super::HandleStartingNewPlayer_Implementation(NewPlayer); + } +} + +AActor* AALSGameMode::ChoosePlayerStart_Implementation(AController* Player) +{ + /*if (UALSPlayerSpawningManagerComponent* PlayerSpawningComponent = GameState->FindComponentByClass()) + { + return PlayerSpawningComponent->ChoosePlayerStart(Player); + }*/ + + return Super::ChoosePlayerStart_Implementation(Player); +} + +void AALSGameMode::FinishRestartPlayer(AController* NewPlayer, const FRotator& StartRotation) +{ + /*if (UALSPlayerSpawningManagerComponent* PlayerSpawningComponent = GameState->FindComponentByClass()) + { + PlayerSpawningComponent->FinishRestartPlayer(NewPlayer, StartRotation); + }*/ + + Super::FinishRestartPlayer(NewPlayer, StartRotation); +} + +bool AALSGameMode::PlayerCanRestart_Implementation(APlayerController* Player) +{ + return ControllerCanRestart(Player); +} + +bool AALSGameMode::ControllerCanRestart(AController* Controller) +{ + if (APlayerController* PC = Cast(Controller)) + { + if (!Super::PlayerCanRestart_Implementation(PC)) + { + return false; + } + } + else + { + // Bot version of Super::PlayerCanRestart_Implementation + if ((Controller == nullptr) || Controller->IsPendingKillPending()) + { + return false; + } + } + + /*if (UALSPlayerSpawningManagerComponent* PlayerSpawningComponent = GameState->FindComponentByClass()) + { + return PlayerSpawningComponent->ControllerCanRestart(Controller); + }*/ + + return true; +} + +void AALSGameMode::InitGameState() +{ + Super::InitGameState(); + + // Listen for the experience load to complete + UALSExperienceManagerComponent* ExperienceComponent = GameState->FindComponentByClass(); + check(ExperienceComponent); + ExperienceComponent->CallOrRegister_OnExperienceLoaded(FOnALSExperienceLoaded::FDelegate::CreateUObject(this, &ThisClass::OnExperienceLoaded)); +} + +void AALSGameMode::OnPostLogin(AController* NewPlayer) +{ + Super::OnPostLogin(NewPlayer); + + OnGameModeCombinedPostLoginDelegate.Broadcast(this, NewPlayer); +} + +void AALSGameMode::RequestPlayerRestartNextFrame(AController* Controller, bool bForceReset) +{ + if (bForceReset && (Controller != nullptr)) + { + Controller->Reset(); + } + + if (APlayerController* PC = Cast(Controller)) + { + GetWorldTimerManager().SetTimerForNextTick(PC, &APlayerController::ServerRestartPlayer_Implementation); + } + /*else if (AALSPlayerBotController* BotController = Cast(Controller)) + { + GetWorldTimerManager().SetTimerForNextTick(BotController, &AALSPlayerBotController::ServerRestartController); + }*/ +} + +bool AALSGameMode::UpdatePlayerStartSpot(AController* Player, const FString& Portal, FString& OutErrorMessage) +{ + // Do nothing, we'll wait until PostLogin when we try to spawn the player for real. + // Doing anything right now is no good, systems like team assignment haven't even occurred yet. + return true; +} + +void AALSGameMode::FailedToRestartPlayer(AController* NewPlayer) +{ + Super::FailedToRestartPlayer(NewPlayer); + + // If we tried to spawn a pawn and it failed, lets try again *note* check if there's actually a pawn class + // before we try this forever. + if (UClass* PawnClass = GetDefaultPawnClassForController(NewPlayer)) + { + if (APlayerController* NewPC = Cast(NewPlayer)) + { + // If it's a player don't loop forever, maybe something changed and they can no longer restart if so stop trying. + if (PlayerCanRestart(NewPC)) + { + RequestPlayerRestartNextFrame(NewPlayer, false); + } + else + { + UE_LOG(LogALSExperience, Verbose, TEXT("FailedToRestartPlayer(%s) and PlayerCanRestart returned false, so we're not going to try again."), *GetPathNameSafe(NewPlayer)); + } + } + else + { + RequestPlayerRestartNextFrame(NewPlayer, false); + } + } + else + { + UE_LOG(LogALS, Verbose, TEXT("FailedToRestartPlayer(%s) but there's no pawn class so giving up."), *GetPathNameSafe(NewPlayer)); + } +} diff --git a/Source/ALSV4_CPP/Private/GameModes/ALSGameState.cpp b/Source/ALSV4_CPP/Private/GameModes/ALSGameState.cpp new file mode 100644 index 00000000..ba718ea3 --- /dev/null +++ b/Source/ALSV4_CPP/Private/GameModes/ALSGameState.cpp @@ -0,0 +1,101 @@ +// Fill out your copyright notice in the Description page of Project Settings. + +#include "GameModes/ALSGameState.h" + +#include "AbilitySystem/ALSAbilitySystemComponent.h" +#include "AbilitySystemComponent.h" +#include "Containers/Array.h" +#include "Engine/EngineBaseTypes.h" +#include "GameFramework/GameplayMessageSubsystem.h" +#include "GameModes/ALSExperienceManagerComponent.h" +#include "HAL/Platform.h" +#include "Misc/AssertionMacros.h" +#include "Net/UnrealNetwork.h" + +#include UE_INLINE_GENERATED_CPP_BY_NAME(ALSGameState) + +class APlayerState; +class FLifetimeProperty; + +extern ENGINE_API float GAverageFPS; + + +AALSGameState::AALSGameState(const FObjectInitializer& ObjectInitializer) + : Super(ObjectInitializer) +{ + PrimaryActorTick.bCanEverTick = true; + PrimaryActorTick.bStartWithTickEnabled = true; + + AbilitySystemComponent = ObjectInitializer.CreateDefaultSubobject(this, TEXT("AbilitySystemComponent")); + AbilitySystemComponent->SetIsReplicated(true); + AbilitySystemComponent->SetReplicationMode(EGameplayEffectReplicationMode::Mixed); + + ExperienceManagerComponent = CreateDefaultSubobject(TEXT("ExperienceManagerComponent")); + + ServerFPS = 0.0f; +} + +void AALSGameState::PreInitializeComponents() +{ + Super::PreInitializeComponents(); +} + +void AALSGameState::PostInitializeComponents() +{ + Super::PostInitializeComponents(); + + check(AbilitySystemComponent); + AbilitySystemComponent->InitAbilityActorInfo(/*Owner=*/ this, /*Avatar=*/ this); +} + +UAbilitySystemComponent* AALSGameState::GetAbilitySystemComponent() const +{ + return AbilitySystemComponent; +} + +void AALSGameState::EndPlay(const EEndPlayReason::Type EndPlayReason) +{ + Super::EndPlay(EndPlayReason); +} + +void AALSGameState::AddPlayerState(APlayerState* PlayerState) +{ + Super::AddPlayerState(PlayerState); +} + +void AALSGameState::RemovePlayerState(APlayerState* PlayerState) +{ + //@TODO: This isn't getting called right now (only the 'rich' AGameMode uses it, not AGameModeBase) + // Need to at least comment the engine code, and possibly move things around + Super::RemovePlayerState(PlayerState); +} + +void AALSGameState::GetLifetimeReplicatedProps(TArray& OutLifetimeProps) const +{ + Super::GetLifetimeReplicatedProps(OutLifetimeProps); + + DOREPLIFETIME(ThisClass, ServerFPS); +} + +void AALSGameState::Tick(float DeltaSeconds) +{ + Super::Tick(DeltaSeconds); + + if (GetLocalRole() == ROLE_Authority) + { + ServerFPS = GAverageFPS; + } +} + +void AALSGameState::MulticastMessageToClients_Implementation(const FALSVerbMessage Message) +{ + if (GetNetMode() == NM_Client) + { + UGameplayMessageSubsystem::Get(this).BroadcastMessage(Message.Verb, Message); + } +} + +void AALSGameState::MulticastReliableMessageToClients_Implementation(const FALSVerbMessage Message) +{ + MulticastMessageToClients_Implementation(Message); +} diff --git a/Source/ALSV4_CPP/Private/GameModes/ALSWorldSettings.cpp b/Source/ALSV4_CPP/Private/GameModes/ALSWorldSettings.cpp new file mode 100644 index 00000000..50f75503 --- /dev/null +++ b/Source/ALSV4_CPP/Private/GameModes/ALSWorldSettings.cpp @@ -0,0 +1,54 @@ +#include "GameModes/ALSWorldSettings.h" +#include "GameFramework/PlayerStart.h" +#include "EngineUtils.h" +#include "Misc/UObjectToken.h" +#include "Logging/TokenizedMessage.h" +#include "Logging/MessageLog.h" +#include "GameModes/ALSExperienceDefinition.h" +#include "ALSLogChannels.h" +#include "Engine/AssetManager.h" + +#include UE_INLINE_GENERATED_CPP_BY_NAME(ALSWorldSettings) + +AALSWorldSettings::AALSWorldSettings(const FObjectInitializer& ObjectInitializer) + : Super(ObjectInitializer) +{ +} + +FPrimaryAssetId AALSWorldSettings::GetDefaultGameplayExperience() const +{ + FPrimaryAssetId Result; + if (!DefaultGameplayExperience.IsNull()) + { + Result = UAssetManager::Get().GetPrimaryAssetIdForPath(DefaultGameplayExperience.ToSoftObjectPath()); + + if (!Result.IsValid()) + { + UE_LOG(LogALS, Error, TEXT("%s.DefaultGameplayExperience is %s but that failed to resolve into an asset ID (you might need to add a path to the Asset Rules in your game feature plugin or project settings"), + *GetPathNameSafe(this), *DefaultGameplayExperience.ToString()); + } + } + return Result; +} + +#if WITH_EDITOR +void AALSWorldSettings::CheckForErrors() +{ + Super::CheckForErrors(); + + FMessageLog MapCheck("MapCheck"); + + for (TActorIterator PlayerStartIt(GetWorld()); PlayerStartIt; ++PlayerStartIt) + { + APlayerStart* PlayerStart = *PlayerStartIt; + if (IsValid(PlayerStart) && PlayerStart->GetClass() == APlayerStart::StaticClass()) + { + MapCheck.Warning() + ->AddToken(FUObjectToken::Create(PlayerStart)) + ->AddToken(FTextToken::Create(FText::FromString("is a normal APlayerStart, replace with AALSPlayerStart."))); + } + } + + //@TODO: Make sure the soft object path is something that can actually be turned into a primary asset ID (e.g., is not pointing to an experience in an unscanned directory) +} +#endif \ No newline at end of file diff --git a/Source/ALSV4_CPP/Public/GameModes/ALSExperienceActionSet.h b/Source/ALSV4_CPP/Public/GameModes/ALSExperienceActionSet.h new file mode 100644 index 00000000..24f30653 --- /dev/null +++ b/Source/ALSV4_CPP/Public/GameModes/ALSExperienceActionSet.h @@ -0,0 +1,42 @@ +// Fill out your copyright notice in the Description page of Project Settings. + +#pragma once + +#include "CoreMinimal.h" +#include "Engine/DataAsset.h" +#include "ALSExperienceActionSet.generated.h" + +class UGameFeatureAction; + +/** + * Definition of a set of actions to perform as part of entering an experience + */ +UCLASS(BlueprintType, NotBlueprintable) +class ALSV4_CPP_API UALSExperienceActionSet : public UPrimaryDataAsset +{ + GENERATED_BODY() + +public: + UALSExperienceActionSet(); + + //~UObject interface + #if WITH_EDITOR + virtual EDataValidationResult IsDataValid(TArray& ValidationErrors) override; +#endif + //~End of UObject interface + + //~UPrimaryDataAsset interface + #if WITH_EDITORONLY_DATA + virtual void UpdateAssetBundleData() override; +#endif + //~End of UPrimaryDataAsset interface + + public: + // List of actions to perform as this experience is loaded/activated/deactivated/unloaded + UPROPERTY(EditAnywhere, Instanced, Category="Actions to Perform") + TArray> Actions; + + // List of Game Feature Plugins this experience wants to have active + UPROPERTY(EditAnywhere, Category="Feature Dependencies") + TArray GameFeaturesToEnable; +}; diff --git a/Source/ALSV4_CPP/Public/GameModes/ALSExperienceDefinition.h b/Source/ALSV4_CPP/Public/GameModes/ALSExperienceDefinition.h new file mode 100644 index 00000000..cc77eead --- /dev/null +++ b/Source/ALSV4_CPP/Public/GameModes/ALSExperienceDefinition.h @@ -0,0 +1,53 @@ +// Fill out your copyright notice in the Description page of Project Settings. + +#pragma once + +#include "CoreMinimal.h" +#include "Engine/DataAsset.h" +#include "ALSExperienceDefinition.generated.h" + +class UGameFeatureAction; +class UALSPawnData; +class UALSExperienceActionSet; + +/** + * Definition of an experience + */ +UCLASS(BlueprintType, Const) +class ALSV4_CPP_API UALSExperienceDefinition : public UPrimaryDataAsset +{ + GENERATED_BODY() + +public: + UALSExperienceDefinition(); + + //~UObject interface + #if WITH_EDITOR + virtual EDataValidationResult IsDataValid(TArray& ValidationErrors) override; +#endif + //~End of UObject interface + + //~UPrimaryDataAsset interface + #if WITH_EDITORONLY_DATA + virtual void UpdateAssetBundleData() override; +#endif + //~End of UPrimaryDataAsset interface + + public: + // List of Game Feature Plugins this experience wants to have active + UPROPERTY(EditDefaultsOnly, Category = Gameplay) + TArray GameFeaturesToEnable; + + /** The default pawn class to spawn for players */ + //@TODO: Make soft? + UPROPERTY(EditDefaultsOnly, Category=Gameplay) + TObjectPtr DefaultPawnData; + + // List of actions to perform as this experience is loaded/activated/deactivated/unloaded + UPROPERTY(EditDefaultsOnly, Instanced, Category="Actions") + TArray> Actions; + + // List of additional action sets to compose into this experience + UPROPERTY(EditDefaultsOnly, Category=Gameplay) + TArray> ActionSets; +}; diff --git a/Source/ALSV4_CPP/Public/GameModes/ALSExperienceManager.h b/Source/ALSV4_CPP/Public/GameModes/ALSExperienceManager.h new file mode 100644 index 00000000..b7aa139c --- /dev/null +++ b/Source/ALSV4_CPP/Public/GameModes/ALSExperienceManager.h @@ -0,0 +1,32 @@ +// Fill out your copyright notice in the Description page of Project Settings. + +#pragma once + +#include "CoreMinimal.h" +#include "Subsystems/EngineSubsystem.h" +#include "ALSExperienceManager.generated.h" + +/** + * Manager for experiences - primarily for arbitration between multiple PIE sessions + */ +UCLASS(MinimalAPI) +class UALSExperienceManager : public UEngineSubsystem +{ + GENERATED_BODY() + +public: +#if WITH_EDITOR + ALSV4_CPP_API void OnPlayInEditorBegun(); + + static void NotifyOfPluginActivation(const FString PluginURL); + static bool RequestToDeactivatePlugin(const FString PluginURL); +#else + static void NotifyOfPluginActivation(const FString PluginURL) {} + static bool RequestToDeactivatePlugin(const FString PluginURL) { return true; } +#endif + +private: + // The map of requests to active count for a given game feature plugin + // (to allow first in, last out activation management during PIE) + TMap GameFeaturePluginRequestCountMap; +}; diff --git a/Source/ALSV4_CPP/Public/GameModes/ALSExperienceManagerComponent.h b/Source/ALSV4_CPP/Public/GameModes/ALSExperienceManagerComponent.h new file mode 100644 index 00000000..e21193fb --- /dev/null +++ b/Source/ALSV4_CPP/Public/GameModes/ALSExperienceManagerComponent.h @@ -0,0 +1,103 @@ +// Fill out your copyright notice in the Description page of Project Settings. + +#pragma once + +#include "CoreMinimal.h" +#include "Components/GameStateComponent.h" +#include "GameFeaturePluginOperationResult.h" +#include "LoadingProcessInterface.h" + +#include "ALSExperienceManagerComponent.generated.h" + +class UALSExperienceDefinition; + +DECLARE_MULTICAST_DELEGATE_OneParam(FOnALSExperienceLoaded, const UALSExperienceDefinition* /*Experience*/); + +enum class EALSExperienceLoadState +{ + Unloaded, + Loading, + LoadingGameFeatures, + LoadingChaosTestingDelay, + ExecutingActions, + Loaded, + Deactivating +}; + +UCLASS() +class UALSExperienceManagerComponent final : public UGameStateComponent, public ILoadingProcessInterface +{ + GENERATED_BODY() + +public: + + UALSExperienceManagerComponent(const FObjectInitializer& ObjectInitializer = FObjectInitializer::Get()); + + //~UActorComponent interface + virtual void EndPlay(const EEndPlayReason::Type EndPlayReason) override; + //~End of UActorComponent interface + + //~ILoadingProcessInterface interface + virtual bool ShouldShowLoadingScreen(FString& OutReason) const override; + //~End of ILoadingProcessInterface + +#if WITH_SERVER_CODE + void ServerSetCurrentExperience(FPrimaryAssetId ExperienceId); +#endif + + // Ensures the delegate is called once the experience has been loaded, + // before others are called. + // However, if the experience has already loaded, calls the delegate immediately. + void CallOrRegister_OnExperienceLoaded_HighPriority(FOnALSExperienceLoaded::FDelegate&& Delegate); + + // Ensures the delegate is called once the experience has been loaded + // If the experience has already loaded, calls the delegate immediately + void CallOrRegister_OnExperienceLoaded(FOnALSExperienceLoaded::FDelegate&& Delegate); + + // Ensures the delegate is called once the experience has been loaded + // If the experience has already loaded, calls the delegate immediately + void CallOrRegister_OnExperienceLoaded_LowPriority(FOnALSExperienceLoaded::FDelegate&& Delegate); + + // This returns the current experience if it is fully loaded, asserting otherwise + // (i.e., if you called it too soon) + const UALSExperienceDefinition* GetCurrentExperienceChecked() const; + + // Returns true if the experience is fully loaded + bool IsExperienceLoaded() const; + +private: + UFUNCTION() + void OnRep_CurrentExperience(); + + void StartExperienceLoad(); + void OnExperienceLoadComplete(); + void OnGameFeaturePluginLoadComplete(const UE::GameFeatures::FResult& Result); + void OnExperienceFullLoadCompleted(); + + void OnActionDeactivationCompleted(); + void OnAllActionsDeactivated(); + +private: + UPROPERTY(ReplicatedUsing=OnRep_CurrentExperience) + TObjectPtr CurrentExperience; + + EALSExperienceLoadState LoadState = EALSExperienceLoadState::Unloaded; + + int32 NumGameFeaturePluginsLoading = 0; + TArray GameFeaturePluginURLs; + + int32 NumObservedPausers = 0; + int32 NumExpectedPausers = 0; + + /** + * Delegate called when the experience has finished loading just before others + * (e.g., subsystems that set up for regular gameplay) + */ + FOnALSExperienceLoaded OnExperienceLoaded_HighPriority; + + /** Delegate called when the experience has finished loading */ + FOnALSExperienceLoaded OnExperienceLoaded; + + /** Delegate called when the experience has finished loading */ + FOnALSExperienceLoaded OnExperienceLoaded_LowPriority; +}; diff --git a/Source/ALSV4_CPP/Public/GameModes/ALSGameMode.h b/Source/ALSV4_CPP/Public/GameModes/ALSGameMode.h new file mode 100644 index 00000000..9f3c60b8 --- /dev/null +++ b/Source/ALSV4_CPP/Public/GameModes/ALSGameMode.h @@ -0,0 +1,87 @@ +// Fill out your copyright notice in the Description page of Project Settings. + +#pragma once + +#include "CoreMinimal.h" +#include "Delegates/Delegate.h" +#include "Math/Rotator.h" +#include "Math/Transform.h" +#include "ModularGameMode.h" +#include "UObject/UObjectGlobals.h" +#include "ALSGameMode.generated.h" + +class AActor; +class AController; +class AGameModeBase; +class APawn; +class APlayerController; +class UClass; +class UALSExperienceDefinition; +class UALSPawnData; +class UObject; +struct FFrame; +struct FPrimaryAssetId; + +/** + * Post login event, triggered when a player joins the game as well as after non-seamless ServerTravel + * + * This is called after the player has finished initialization + */ +DECLARE_MULTICAST_DELEGATE_TwoParams(FOnGameModeCombinedPostLogin, AGameModeBase* /*GameMode*/, AController* /*NewPlayer*/); + +/** + * AALSGameMode + * + * The base game mode class used by this project. + */ +UCLASS(Config = Game, Meta = (ShortTooltip = "The base game mode class used by this project.")) +class ALSV4_CPP_API AALSGameMode : public AModularGameModeBase +{ + GENERATED_BODY() + +public: + + AALSGameMode(const FObjectInitializer& ObjectInitializer = FObjectInitializer::Get()); + + UFUNCTION(BlueprintCallable, Category = "ALS|Pawn") + const UALSPawnData* GetPawnDataForController(const AController* InController) const; + + //~AGameModeBase interface + virtual void InitGame(const FString& MapName, const FString& Options, FString& ErrorMessage) override; + virtual UClass* GetDefaultPawnClassForController_Implementation(AController* InController) override; + virtual APawn* SpawnDefaultPawnAtTransform_Implementation(AController* NewPlayer, const FTransform& SpawnTransform) override; + virtual bool ShouldSpawnAtStartSpot(AController* Player) override; + virtual void HandleStartingNewPlayer_Implementation(APlayerController* NewPlayer) override; + virtual AActor* ChoosePlayerStart_Implementation(AController* Player) override; + virtual void FinishRestartPlayer(AController* NewPlayer, const FRotator& StartRotation) override; + virtual bool PlayerCanRestart_Implementation(APlayerController* Player) override; + virtual void InitGameState() override; + //~End of AGameModeBase interface + + FOnGameModeCombinedPostLogin& OnGameModeCombinedPostLogin() { return OnGameModeCombinedPostLoginDelegate; } + + // Restart (respawn) the specified player or bot next frame + // - If bForceReset is true, the controller will be reset this frame (abandoning the currently possessed pawn, if any) + UFUNCTION(BlueprintCallable) + void RequestPlayerRestartNextFrame(AController* Controller, bool bForceReset = false); + + // Agnostic version of PlayerCanRestart that can be used for both player bots and players + virtual bool ControllerCanRestart(AController* Controller); + +private: + FOnGameModeCombinedPostLogin OnGameModeCombinedPostLoginDelegate; + +protected: + //~AGameModeBase interface + virtual bool UpdatePlayerStartSpot(AController* Player, const FString& Portal, FString& OutErrorMessage) override; + virtual void OnPostLogin(AController* NewPlayer) override; + virtual void FailedToRestartPlayer(AController* NewPlayer) override; + //~End of AGameModeBase interface + + void OnExperienceLoaded(const UALSExperienceDefinition* CurrentExperience); + bool IsExperienceLoaded() const; + + void OnMatchAssignmentGiven(FPrimaryAssetId ExperienceId, const FString& ExperienceIdSource); + + void HandleMatchAssignmentIfNotExpectingOne(); +}; diff --git a/Source/ALSV4_CPP/Public/GameModes/ALSGameState.h b/Source/ALSV4_CPP/Public/GameModes/ALSGameState.h new file mode 100644 index 00000000..597a420a --- /dev/null +++ b/Source/ALSV4_CPP/Public/GameModes/ALSGameState.h @@ -0,0 +1,80 @@ +// Fill out your copyright notice in the Description page of Project Settings. + +#pragma once + +#include "AbilitySystemInterface.h" +#include "Engine/EngineTypes.h" +#include "Messages/ALSVerbMessage.h" +#include "ModularGameState.h" +#include "UObject/UObjectGlobals.h" + +#include "ALSGameState.generated.h" + +class APlayerState; +class UAbilitySystemComponent; +class UALSAbilitySystemComponent; +class UALSExperienceManagerComponent; +class UObject; +struct FFrame; + +/** + * AALSGameState + * + * The base game state class used by this project. + */ +UCLASS(Config = Game) +class ALSV4_CPP_API AALSGameState : public AModularGameStateBase, public IAbilitySystemInterface +{ + GENERATED_BODY() + +public: + + AALSGameState(const FObjectInitializer& ObjectInitializer = FObjectInitializer::Get()); + + float GetServerFPS() const { return ServerFPS; } + + //~AActor interface + virtual void PreInitializeComponents() override; + virtual void PostInitializeComponents() override; + virtual void EndPlay(const EEndPlayReason::Type EndPlayReason) override; + //~End of AActor interface + + //~AGameStateBase interface + virtual void AddPlayerState(APlayerState* PlayerState) override; + virtual void RemovePlayerState(APlayerState* PlayerState) override; + //~End of AGameStateBase interface + + //~IAbilitySystemInterface + virtual UAbilitySystemComponent* GetAbilitySystemComponent() const override; + //~End of IAbilitySystemInterface + + UFUNCTION(BlueprintCallable, Category = "ALS|GameState") + UALSAbilitySystemComponent* GetALSAbilitySystemComponent() const { return AbilitySystemComponent; } + + // Send a message that all clients will (probably) get + // (use only for client notifications like eliminations, server join messages, etc... that can handle being lost) + UFUNCTION(NetMulticast, Unreliable, BlueprintCallable, Category = "ALS|GameState") + void MulticastMessageToClients(const FALSVerbMessage Message); + + // Send a message that all clients will be guaranteed to get + // (use only for client notifications that cannot handle being lost) + UFUNCTION(NetMulticast, Reliable, BlueprintCallable, Category = "ALS|GameState") + void MulticastReliableMessageToClients(const FALSVerbMessage Message); + +private: + UPROPERTY() + TObjectPtr ExperienceManagerComponent; + + // The ability system component subobject for game-wide things (primarily gameplay cues) + UPROPERTY(VisibleAnywhere, Category = "ALS|GameState") + TObjectPtr AbilitySystemComponent; + + +protected: + + virtual void Tick(float DeltaSeconds) override; + +protected: + UPROPERTY(Replicated) + float ServerFPS; +}; diff --git a/Source/ALSV4_CPP/Public/GameModes/ALSWorldSettings.h b/Source/ALSV4_CPP/Public/GameModes/ALSWorldSettings.h new file mode 100644 index 00000000..e648cf2b --- /dev/null +++ b/Source/ALSV4_CPP/Public/GameModes/ALSWorldSettings.h @@ -0,0 +1,42 @@ +// Fill out your copyright notice in the Description page of Project Settings. + +#pragma once + +#include "CoreMinimal.h" +#include "GameFramework/WorldSettings.h" +#include "ALSWorldSettings.generated.h" + +class UALSExperienceDefinition; + + +UCLASS() +class ALSV4_CPP_API AALSWorldSettings : public AWorldSettings +{ + GENERATED_BODY() + +public: + + AALSWorldSettings(const FObjectInitializer& ObjectInitializer); + +#if WITH_EDITOR + virtual void CheckForErrors() override; +#endif + +public: + // Returns the default experience to use when a server opens this map if it is not overridden by the user-facing experience + FPrimaryAssetId GetDefaultGameplayExperience() const; + +protected: + // The default experience to use when a server opens this map if it is not overridden by the user-facing experience + UPROPERTY(EditDefaultsOnly, Category=GameMode) + TSoftClassPtr DefaultGameplayExperience; + +public: + +#if WITH_EDITORONLY_DATA + // Is this level part of a front-end or other standalone experience? + // When set, the net mode will be forced to Standalone when you hit Play in the editor + UPROPERTY(EditDefaultsOnly, Category=PIE) + bool ForceStandaloneNetMode = false; +#endif +}; From 27cb034442caea7741f2f5e7c921b138e49d56af Mon Sep 17 00:00:00 2001 From: Helcio Laurentino do Carmo Junior Date: Mon, 1 May 2023 18:29:30 -0300 Subject: [PATCH 10/17] feat(character): Add character classes --- .../Private/Character/ALSBaseCharacter.cpp | 51 +- .../Private/Character/ALSCharacter.cpp | 106 +++- .../Private/Character/ALSHeroComponent.cpp | 517 ++++++++++++++++++ .../ALSV4_CPP/Private/Character/ALSPawn.cpp | 31 ++ .../Private/Character/ALSPawnComponent.cpp | 13 + .../Private/Character/ALSPawnData.cpp | 12 + .../Character/ALSPawnExtensionComponent.cpp | 353 ++++++++++++ .../Private/Character/ALSPlayerController.cpp | 2 + .../Public/Character/ALSBaseCharacter.h | 10 +- .../ALSV4_CPP/Public/Character/ALSCharacter.h | 27 +- .../Public/Character/ALSHeroComponent.h | 102 ++++ Source/ALSV4_CPP/Public/Character/ALSPawn.h | 30 + .../Public/Character/ALSPawnComponent.h | 41 ++ .../ALSV4_CPP/Public/Character/ALSPawnData.h | 53 ++ .../Character/ALSPawnExtensionComponent.h | 115 ++++ .../Public/Character/ALSPlayerController.h | 3 + 16 files changed, 1444 insertions(+), 22 deletions(-) create mode 100644 Source/ALSV4_CPP/Private/Character/ALSHeroComponent.cpp create mode 100644 Source/ALSV4_CPP/Private/Character/ALSPawn.cpp create mode 100644 Source/ALSV4_CPP/Private/Character/ALSPawnComponent.cpp create mode 100644 Source/ALSV4_CPP/Private/Character/ALSPawnData.cpp create mode 100644 Source/ALSV4_CPP/Private/Character/ALSPawnExtensionComponent.cpp create mode 100644 Source/ALSV4_CPP/Public/Character/ALSHeroComponent.h create mode 100644 Source/ALSV4_CPP/Public/Character/ALSPawn.h create mode 100644 Source/ALSV4_CPP/Public/Character/ALSPawnComponent.h create mode 100644 Source/ALSV4_CPP/Public/Character/ALSPawnData.h create mode 100644 Source/ALSV4_CPP/Public/Character/ALSPawnExtensionComponent.h diff --git a/Source/ALSV4_CPP/Private/Character/ALSBaseCharacter.cpp b/Source/ALSV4_CPP/Private/Character/ALSBaseCharacter.cpp index 65cc49d8..6d943ea8 100644 --- a/Source/ALSV4_CPP/Private/Character/ALSBaseCharacter.cpp +++ b/Source/ALSV4_CPP/Private/Character/ALSBaseCharacter.cpp @@ -587,6 +587,25 @@ FVector AALSBaseCharacter::GetMovementInput() const return ReplicatedCurrentAcceleration; } +void AALSBaseCharacter::RollStart() +{ + // Roll + if (bHasMovementInput) + { + float MovementInputYaw, MovementInputPitch; + const FVector InputForwardVector = UKismetMathLibrary::GetForwardVector(GetControlRotation()) * LastForwardInput; + const FVector InputRightVector = UKismetMathLibrary::GetRightVector(GetControlRotation()) * LastRightInput; + UKismetMathLibrary::GetYawPitchFromVector( + GetCharacterMovement()->GetLastInputVector(), MovementInputYaw,MovementInputPitch + ); + FRotator RollRotator = GetActorRotation(); + RollRotator.Yaw = MovementInputYaw; + SetActorRotation(RollRotator); + } + + Replicated_PlayMontage(GetRollAnimation(), 1.15f); +} + float AALSBaseCharacter::GetAnimCurveValue(FName CurveName) const { if (GetMesh()->GetAnimInstance()) @@ -983,6 +1002,7 @@ void AALSBaseCharacter::SetEssentialValues(float DeltaTime) { ReplicatedCurrentAcceleration = GetCharacterMovement()->GetCurrentAcceleration(); ReplicatedControlRotation = GetControlRotation(); + ReplicatedControlRotation.Pitch = 0; EasedMaxAcceleration = GetCharacterMovement()->GetMaxAcceleration(); } else @@ -1273,18 +1293,32 @@ void AALSBaseCharacter::RightMovementAction_Implementation(float Value) void AALSBaseCharacter::CameraUpAction_Implementation(float Value) { + LastCameraUpInput = Value; + if (GetViewMode() != EALSViewMode::TopDown) { AddControllerPitchInput(LookUpDownRate * Value); } + else + { + FVector CameraVector = FVector(LastCameraUpInput, LastCameraRightInput, 0.0f); + GetController()->SetControlRotation(UKismetMathLibrary::MakeRotFromX(CameraVector)); + } } void AALSBaseCharacter::CameraRightAction_Implementation(float Value) { + LastCameraRightInput = Value; + if (GetViewMode() != EALSViewMode::TopDown) { AddControllerYawInput(LookLeftRightRate * Value); } + else + { + FVector CameraVector = FVector(LastCameraUpInput, LastCameraRightInput, 0.0f); + GetController()->SetControlRotation(UKismetMathLibrary::MakeRotFromX(CameraVector)); + } } void AALSBaseCharacter::JumpAction_Implementation(bool bValue) @@ -1396,22 +1430,9 @@ void AALSBaseCharacter::StanceAction_Implementation() if (LastStanceInputTime - PrevStanceInputTime <= RollDoubleTapTimeout) { - // Roll - if (bHasMovementInput) - { - float MovementInputYaw, MovementInputPitch; - const FVector InputForwardVector = UKismetMathLibrary::GetForwardVector(GetControlRotation()) * LastForwardInput; - const FVector InputRightVector = UKismetMathLibrary::GetRightVector(GetControlRotation()) * LastRightInput; - UKismetMathLibrary::GetYawPitchFromVector( - GetCharacterMovement()->GetLastInputVector(), MovementInputYaw,MovementInputPitch - ); - FRotator RollRotator = GetActorRotation(); - RollRotator.Yaw = MovementInputYaw; - SetActorRotation(RollRotator); - } + // Double tap + RollStart(); - Replicated_PlayMontage(GetRollAnimation(), 1.15f); - if (Stance == EALSStance::Standing) { SetDesiredStance(EALSStance::Crouching); diff --git a/Source/ALSV4_CPP/Private/Character/ALSCharacter.cpp b/Source/ALSV4_CPP/Private/Character/ALSCharacter.cpp index b58d0f1b..2b0e180b 100644 --- a/Source/ALSV4_CPP/Private/Character/ALSCharacter.cpp +++ b/Source/ALSV4_CPP/Private/Character/ALSCharacter.cpp @@ -4,8 +4,11 @@ #include "Character/ALSCharacter.h" +#include "ALSGameplayTags.h" +#include "AbilitySystem/ALSAbilitySystemComponent.h" #include "Engine/StaticMesh.h" #include "AI/ALSAIController.h" +#include "Character/ALSPawnExtensionComponent.h" #include "Kismet/GameplayStatics.h" AALSCharacter::AALSCharacter(const FObjectInitializer& ObjectInitializer) @@ -20,9 +23,23 @@ AALSCharacter::AALSCharacter(const FObjectInitializer& ObjectInitializer) StaticMesh = CreateDefaultSubobject(TEXT("StaticMesh")); StaticMesh->SetupAttachment(HeldObjectRoot); + PawnExtComponent = CreateDefaultSubobject(TEXT("PawnExtensionComponent")); + PawnExtComponent->OnAbilitySystemInitialized_RegisterAndCall(FSimpleMulticastDelegate::FDelegate::CreateUObject(this, &ThisClass::OnAbilitySystemInitialized)); + PawnExtComponent->OnAbilitySystemUninitialized_Register(FSimpleMulticastDelegate::FDelegate::CreateUObject(this, &ThisClass::OnAbilitySystemUninitialized)); + AIControllerClass = AALSAIController::StaticClass(); } +UALSAbilitySystemComponent* AALSCharacter::GetALSAbilitySystemComponent() const +{ + return Cast(GetAbilitySystemComponent()); +} + +UAbilitySystemComponent* AALSCharacter::GetAbilitySystemComponent() const +{ + return PawnExtComponent->GetALSAbilitySystemComponent(); +} + void AALSCharacter::ClearHeldObject() { StaticMesh->SetStaticMesh(nullptr); @@ -102,6 +119,83 @@ FVector AALSCharacter::GetFirstPersonCameraTarget() return GetMesh()->GetSocketLocation(TEXT("FP_Camera")); } +void AALSCharacter::OnAbilitySystemInitialized() +{ + UALSAbilitySystemComponent* ALSASC = GetALSAbilitySystemComponent(); + check(ALSASC); +} + +void AALSCharacter::OnAbilitySystemUninitialized() +{ + // TODO: Unititialize components +} + +void AALSCharacter::PossessedBy(AController* NewController) +{ + Super::PossessedBy(NewController); + + PawnExtComponent->HandleControllerChanged(); +} + +void AALSCharacter::UnPossessed() +{ + AController* const OldController = Controller; + + Super::UnPossessed(); + + PawnExtComponent->HandleControllerChanged(); +} + +void AALSCharacter::OnRep_Controller() +{ + Super::OnRep_Controller(); + + PawnExtComponent->HandleControllerChanged(); +} + +void AALSCharacter::OnRep_PlayerState() +{ + Super::OnRep_PlayerState(); + + PawnExtComponent->HandlePlayerStateReplicated(); +} + +void AALSCharacter::SetupPlayerInputComponent(UInputComponent* PlayerInputComponent) +{ + Super::SetupPlayerInputComponent(PlayerInputComponent); + + PawnExtComponent->SetupPlayerInputComponent(); +} + +void AALSCharacter::InitializeGameplayTags() +{ + // Clear tags that may be lingering on the ability system from the previous pawn. + if (UALSAbilitySystemComponent* ALSASC = GetALSAbilitySystemComponent()) + { + const FALSGameplayTags& GameplayTags = FALSGameplayTags::Get(); + + for (const TPair& TagMapping : GameplayTags.MovementModeTagMap) + { + if (TagMapping.Value.IsValid()) + { + ALSASC->SetLooseGameplayTagCount(TagMapping.Value, 0); + } + } + + for (const TPair& TagMapping : GameplayTags.CustomMovementModeTagMap) + { + if (TagMapping.Value.IsValid()) + { + ALSASC->SetLooseGameplayTagCount(TagMapping.Value, 0); + } + } + + //UALSCharacterMovementComponent* ALSMoveComp = CastChecked(GetCharacterMovement()); + //SetMovementModeTag(ALSMoveComp->MovementMode, ALSMoveComp->CustomMovementMode, true); + } +} + + void AALSCharacter::OnOverlayStateChanged(EALSOverlayState PreviousState) { Super::OnOverlayStateChanged(PreviousState); @@ -130,14 +224,16 @@ void AALSCharacter::EnableCursor(bool bEnable) } UE_LOG(LogTemp, Warning, TEXT("EanbleCursor: %s"), bEnable ? TEXT("true") : TEXT("false")); - PlayerController->bShowMouseCursor = bEnable; + /*PlayerController->bShowMouseCursor = bEnable; PlayerController->bEnableClickEvents = bEnable; - PlayerController->bEnableMouseOverEvents = bEnable; + PlayerController->bEnableMouseOverEvents = bEnable;*/ } void AALSCharacter::UpdateAimMovement(float DeltaTime) { - if (!PlayerController || GetViewMode() != EALSViewMode::TopDown) + if (!PlayerController + || GetViewMode() != EALSViewMode::TopDown + || GetRotationMode() != EALSRotationMode::LookingDirection) { return; } @@ -177,10 +273,10 @@ void AALSCharacter::BeginPlay() PlayerController = Cast(GetController()); - if (ViewMode == EALSViewMode::TopDown) + /*if (ViewMode == EALSViewMode::TopDown) { EnableCursor(true); - } + }*/ UpdateHeldObject(); } diff --git a/Source/ALSV4_CPP/Private/Character/ALSHeroComponent.cpp b/Source/ALSV4_CPP/Private/Character/ALSHeroComponent.cpp new file mode 100644 index 00000000..38e86f42 --- /dev/null +++ b/Source/ALSV4_CPP/Private/Character/ALSHeroComponent.cpp @@ -0,0 +1,517 @@ +// Fill out your copyright notice in the Description page of Project Settings. + + +#include "Character/ALSHeroComponent.h" +#include "ALSLogChannels.h" +#include "GameFramework/Pawn.h" +#include "EnhancedInputComponent.h" +#include "EnhancedInputSubsystems.h" +#include "Player/ALSPlayerController2.h" +#include "Player/ALSPlayerState.h" +#include "Character/ALSPawnExtensionComponent.h" +#include "Character/ALSPawnData.h" +#include "Character/ALSCharacter.h" +#include "AbilitySystem/ALSAbilitySystemComponent.h" +#include "Input/ALSInputConfig.h" +#include "Input/ALSInputComponent.h" +// #include "Camera/ALSCameraComponent.h" +#include "ALSGameplayTags.h" +#include "Engine/LocalPlayer.h" +#include "Camera/ALSCameraMode.h" +#include "Components/GameFrameworkComponentManager.h" +#include "Settings/ALSSettingsLocal.h" +#include "System/ALSAssetManager.h" +#include "PlayerMappableInputConfig.h" +#include "Camera/ALSCameraComponent.h" + + +#if WITH_EDITOR +#include "Misc/UObjectToken.h" +#endif // WITH_EDITOR + +namespace ALSHero +{ + static const float LookYawRate = 300.0f; + static const float LookPitchRate = 165.0f; +}; + +const FName UALSHeroComponent::NAME_BindInputsNow("BindInputsNow"); + +UALSHeroComponent::UALSHeroComponent(const FObjectInitializer& ObjectInitializer) + : Super(ObjectInitializer) +{ + // AbilityCameraMode = nullptr; + bPawnHasInitialized = false; + bReadyToBindInputs = false; +} + +void UALSHeroComponent::OnRegister() +{ + Super::OnRegister(); + + UE_LOG(LogTemp, Warning, TEXT("UALSHeroComponent::OnRegister()")) + + if (const APawn* Pawn = GetPawn()) + { + if (UALSPawnExtensionComponent* PawnExtComp = UALSPawnExtensionComponent::FindPawnExtensionComponent(Pawn)) + { + UE_LOG(LogTemp, Warning, TEXT("UALSHeroComponent::FindPawnExtensionComponent()")) + PawnExtComp->OnPawnReadyToInitialize_RegisterAndCall(FSimpleMulticastDelegate::FDelegate::CreateUObject(this, &ThisClass::OnPawnReadyToInitialize)); + } + } + else + { + UE_LOG(LogALS, Error, TEXT("[UALSHeroComponent::OnRegister] This component has been added to a blueprint whose base class is not a Pawn. To use this component, it MUST be placed on a Pawn Blueprint.")); + +#if WITH_EDITOR + if (GIsEditor) + { + static const FText Message = NSLOCTEXT("ALSHeroComponent", "NotOnPawnError", "has been added to a blueprint whose base class is not a Pawn. To use this component, it MUST be placed on a Pawn Blueprint. This will cause a crash if you PIE!"); + static const FName HeroMessageLogName = TEXT("ALSHeroComponent"); + + FMessageLog(HeroMessageLogName).Error() + ->AddToken(FUObjectToken::Create(this, FText::FromString(GetNameSafe(this)))) + ->AddToken(FTextToken::Create(Message)); + + FMessageLog(HeroMessageLogName).Open(); + } +#endif + } +} + +bool UALSHeroComponent::IsPawnComponentReadyToInitialize() const +{ + // The player state is required. + if (!GetPlayerState()) + { + return false; + } + + const APawn* Pawn = GetPawn(); + + // A pawn is required. + if (!Pawn) + { + return false; + } + + // If we're authority or autonomous, we need to wait for a controller with registered ownership of the player state. + if (Pawn->GetLocalRole() != ROLE_SimulatedProxy) + { + AController* Controller = GetController(); + + const bool bHasControllerPairedWithPS = (Controller != nullptr) && \ + (Controller->PlayerState != nullptr) && \ + (Controller->PlayerState->GetOwner() == Controller); + + if (!bHasControllerPairedWithPS) + { + return false; + } + } + + const bool bIsLocallyControlled = Pawn->IsLocallyControlled(); + const bool bIsBot = Pawn->IsBotControlled(); + + if (bIsLocallyControlled && !bIsBot) + { + // The input component is required when locally controlled. + if (!Pawn->InputComponent) + { + return false; + } + } + + return true; +} + +void UALSHeroComponent::OnPawnReadyToInitialize() +{ + UE_LOG(LogTemp, Warning, TEXT("UALSHeroComponent::OnPawnReadyToInitialize")) + + if (!ensure(!bPawnHasInitialized)) + { + // Don't initialize twice + return; + } + + APawn* Pawn = GetPawn(); + if (!Pawn) + { + return; + } + const bool bIsLocallyControlled = Pawn->IsLocallyControlled(); + + AALSPlayerState* ALSPS = GetPlayerState(); + check(ALSPS); + + const UALSPawnData* PawnData = nullptr; + + if (UALSPawnExtensionComponent* PawnExtComp = UALSPawnExtensionComponent::FindPawnExtensionComponent(Pawn)) + { + PawnData = PawnExtComp->GetPawnData(); + + // The player state holds the persistent data for this player (state that persists across deaths and multiple pawns). + // The ability system component and attribute sets live on the player state. + PawnExtComp->InitializeAbilitySystem(ALSPS->GetALSAbilitySystemComponent(), ALSPS); + } + + if (AALSPlayerController2* ALSPC = GetController()) + { + if (Pawn->InputComponent != nullptr) + { + InitializePlayerInput(Pawn->InputComponent); + } + } + + if (bIsLocallyControlled && PawnData) + { + if (UALSCameraComponent* CameraComponent = UALSCameraComponent::FindCameraComponent(Pawn)) + { + CameraComponent->DetermineCameraModeDelegate.BindUObject(this, &ThisClass::DetermineCameraMode); + } + } + + bPawnHasInitialized = true; +} + +void UALSHeroComponent::BeginPlay() +{ + Super::BeginPlay(); +} + +void UALSHeroComponent::EndPlay(const EEndPlayReason::Type EndPlayReason) +{ + if (const APawn* Pawn = GetPawn()) + { + if (UALSPawnExtensionComponent* PawnExtComp = UALSPawnExtensionComponent::FindPawnExtensionComponent(Pawn)) + { + PawnExtComp->UninitializeAbilitySystem(); + } + } + + Super::EndPlay(EndPlayReason); +} + +void UALSHeroComponent::InitializePlayerInput(UInputComponent* PlayerInputComponent) +{ + UE_LOG(LogTemp, Warning, TEXT("UALSHeroComponent::InitializePlayerInput")) + check(PlayerInputComponent); + + const APawn* Pawn = GetPawn(); + if (!Pawn) + { + return; + } + + const APlayerController* PC = GetController(); + check(PC); + + const ULocalPlayer* LP = PC->GetLocalPlayer(); + check(LP); + + UEnhancedInputLocalPlayerSubsystem* Subsystem = LP->GetSubsystem(); + check(Subsystem); + + Subsystem->ClearAllMappings(); + + if (const UALSPawnExtensionComponent* PawnExtComp = UALSPawnExtensionComponent::FindPawnExtensionComponent(Pawn)) + { + if (const UALSPawnData* PawnData = PawnExtComp->GetPawnData()) + { + if (const UALSInputConfig* InputConfig = PawnData->InputConfig) + { + const FALSGameplayTags& GameplayTags = FALSGameplayTags::Get(); + + // Register any default input configs with the settings so that they will be applied to the player during AddInputMappings + for (const FMappableConfigPair& Pair : DefaultInputConfigs) + { + FMappableConfigPair::ActivatePair(Pair); + } + + UALSInputComponent* ALSIC = CastChecked(PlayerInputComponent); + ALSIC->AddInputMappings(InputConfig, Subsystem); + if (UALSSettingsLocal* LocalSettings = UALSSettingsLocal::Get()) + { + LocalSettings->OnInputConfigActivated.AddUObject(this, &UALSHeroComponent::OnInputConfigActivated); + LocalSettings->OnInputConfigDeactivated.AddUObject(this, &UALSHeroComponent::OnInputConfigDeactivated); + } + + TArray BindHandles; + ALSIC->BindAbilityActions(InputConfig, this, &ThisClass::Input_AbilityInputTagPressed, &ThisClass::Input_AbilityInputTagReleased, /*out*/ BindHandles); + + ALSIC->BindNativeAction(InputConfig, GameplayTags.InputTag_Move, ETriggerEvent::Triggered, this, &ThisClass::Input_Move, /*bLogIfNotFound=*/ true); + ALSIC->BindNativeAction(InputConfig, GameplayTags.InputTag_Look_Mouse, ETriggerEvent::Triggered, this, &ThisClass::Input_LookMouse, /*bLogIfNotFound=*/ true); + ALSIC->BindNativeAction(InputConfig, GameplayTags.InputTag_Look_Stick, ETriggerEvent::Triggered, this, &ThisClass::Input_LookStick, /*bLogIfNotFound=*/ true); + ALSIC->BindNativeAction(InputConfig, GameplayTags.InputTag_Crouch, ETriggerEvent::Triggered, this, &ThisClass::Input_Crouch, /*bLogIfNotFound=*/ true); + ALSIC->BindNativeAction(InputConfig, GameplayTags.InputTag_AutoRun, ETriggerEvent::Triggered, this, &ThisClass::Input_AutoRun, /*bLogIfNotFound=*/ true); + UE_LOG(LogTemp, Warning, TEXT("UALSHeroComponent::InitializePlayerInput - BindNativeAction")) + } + } + } + + if (ensure(!bReadyToBindInputs)) + { + bReadyToBindInputs = true; + } + + UGameFrameworkComponentManager::SendGameFrameworkComponentExtensionEvent(const_cast(PC), NAME_BindInputsNow); + UGameFrameworkComponentManager::SendGameFrameworkComponentExtensionEvent(const_cast(Pawn), NAME_BindInputsNow); +} + +void UALSHeroComponent::OnInputConfigActivated(const FLoadedMappableConfigPair& ConfigPair) +{ + UE_LOG(LogTemp, Warning, TEXT("UALSHeroComponent::OnInputConfigActivated")) + if (AALSPlayerController2* ALSPC = GetController()) + { + if (APawn* Pawn = GetPawn()) + { + if (UALSInputComponent* ALSIC = Cast(Pawn->InputComponent)) + { + if (const ULocalPlayer* LP = ALSPC->GetLocalPlayer()) + { + if (UEnhancedInputLocalPlayerSubsystem* Subsystem = LP->GetSubsystem()) + { + ALSIC->AddInputConfig(ConfigPair, Subsystem); + } + } + } + } + } +} + +void UALSHeroComponent::OnInputConfigDeactivated(const FLoadedMappableConfigPair& ConfigPair) +{ + if (AALSPlayerController2* ALSPC = GetController()) + { + if (APawn* Pawn = GetPawn()) + { + if (UALSInputComponent* ALSIC = Cast(Pawn->InputComponent)) + { + if (const ULocalPlayer* LP = ALSPC->GetLocalPlayer()) + { + if (UEnhancedInputLocalPlayerSubsystem* Subsystem = LP->GetSubsystem()) + { + ALSIC->RemoveInputConfig(ConfigPair, Subsystem); + } + } + } + } + } +} + +void UALSHeroComponent::AddAdditionalInputConfig(const UALSInputConfig* InputConfig) +{ + TArray BindHandles; + + const APawn* Pawn = GetPawn(); + if (!Pawn) + { + return; + } + + UALSInputComponent* ALSIC = Pawn->FindComponentByClass(); + check(ALSIC); + + const APlayerController* PC = GetController(); + check(PC); + + const ULocalPlayer* LP = PC->GetLocalPlayer(); + check(LP); + + UEnhancedInputLocalPlayerSubsystem* Subsystem = LP->GetSubsystem(); + check(Subsystem); + + if (const UALSPawnExtensionComponent* PawnExtComp = UALSPawnExtensionComponent::FindPawnExtensionComponent(Pawn)) + { + ALSIC->BindAbilityActions(InputConfig, this, &ThisClass::Input_AbilityInputTagPressed, &ThisClass::Input_AbilityInputTagReleased, /*out*/ BindHandles); + } +} + +void UALSHeroComponent::RemoveAdditionalInputConfig(const UALSInputConfig* InputConfig) +{ + //@TODO: Implement me! +} + +bool UALSHeroComponent::HasPawnInitialized() const +{ + return bPawnHasInitialized; +} + +bool UALSHeroComponent::IsReadyToBindInputs() const +{ + return bReadyToBindInputs; +} + +void UALSHeroComponent::Input_AbilityInputTagPressed(FGameplayTag InputTag) +{ + if (const APawn* Pawn = GetPawn()) + { + if (const UALSPawnExtensionComponent* PawnExtComp = UALSPawnExtensionComponent::FindPawnExtensionComponent(Pawn)) + { + if (UALSAbilitySystemComponent* ALSASC = PawnExtComp->GetALSAbilitySystemComponent()) + { + ALSASC->AbilityInputTagPressed(InputTag); + } + } + } +} + +void UALSHeroComponent::Input_AbilityInputTagReleased(FGameplayTag InputTag) +{ + const APawn* Pawn = GetPawn(); + if (!Pawn) + { + return; + } + + if (const UALSPawnExtensionComponent* PawnExtComp = UALSPawnExtensionComponent::FindPawnExtensionComponent(Pawn)) + { + if (UALSAbilitySystemComponent* ALSASC = PawnExtComp->GetALSAbilitySystemComponent()) + { + ALSASC->AbilityInputTagReleased(InputTag); + } + } +} + +void UALSHeroComponent::Input_Move(const FInputActionValue& InputActionValue) +{ + UE_LOG(LogTemp, Warning, TEXT("INPUT_MOOOOVE")) + + APawn* Pawn = GetPawn(); + AController* Controller = Pawn ? Pawn->GetController() : nullptr; + + // If the player has attempted to move again then cancel auto running + if (AALSPlayerController2* ALSController = Cast(Controller)) + { + ALSController->SetIsAutoRunning(false); + } + + if (Controller) + { + const FVector2D Value = InputActionValue.Get(); + const FRotator MovementRotation(0.0f, Controller->GetControlRotation().Yaw, 0.0f); + + if (Value.X != 0.0f) + { + const FVector MovementDirection = MovementRotation.RotateVector(FVector::RightVector); + Pawn->AddMovementInput(MovementDirection, Value.X); + } + + if (Value.Y != 0.0f) + { + const FVector MovementDirection = MovementRotation.RotateVector(FVector::ForwardVector); + Pawn->AddMovementInput(MovementDirection, Value.Y); + } + } +} + +void UALSHeroComponent::Input_LookMouse(const FInputActionValue& InputActionValue) +{ + APawn* Pawn = GetPawn(); + + if (!Pawn) + { + return; + } + + const FVector2D Value = InputActionValue.Get(); + + if (Value.X != 0.0f) + { + Pawn->AddControllerYawInput(Value.X); + } + + if (Value.Y != 0.0f) + { + Pawn->AddControllerPitchInput(Value.Y); + } +} + +void UALSHeroComponent::Input_LookStick(const FInputActionValue& InputActionValue) +{ + APawn* Pawn = GetPawn(); + + if (!Pawn) + { + return; + } + + const FVector2D Value = InputActionValue.Get(); + + const UWorld* World = GetWorld(); + check(World); + + if (Value.X != 0.0f) + { + Pawn->AddControllerYawInput(Value.X * ALSHero::LookYawRate * World->GetDeltaSeconds()); + } + + if (Value.Y != 0.0f) + { + Pawn->AddControllerPitchInput(Value.Y * ALSHero::LookPitchRate * World->GetDeltaSeconds()); + } +} + +void UALSHeroComponent::Input_Crouch(const FInputActionValue& InputActionValue) +{ + UE_LOG(LogTemp, Warning, TEXT("UALSHeroComponent::Input_Crouch")) + if (AALSCharacter* Character = GetPawn()) + { + Character->Crouch(); + } +} + +void UALSHeroComponent::Input_AutoRun(const FInputActionValue& InputActionValue) +{ + if (APawn* Pawn = GetPawn()) + { + if (AALSPlayerController2* Controller = Cast(Pawn->GetController())) + { + // Toggle auto running + Controller->SetIsAutoRunning(!Controller->GetIsAutoRunning()); + } + } +} + +TSubclassOf UALSHeroComponent::DetermineCameraMode() const +{ + if (AbilityCameraMode) + { + return AbilityCameraMode; + } + + const APawn* Pawn = GetPawn(); + if (!Pawn) + { + return nullptr; + } + + if (UALSPawnExtensionComponent* PawnExtComp = UALSPawnExtensionComponent::FindPawnExtensionComponent(Pawn)) + { + if (const UALSPawnData* PawnData = PawnExtComp->GetPawnData()) + { + return PawnData->DefaultCameraMode; + } + } + + return nullptr; +} + +void UALSHeroComponent::SetAbilityCameraMode(TSubclassOf CameraMode, const FGameplayAbilitySpecHandle& OwningSpecHandle) +{ + if (CameraMode) + { + AbilityCameraMode = CameraMode; + AbilityCameraModeOwningSpecHandle = OwningSpecHandle; + } +} + +void UALSHeroComponent::ClearAbilityCameraMode(const FGameplayAbilitySpecHandle& OwningSpecHandle) +{ + if (AbilityCameraModeOwningSpecHandle == OwningSpecHandle) + { + AbilityCameraMode = nullptr; + AbilityCameraModeOwningSpecHandle = FGameplayAbilitySpecHandle(); + } +} diff --git a/Source/ALSV4_CPP/Private/Character/ALSPawn.cpp b/Source/ALSV4_CPP/Private/Character/ALSPawn.cpp new file mode 100644 index 00000000..8e604124 --- /dev/null +++ b/Source/ALSV4_CPP/Private/Character/ALSPawn.cpp @@ -0,0 +1,31 @@ +// Fill out your copyright notice in the Description page of Project Settings. + + +#include "Character/ALSPawn.h" +#include "GameFramework/Controller.h" + + +AALSPawn::AALSPawn(const FObjectInitializer& ObjectInitializer) + : Super(ObjectInitializer) +{ +} + +void AALSPawn::PreInitializeComponents() +{ + Super::PreInitializeComponents(); +} + +void AALSPawn::EndPlay(const EEndPlayReason::Type EndPlayReason) +{ + Super::EndPlay(EndPlayReason); +} + +void AALSPawn::PossessedBy(AController* NewController) +{ + Super::PossessedBy(NewController); +} + +void AALSPawn::UnPossessed() +{ + Super::UnPossessed(); +} diff --git a/Source/ALSV4_CPP/Private/Character/ALSPawnComponent.cpp b/Source/ALSV4_CPP/Private/Character/ALSPawnComponent.cpp new file mode 100644 index 00000000..5566d5cf --- /dev/null +++ b/Source/ALSV4_CPP/Private/Character/ALSPawnComponent.cpp @@ -0,0 +1,13 @@ +// Fill out your copyright notice in the Description page of Project Settings. + + +#include "Character/ALSPawnComponent.h" + + +UALSPawnComponent::UALSPawnComponent(const FObjectInitializer& ObjectInitializer) + : Super(ObjectInitializer) +{ + PrimaryComponentTick.bStartWithTickEnabled = false; + PrimaryComponentTick.bCanEverTick = false; +} + diff --git a/Source/ALSV4_CPP/Private/Character/ALSPawnData.cpp b/Source/ALSV4_CPP/Private/Character/ALSPawnData.cpp new file mode 100644 index 00000000..36bc44f0 --- /dev/null +++ b/Source/ALSV4_CPP/Private/Character/ALSPawnData.cpp @@ -0,0 +1,12 @@ +// Fill out your copyright notice in the Description page of Project Settings. + + +#include "Character/ALSPawnData.h" + +UALSPawnData::UALSPawnData(const FObjectInitializer& ObjectInitializer) + : Super(ObjectInitializer) +{ + PawnClass = nullptr; + InputConfig = nullptr; + DefaultCameraMode = nullptr; +} diff --git a/Source/ALSV4_CPP/Private/Character/ALSPawnExtensionComponent.cpp b/Source/ALSV4_CPP/Private/Character/ALSPawnExtensionComponent.cpp new file mode 100644 index 00000000..504cae10 --- /dev/null +++ b/Source/ALSV4_CPP/Private/Character/ALSPawnExtensionComponent.cpp @@ -0,0 +1,353 @@ +// Fill out your copyright notice in the Description page of Project Settings. + + +#include "Character/ALSPawnExtensionComponent.h" + +#include "ALSGameplayTags.h" +#include "ALSLogChannels.h" +#include "Net/UnrealNetwork.h" +#include "GameFramework/Pawn.h" +#include "GameFramework/Controller.h" +#include "Character/ALSPawnData.h" +#include "Components/GameFrameworkComponentManager.h" +#include "Components/GameFrameworkInitStateInterface.h" +#include "AbilitySystem/ALSAbilitySystemComponent.h" + +const FName UALSPawnExtensionComponent::NAME_ActorFeatureName("PawnExtension"); + +UALSPawnExtensionComponent::UALSPawnExtensionComponent(const FObjectInitializer& ObjectInitializer) + : Super(ObjectInitializer) +{ + PrimaryComponentTick.bStartWithTickEnabled = false; + PrimaryComponentTick.bCanEverTick = false; + + SetIsReplicatedByDefault(true); + + PawnData = nullptr; + AbilitySystemComponent = nullptr; + bPawnReadyToInitialize = false; +} + +void UALSPawnExtensionComponent::GetLifetimeReplicatedProps(TArray& OutLifetimeProps) const +{ + Super::GetLifetimeReplicatedProps(OutLifetimeProps); + + DOREPLIFETIME(UALSPawnExtensionComponent, PawnData); +} + +void UALSPawnExtensionComponent::OnRegister() +{ + Super::OnRegister(); + UE_LOG(LogTemp, Warning, TEXT("UALSPawnExtensionComponent::OnRegister()")) + + const APawn* Pawn = GetPawn(); + ensureAlwaysMsgf((Pawn != nullptr), TEXT("ALSPawnExtensionComponent on [%s] can only be added to Pawn actors."), *GetNameSafe(GetOwner())); + + TArray PawnExtensionComponents; + Pawn->GetComponents(UALSPawnExtensionComponent::StaticClass(), PawnExtensionComponents); + ensureAlwaysMsgf((PawnExtensionComponents.Num() == 1), TEXT("Only one ALSPawnExtensionComponent should exist on [%s]."), *GetNameSafe(GetOwner())); +} + +void UALSPawnExtensionComponent::SetPawnData(const UALSPawnData* InPawnData) +{ + check(InPawnData); + + bPawnReadyToInitialize = false; + + APawn* Pawn = GetPawnChecked(); + + if (Pawn->GetLocalRole() != ROLE_Authority) + { + return; + } + + if (PawnData) + { + UE_LOG(LogALS, Error, TEXT("Trying to set PawnData [%s] on pawn [%s] that already has valid PawnData [%s]."), *GetNameSafe(InPawnData), *GetNameSafe(Pawn), *GetNameSafe(PawnData)); + return; + } + + PawnData = InPawnData; + + Pawn->ForceNetUpdate(); + + CheckPawnReadyToInitialize(); +} + +void UALSPawnExtensionComponent::OnRep_PawnData() +{ + CheckPawnReadyToInitialize(); +} + +void UALSPawnExtensionComponent::InitializeAbilitySystem(UALSAbilitySystemComponent* InASC, AActor* InOwnerActor) +{ + check(InASC); + check(InOwnerActor); + + if (AbilitySystemComponent == InASC) + { + // The ability system component hasn't changed. + return; + } + + if (AbilitySystemComponent) + { + // Clean up the old ability system component. + UninitializeAbilitySystem(); + } + + APawn* Pawn = GetPawnChecked(); + AActor* ExistingAvatar = InASC->GetAvatarActor(); + + UE_LOG(LogALS, Verbose, TEXT("Setting up ASC [%s] on pawn [%s] owner [%s], existing [%s] "), *GetNameSafe(InASC), *GetNameSafe(Pawn), *GetNameSafe(InOwnerActor), *GetNameSafe(ExistingAvatar)); + + if ((ExistingAvatar != nullptr) && (ExistingAvatar != Pawn)) + { + UE_LOG(LogALS, Log, TEXT("Existing avatar (authority=%d)"), ExistingAvatar->HasAuthority() ? 1 : 0); + + // There is already a pawn acting as the ASC's avatar, so we need to kick it out + // This can happen on clients if they're lagged: their new pawn is spawned + possessed before the dead one is removed + ensure(!ExistingAvatar->HasAuthority()); + + if (UALSPawnExtensionComponent* OtherExtensionComponent = FindPawnExtensionComponent(ExistingAvatar)) + { + OtherExtensionComponent->UninitializeAbilitySystem(); + } + } + + AbilitySystemComponent = InASC; + AbilitySystemComponent->InitAbilityActorInfo(InOwnerActor, Pawn); + + if (ensure(PawnData)) + { + InASC->SetTagRelationshipMapping(PawnData->TagRelationshipMapping); + } + + OnAbilitySystemInitialized.Broadcast(); +} + +void UALSPawnExtensionComponent::UninitializeAbilitySystem() +{ + if (!AbilitySystemComponent) + { + return; + } + + // Uninitialize the ASC if we're still the avatar actor (otherwise another pawn already did it when they became the avatar actor) + if (AbilitySystemComponent->GetAvatarActor() == GetOwner()) + { + AbilitySystemComponent->CancelAbilities(nullptr, nullptr); + AbilitySystemComponent->ClearAbilityInput(); + AbilitySystemComponent->RemoveAllGameplayCues(); + + if (AbilitySystemComponent->GetOwnerActor() != nullptr) + { + AbilitySystemComponent->SetAvatarActor(nullptr); + } + else + { + // If the ASC doesn't have a valid owner, we need to clear *all* actor info, not just the avatar pairing + AbilitySystemComponent->ClearActorInfo(); + } + + OnAbilitySystemUninitialized.Broadcast(); + } + + AbilitySystemComponent = nullptr; +} + +void UALSPawnExtensionComponent::HandleControllerChanged() +{ + if (AbilitySystemComponent && (AbilitySystemComponent->GetAvatarActor() == GetPawnChecked())) + { + ensure(AbilitySystemComponent->AbilityActorInfo->OwnerActor == AbilitySystemComponent->GetOwnerActor()); + if (AbilitySystemComponent->GetOwnerActor() == nullptr) + { + UninitializeAbilitySystem(); + } + else + { + AbilitySystemComponent->RefreshAbilityActorInfo(); + } + } + + CheckPawnReadyToInitialize(); +} + +void UALSPawnExtensionComponent::HandlePlayerStateReplicated() +{ + CheckPawnReadyToInitialize(); +} + +void UALSPawnExtensionComponent::SetupPlayerInputComponent() +{ + CheckPawnReadyToInitialize(); +} + +bool UALSPawnExtensionComponent::CheckPawnReadyToInitialize() +{ + UE_LOG(LogTemp, Warning, TEXT("CheckPawnReadyToInitialize")) + if (bPawnReadyToInitialize) + { + return true; + } + + // Pawn data is required. + if (!PawnData) + { + return false; + } + UE_LOG(LogTemp, Warning, TEXT("HAS PAWN DATA")) + + APawn* Pawn = GetPawnChecked(); + + const bool bHasAuthority = Pawn->HasAuthority(); + const bool bIsLocallyControlled = Pawn->IsLocallyControlled(); + + if (bHasAuthority || bIsLocallyControlled) + { + // Check for being possessed by a controller. + if (!GetController()) + { + return false; + } + } + + // Allow pawn components to have requirements. + TArray InteractableComponents = Pawn->GetComponentsByInterface(UALSReadyInterface::StaticClass()); + for (UActorComponent* InteractableComponent : InteractableComponents) + { + const IALSReadyInterface* Ready = CastChecked(InteractableComponent); + if (!Ready->IsPawnComponentReadyToInitialize()) + { + return false; + } + } + UE_LOG(LogTemp, Warning, TEXT("IS READY TO INITIALIZE")) + + // Pawn is ready to initialize. + bPawnReadyToInitialize = true; + OnPawnReadyToInitialize.Broadcast(); + BP_OnPawnReadyToInitialize.Broadcast(); + + return true; +} + +void UALSPawnExtensionComponent::CheckDefaultInitialization() +{ + // Before checking our progress, try progressing any other features we might depend on + CheckDefaultInitializationForImplementers(); + + const FALSGameplayTags& InitTags = FALSGameplayTags::Get(); + static const TArray StateChain = { InitTags.InitState_Spawned, InitTags.InitState_DataAvailable, InitTags.InitState_DataInitialized, InitTags.InitState_GameplayReady }; + + // This will try to progress from spawned (which is only set in BeginPlay) through the data initialization stages until it gets to gameplay ready + ContinueInitStateChain(StateChain); +} + +bool UALSPawnExtensionComponent::CanChangeInitState(UGameFrameworkComponentManager* Manager, FGameplayTag CurrentState, FGameplayTag DesiredState) const +{ + check(Manager); + + APawn* Pawn = GetPawn(); + const FALSGameplayTags& InitTags = FALSGameplayTags::Get(); + + if (!CurrentState.IsValid() && DesiredState == InitTags.InitState_Spawned) + { + // As long as we are on a valid pawn, we count as spawned + if (Pawn) + { + return true; + } + } + if (CurrentState == InitTags.InitState_Spawned && DesiredState == InitTags.InitState_DataAvailable) + { + // Pawn data is required. + if (!PawnData) + { + return false; + } + + const bool bHasAuthority = Pawn->HasAuthority(); + const bool bIsLocallyControlled = Pawn->IsLocallyControlled(); + + if (bHasAuthority || bIsLocallyControlled) + { + // Check for being possessed by a controller. + if (!GetController()) + { + return false; + } + } + + return true; + } + else if (CurrentState == InitTags.InitState_DataAvailable && DesiredState == InitTags.InitState_DataInitialized) + { + // Transition to initialize if all features have their data available + return Manager->HaveAllFeaturesReachedInitState(Pawn, InitTags.InitState_DataAvailable); + } + else if (CurrentState == InitTags.InitState_DataInitialized && DesiredState == InitTags.InitState_GameplayReady) + { + return true; + } + + return false; +} + +void UALSPawnExtensionComponent::HandleChangeInitState(UGameFrameworkComponentManager* Manager, FGameplayTag CurrentState, FGameplayTag DesiredState) +{ + if (DesiredState == FALSGameplayTags::Get().InitState_DataInitialized) + { + // This is currently all handled by other components listening to this state change + } +} + +void UALSPawnExtensionComponent::OnActorInitStateChanged(const FActorInitStateChangedParams& Params) +{ + // If another feature is now in DataAvailable, see if we should transition to DataInitialized + if (Params.FeatureName != NAME_ActorFeatureName) + { + const FALSGameplayTags& InitTags = FALSGameplayTags::Get(); + if (Params.FeatureState == InitTags.InitState_DataAvailable) + { + CheckDefaultInitialization(); + } + } +} + + +void UALSPawnExtensionComponent::OnPawnReadyToInitialize_RegisterAndCall(FSimpleMulticastDelegate::FDelegate Delegate) +{ + if (!OnPawnReadyToInitialize.IsBoundToObject(Delegate.GetUObject())) + { + OnPawnReadyToInitialize.Add(Delegate); + } + + if (bPawnReadyToInitialize) + { + Delegate.Execute(); + } +} + +void UALSPawnExtensionComponent::OnAbilitySystemInitialized_RegisterAndCall(FSimpleMulticastDelegate::FDelegate Delegate) +{ + if (!OnAbilitySystemInitialized.IsBoundToObject(Delegate.GetUObject())) + { + OnAbilitySystemInitialized.Add(Delegate); + } + + if (AbilitySystemComponent) + { + Delegate.Execute(); + } +} + +void UALSPawnExtensionComponent::OnAbilitySystemUninitialized_Register(FSimpleMulticastDelegate::FDelegate Delegate) +{ + if (!OnAbilitySystemUninitialized.IsBoundToObject(Delegate.GetUObject())) + { + OnAbilitySystemUninitialized.Add(Delegate); + } +} + diff --git a/Source/ALSV4_CPP/Private/Character/ALSPlayerController.cpp b/Source/ALSV4_CPP/Private/Character/ALSPlayerController.cpp index ce68c74c..ad5ddae7 100644 --- a/Source/ALSV4_CPP/Private/Character/ALSPlayerController.cpp +++ b/Source/ALSV4_CPP/Private/Character/ALSPlayerController.cpp @@ -63,6 +63,7 @@ void AALSPlayerController::SetupInputComponent() EnhancedInputComponent->ClearDebugKeyBindings(); BindActions(DefaultInputMappingContext); + BindActions(GamepadInputMappingContext); BindActions(DebugInputMappingContext); } else @@ -102,6 +103,7 @@ void AALSPlayerController::SetupInputs() FModifyContextOptions Options; Options.bForceImmediately = 1; Subsystem->AddMappingContext(DefaultInputMappingContext, 1, Options); + Subsystem->AddMappingContext(GamepadInputMappingContext, 2, Options); UALSDebugComponent* DebugComp = Cast(PossessedCharacter->GetComponentByClass(UALSDebugComponent::StaticClass())); if (DebugComp) { diff --git a/Source/ALSV4_CPP/Public/Character/ALSBaseCharacter.h b/Source/ALSV4_CPP/Public/Character/ALSBaseCharacter.h index 5148c0aa..208b6acf 100644 --- a/Source/ALSV4_CPP/Public/Character/ALSBaseCharacter.h +++ b/Source/ALSV4_CPP/Public/Character/ALSBaseCharacter.h @@ -5,6 +5,7 @@ #pragma once #include "CoreMinimal.h" +#include "ModularCharacter.h" #include "Components/TimelineComponent.h" #include "Library/ALSCharacterEnumLibrary.h" #include "Library/ALSCharacterStructLibrary.h" @@ -27,7 +28,7 @@ DECLARE_DYNAMIC_MULTICAST_DELEGATE_OneParam(FRagdollStateChangedSignature, bool, * Base character class */ UCLASS(BlueprintType) -class ALSV4_CPP_API AALSBaseCharacter : public ACharacter +class ALSV4_CPP_API AALSBaseCharacter : public AModularCharacter { GENERATED_BODY() @@ -246,6 +247,9 @@ class ALSV4_CPP_API AALSBaseCharacter : public ACharacter UFUNCTION(BlueprintCallable, BlueprintImplementableEvent, Category = "ALS|Movement System") UAnimMontage* GetRollAnimation(); + UFUNCTION(BlueprintCallable, Category = "ALS|Character States") + void RollStart(); + /** Utility */ UFUNCTION(BlueprintCallable, Category = "ALS|Utility") @@ -630,6 +634,10 @@ class ALSV4_CPP_API AALSBaseCharacter : public ACharacter /** Last right input action pressed */ float LastRightInput = 0.0f; + + float LastCameraUpInput = 0.0f; + + float LastCameraRightInput = 0.0f; /* Timer to manage reset of braking friction factor after on landed event */ FTimerHandle OnLandedFrictionResetTimer; diff --git a/Source/ALSV4_CPP/Public/Character/ALSCharacter.h b/Source/ALSV4_CPP/Public/Character/ALSCharacter.h index eef2aecb..a2a5ce81 100644 --- a/Source/ALSV4_CPP/Public/Character/ALSCharacter.h +++ b/Source/ALSV4_CPP/Public/Character/ALSCharacter.h @@ -5,20 +5,29 @@ #pragma once #include "CoreMinimal.h" +#include "AbilitySystemInterface.h" #include "Character/ALSBaseCharacter.h" #include "ALSCharacter.generated.h" +class UALSAbilitySystemComponent; +class UALSPawnExtensionComponent; + /** * Specialized character class, with additional features like held object etc. */ UCLASS(Blueprintable, BlueprintType) -class ALSV4_CPP_API AALSCharacter : public AALSBaseCharacter +class ALSV4_CPP_API AALSCharacter : public AALSBaseCharacter, public IAbilitySystemInterface { GENERATED_BODY() public: AALSCharacter(const FObjectInitializer& ObjectInitializer); + + UFUNCTION(BlueprintCallable, Category = "ALS|Character") + UALSAbilitySystemComponent* GetALSAbilitySystemComponent() const; + virtual UAbilitySystemComponent* GetAbilitySystemComponent() const override; + /** Implemented on BP to update held objects */ UFUNCTION(BlueprintImplementableEvent, BlueprintCallable, Category = "ALS|HeldObject") void UpdateHeldObject(); @@ -43,6 +52,19 @@ class ALSV4_CPP_API AALSCharacter : public AALSBaseCharacter virtual FVector GetFirstPersonCameraTarget() override; protected: + virtual void PossessedBy(AController* NewController) override; + virtual void UnPossessed() override; + + virtual void OnRep_Controller() override; + virtual void OnRep_PlayerState() override; + + virtual void SetupPlayerInputComponent(UInputComponent* PlayerInputComponent) override; + + void InitializeGameplayTags(); + + virtual void OnAbilitySystemInitialized(); + virtual void OnAbilitySystemUninitialized(); + virtual void Tick(float DeltaTime) override; virtual void BeginPlay() override; @@ -71,6 +93,9 @@ class ALSV4_CPP_API AALSCharacter : public AALSBaseCharacter private: bool bNeedsColorReset = false; + UPROPERTY(VisibleAnywhere, BlueprintReadOnly, Category = "ALS|Character", Meta = (AllowPrivateAccess = "true")) + TObjectPtr PawnExtComponent; + UPROPERTY() APlayerController* PlayerController; }; diff --git a/Source/ALSV4_CPP/Public/Character/ALSHeroComponent.h b/Source/ALSV4_CPP/Public/Character/ALSHeroComponent.h new file mode 100644 index 00000000..22886669 --- /dev/null +++ b/Source/ALSV4_CPP/Public/Character/ALSHeroComponent.h @@ -0,0 +1,102 @@ +// Fill out your copyright notice in the Description page of Project Settings. + +#pragma once + +#include "CoreMinimal.h" +#include "Character/ALSPawnComponent.h" +#include "GameplayTagContainer.h" +#include "GameplayAbilitySpec.h" +#include "Input/ALSMappableConfigPair.h" +#include "ALSHeroComponent.generated.h" + + +class AALSPlayerState; +class UInputComponent; +struct FInputActionValue; +class UALSInputConfig; +class UALSCameraMode; + +/** + * UALSHeroComponent + * + * A component used to create a player controlled pawns (characters, vehicles, etc..). + */ +UCLASS(Blueprintable, Meta=(BlueprintSpawnableComponent)) +class ALSV4_CPP_API UALSHeroComponent : public UALSPawnComponent +{ + GENERATED_BODY() + +public: + + UALSHeroComponent(const FObjectInitializer& ObjectInitializer); + + // Returns the hero component if one exists on the specified actor. + UFUNCTION(BlueprintPure, Category = "ALS|Hero") + static UALSHeroComponent* FindHeroComponent(const AActor* Actor) { return (Actor ? Actor->FindComponentByClass() : nullptr); } + + // TOOD: Create ability to define the camera behavior for each ability + void SetAbilityCameraMode(TSubclassOf CameraMode, const FGameplayAbilitySpecHandle& OwningSpecHandle); + void ClearAbilityCameraMode(const FGameplayAbilitySpecHandle& OwningSpecHandle); + + void AddAdditionalInputConfig(const UALSInputConfig* InputConfig); + void RemoveAdditionalInputConfig(const UALSInputConfig* InputConfig); + + /** True if this has completed OnPawnReadyToInitialize so is prepared for late-added features */ + bool HasPawnInitialized() const; + + /** True if this player has sent the BindInputsNow event and is prepared for bindings */ + bool IsReadyToBindInputs() const; + + static const FName NAME_BindInputsNow; + +protected: + + virtual void OnRegister() override; + + virtual bool IsPawnComponentReadyToInitialize() const override; + void OnPawnReadyToInitialize(); + + virtual void BeginPlay() override; + virtual void EndPlay(const EEndPlayReason::Type EndPlayReason) override; + + virtual void InitializePlayerInput(UInputComponent* PlayerInputComponent); + + void Input_AbilityInputTagPressed(FGameplayTag InputTag); + void Input_AbilityInputTagReleased(FGameplayTag InputTag); + + void Input_Move(const FInputActionValue& InputActionValue); + void Input_LookMouse(const FInputActionValue& InputActionValue); + void Input_LookStick(const FInputActionValue& InputActionValue); + void Input_Crouch(const FInputActionValue& InputActionValue); + void Input_AutoRun(const FInputActionValue& InputActionValue); + + // TODO: Define the camera mode + TSubclassOf DetermineCameraMode() const; + + void OnInputConfigActivated(const FLoadedMappableConfigPair& ConfigPair); + void OnInputConfigDeactivated(const FLoadedMappableConfigPair& ConfigPair); + +protected: + + /** + * Input Configs that should be added to this player when initalizing the input. + * + * NOTE: You should only add to this if you do not have a game feature plugin accessible to you. + * If you do, then use the GameFeatureAction_AddInputConfig instead. + */ + UPROPERTY(EditAnywhere) + TArray DefaultInputConfigs; + + // Camera mode set by an ability. + // TODO: This should be a stack of camera modes, so that abilities can push and pop camera modes. + TSubclassOf AbilityCameraMode; + + // Spec handle for the last ability to set a camera mode. + FGameplayAbilitySpecHandle AbilityCameraModeOwningSpecHandle; + + // True when the pawn has fully finished initialization + bool bPawnHasInitialized; + + // True when player input bindings have been applyed, will never be true for non-players + bool bReadyToBindInputs; +}; diff --git a/Source/ALSV4_CPP/Public/Character/ALSPawn.h b/Source/ALSV4_CPP/Public/Character/ALSPawn.h new file mode 100644 index 00000000..fdd93954 --- /dev/null +++ b/Source/ALSV4_CPP/Public/Character/ALSPawn.h @@ -0,0 +1,30 @@ +// Fill out your copyright notice in the Description page of Project Settings. + +#pragma once + +#include "CoreMinimal.h" +#include "ModularPawn.h" +#include "ALSPawn.generated.h" + +/** + * AALSPawn + */ +UCLASS() +class ALSV4_CPP_API AALSPawn : public AModularPawn +{ + GENERATED_BODY() + +public: + + AALSPawn(const FObjectInitializer& ObjectInitializer = FObjectInitializer::Get()); + + //~AActor interface + virtual void PreInitializeComponents() override; + virtual void EndPlay(const EEndPlayReason::Type EndPlayReason) override; + //~End of AActor interface + + //~APawn interface + virtual void PossessedBy(AController* NewController) override; + virtual void UnPossessed() override; + //~End of APawn interface +}; diff --git a/Source/ALSV4_CPP/Public/Character/ALSPawnComponent.h b/Source/ALSV4_CPP/Public/Character/ALSPawnComponent.h new file mode 100644 index 00000000..52f3b8f1 --- /dev/null +++ b/Source/ALSV4_CPP/Public/Character/ALSPawnComponent.h @@ -0,0 +1,41 @@ +// Fill out your copyright notice in the Description page of Project Settings. + +#pragma once + +#include "CoreMinimal.h" +#include "Components/PawnComponent.h" +#include "UObject/Interface.h" +#include "ALSPawnComponent.generated.h" + + +UINTERFACE(BlueprintType) +class ALSV4_CPP_API UALSReadyInterface : public UInterface +{ + GENERATED_BODY() +}; + +class IALSReadyInterface +{ + GENERATED_BODY() + +public: + virtual bool IsPawnComponentReadyToInitialize() const = 0; +}; + + +/** + * UALSPawnComponent + * + * An actor component that can be used for adding custom behavior to pawns. + */ +UCLASS(Blueprintable, Meta = (BlueprintSpawnableComponent)) +class ALSV4_CPP_API UALSPawnComponent : public UPawnComponent, public IALSReadyInterface +{ + GENERATED_BODY() + +public: + + UALSPawnComponent(const FObjectInitializer& ObjectInitializer); + + virtual bool IsPawnComponentReadyToInitialize() const override { return true; } +}; diff --git a/Source/ALSV4_CPP/Public/Character/ALSPawnData.h b/Source/ALSV4_CPP/Public/Character/ALSPawnData.h new file mode 100644 index 00000000..93ccc992 --- /dev/null +++ b/Source/ALSV4_CPP/Public/Character/ALSPawnData.h @@ -0,0 +1,53 @@ +// Fill out your copyright notice in the Description page of Project Settings. + +#pragma once + +#include "CoreMinimal.h" +#include "Engine/DataAsset.h" +#include "Templates/SubclassOf.h" +#include "UObject/UObjectGlobals.h" +#include "ALSPawnData.generated.h" + +class APawn; +class UALSAbilitySet; +class UALSInputConfig; +class UALSAbilityTagRelationshipMapping; +class UALSCameraMode; + + +/** + * UALSPawnData + * + * Non-mutable data asset that contains properties used to define a pawn. + */ +UCLASS(BlueprintType, Const, Meta = (DisplayName = "ALS Pawn Data", ShortTooltip = "Data asset used to define a Pawn.")) +class ALSV4_CPP_API UALSPawnData : public UPrimaryDataAsset +{ + GENERATED_BODY() + +public: + + UALSPawnData(const FObjectInitializer& ObjectInitializer); + +public: + + // Class to instantiate for this pawn (should usually derive from AALSPawn or AALSCharacter). + UPROPERTY(EditDefaultsOnly, BlueprintReadOnly, Category = "ALS|Pawn") + TSubclassOf PawnClass; + + // Ability sets to grant to this pawn's ability system. + UPROPERTY(EditDefaultsOnly, BlueprintReadOnly, Category = "ALS|Abilities") + TArray AbilitySets; + + // What mapping of ability tags to use for actions taking by this pawn + UPROPERTY(EditDefaultsOnly, BlueprintReadOnly, Category = "ALS|Abilities") + UALSAbilityTagRelationshipMapping* TagRelationshipMapping; + + // Input configuration used by player controlled pawns to create input mappings and bind input actions. + UPROPERTY(EditDefaultsOnly, BlueprintReadOnly, Category = "ALS|Input") + UALSInputConfig* InputConfig; + + // Default camera mode used by player controlled pawns. + UPROPERTY(EditDefaultsOnly, BlueprintReadOnly, Category = "ALS|Camera") + TSubclassOf DefaultCameraMode; +}; diff --git a/Source/ALSV4_CPP/Public/Character/ALSPawnExtensionComponent.h b/Source/ALSV4_CPP/Public/Character/ALSPawnExtensionComponent.h new file mode 100644 index 00000000..1268a911 --- /dev/null +++ b/Source/ALSV4_CPP/Public/Character/ALSPawnExtensionComponent.h @@ -0,0 +1,115 @@ +// Fill out your copyright notice in the Description page of Project Settings. + +#pragma once + +#include "CoreMinimal.h" +#include "ALSPawnComponent.h" +#include "Components/GameFrameworkInitStateInterface.h" +#include "ALSPawnExtensionComponent.generated.h" + + +class UALSPawnData; +class UALSAbilitySystemComponent; + +DECLARE_DYNAMIC_MULTICAST_DELEGATE(FALSDynamicMulticastDelegate); + +/** + * UALSPawnExtensionComponent + * + * Component used to add functionality to all Pawn classes. + */ +UCLASS() +class ALSV4_CPP_API UALSPawnExtensionComponent : public UALSPawnComponent, public IGameFrameworkInitStateInterface +{ + GENERATED_BODY() + +public: + + UALSPawnExtensionComponent(const FObjectInitializer& ObjectInitializer); + + /** The name of this overall feature, this one depends on the other named component features */ + static const FName NAME_ActorFeatureName; + + //~ Begin IGameFrameworkInitStateInterface interface + virtual FName GetFeatureName() const override { return NAME_ActorFeatureName; } + virtual bool CanChangeInitState(UGameFrameworkComponentManager* Manager, FGameplayTag CurrentState, FGameplayTag DesiredState) const override; + virtual void HandleChangeInitState(UGameFrameworkComponentManager* Manager, FGameplayTag CurrentState, FGameplayTag DesiredState) override; + virtual void OnActorInitStateChanged(const FActorInitStateChangedParams& Params) override; + virtual void CheckDefaultInitialization() override; + //~ End IGameFrameworkInitStateInterface interface + + // Returns the pawn extension component if one exists on the specified actor. + UFUNCTION(BlueprintPure, Category = "ALS|Pawn") + static UALSPawnExtensionComponent* FindPawnExtensionComponent(const AActor* Actor) { return (Actor ? Actor->FindComponentByClass() : nullptr); } + + template + const T* GetPawnData() const { return Cast(PawnData); } + + void SetPawnData(const UALSPawnData* InPawnData); + + UFUNCTION(BlueprintPure, Category = "ALS|Pawn") + UALSAbilitySystemComponent* GetALSAbilitySystemComponent() const { return AbilitySystemComponent; } + + // Should be called by the owning pawn to become the avatar of the ability system. + void InitializeAbilitySystem(UALSAbilitySystemComponent* InASC, AActor* InOwnerActor); + + // Should be called by the owning pawn to remove itself as the avatar of the ability system. + void UninitializeAbilitySystem(); + + // Should be called by the owning pawn when the pawn's controller changes. + void HandleControllerChanged(); + + // Should be called by the owning pawn when the player state has been replicated. + void HandlePlayerStateReplicated(); + + // Should be called by the owning pawn when the input component is setup. + void SetupPlayerInputComponent(); + + // Call this anytime the pawn needs to check if it's ready to be initialized (pawn data assigned, possessed, etc..). + bool CheckPawnReadyToInitialize(); + + // Returns true if the pawn is ready to be initialized. + UFUNCTION(BlueprintCallable, BlueprintPure = false, Category = "ALS|Pawn", Meta = (ExpandBoolAsExecs = "ReturnValue")) + bool IsPawnReadyToInitialize() const { return bPawnReadyToInitialize; } + + // Register with the OnPawnReadyToInitialize delegate and broadcast if condition is already met. + void OnPawnReadyToInitialize_RegisterAndCall(FSimpleMulticastDelegate::FDelegate Delegate); + + // Register with the OnAbilitySystemInitialized delegate and broadcast if condition is already met. + void OnAbilitySystemInitialized_RegisterAndCall(FSimpleMulticastDelegate::FDelegate Delegate); + + // Register with the OnAbilitySystemUninitialized delegate. + void OnAbilitySystemUninitialized_Register(FSimpleMulticastDelegate::FDelegate Delegate); + +protected: + + virtual void OnRegister() override; + + UFUNCTION() + void OnRep_PawnData(); + + // Delegate fired when pawn has everything needed for initialization. + FSimpleMulticastDelegate OnPawnReadyToInitialize; + + UPROPERTY(BlueprintAssignable, Meta = (DisplayName = "On Pawn Ready To Initialize")) + FALSDynamicMulticastDelegate BP_OnPawnReadyToInitialize; + + // Delegate fired when our pawn becomes the ability system's avatar actor + FSimpleMulticastDelegate OnAbilitySystemInitialized; + + // Delegate fired when our pawn is removed as the ability system's avatar actor + FSimpleMulticastDelegate OnAbilitySystemUninitialized; + +protected: + + // Pawn data used to create the pawn. Specified from a spawn function or on a placed instance. + UPROPERTY(EditInstanceOnly, ReplicatedUsing = OnRep_PawnData, Category = "ALS|Pawn") + const UALSPawnData* PawnData; + + // Pointer to the ability system component that is cached for convenience. + UPROPERTY() + UALSAbilitySystemComponent* AbilitySystemComponent; + + // True when the pawn has everything needed for initialization. + int32 bPawnReadyToInitialize : 1; +}; diff --git a/Source/ALSV4_CPP/Public/Character/ALSPlayerController.h b/Source/ALSV4_CPP/Public/Character/ALSPlayerController.h index 1b80fc20..8f3d6264 100644 --- a/Source/ALSV4_CPP/Public/Character/ALSPlayerController.h +++ b/Source/ALSV4_CPP/Public/Character/ALSPlayerController.h @@ -117,6 +117,9 @@ class ALSV4_CPP_API AALSPlayerController : public APlayerController UPROPERTY(EditDefaultsOnly, BlueprintReadWrite, Category = "ALS|Input") TObjectPtr DefaultInputMappingContext = nullptr; + UPROPERTY(EditDefaultsOnly, BlueprintReadWrite, Category = "ALS|Input") + TObjectPtr GamepadInputMappingContext = nullptr; + UPROPERTY(EditDefaultsOnly, BlueprintReadWrite, Category = "ALS|Input") TObjectPtr DebugInputMappingContext = nullptr; }; From a8cad9eae3d4c1352cd99517a0eb5b2034c798e4 Mon Sep 17 00:00:00 2001 From: Helcio Laurentino do Carmo Junior Date: Mon, 1 May 2023 18:29:50 -0300 Subject: [PATCH 11/17] feat(animation): Add character animation class --- .../Private/Character/Animation/ALSCharacterAnimInstance.cpp | 5 +++++ .../Public/Character/Animation/ALSCharacterAnimInstance.h | 3 +++ 2 files changed, 8 insertions(+) diff --git a/Source/ALSV4_CPP/Private/Character/Animation/ALSCharacterAnimInstance.cpp b/Source/ALSV4_CPP/Private/Character/Animation/ALSCharacterAnimInstance.cpp index 97776d01..5992054d 100644 --- a/Source/ALSV4_CPP/Private/Character/Animation/ALSCharacterAnimInstance.cpp +++ b/Source/ALSV4_CPP/Private/Character/Animation/ALSCharacterAnimInstance.cpp @@ -51,6 +51,11 @@ void UALSCharacterAnimInstance::NativeInitializeAnimation() } } +void UALSCharacterAnimInstance::InitializeWithAbilitySystem(UAbilitySystemComponent* ASC) +{ + // TODO: Implement this +} + void UALSCharacterAnimInstance::NativeBeginPlay() { // it seems to be that the player pawn components are not really initialized diff --git a/Source/ALSV4_CPP/Public/Character/Animation/ALSCharacterAnimInstance.h b/Source/ALSV4_CPP/Public/Character/Animation/ALSCharacterAnimInstance.h index a4afa5ac..7bd15339 100644 --- a/Source/ALSV4_CPP/Public/Character/Animation/ALSCharacterAnimInstance.h +++ b/Source/ALSV4_CPP/Public/Character/Animation/ALSCharacterAnimInstance.h @@ -11,6 +11,7 @@ #include "ALSCharacterAnimInstance.generated.h" // forward declarations +class UAbilitySystemComponent; class UALSDebugComponent; class AALSBaseCharacter; class UCurveFloat; @@ -28,6 +29,8 @@ class ALSV4_CPP_API UALSCharacterAnimInstance : public UAnimInstance public: virtual void NativeInitializeAnimation() override; + virtual void InitializeWithAbilitySystem(UAbilitySystemComponent* ASC); + virtual void NativeBeginPlay() override; virtual void NativeUpdateAnimation(float DeltaSeconds) override; From 366f6f72766f85a0a333dfd100ca818f00fb36ea Mon Sep 17 00:00:00 2001 From: Helcio Laurentino do Carmo Junior Date: Mon, 1 May 2023 18:30:16 -0300 Subject: [PATCH 12/17] feat(player): Add player classes --- .../Private/Player/ALSLocalPlayer.cpp | 53 ++++ .../Private/Player/ALSPlayerController2.cpp | 276 ++++++++++++++++++ .../Private/Player/ALSPlayerState.cpp | 240 +++++++++++++++ .../ALSV4_CPP/Public/Player/ALSLocalPlayer.h | 47 +++ .../Public/Player/ALSPlayerController2.h | 117 ++++++++ .../ALSV4_CPP/Public/Player/ALSPlayerState.h | 131 +++++++++ 6 files changed, 864 insertions(+) create mode 100644 Source/ALSV4_CPP/Private/Player/ALSLocalPlayer.cpp create mode 100644 Source/ALSV4_CPP/Private/Player/ALSPlayerController2.cpp create mode 100644 Source/ALSV4_CPP/Private/Player/ALSPlayerState.cpp create mode 100644 Source/ALSV4_CPP/Public/Player/ALSLocalPlayer.h create mode 100644 Source/ALSV4_CPP/Public/Player/ALSPlayerController2.h create mode 100644 Source/ALSV4_CPP/Public/Player/ALSPlayerState.h diff --git a/Source/ALSV4_CPP/Private/Player/ALSLocalPlayer.cpp b/Source/ALSV4_CPP/Private/Player/ALSLocalPlayer.cpp new file mode 100644 index 00000000..f94234fd --- /dev/null +++ b/Source/ALSV4_CPP/Private/Player/ALSLocalPlayer.cpp @@ -0,0 +1,53 @@ +// Fill out your copyright notice in the Description page of Project Settings. + + +#include "Player/ALSLocalPlayer.h" +#include "InputMappingContext.h" +#include "AudioMixerBlueprintLibrary.h" +#include "GameFramework/PlayerController.h" + +UALSLocalPlayer::UALSLocalPlayer() +{ +} + +void UALSLocalPlayer::SwitchController(class APlayerController* PC) +{ + Super::SwitchController(PC); + + OnPlayerControllerChanged(PlayerController); +} + +bool UALSLocalPlayer::SpawnPlayActor(const FString& URL, FString& OutError, UWorld* InWorld) +{ + const bool bResult = Super::SpawnPlayActor(URL, OutError, InWorld); + + OnPlayerControllerChanged(PlayerController); + + return bResult; +} + +void UALSLocalPlayer::InitOnlineSession() +{ + OnPlayerControllerChanged(PlayerController); + + Super::InitOnlineSession(); +} + +void UALSLocalPlayer::OnAudioOutputDeviceChanged(const FString& InAudioOutputDeviceId) +{ + FOnCompletedDeviceSwap DevicesSwappedCallback; + DevicesSwappedCallback.BindUFunction(this, FName("OnCompletedAudioDeviceSwap")); + UAudioMixerBlueprintLibrary::SwapAudioOutputDevice(GetWorld(), InAudioOutputDeviceId, DevicesSwappedCallback); +} + +void UALSLocalPlayer::OnCompletedAudioDeviceSwap(const FSwapAudioOutputResult& SwapResult) +{ + if (SwapResult.Result == ESwapAudioOutputDeviceResultState::Failure) + { + } +} + +void UALSLocalPlayer::OnPlayerControllerChanged(APlayerController* NewController) +{ +} + diff --git a/Source/ALSV4_CPP/Private/Player/ALSPlayerController2.cpp b/Source/ALSV4_CPP/Private/Player/ALSPlayerController2.cpp new file mode 100644 index 00000000..c9deb5f3 --- /dev/null +++ b/Source/ALSV4_CPP/Private/Player/ALSPlayerController2.cpp @@ -0,0 +1,276 @@ +// Fill out your copyright notice in the Description page of Project Settings. + + +#include "Player/ALSPlayerController2.h" +#include "ALSLogChannels.h" +#include "Player/ALSPlayerState.h" +#include "Character/ALSPawnData.h" +#include "AbilitySystem/ALSAbilitySystemComponent.h" +#include "EngineUtils.h" +#include "ALSGameplayTags.h" +#include "GameFramework/Pawn.h" +#include "AbilitySystemGlobals.h" +#include "CommonInputSubsystem.h" +#include "Player/ALSLocalPlayer.h" + +AALSPlayerController2::AALSPlayerController2(const FObjectInitializer& ObjectInitializer) + : Super(ObjectInitializer) +{ +} + +void AALSPlayerController2::PreInitializeComponents() +{ + Super::PreInitializeComponents(); +} + +void AALSPlayerController2::BeginPlay() +{ + Super::BeginPlay(); + SetActorHiddenInGame(false); +} + +void AALSPlayerController2::EndPlay(const EEndPlayReason::Type EndPlayReason) +{ + Super::EndPlay(EndPlayReason); +} + +void AALSPlayerController2::ReceivedPlayer() +{ + Super::ReceivedPlayer(); +} + +void AALSPlayerController2::PlayerTick(float DeltaTime) +{ + Super::PlayerTick(DeltaTime); + + // If we are auto running then add some player input + if (GetIsAutoRunning()) + { + if (APawn* CurrentPawn = GetPawn()) + { + const FRotator MovementRotation(0.0f, GetControlRotation().Yaw, 0.0f); + const FVector MovementDirection = MovementRotation.RotateVector(FVector::ForwardVector); + CurrentPawn->AddMovementInput(MovementDirection, 1.0f); + } + } +} + +AALSPlayerState* AALSPlayerController2::GetALSPlayerState() const +{ + return CastChecked(PlayerState, ECastCheckedType::NullAllowed); +} + +UALSAbilitySystemComponent* AALSPlayerController2::GetALSAbilitySystemComponent() const +{ + const AALSPlayerState* ALSPS = GetALSPlayerState(); + return (ALSPS ? ALSPS->GetALSAbilitySystemComponent() : nullptr); +} + +void AALSPlayerController2::OnPlayerStateChangedTeam(UObject* TeamAgent, int32 OldTeam, int32 NewTeam) +{ +} + +void AALSPlayerController2::OnPlayerStateChanged() +{ + // Empty, place for derived classes to implement without having to hook all the other events +} + +void AALSPlayerController2::BroadcastOnPlayerStateChanged() +{ + OnPlayerStateChanged(); + + LastSeenPlayerState = PlayerState; +} + +void AALSPlayerController2::InitPlayerState() +{ + Super::InitPlayerState(); + BroadcastOnPlayerStateChanged(); +} + +void AALSPlayerController2::CleanupPlayerState() +{ + Super::CleanupPlayerState(); + BroadcastOnPlayerStateChanged(); +} + +void AALSPlayerController2::OnRep_PlayerState() +{ + Super::OnRep_PlayerState(); + BroadcastOnPlayerStateChanged(); +} + +void AALSPlayerController2::SetPlayer(UPlayer* InPlayer) +{ + Super::SetPlayer(InPlayer); +} + +void AALSPlayerController2::PreProcessInput(const float DeltaTime, const bool bGamePaused) +{ + Super::PreProcessInput(DeltaTime, bGamePaused); +} + +void AALSPlayerController2::PostProcessInput(const float DeltaTime, const bool bGamePaused) +{ + if (UALSAbilitySystemComponent* ALSASC = GetALSAbilitySystemComponent()) + { + ALSASC->ProcessAbilityInput(DeltaTime, bGamePaused); + } + + Super::PostProcessInput(DeltaTime, bGamePaused); +} + +// TODO: Fix this +/* +void AALSPlayerController2::OnCameraPenetratingTarget() +{ + bHideViewTargetPawnNextFrame = true; +}*/ + +void AALSPlayerController2::OnPossess(APawn* InPawn) +{ + Super::OnPossess(InPawn); + + SetIsAutoRunning(false); +} + +void AALSPlayerController2::SetIsAutoRunning(const bool bEnabled) +{ + const bool bIsAutoRunning = GetIsAutoRunning(); + if (bEnabled != bIsAutoRunning) + { + if (!bEnabled) + { + OnEndAutoRun(); + } + else + { + OnStartAutoRun(); + } + } +} + +bool AALSPlayerController2::GetIsAutoRunning() const +{ + bool bIsAutoRunning = false; + if (const UALSAbilitySystemComponent* ALSASC = GetALSAbilitySystemComponent()) + { + bIsAutoRunning = ALSASC->GetTagCount(FALSGameplayTags::Get().Status_AutoRunning) > 0; + } + return bIsAutoRunning; +} + +void AALSPlayerController2::OnStartAutoRun() +{ + if (UALSAbilitySystemComponent* ALSASC = GetALSAbilitySystemComponent()) + { + ALSASC->SetLooseGameplayTagCount(FALSGameplayTags::Get().Status_AutoRunning, 1); + K2_OnStartAutoRun(); + } +} + +void AALSPlayerController2::OnEndAutoRun() +{ + if (UALSAbilitySystemComponent* ALSASC = GetALSAbilitySystemComponent()) + { + ALSASC->SetLooseGameplayTagCount(FALSGameplayTags::Get().Status_AutoRunning, 0); + K2_OnEndAutoRun(); + } +} + +void AALSPlayerController2::UpdateForceFeedback(IInputInterface* InputInterface, const int32 ControllerId) +{ + if (bForceFeedbackEnabled) + { + if (const UCommonInputSubsystem* CommonInputSubsystem = UCommonInputSubsystem::Get(GetLocalPlayer())) + { + const ECommonInputType CurrentInputType = CommonInputSubsystem->GetCurrentInputType(); + if (CurrentInputType == ECommonInputType::Gamepad || CurrentInputType == ECommonInputType::Touch) + { + InputInterface->SetForceFeedbackChannelValues(ControllerId, ForceFeedbackValues); + return; + } + } + } + + InputInterface->SetForceFeedbackChannelValues(ControllerId, FForceFeedbackValues()); +} + +void AALSPlayerController2::UpdateHiddenComponents(const FVector& ViewLocation, TSet& OutHiddenComponents) +{ + Super::UpdateHiddenComponents(ViewLocation, OutHiddenComponents); + + if (bHideViewTargetPawnNextFrame) + { + AActor* const ViewTargetPawn = PlayerCameraManager ? Cast(PlayerCameraManager->GetViewTarget()) : nullptr; + if (ViewTargetPawn) + { + // internal helper func to hide all the components + auto AddToHiddenComponents = [&OutHiddenComponents](const TInlineComponentArray& InComponents) + { + // add every component and all attached children + for (UPrimitiveComponent* Comp : InComponents) + { + if (Comp->IsRegistered()) + { + OutHiddenComponents.Add(Comp->ComponentId); + + for (USceneComponent* AttachedChild : Comp->GetAttachChildren()) + { + static FName NAME_NoParentAutoHide(TEXT("NoParentAutoHide")); + UPrimitiveComponent* AttachChildPC = Cast(AttachedChild); + if (AttachChildPC && AttachChildPC->IsRegistered() && !AttachChildPC->ComponentTags.Contains(NAME_NoParentAutoHide)) + { + OutHiddenComponents.Add(AttachChildPC->ComponentId); + } + } + } + } + }; + + //TODO Solve with an interface. Gather hidden components or something. + //TODO Hiding isn't awesome, sometimes you want the effect of a fade out over a proximity, needs to bubble up to designers. + + // hide pawn's components + TInlineComponentArray PawnComponents; + ViewTargetPawn->GetComponents(PawnComponents); + AddToHiddenComponents(PawnComponents); + + //// hide weapon too + //if (ViewTargetPawn->CurrentWeapon) + //{ + // TInlineComponentArray WeaponComponents; + // ViewTargetPawn->CurrentWeapon->GetComponents(WeaponComponents); + // AddToHiddenComponents(WeaponComponents); + //} + } + + // we consumed it, reset for next frame + bHideViewTargetPawnNextFrame = false; + } +} + +void AALSPlayerController2::OnUnPossess() +{ + // Make sure the pawn that is being unpossessed doesn't remain our ASC's avatar actor + if (APawn* PawnBeingUnpossessed = GetPawn()) + { + if (UAbilitySystemComponent* ASC = UAbilitySystemGlobals::GetAbilitySystemComponentFromActor(PlayerState)) + { + if (ASC->GetAvatarActor() == PawnBeingUnpossessed) + { + ASC->SetAvatarActor(nullptr); + } + } + } + + Super::OnUnPossess(); +} + +////////////////////////////////////////////////////////////////////// +// AALSReplayPlayerController + +void AALSReplayPlayerController::SetPlayer(UPlayer* InPlayer) +{ + Super::SetPlayer(InPlayer); +} diff --git a/Source/ALSV4_CPP/Private/Player/ALSPlayerState.cpp b/Source/ALSV4_CPP/Private/Player/ALSPlayerState.cpp new file mode 100644 index 00000000..cc8999ed --- /dev/null +++ b/Source/ALSV4_CPP/Private/Player/ALSPlayerState.cpp @@ -0,0 +1,240 @@ +// Fill out your copyright notice in the Description page of Project Settings. + +#include "Player/ALSPlayerState.h" +#include "AbilitySystem/ALSAbilitySet.h" +#include "AbilitySystem/ALSAbilitySystemComponent.h" +#include "AbilitySystemComponent.h" +#include "Character/ALSPawnData.h" +#include "Character/ALSPawnExtensionComponent.h" +#include "Components/GameFrameworkComponentManager.h" +#include "Containers/Array.h" +#include "Containers/UnrealString.h" +#include "CoreTypes.h" +#include "Delegates/Delegate.h" +#include "Engine/EngineBaseTypes.h" +#include "Engine/EngineTypes.h" +#include "Engine/World.h" +#include "GameFramework/GameStateBase.h" +#include "GameFramework/GameplayMessageSubsystem.h" +#include "GameFramework/Pawn.h" +#include "GameModes/ALSExperienceManagerComponent.h" +//@TODO: Would like to isolate this a bit better to get the pawn data in here without this having to know about other stuff +#include "GameModes/ALSGameMode.h" +#include "GameplayTagContainer.h" +#include "Logging/LogCategory.h" +#include "Logging/LogMacros.h" +#include "ALSLogChannels.h" +#include "Player/ALSPlayerController2.h" +#include "Misc/AssertionMacros.h" +#include "Net/Core/PushModel/PushModel.h" +#include "Net/UnrealNetwork.h" +#include "Trace/Detail/Channel.h" +#include "UObject/NameTypes.h" +#include "UObject/UObjectBaseUtility.h" + +#include UE_INLINE_GENERATED_CPP_BY_NAME(ALSPlayerState) + +class AController; +class APlayerState; +class FLifetimeProperty; + +const FName AALSPlayerState::NAME_ALSAbilityReady("ALSAbilitiesReady"); + +AALSPlayerState::AALSPlayerState(const FObjectInitializer& ObjectInitializer) + : Super(ObjectInitializer) + , MyPlayerConnectionType(EALSPlayerConnectionType::Player) +{ + AbilitySystemComponent = ObjectInitializer.CreateDefaultSubobject(this, TEXT("AbilitySystemComponent")); + AbilitySystemComponent->SetIsReplicated(true); + AbilitySystemComponent->SetReplicationMode(EGameplayEffectReplicationMode::Mixed); + + // AbilitySystemComponent needs to be updated at a high frequency. + NetUpdateFrequency = 100.0f; +} + +void AALSPlayerState::PreInitializeComponents() +{ + Super::PreInitializeComponents(); +} + +void AALSPlayerState::Reset() +{ + Super::Reset(); +} + +void AALSPlayerState::ClientInitialize(AController* C) +{ + Super::ClientInitialize(C); + + if (UALSPawnExtensionComponent* PawnExtComp = UALSPawnExtensionComponent::FindPawnExtensionComponent(GetPawn())) + { + PawnExtComp->CheckDefaultInitialization(); + } +} + +void AALSPlayerState::CopyProperties(APlayerState* PlayerState) +{ + Super::CopyProperties(PlayerState); + + //@TODO: Copy stats +} + +void AALSPlayerState::OnDeactivated() +{ + bool bDestroyDeactivatedPlayerState = false; + + switch (GetPlayerConnectionType()) + { + case EALSPlayerConnectionType::Player: + case EALSPlayerConnectionType::InactivePlayer: + //@TODO: Ask the experience if we should destroy disconnecting players immediately or leave them around + // (e.g., for long running servers where they might build up if lots of players cycle through) + bDestroyDeactivatedPlayerState = true; + break; + default: + bDestroyDeactivatedPlayerState = true; + break; + } + + SetPlayerConnectionType(EALSPlayerConnectionType::InactivePlayer); + + if (bDestroyDeactivatedPlayerState) + { + Destroy(); + } +} + +void AALSPlayerState::OnReactivated() +{ + if (GetPlayerConnectionType() == EALSPlayerConnectionType::InactivePlayer) + { + SetPlayerConnectionType(EALSPlayerConnectionType::Player); + } +} + +void AALSPlayerState::OnExperienceLoaded(const UALSExperienceDefinition* /*CurrentExperience*/) +{ + UE_LOG(LogTemp, Warning, TEXT("AALSPlayerState::OnExperienceLoaded()")) + if (AALSGameMode* ALSGameMode = GetWorld()->GetAuthGameMode()) + { + if (const UALSPawnData* NewPawnData = ALSGameMode->GetPawnDataForController(GetOwningController())) + { + SetPawnData(NewPawnData); + } + else + { + UE_LOG(LogALS, Error, TEXT("AALSPlayerState::OnExperienceLoaded(): Unable to find PawnData to initialize player state [%s]!"), *GetNameSafe(this)); + } + } +} + +void AALSPlayerState::GetLifetimeReplicatedProps(TArray& OutLifetimeProps) const +{ + Super::GetLifetimeReplicatedProps(OutLifetimeProps); + + FDoRepLifetimeParams SharedParams; + SharedParams.bIsPushBased = true; + + DOREPLIFETIME_WITH_PARAMS_FAST(ThisClass, PawnData, SharedParams); + DOREPLIFETIME_WITH_PARAMS_FAST(ThisClass, MyPlayerConnectionType, SharedParams) + + DOREPLIFETIME(ThisClass, StatTags); +} + +AALSPlayerController2* AALSPlayerState::GetALSPlayerController() const +{ + return Cast(GetOwner()); +} + +UAbilitySystemComponent* AALSPlayerState::GetAbilitySystemComponent() const +{ + return GetALSAbilitySystemComponent(); +} + +void AALSPlayerState::PostInitializeComponents() +{ + Super::PostInitializeComponents(); + + check(AbilitySystemComponent); + AbilitySystemComponent->InitAbilityActorInfo(this, GetPawn()); + + if (GetNetMode() != NM_Client) + { + AGameStateBase* GameState = GetWorld()->GetGameState(); + check(GameState); + UALSExperienceManagerComponent* ExperienceComponent = GameState->FindComponentByClass(); + check(ExperienceComponent); + ExperienceComponent->CallOrRegister_OnExperienceLoaded(FOnALSExperienceLoaded::FDelegate::CreateUObject(this, &ThisClass::OnExperienceLoaded)); + } +} + +void AALSPlayerState::SetPawnData(const UALSPawnData* InPawnData) +{ + check(InPawnData); + + if (GetLocalRole() != ROLE_Authority) + { + return; + } + + if (PawnData) + { + UE_LOG(LogALS, Error, TEXT("Trying to set PawnData [%s] on player state [%s] that already has valid PawnData [%s]."), *GetNameSafe(InPawnData), *GetNameSafe(this), *GetNameSafe(PawnData)); + return; + } + + MARK_PROPERTY_DIRTY_FROM_NAME(ThisClass, PawnData, this); + PawnData = InPawnData; + + for (const UALSAbilitySet* AbilitySet : PawnData->AbilitySets) + { + if (AbilitySet) + { + AbilitySet->GiveToAbilitySystem(AbilitySystemComponent, nullptr); + } + } + + UGameFrameworkComponentManager::SendGameFrameworkComponentExtensionEvent(this, NAME_ALSAbilityReady); + + ForceNetUpdate(); +} + +void AALSPlayerState::OnRep_PawnData() +{ +} + +void AALSPlayerState::SetPlayerConnectionType(EALSPlayerConnectionType NewType) +{ + MARK_PROPERTY_DIRTY_FROM_NAME(ThisClass, MyPlayerConnectionType, this); + MyPlayerConnectionType = NewType; +} + +void AALSPlayerState::AddStatTagStack(FGameplayTag Tag, int32 StackCount) +{ + StatTags.AddStack(Tag, StackCount); +} + +void AALSPlayerState::RemoveStatTagStack(FGameplayTag Tag, int32 StackCount) +{ + StatTags.RemoveStack(Tag, StackCount); +} + +int32 AALSPlayerState::GetStatTagStackCount(FGameplayTag Tag) const +{ + return StatTags.GetStackCount(Tag); +} + +bool AALSPlayerState::HasStatTag(FGameplayTag Tag) const +{ + return StatTags.ContainsTag(Tag); +} + +void AALSPlayerState::ClientBroadcastMessage_Implementation(const FALSVerbMessage Message) +{ + // This check is needed to prevent running the action when in standalone mode + if (GetNetMode() == NM_Client) + { + UGameplayMessageSubsystem::Get(this).BroadcastMessage(Message.Verb, Message); + } +} + diff --git a/Source/ALSV4_CPP/Public/Player/ALSLocalPlayer.h b/Source/ALSV4_CPP/Public/Player/ALSLocalPlayer.h new file mode 100644 index 00000000..7eee8695 --- /dev/null +++ b/Source/ALSV4_CPP/Public/Player/ALSLocalPlayer.h @@ -0,0 +1,47 @@ +// Fill out your copyright notice in the Description page of Project Settings. + +#pragma once + +#include "CoreMinimal.h" +#include "CommonLocalPlayer.h" +#include "ALSLocalPlayer.generated.h" + +class UInputMappingContext; + +/** + * UALSLocalPlayer + */ +UCLASS() +class ALSV4_CPP_API UALSLocalPlayer : public UCommonLocalPlayer +{ + GENERATED_BODY() + +public: + + UALSLocalPlayer(); + + //~UPlayer interface + virtual void SwitchController(class APlayerController* PC) override; + //~End of UPlayer interface + + //~ULocalPlayer interface + virtual bool SpawnPlayActor(const FString& URL, FString& OutError, UWorld* InWorld) override; + virtual void InitOnlineSession() override; + //~End of ULocalPlayer interface + +protected: + void OnAudioOutputDeviceChanged(const FString& InAudioOutputDeviceId); + + UFUNCTION() + void OnCompletedAudioDeviceSwap(const FSwapAudioOutputResult& SwapResult); + + virtual void OnPlayerControllerChanged(APlayerController* NewController); + +protected: + UPROPERTY(Transient) + mutable const UInputMappingContext* InputMappingContext; + + UPROPERTY() + TWeakObjectPtr LastBoundPC; +}; + diff --git a/Source/ALSV4_CPP/Public/Player/ALSPlayerController2.h b/Source/ALSV4_CPP/Public/Player/ALSPlayerController2.h new file mode 100644 index 00000000..d1eb9fd1 --- /dev/null +++ b/Source/ALSV4_CPP/Public/Player/ALSPlayerController2.h @@ -0,0 +1,117 @@ +// Fill out your copyright notice in the Description page of Project Settings. + +#pragma once + +#include "CoreMinimal.h" +#include "GameFramework/PlayerController.h" +#include "CommonPlayerController.h" +#include "ALSPlayerController2.generated.h" + +class UALSSettingsShared; +class AALSPlayerState; +class UALSAbilitySystemComponent; +class APawn; + +/** + * AALSPlayerController2 + * + * The base player controller class used by this project. + */ +UCLASS(Config = Game, Meta = (ShortTooltip = "The base player controller class used by this project.")) +class ALSV4_CPP_API AALSPlayerController2 : public ACommonPlayerController +{ + GENERATED_BODY() + +public: + + AALSPlayerController2(const FObjectInitializer& ObjectInitializer = FObjectInitializer::Get()); + + UFUNCTION(BlueprintCallable, Category = "ALS|PlayerController") + AALSPlayerState* GetALSPlayerState() const; + + UFUNCTION(BlueprintCallable, Category = "ALS|PlayerController") + UALSAbilitySystemComponent* GetALSAbilitySystemComponent() const; + + //~AActor interface + virtual void PreInitializeComponents() override; + virtual void BeginPlay() override; + virtual void EndPlay(const EEndPlayReason::Type EndPlayReason) override; + //~End of AActor interface + + //~AController interface + virtual void OnUnPossess() override; + //~End of AController interface + + //~APlayerController interface + virtual void ReceivedPlayer() override; + virtual void PlayerTick(float DeltaTime) override; + //~End of APlayerController interface + + //~IALSCameraAssistInterface interface + // TODO: Implement this + // virtual void OnCameraPenetratingTarget() override; + //~End of IALSCameraAssistInterface interface + + //~ACommonPlayerController interface + virtual void OnPossess(APawn* InPawn) override; + //~End of ACommonPlayerController interface + + UFUNCTION(BlueprintCallable, Category = "ALS|Character") + void SetIsAutoRunning(const bool bEnabled); + + UFUNCTION(BlueprintCallable, Category = "ALS|Character") + bool GetIsAutoRunning() const; + +private: + UPROPERTY() + APlayerState* LastSeenPlayerState; + +private: + UFUNCTION() + void OnPlayerStateChangedTeam(UObject* TeamAgent, int32 OldTeam, int32 NewTeam); + +protected: + // Called when the player state is set or cleared + virtual void OnPlayerStateChanged(); + +private: + void BroadcastOnPlayerStateChanged(); + +protected: + //~AController interface + virtual void InitPlayerState() override; + virtual void CleanupPlayerState() override; + virtual void OnRep_PlayerState() override; + //~End of AController interface + + //~APlayerController interface + virtual void SetPlayer(UPlayer* InPlayer) override; + + virtual void UpdateForceFeedback(IInputInterface* InputInterface, const int32 ControllerId) override; + virtual void UpdateHiddenComponents(const FVector& ViewLocation, TSet& OutHiddenComponents) override; + + virtual void PreProcessInput(const float DeltaTime, const bool bGamePaused) override; + virtual void PostProcessInput(const float DeltaTime, const bool bGamePaused) override; + //~End of APlayerController interface + + void OnStartAutoRun(); + void OnEndAutoRun(); + + UFUNCTION(BlueprintImplementableEvent, meta=(DisplayName="OnStartAutoRun")) + void K2_OnStartAutoRun(); + + UFUNCTION(BlueprintImplementableEvent, meta=(DisplayName="OnEndAutoRun")) + void K2_OnEndAutoRun(); + + bool bHideViewTargetPawnNextFrame = false; +}; + + +// A player controller used for replay capture and playback +UCLASS() +class AALSReplayPlayerController : public AALSPlayerController2 +{ + GENERATED_BODY() + + virtual void SetPlayer(UPlayer* InPlayer) override; +}; diff --git a/Source/ALSV4_CPP/Public/Player/ALSPlayerState.h b/Source/ALSV4_CPP/Public/Player/ALSPlayerState.h new file mode 100644 index 00000000..9860870b --- /dev/null +++ b/Source/ALSV4_CPP/Public/Player/ALSPlayerState.h @@ -0,0 +1,131 @@ +// Fill out your copyright notice in the Description page of Project Settings. + +#pragma once + +#include "CoreMinimal.h" +#include "AbilitySystemInterface.h" +#include "HAL/Platform.h" +#include "Messages/ALSVerbMessage.h" +#include "ModularPlayerState.h" +#include "System/GameplayTagStack.h" +#include "Templates/Casts.h" +#include "UObject/UObjectGlobals.h" + +#include "ALSPlayerState.generated.h" + +class AController; +class AALSPlayerController2; +class APlayerState; +class FName; +class UAbilitySystemComponent; +class UALSAbilitySystemComponent; +class UALSExperienceDefinition; +class UALSPawnData; +class UObject; +struct FFrame; +struct FGameplayTag; + +/** Defines the types of client connected */ +UENUM() +enum class EALSPlayerConnectionType : uint8 +{ + // An active player + Player = 0, + + // Spectator connected to a running game + LiveSpectator, + + // Spectating a demo recording offline + ReplaySpectator, + + // A deactivated player (disconnected) + InactivePlayer +}; + +/** + * AALSPlayerState + * + * Base player state class used by this project. + */ +UCLASS(Config=Game) +class ALSV4_CPP_API AALSPlayerState : public AModularPlayerState, public IAbilitySystemInterface +{ + GENERATED_BODY() + +public: + AALSPlayerState(const FObjectInitializer& ObjectInitializer = FObjectInitializer::Get()); + + UFUNCTION(BlueprintCallable, Category = "ALS|PlayerState") + AALSPlayerController2* GetALSPlayerController() const; + + UFUNCTION(BlueprintCallable, Category = "ALS|PlayerState") + UALSAbilitySystemComponent* GetALSAbilitySystemComponent() const { return AbilitySystemComponent; } + virtual UAbilitySystemComponent* GetAbilitySystemComponent() const override; + + template + const T* GetPawnData() const { return Cast(PawnData); } + + void SetPawnData(const UALSPawnData* InPawnData); + + //~AActor interface + virtual void PreInitializeComponents() override; + virtual void PostInitializeComponents() override; + //~End of AActor interface + + //~APlayerState interface + virtual void Reset() override; + virtual void ClientInitialize(AController* C) override; + virtual void CopyProperties(APlayerState* PlayerState) override; + virtual void OnDeactivated() override; + virtual void OnReactivated() override; + //~End of APlayerState interface + + static const FName NAME_ALSAbilityReady; + + void SetPlayerConnectionType(EALSPlayerConnectionType NewType); + EALSPlayerConnectionType GetPlayerConnectionType() const { return MyPlayerConnectionType; } + + // Adds a specified number of stacks to the tag (does nothing if StackCount is below 1) + UFUNCTION(BlueprintCallable, BlueprintAuthorityOnly, Category=Teams) + void AddStatTagStack(FGameplayTag Tag, int32 StackCount); + + // Removes a specified number of stacks from the tag (does nothing if StackCount is below 1) + UFUNCTION(BlueprintCallable, BlueprintAuthorityOnly, Category=Teams) + void RemoveStatTagStack(FGameplayTag Tag, int32 StackCount); + + // Returns the stack count of the specified tag (or 0 if the tag is not present) + UFUNCTION(BlueprintCallable, Category=Teams) + int32 GetStatTagStackCount(FGameplayTag Tag) const; + + // Returns true if there is at least one stack of the specified tag + UFUNCTION(BlueprintCallable, Category=Teams) + bool HasStatTag(FGameplayTag Tag) const; + + // Send a message to just this player + // (use only for client notifications like accolades, quest toasts, etc... that can handle being occasionally lost) + UFUNCTION(Client, Unreliable, BlueprintCallable, Category = "ALS|PlayerState") + void ClientBroadcastMessage(const FALSVerbMessage Message); + +private: + void OnExperienceLoaded(const UALSExperienceDefinition* CurrentExperience); + +protected: + UFUNCTION() + void OnRep_PawnData(); + +protected: + UPROPERTY(ReplicatedUsing = OnRep_PawnData) + TObjectPtr PawnData; + +private: + + // The ability system component sub-object used by player characters. + UPROPERTY(VisibleAnywhere, Category = "ALS|PlayerState") + TObjectPtr AbilitySystemComponent; + + UPROPERTY(Replicated) + EALSPlayerConnectionType MyPlayerConnectionType; + + UPROPERTY(Replicated) + FGameplayTagStackContainer StatTags; +}; From 09f3382f85282cc08d12c35dbb8b267c30dbeb8f Mon Sep 17 00:00:00 2001 From: Helcio Laurentino do Carmo Junior Date: Mon, 1 May 2023 18:30:41 -0300 Subject: [PATCH 13/17] feat(system): Add system classes --- .../Private/System/ALSAssetManager.cpp | 285 ++++++++++++++++++ .../System/ALSAssetManagerStartupJob.cpp | 29 ++ .../ALSV4_CPP/Private/System/ALSGameData.cpp | 14 + .../Private/System/GameplayTagStack.cpp | 109 +++++++ .../ALSV4_CPP/Public/System/ALSAssetManager.h | 171 +++++++++++ .../Public/System/ALSAssetManagerStartupJob.h | 51 ++++ Source/ALSV4_CPP/Public/System/ALSGameData.h | 41 +++ .../Public/System/GameplayTagStack.h | 107 +++++++ 8 files changed, 807 insertions(+) create mode 100644 Source/ALSV4_CPP/Private/System/ALSAssetManager.cpp create mode 100644 Source/ALSV4_CPP/Private/System/ALSAssetManagerStartupJob.cpp create mode 100644 Source/ALSV4_CPP/Private/System/ALSGameData.cpp create mode 100644 Source/ALSV4_CPP/Private/System/GameplayTagStack.cpp create mode 100644 Source/ALSV4_CPP/Public/System/ALSAssetManager.h create mode 100644 Source/ALSV4_CPP/Public/System/ALSAssetManagerStartupJob.h create mode 100644 Source/ALSV4_CPP/Public/System/ALSGameData.h create mode 100644 Source/ALSV4_CPP/Public/System/GameplayTagStack.h diff --git a/Source/ALSV4_CPP/Private/System/ALSAssetManager.cpp b/Source/ALSV4_CPP/Private/System/ALSAssetManager.cpp new file mode 100644 index 00000000..afa71a0f --- /dev/null +++ b/Source/ALSV4_CPP/Private/System/ALSAssetManager.cpp @@ -0,0 +1,285 @@ +// Copyright Epic Games, Inc. All Rights Reserved. + +#include "System/ALSAssetManager.h" +#include "ALSLogChannels.h" +#include "ALSGameplayTags.h" +#include "System/ALSGameData.h" +#include "AbilitySystemGlobals.h" +#include "Character/ALSPawnData.h" +#include "Stats/StatsMisc.h" +#include "Engine/Engine.h" +// #include "AbilitySystem/ALSGameplayCueManager.h" +#include "SWarningOrErrorBox.h" +#include "Misc/ScopedSlowTask.h" + +#include UE_INLINE_GENERATED_CPP_BY_NAME(ALSAssetManager) + +const FName FALSBundles::Equipped("Equipped"); + +////////////////////////////////////////////////////////////////////// + +static FAutoConsoleCommand CVarDumpLoadedAssets( + TEXT("ALS.DumpLoadedAssets"), + TEXT("Shows all assets that were loaded via the asset manager and are currently in memory."), + FConsoleCommandDelegate::CreateStatic(UALSAssetManager::DumpLoadedAssets) +); + +////////////////////////////////////////////////////////////////////// + +#define STARTUP_JOB_WEIGHTED(JobFunc, JobWeight) StartupJobs.Add(FALSAssetManagerStartupJob(#JobFunc, [this](const FALSAssetManagerStartupJob& StartupJob, TSharedPtr& LoadHandle){JobFunc;}, JobWeight)) +#define STARTUP_JOB(JobFunc) STARTUP_JOB_WEIGHTED(JobFunc, 1.f) + +////////////////////////////////////////////////////////////////////// + +UALSAssetManager::UALSAssetManager() +{ + DefaultPawnData = nullptr; +} + +UALSAssetManager& UALSAssetManager::Get() +{ + check(GEngine); + + if (UALSAssetManager* Singleton = Cast(GEngine->AssetManager)) + { + return *Singleton; + } + + UE_LOG(LogALS, Fatal, TEXT("Invalid AssetManagerClassName in DefaultEngine.ini. It must be set to ALSAssetManager!")); + + // Fatal error above prevents this from being called. + return *NewObject(); +} + +UObject* UALSAssetManager::SynchronousLoadAsset(const FSoftObjectPath& AssetPath) +{ + if (AssetPath.IsValid()) + { + TUniquePtr LogTimePtr; + + if (ShouldLogAssetLoads()) + { + LogTimePtr = MakeUnique(*FString::Printf(TEXT("Synchronously loaded asset [%s]"), *AssetPath.ToString()), nullptr, FScopeLogTime::ScopeLog_Seconds); + } + + if (UAssetManager::IsValid()) + { + return UAssetManager::GetStreamableManager().LoadSynchronous(AssetPath, false); + } + + // Use LoadObject if asset manager isn't ready yet. + return AssetPath.TryLoad(); + } + + return nullptr; +} + +bool UALSAssetManager::ShouldLogAssetLoads() +{ + static bool bLogAssetLoads = FParse::Param(FCommandLine::Get(), TEXT("LogAssetLoads")); + return bLogAssetLoads; +} + +void UALSAssetManager::AddLoadedAsset(const UObject* Asset) +{ + if (ensureAlways(Asset)) + { + FScopeLock LoadedAssetsLock(&LoadedAssetsCritical); + LoadedAssets.Add(Asset); + } +} + +void UALSAssetManager::DumpLoadedAssets() +{ + UE_LOG(LogALS, Log, TEXT("========== Start Dumping Loaded Assets ==========")); + + for (const UObject* LoadedAsset : Get().LoadedAssets) + { + UE_LOG(LogALS, Log, TEXT(" %s"), *GetNameSafe(LoadedAsset)); + } + + UE_LOG(LogALS, Log, TEXT("... %d assets in loaded pool"), Get().LoadedAssets.Num()); + UE_LOG(LogALS, Log, TEXT("========== Finish Dumping Loaded Assets ==========")); +} + +void UALSAssetManager::StartInitialLoading() +{ + UE_LOG(LogTemp, Warning, TEXT("UALSAssetManager::StartInitialLoading")) + + SCOPED_BOOT_TIMING("UALSAssetManager::StartInitialLoading"); + + // This does all of the scanning, need to do this now even if loads are deferred + Super::StartInitialLoading(); + + STARTUP_JOB(InitializeAbilitySystem()); + //STARTUP_JOB(InitializeGameplayCueManager()); + + { + // Load base game data asset + STARTUP_JOB_WEIGHTED(GetGameData(), 25.f); + } + + // Run all the queued up startup jobs + DoAllStartupJobs(); +} + +void UALSAssetManager::InitializeAbilitySystem() +{ + UE_LOG(LogTemp, Warning, TEXT("UALSAssetManager::InitializeAbilitySystem")) + SCOPED_BOOT_TIMING("UALSAssetManager::InitializeAbilitySystem"); + + FALSGameplayTags::InitializeNativeTags(); + + UAbilitySystemGlobals::Get().InitGlobalData(); +} + +void UALSAssetManager::InitializeGameplayCueManager() +{ + SCOPED_BOOT_TIMING("UALSAssetManager::InitializeGameplayCueManager"); + + /*UALSGameplayCueManager* GCM = UALSGameplayCueManager::Get(); + check(GCM); + GCM->LoadAlwaysLoadedCues();*/ +} + + +const UALSGameData& UALSAssetManager::GetGameData() +{ + return GetOrLoadTypedGameData(ALSGameDataPath); +} + +const UALSPawnData* UALSAssetManager::GetDefaultPawnData() const +{ + return GetAsset(DefaultPawnData); +} + +UPrimaryDataAsset* UALSAssetManager::LoadGameDataOfClass(TSubclassOf DataClass, const TSoftObjectPtr& DataClassPath, FPrimaryAssetType PrimaryAssetType) +{ + UPrimaryDataAsset* Asset = nullptr; + + DECLARE_SCOPE_CYCLE_COUNTER(TEXT("Loading GameData Object"), STAT_GameData, STATGROUP_LoadTime); + if (!DataClassPath.IsNull()) + { +#if WITH_EDITOR + FScopedSlowTask SlowTask(0, FText::Format(NSLOCTEXT("ALSEditor", "BeginLoadingGameDataTask", "Loading GameData {0}"), FText::FromName(DataClass->GetFName()))); + const bool bShowCancelButton = false; + const bool bAllowInPIE = true; + SlowTask.MakeDialog(bShowCancelButton, bAllowInPIE); +#endif + UE_LOG(LogALS, Log, TEXT("Loading GameData: %s ..."), *DataClassPath.ToString()); + SCOPE_LOG_TIME_IN_SECONDS(TEXT(" ... GameData loaded!"), nullptr); + + // This can be called recursively in the editor because it is called on demand from PostLoad so force a sync load for primary asset and async load the rest in that case + if (GIsEditor) + { + Asset = DataClassPath.LoadSynchronous(); + LoadPrimaryAssetsWithType(PrimaryAssetType); + } + else + { + TSharedPtr Handle = LoadPrimaryAssetsWithType(PrimaryAssetType); + if (Handle.IsValid()) + { + Handle->WaitUntilComplete(0.0f, false); + + // This should always work + Asset = Cast(Handle->GetLoadedAsset()); + } + } + } + + if (Asset) + { + GameDataMap.Add(DataClass, Asset); + } + else + { + // It is not acceptable to fail to load any GameData asset. It will result in soft failures that are hard to diagnose. + UE_LOG(LogALS, Fatal, TEXT("Failed to load GameData asset at %s. Type %s. This is not recoverable and likely means you do not have the correct data to run %s."), *DataClassPath.ToString(), *PrimaryAssetType.ToString(), FApp::GetProjectName()); + } + + return Asset; +} + + +void UALSAssetManager::DoAllStartupJobs() +{ + SCOPED_BOOT_TIMING("UALSAssetManager::DoAllStartupJobs"); + const double AllStartupJobsStartTime = FPlatformTime::Seconds(); + + if (IsRunningDedicatedServer()) + { + // No need for periodic progress updates, just run the jobs + for (const FALSAssetManagerStartupJob& StartupJob : StartupJobs) + { + StartupJob.DoJob(); + } + } + else + { + if (StartupJobs.Num() > 0) + { + float TotalJobValue = 0.0f; + for (const FALSAssetManagerStartupJob& StartupJob : StartupJobs) + { + TotalJobValue += StartupJob.JobWeight; + } + + float AccumulatedJobValue = 0.0f; + for (FALSAssetManagerStartupJob& StartupJob : StartupJobs) + { + const float JobValue = StartupJob.JobWeight; + StartupJob.SubstepProgressDelegate.BindLambda([This = this, AccumulatedJobValue, JobValue, TotalJobValue](float NewProgress) + { + const float SubstepAdjustment = FMath::Clamp(NewProgress, 0.0f, 1.0f) * JobValue; + const float OverallPercentWithSubstep = (AccumulatedJobValue + SubstepAdjustment) / TotalJobValue; + + This->UpdateInitialGameContentLoadPercent(OverallPercentWithSubstep); + }); + + StartupJob.DoJob(); + + StartupJob.SubstepProgressDelegate.Unbind(); + + AccumulatedJobValue += JobValue; + + UpdateInitialGameContentLoadPercent(AccumulatedJobValue / TotalJobValue); + } + } + else + { + UpdateInitialGameContentLoadPercent(1.0f); + } + } + + StartupJobs.Empty(); + + UE_LOG(LogALS, Display, TEXT("All startup jobs took %.2f seconds to complete"), FPlatformTime::Seconds() - AllStartupJobsStartTime); +} + +void UALSAssetManager::UpdateInitialGameContentLoadPercent(float GameContentPercent) +{ + // Could route this to the early startup loading screen +} + +#if WITH_EDITOR +void UALSAssetManager::PreBeginPIE(bool bStartSimulate) +{ + Super::PreBeginPIE(bStartSimulate); + + { + FScopedSlowTask SlowTask(0, NSLOCTEXT("ALSEditor", "BeginLoadingPIEData", "Loading PIE Data")); + const bool bShowCancelButton = false; + const bool bAllowInPIE = true; + SlowTask.MakeDialog(bShowCancelButton, bAllowInPIE); + + //const UALSGameData& LocalGameDataCommon = GetGameData(); + + // Intentionally after GetGameData to avoid counting GameData time in this timer + SCOPE_LOG_TIME_IN_SECONDS(TEXT("PreBeginPIE asset preloading complete"), nullptr); + + // You could add preloading of anything else needed for the experience we'll be using here + // (e.g., by grabbing the default experience from the world settings + the experience override in developer settings) + } +} +#endif diff --git a/Source/ALSV4_CPP/Private/System/ALSAssetManagerStartupJob.cpp b/Source/ALSV4_CPP/Private/System/ALSAssetManagerStartupJob.cpp new file mode 100644 index 00000000..af645532 --- /dev/null +++ b/Source/ALSV4_CPP/Private/System/ALSAssetManagerStartupJob.cpp @@ -0,0 +1,29 @@ +// Copyright Epic Games, Inc. All Rights Reserved. + +#include "System/ALSAssetManagerStartupJob.h" + +#include "HAL/Platform.h" +#include "Logging/LogCategory.h" +#include "Logging/LogMacros.h" +#include "ALSLogChannels.h" +#include "Trace/Detail/Channel.h" + +TSharedPtr FALSAssetManagerStartupJob::DoJob() const +{ + const double JobStartTime = FPlatformTime::Seconds(); + + TSharedPtr Handle; + UE_LOG(LogALS, Display, TEXT("Startup job \"%s\" starting"), *JobName); + JobFunc(*this, Handle); + + if (Handle.IsValid()) + { + Handle->BindUpdateDelegate(FStreamableUpdateDelegate::CreateRaw(this, &FALSAssetManagerStartupJob::UpdateSubstepProgressFromStreamable)); + Handle->WaitUntilComplete(0.0f, false); + Handle->BindUpdateDelegate(FStreamableUpdateDelegate()); + } + + UE_LOG(LogALS, Display, TEXT("Startup job \"%s\" took %.2f seconds to complete"), *JobName, FPlatformTime::Seconds() - JobStartTime); + + return Handle; +} diff --git a/Source/ALSV4_CPP/Private/System/ALSGameData.cpp b/Source/ALSV4_CPP/Private/System/ALSGameData.cpp new file mode 100644 index 00000000..773fcc82 --- /dev/null +++ b/Source/ALSV4_CPP/Private/System/ALSGameData.cpp @@ -0,0 +1,14 @@ +// Fill out your copyright notice in the Description page of Project Settings. + + +#include "System/ALSGameData.h" +#include "System/ALSAssetManager.h" + +UALSGameData::UALSGameData() +{ +} + +const UALSGameData& UALSGameData::UALSGameData::Get() +{ + return UALSAssetManager::Get().GetGameData(); +} \ No newline at end of file diff --git a/Source/ALSV4_CPP/Private/System/GameplayTagStack.cpp b/Source/ALSV4_CPP/Private/System/GameplayTagStack.cpp new file mode 100644 index 00000000..c25fed60 --- /dev/null +++ b/Source/ALSV4_CPP/Private/System/GameplayTagStack.cpp @@ -0,0 +1,109 @@ +#include "System/GameplayTagStack.h" + +#include "Logging/LogVerbosity.h" +#include "UObject/Stack.h" + +#include UE_INLINE_GENERATED_CPP_BY_NAME(GameplayTagStack) + +////////////////////////////////////////////////////////////////////// +// FGameplayTagStack + +FString FGameplayTagStack::GetDebugString() const +{ + return FString::Printf(TEXT("%sx%d"), *Tag.ToString(), StackCount); +} + +////////////////////////////////////////////////////////////////////// +// FGameplayTagStackContainer + +void FGameplayTagStackContainer::AddStack(FGameplayTag Tag, int32 StackCount) +{ + if (!Tag.IsValid()) + { + FFrame::KismetExecutionMessage(TEXT("An invalid tag was passed to AddStack"), ELogVerbosity::Warning); + return; + } + + if (StackCount > 0) + { + for (FGameplayTagStack& Stack : Stacks) + { + if (Stack.Tag == Tag) + { + const int32 NewCount = Stack.StackCount + StackCount; + Stack.StackCount = NewCount; + TagToCountMap[Tag] = NewCount; + MarkItemDirty(Stack); + return; + } + } + + FGameplayTagStack& NewStack = Stacks.Emplace_GetRef(Tag, StackCount); + MarkItemDirty(NewStack); + TagToCountMap.Add(Tag, StackCount); + } +} + +void FGameplayTagStackContainer::RemoveStack(FGameplayTag Tag, int32 StackCount) +{ + if (!Tag.IsValid()) + { + FFrame::KismetExecutionMessage(TEXT("An invalid tag was passed to RemoveStack"), ELogVerbosity::Warning); + return; + } + + //@TODO: Should we error if you try to remove a stack that doesn't exist or has a smaller count? + if (StackCount > 0) + { + for (auto It = Stacks.CreateIterator(); It; ++It) + { + FGameplayTagStack& Stack = *It; + if (Stack.Tag == Tag) + { + if (Stack.StackCount <= StackCount) + { + It.RemoveCurrent(); + TagToCountMap.Remove(Tag); + MarkArrayDirty(); + } + else + { + const int32 NewCount = Stack.StackCount - StackCount; + Stack.StackCount = NewCount; + TagToCountMap[Tag] = NewCount; + MarkItemDirty(Stack); + } + return; + } + } + } +} + +void FGameplayTagStackContainer::PreReplicatedRemove(const TArrayView RemovedIndices, int32 FinalSize) +{ + for (int32 Index : RemovedIndices) + { + const FGameplayTag Tag = Stacks[Index].Tag; + TagToCountMap.Remove(Tag); + } +} + +void FGameplayTagStackContainer::PostReplicatedAdd(const TArrayView AddedIndices, int32 FinalSize) +{ + for (int32 Index : AddedIndices) + { + const FGameplayTagStack& Stack = Stacks[Index]; + TagToCountMap.Add(Stack.Tag, Stack.StackCount); + } +} + +void FGameplayTagStackContainer::PostReplicatedChange(const TArrayView ChangedIndices, int32 FinalSize) +{ + for (int32 Index : ChangedIndices) + { + const FGameplayTagStack& Stack = Stacks[Index]; + TagToCountMap[Stack.Tag] = Stack.StackCount; + } +} + + diff --git a/Source/ALSV4_CPP/Public/System/ALSAssetManager.h b/Source/ALSV4_CPP/Public/System/ALSAssetManager.h new file mode 100644 index 00000000..a7c85382 --- /dev/null +++ b/Source/ALSV4_CPP/Public/System/ALSAssetManager.h @@ -0,0 +1,171 @@ +// Copyright Epic Games, Inc. All Rights Reserved. + +#pragma once + +#include "CoreMinimal.h" +#include "Engine/AssetManager.h" +#include "Engine/DataAsset.h" +#include "ALSAssetManagerStartupJob.h" +#include "ALSAssetManager.generated.h" + +class UALSGameData; +class UALSPawnData; + +struct FALSBundles +{ + static const FName Equipped; +}; + + +/** + * UALSAssetManager + * + * Game implementation of the asset manager that overrides functionality and stores game-specific types. + * It is expected that most games will want to override AssetManager as it provides a good place for game-specific loading logic. + * This class is used by setting 'AssetManagerClassName' in DefaultEngine.ini. + */ +UCLASS(Config = Game) +class ALSV4_CPP_API UALSAssetManager : public UAssetManager +{ + GENERATED_BODY() + +public: + + UALSAssetManager(); + + // Returns the AssetManager singleton object. + static UALSAssetManager& Get(); + + // Returns the asset referenced by a TSoftObjectPtr. This will synchronously load the asset if it's not already loaded. + template + static AssetType* GetAsset(const TSoftObjectPtr& AssetPointer, bool bKeepInMemory = true); + + // Returns the subclass referenced by a TSoftClassPtr. This will synchronously load the asset if it's not already loaded. + template + static TSubclassOf GetSubclass(const TSoftClassPtr& AssetPointer, bool bKeepInMemory = true); + + // Logs all assets currently loaded and tracked by the asset manager. + static void DumpLoadedAssets(); + + const UALSGameData& GetGameData(); + const UALSPawnData* GetDefaultPawnData() const; + +protected: + template + const GameDataClass& GetOrLoadTypedGameData(const TSoftObjectPtr& DataPath) + { + if (TObjectPtr const * pResult = GameDataMap.Find(GameDataClass::StaticClass())) + { + return *CastChecked(*pResult); + } + + // Does a blocking load if needed + return *CastChecked(LoadGameDataOfClass(GameDataClass::StaticClass(), DataPath, GameDataClass::StaticClass()->GetFName())); + } + + + static UObject* SynchronousLoadAsset(const FSoftObjectPath& AssetPath); + static bool ShouldLogAssetLoads(); + + // Thread safe way of adding a loaded asset to keep in memory. + void AddLoadedAsset(const UObject* Asset); + + //~UAssetManager interface + virtual void StartInitialLoading() override; +#if WITH_EDITOR + virtual void PreBeginPIE(bool bStartSimulate) override; +#endif + //~End of UAssetManager interface + + UPrimaryDataAsset* LoadGameDataOfClass(TSubclassOf DataClass, const TSoftObjectPtr& DataClassPath, FPrimaryAssetType PrimaryAssetType); + +protected: + + // Global game data asset to use. + UPROPERTY(Config) + TSoftObjectPtr ALSGameDataPath; + + // Loaded version of the game data + UPROPERTY(Transient) + TMap, TObjectPtr> GameDataMap; + + // Pawn data used when spawning player pawns if there isn't one set on the player state. + UPROPERTY(Config) + TSoftObjectPtr DefaultPawnData; + +private: + // Flushes the StartupJobs array. Processes all startup work. + void DoAllStartupJobs(); + + // Sets up the ability system + void InitializeAbilitySystem(); + void InitializeGameplayCueManager(); + + // Called periodically during loads, could be used to feed the status to a loading screen + void UpdateInitialGameContentLoadPercent(float GameContentPercent); + + // The list of tasks to execute on startup. Used to track startup progress. + TArray StartupJobs; + +private: + + // Assets loaded and tracked by the asset manager. + UPROPERTY() + TSet> LoadedAssets; + + // Used for a scope lock when modifying the list of load assets. + FCriticalSection LoadedAssetsCritical; +}; + + +template +AssetType* UALSAssetManager::GetAsset(const TSoftObjectPtr& AssetPointer, bool bKeepInMemory) +{ + AssetType* LoadedAsset = nullptr; + + const FSoftObjectPath& AssetPath = AssetPointer.ToSoftObjectPath(); + + if (AssetPath.IsValid()) + { + LoadedAsset = AssetPointer.Get(); + if (!LoadedAsset) + { + LoadedAsset = Cast(SynchronousLoadAsset(AssetPath)); + ensureAlwaysMsgf(LoadedAsset, TEXT("Failed to load asset [%s]"), *AssetPointer.ToString()); + } + + if (LoadedAsset && bKeepInMemory) + { + // Added to loaded asset list. + Get().AddLoadedAsset(Cast(LoadedAsset)); + } + } + + return LoadedAsset; +} + +template +TSubclassOf UALSAssetManager::GetSubclass(const TSoftClassPtr& AssetPointer, bool bKeepInMemory) +{ + TSubclassOf LoadedSubclass; + + const FSoftObjectPath& AssetPath = AssetPointer.ToSoftObjectPath(); + + if (AssetPath.IsValid()) + { + LoadedSubclass = AssetPointer.Get(); + if (!LoadedSubclass) + { + LoadedSubclass = Cast(SynchronousLoadAsset(AssetPath)); + ensureAlwaysMsgf(LoadedSubclass, TEXT("Failed to load asset class [%s]"), *AssetPointer.ToString()); + } + + if (LoadedSubclass && bKeepInMemory) + { + // Added to loaded asset list. + Get().AddLoadedAsset(Cast(LoadedSubclass)); + } + } + + return LoadedSubclass; +} diff --git a/Source/ALSV4_CPP/Public/System/ALSAssetManagerStartupJob.h b/Source/ALSV4_CPP/Public/System/ALSAssetManagerStartupJob.h new file mode 100644 index 00000000..4eab6746 --- /dev/null +++ b/Source/ALSV4_CPP/Public/System/ALSAssetManagerStartupJob.h @@ -0,0 +1,51 @@ +// Copyright Epic Games, Inc. All Rights Reserved. + +#pragma once + +#include "Containers/UnrealString.h" +#include "Delegates/Delegate.h" +#include "Engine/StreamableManager.h" +#include "HAL/PlatformTime.h" +#include "Templates/Function.h" +#include "Templates/SharedPointer.h" + +DECLARE_DELEGATE_OneParam(FALSAssetManagerStartupJobSubstepProgress, float /*NewProgress*/); + +/** Handles reporting progress from streamable handles */ +struct ALSV4_CPP_API FALSAssetManagerStartupJob +{ + FALSAssetManagerStartupJobSubstepProgress SubstepProgressDelegate; + TFunction&)> JobFunc; + FString JobName; + float JobWeight; + mutable double LastUpdate = 0; + + /** Simple job that is all synchronous */ + FALSAssetManagerStartupJob(const FString& InJobName, const TFunction&)>& InJobFunc, float InJobWeight) + : JobFunc(InJobFunc) + , JobName(InJobName) + , JobWeight(InJobWeight) + {} + + /** Perform actual loading, will return a handle if it created one */ + TSharedPtr DoJob() const; + + void UpdateSubstepProgress(float NewProgress) const + { + SubstepProgressDelegate.ExecuteIfBound(NewProgress); + } + + void UpdateSubstepProgressFromStreamable(TSharedRef StreamableHandle) const + { + if (SubstepProgressDelegate.IsBound()) + { + // StreamableHandle::GetProgress traverses() a large graph and is quite expensive + double Now = FPlatformTime::Seconds(); + if (LastUpdate - Now > 1.0 / 60) + { + SubstepProgressDelegate.Execute(StreamableHandle->GetProgress()); + LastUpdate = Now; + } + } + } +}; diff --git a/Source/ALSV4_CPP/Public/System/ALSGameData.h b/Source/ALSV4_CPP/Public/System/ALSGameData.h new file mode 100644 index 00000000..1dcc6cd4 --- /dev/null +++ b/Source/ALSV4_CPP/Public/System/ALSGameData.h @@ -0,0 +1,41 @@ +// Fill out your copyright notice in the Description page of Project Settings. + +#pragma once + +#include "CoreMinimal.h" +#include "Engine/DataAsset.h" +#include "ALSGameData.generated.h" + +class UGameplayEffect; + +/** + * UALSGameData + * + * Non-mutable data asset that contains global game data. + */ +UCLASS(BlueprintType, Const, Meta = (DisplayName = "ALS Game Data", ShortTooltip = "Data asset containing global game data.")) +class ALSV4_CPP_API UALSGameData : public UPrimaryDataAsset +{ + GENERATED_BODY() + +public: + + UALSGameData(); + + // Returns the loaded game data. + static const UALSGameData& Get(); + +public: + + // Gameplay effect used to apply damage. Uses SetByCaller for the damage magnitude. + UPROPERTY(EditDefaultsOnly, Category = "Default Gameplay Effects", meta = (DisplayName = "Damage Gameplay Effect (SetByCaller)")) + TSoftClassPtr DamageGameplayEffect_SetByCaller; + + // Gameplay effect used to apply healing. Uses SetByCaller for the healing magnitude. + UPROPERTY(EditDefaultsOnly, Category = "Default Gameplay Effects", meta = (DisplayName = "Heal Gameplay Effect (SetByCaller)")) + TSoftClassPtr HealGameplayEffect_SetByCaller; + + // Gameplay effect used to add and remove dynamic tags. + UPROPERTY(EditDefaultsOnly, Category = "Default Gameplay Effects") + TSoftClassPtr DynamicTagGameplayEffect; +}; diff --git a/Source/ALSV4_CPP/Public/System/GameplayTagStack.h b/Source/ALSV4_CPP/Public/System/GameplayTagStack.h new file mode 100644 index 00000000..cd1c3fe7 --- /dev/null +++ b/Source/ALSV4_CPP/Public/System/GameplayTagStack.h @@ -0,0 +1,107 @@ +#pragma once + +#include "CoreMinimal.h" +#include "Containers/Array.h" +#include "Containers/ArrayView.h" +#include "Containers/Map.h" +#include "Containers/Set.h" +#include "Containers/SparseArray.h" +#include "Containers/UnrealString.h" +#include "GameplayTagContainer.h" +#include "HAL/Platform.h" +#include "Net/Serialization/FastArraySerializer.h" +#include "Templates/UnrealTemplate.h" +#include "UObject/Class.h" + +#include "GameplayTagStack.generated.h" + +struct FGameplayTagStackContainer; +struct FNetDeltaSerializeInfo; + +/** + * Represents one stack of a gameplay tag (tag + count) + */ +USTRUCT(BlueprintType) +struct FGameplayTagStack : public FFastArraySerializerItem +{ + GENERATED_BODY() + + FGameplayTagStack() + {} + + FGameplayTagStack(FGameplayTag InTag, int32 InStackCount) + : Tag(InTag) + , StackCount(InStackCount) + { + } + + FString GetDebugString() const; + +private: + friend FGameplayTagStackContainer; + + UPROPERTY() + FGameplayTag Tag; + + UPROPERTY() + int32 StackCount = 0; +}; + +/** Container of gameplay tag stacks */ +USTRUCT(BlueprintType) +struct FGameplayTagStackContainer : public FFastArraySerializer +{ + GENERATED_BODY() + + FGameplayTagStackContainer() + // : Owner(nullptr) + { + } + +public: + // Adds a specified number of stacks to the tag (does nothing if StackCount is below 1) + void AddStack(FGameplayTag Tag, int32 StackCount); + + // Removes a specified number of stacks from the tag (does nothing if StackCount is below 1) + void RemoveStack(FGameplayTag Tag, int32 StackCount); + + // Returns the stack count of the specified tag (or 0 if the tag is not present) + int32 GetStackCount(FGameplayTag Tag) const + { + return TagToCountMap.FindRef(Tag); + } + + // Returns true if there is at least one stack of the specified tag + bool ContainsTag(FGameplayTag Tag) const + { + return TagToCountMap.Contains(Tag); + } + + //~FFastArraySerializer contract + void PreReplicatedRemove(const TArrayView RemovedIndices, int32 FinalSize); + void PostReplicatedAdd(const TArrayView AddedIndices, int32 FinalSize); + void PostReplicatedChange(const TArrayView ChangedIndices, int32 FinalSize); + //~End of FFastArraySerializer contract + + bool NetDeltaSerialize(FNetDeltaSerializeInfo& DeltaParms) + { + return FFastArraySerializer::FastArrayDeltaSerialize(Stacks, DeltaParms, *this); + } + +private: + // Replicated list of gameplay tag stacks + UPROPERTY() + TArray Stacks; + + // Accelerated list of tag stacks for queries + TMap TagToCountMap; +}; + +template<> +struct TStructOpsTypeTraits : public TStructOpsTypeTraitsBase2 +{ + enum + { + WithNetDeltaSerializer = true, + }; +}; From 25428ae4787ad3e1ae8449453546e38505a25c0e Mon Sep 17 00:00:00 2001 From: Helcio Laurentino do Carmo Junior Date: Mon, 1 May 2023 18:31:00 -0300 Subject: [PATCH 14/17] feat(settings): Add setting class --- .../Private/Settings/ALSSettingsLocal.cpp | 175 ++++++++++++++++++ .../Public/Settings/ALSSettingsLocal.h | 109 +++++++++++ 2 files changed, 284 insertions(+) create mode 100644 Source/ALSV4_CPP/Private/Settings/ALSSettingsLocal.cpp create mode 100644 Source/ALSV4_CPP/Public/Settings/ALSSettingsLocal.h diff --git a/Source/ALSV4_CPP/Private/Settings/ALSSettingsLocal.cpp b/Source/ALSV4_CPP/Private/Settings/ALSSettingsLocal.cpp new file mode 100644 index 00000000..b7f5aedc --- /dev/null +++ b/Source/ALSV4_CPP/Private/Settings/ALSSettingsLocal.cpp @@ -0,0 +1,175 @@ +// Fill out your copyright notice in the Description page of Project Settings. + + +#include "Settings/ALSSettingsLocal.h" +#include "CommonInputBaseTypes.h" +#include "CommonInputSubsystem.h" +#include "PlayerMappableInputConfig.h" +#include "EnhancedInputSubsystems.h" +#include "Player/ALSLocalPlayer.h" + +UALSSettingsLocal::UALSSettingsLocal() +{ +} + +UALSSettingsLocal* UALSSettingsLocal::Get() +{ + // HACK: Fix this + return GEngine ? CastChecked(GEngine->GetGameUserSettings()) : nullptr; +} + +void UALSSettingsLocal::BeginDestroy() +{ + Super::BeginDestroy(); +} + +void UALSSettingsLocal::SetControllerPlatform(const FName InControllerPlatform) +{ + if (ControllerPlatform != InControllerPlatform) + { + ControllerPlatform = InControllerPlatform; + + // Apply the change to the common input subsystem so that we refresh any input icons we're using. + if (UCommonInputSubsystem* InputSubsystem = UCommonInputSubsystem::Get(GetTypedOuter())) + { + InputSubsystem->SetGamepadInputType(ControllerPlatform); + } + } +} + +FName UALSSettingsLocal::GetControllerPlatform() const +{ + return ControllerPlatform; +} + +void UALSSettingsLocal::RegisterInputConfig(ECommonInputType Type, const UPlayerMappableInputConfig* NewConfig, const bool bIsActive) +{ + if (NewConfig) + { + const int32 ExistingConfigIdx = RegisteredInputConfigs.IndexOfByPredicate( [&NewConfig](const FLoadedMappableConfigPair& Pair) { return Pair.Config == NewConfig; } ); + if (ExistingConfigIdx == INDEX_NONE) + { + const int32 NumAdded = RegisteredInputConfigs.Add(FLoadedMappableConfigPair(NewConfig, Type, bIsActive)); + if (NumAdded != INDEX_NONE) + { + OnInputConfigRegistered.Broadcast(RegisteredInputConfigs[NumAdded]); + } + } + } +} + +int32 UALSSettingsLocal::UnregisterInputConfig(const UPlayerMappableInputConfig* ConfigToRemove) +{ + if (ConfigToRemove) + { + const int32 Index = RegisteredInputConfigs.IndexOfByPredicate( [&ConfigToRemove](const FLoadedMappableConfigPair& Pair) { return Pair.Config == ConfigToRemove; } ); + if (Index != INDEX_NONE) + { + RegisteredInputConfigs.RemoveAt(Index); + return 1; + } + + } + return INDEX_NONE; +} + +void UALSSettingsLocal::ActivateInputConfig(const UPlayerMappableInputConfig* Config) +{ + if (Config) + { + const int32 ExistingConfigIdx = RegisteredInputConfigs.IndexOfByPredicate( [&Config](const FLoadedMappableConfigPair& Pair) { return Pair.Config == Config; } ); + if (ExistingConfigIdx != INDEX_NONE) + { + RegisteredInputConfigs[ExistingConfigIdx].bIsActive = true; + OnInputConfigActivated.Broadcast(RegisteredInputConfigs[ExistingConfigIdx]); + } + } +} + +void UALSSettingsLocal::DeactivateInputConfig(const UPlayerMappableInputConfig* Config) +{ + if (Config) + { + const int32 ExistingConfigIdx = RegisteredInputConfigs.IndexOfByPredicate( [&Config](const FLoadedMappableConfigPair& Pair) { return Pair.Config == Config; } ); + if (ExistingConfigIdx != INDEX_NONE) + { + RegisteredInputConfigs[ExistingConfigIdx].bIsActive = false; + OnInputConfigDeactivated.Broadcast(RegisteredInputConfigs[ExistingConfigIdx]); + } + } +} + +const UPlayerMappableInputConfig* UALSSettingsLocal::GetInputConfigByName(FName ConfigName) const +{ + for (const FLoadedMappableConfigPair& Pair : RegisteredInputConfigs) + { + if (Pair.Config->GetConfigName() == ConfigName) + { + return Pair.Config; + } + } + return nullptr; +} + +void UALSSettingsLocal::GetRegisteredInputConfigsOfType(ECommonInputType Type, TArray& OutArray) const +{ + OutArray.Empty(); + + // If "Count" is passed in then + if (Type == ECommonInputType::Count) + { + OutArray = RegisteredInputConfigs; + return; + } + + for (const FLoadedMappableConfigPair& Pair : RegisteredInputConfigs) + { + if (Pair.Type == Type) + { + OutArray.Emplace(Pair); + } + } +} + +void UALSSettingsLocal::AddOrUpdateCustomKeyboardBindings(const FName MappingName, const FKey NewKey, UALSLocalPlayer* LocalPlayer) +{ + if (MappingName == NAME_None) + { + return; + } + + if (InputConfigName != TEXT("Custom")) + { + // Copy Presets. + if (const UPlayerMappableInputConfig* DefaultConfig = GetInputConfigByName(TEXT("Default"))) + { + for (const FEnhancedActionKeyMapping& Mapping : DefaultConfig->GetPlayerMappableKeys()) + { + // Make sure that the mapping has a valid name, its possible to have an empty name + // if someone has marked a mapping as "Player Mappabe" but deleted the default field value + if (Mapping.PlayerMappableOptions.Name != NAME_None) + { + CustomKeyboardConfig.Add(Mapping.PlayerMappableOptions.Name, Mapping.Key); + } + } + } + + InputConfigName = TEXT("Custom"); + } + + if (CustomKeyboardConfig.Find(MappingName)) + { + // Change the key to the new one + CustomKeyboardConfig[MappingName] = NewKey; + } + else + { + CustomKeyboardConfig.Add(MappingName, NewKey); + } + + // Tell the enhanced input subsystem for this local player that we should remap some input! Woo + if (UEnhancedInputLocalPlayerSubsystem* Subsystem = ULocalPlayer::GetSubsystem(LocalPlayer)) + { + Subsystem->AddPlayerMappedKey(MappingName, NewKey); + } +} \ No newline at end of file diff --git a/Source/ALSV4_CPP/Public/Settings/ALSSettingsLocal.h b/Source/ALSV4_CPP/Public/Settings/ALSSettingsLocal.h new file mode 100644 index 00000000..8b8b23e3 --- /dev/null +++ b/Source/ALSV4_CPP/Public/Settings/ALSSettingsLocal.h @@ -0,0 +1,109 @@ +// Fill out your copyright notice in the Description page of Project Settings. + +#pragma once + +#include "CoreMinimal.h" +#include "GameFramework/GameUserSettings.h" +#include "Input/ALSMappableConfigPair.h" +#include "ALSSettingsLocal.generated.h" + +class UPlayerMappableInputConfig; +class UALSLocalPlayer; + +/** + * UALSSettingsLocal + */ +UCLASS() +class ALSV4_CPP_API UALSSettingsLocal : public UGameUserSettings +{ + GENERATED_BODY() + +public: + UALSSettingsLocal(); + + static UALSSettingsLocal* Get(); + + //~UObject interface + virtual void BeginDestroy() override; + //~End of UObject interface + + // INPUT CONFIGS +public: + // Sets the controller representation to use, a single platform might support multiple kinds of controllers. For + // example, Win64 games could be played with both an XBox or Playstation controller. + UFUNCTION() + void SetControllerPlatform(const FName InControllerPlatform); + UFUNCTION() + FName GetControllerPlatform() const; + + DECLARE_EVENT_OneParam(UALSSettingsLocal, FInputConfigDelegate, const FLoadedMappableConfigPair& /*Config*/); + + /** Delegate called when a new input config has been registered */ + FInputConfigDelegate OnInputConfigRegistered; + + /** Delegate called when a registered input config has been activated */ + FInputConfigDelegate OnInputConfigActivated; + + /** Delegate called when a registered input config has been deactivate */ + FInputConfigDelegate OnInputConfigDeactivated; + + /** Register the given input config with the settings to make it available to the player. */ + void RegisterInputConfig(ECommonInputType Type, const UPlayerMappableInputConfig* NewConfig, const bool bIsActive); + + /** Unregister the given input config. Returns the number of configs removed. */ + int32 UnregisterInputConfig(const UPlayerMappableInputConfig* ConfigToRemove); + + /** Set a registered input config as active */ + void ActivateInputConfig(const UPlayerMappableInputConfig* Config); + + /** Deactivate a registered config */ + void DeactivateInputConfig(const UPlayerMappableInputConfig* Config); + + /** Get an input config with a certain name. If the config doesn't exist then nullptr will be returned. */ + UFUNCTION(BlueprintCallable) + const UPlayerMappableInputConfig* GetInputConfigByName(FName ConfigName) const; + + /** Get all currently registered input configs */ + const TArray& GetAllRegisteredInputConfigs() const { return RegisteredInputConfigs; } + + /** + * Get all registered input configs that match the input type. + * + * @param Type The type of config to get, ECommonInputType::Count will include all configs. + * @param OutArray Array to be populated with the current registered input configs that match the type + */ + void GetRegisteredInputConfigsOfType(ECommonInputType Type, OUT TArray& OutArray) const; + + /** + * Maps the given keyboard setting to the + * + * @param MappingName The name of the FPlayerMappableKeyOptions that you would like to change + * @param NewKey The new key to bind this option to + */ + void AddOrUpdateCustomKeyboardBindings(const FName MappingName, const FKey NewKey, UALSLocalPlayer* LocalPlayer); + + const TMap& GetCustomPlayerInputConfig() const { return CustomKeyboardConfig; } + +private: + UPROPERTY(Config) + FName ControllerPlatform; + + UPROPERTY(Config) + FName ControllerPreset = TEXT("Default"); + + /** The name of the current input config that the user has selected. */ + UPROPERTY(Config) + FName InputConfigName = TEXT("Default"); + + /** + * Array of currently registered input configs. This is populated by game feature plugins + * + * @see UGameFeatureAction_AddInputConfig + */ + UPROPERTY(VisibleAnywhere) + TArray RegisteredInputConfigs; + + /** Array of custom key mappings that have been set by the player. Empty by default. */ + UPROPERTY(Config) + TMap CustomKeyboardConfig; +}; From 128f5a9f5af3928fce8975a17a99342de048a5fd Mon Sep 17 00:00:00 2001 From: Helcio Laurentino do Carmo Junior Date: Mon, 1 May 2023 18:31:19 -0300 Subject: [PATCH 15/17] feat(physic): Add Physic class --- .../Physics/PhysicalMaterialWithTags.cpp | 8 ++++++ .../Public/Physics/PhysicalMaterialWithTags.h | 27 +++++++++++++++++++ 2 files changed, 35 insertions(+) create mode 100644 Source/ALSV4_CPP/Private/Physics/PhysicalMaterialWithTags.cpp create mode 100644 Source/ALSV4_CPP/Public/Physics/PhysicalMaterialWithTags.h diff --git a/Source/ALSV4_CPP/Private/Physics/PhysicalMaterialWithTags.cpp b/Source/ALSV4_CPP/Private/Physics/PhysicalMaterialWithTags.cpp new file mode 100644 index 00000000..3ddde234 --- /dev/null +++ b/Source/ALSV4_CPP/Private/Physics/PhysicalMaterialWithTags.cpp @@ -0,0 +1,8 @@ +// Copyright Epic Games, Inc. All Rights Reserved. + +#include "Physics/PhysicalMaterialWithTags.h" + +UPhysicalMaterialWithTags::UPhysicalMaterialWithTags(const FObjectInitializer& ObjectInitializer) + : Super(ObjectInitializer) +{ +} diff --git a/Source/ALSV4_CPP/Public/Physics/PhysicalMaterialWithTags.h b/Source/ALSV4_CPP/Public/Physics/PhysicalMaterialWithTags.h new file mode 100644 index 00000000..783645a2 --- /dev/null +++ b/Source/ALSV4_CPP/Public/Physics/PhysicalMaterialWithTags.h @@ -0,0 +1,27 @@ +// Copyright Epic Games, Inc. All Rights Reserved. + +#pragma once + +#include "CoreMinimal.h" +#include "PhysicalMaterials/PhysicalMaterial.h" +#include "GameplayTagContainer.h" + +#include "PhysicalMaterialWithTags.generated.h" + +/** + * ULyraWeaponInstance + * + * A piece of equipment representing a weapon spawned and applied to a pawn + */ +UCLASS() +class UPhysicalMaterialWithTags : public UPhysicalMaterial +{ + GENERATED_BODY() + +public: + UPhysicalMaterialWithTags(const FObjectInitializer& ObjectInitializer = FObjectInitializer::Get()); + + // A container of gameplay tags that game code can use to reason about this physical material + UPROPERTY(EditAnywhere, BlueprintReadOnly, Category=PhysicalProperties) + FGameplayTagContainer Tags; +}; From c9245ad4df90ef982ef132d63e2f478abc53d9da Mon Sep 17 00:00:00 2001 From: Helcio Laurentino do Carmo Junior Date: Mon, 1 May 2023 18:31:33 -0300 Subject: [PATCH 16/17] feat(messages): Add message class --- .../Public/Messages/ALSVerbMessage.cpp | 1 + .../Public/Messages/ALSVerbMessage.h | 37 +++++++++++++++++++ 2 files changed, 38 insertions(+) create mode 100644 Source/ALSV4_CPP/Public/Messages/ALSVerbMessage.cpp create mode 100644 Source/ALSV4_CPP/Public/Messages/ALSVerbMessage.h diff --git a/Source/ALSV4_CPP/Public/Messages/ALSVerbMessage.cpp b/Source/ALSV4_CPP/Public/Messages/ALSVerbMessage.cpp new file mode 100644 index 00000000..20e5f909 --- /dev/null +++ b/Source/ALSV4_CPP/Public/Messages/ALSVerbMessage.cpp @@ -0,0 +1 @@ +#include "ALSVerbMessage.h" diff --git a/Source/ALSV4_CPP/Public/Messages/ALSVerbMessage.h b/Source/ALSV4_CPP/Public/Messages/ALSVerbMessage.h new file mode 100644 index 00000000..a04eac02 --- /dev/null +++ b/Source/ALSV4_CPP/Public/Messages/ALSVerbMessage.h @@ -0,0 +1,37 @@ +#pragma once + +#include "CoreMinimal.h" +#include "GameplayTagContainer.h" + +#include "ALSVerbMessage.generated.h" + +// Represents a generic message of the form Instigator Verb Target (in Context, with Magnitude) +USTRUCT(BlueprintType) +struct FALSVerbMessage +{ + GENERATED_BODY() + + UPROPERTY(BlueprintReadWrite, Category=Gameplay) + FGameplayTag Verb; + + UPROPERTY(BlueprintReadWrite, Category=Gameplay) + TObjectPtr Instigator = nullptr; + + UPROPERTY(BlueprintReadWrite, Category=Gameplay) + TObjectPtr Target = nullptr; + + UPROPERTY(BlueprintReadWrite, Category=Gameplay) + FGameplayTagContainer InstigatorTags; + + UPROPERTY(BlueprintReadWrite, Category=Gameplay) + FGameplayTagContainer TargetTags; + + UPROPERTY(BlueprintReadWrite, Category=Gameplay) + FGameplayTagContainer ContextTags; + + UPROPERTY(BlueprintReadWrite, Category=Gameplay) + double Magnitude = 1.0; + + // Returns a debug string representation of this message + ALSV4_CPP_API FString ToString() const; +}; \ No newline at end of file From 4d65e211678d1fb0f8b422908139fe465cea41b5 Mon Sep 17 00:00:00 2001 From: Helcio Laurentino do Carmo Junior Date: Mon, 1 May 2023 18:32:23 -0300 Subject: [PATCH 17/17] feat(blueprint): Adjust blueprints to implement new classes --- .../CharacterLogic/ALS_CharacterBP.uasset | Bin 281145 -> 283130 bytes .../ALS_Player_Controller.uasset | Bin 25630 -> 25553 bytes .../GameModes/ALS_GameMode_SP.uasset | Bin 15598 -> 17231 bytes .../Blueprints/UI/ALS_HUD.uasset | Bin 788011 -> 787056 bytes .../Levels/ALS_DemoLevel.umap | Bin 935905 -> 929746 bytes 5 files changed, 0 insertions(+), 0 deletions(-) diff --git a/Content/AdvancedLocomotionV4/Blueprints/CharacterLogic/ALS_CharacterBP.uasset b/Content/AdvancedLocomotionV4/Blueprints/CharacterLogic/ALS_CharacterBP.uasset index 05fb5d0a2f8053e2f7038c8b4382b3fcd949f6e4..3a97be516ea97adce77421d1a30a0cf9c9c69dc4 100644 GIT binary patch literal 283130 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 literal 281145 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 diff --git a/Content/AdvancedLocomotionV4/Blueprints/CharacterLogic/ALS_Player_Controller.uasset b/Content/AdvancedLocomotionV4/Blueprints/CharacterLogic/ALS_Player_Controller.uasset index e8f4f0da30c93ed0e658ce797b205b9cebf50178..7ce93c15fdfe0878dbed43c7196b3046face82e5 100644 GIT binary patch delta 6165 zcmb_gdr*|u6~7-Y3Ixdl%eT9{1?2rwBUNctA|NbpK?Hd$%Vr})Box7(o81F;G};wp`A{X$!JqMleWnpnl?4IO`3*|P5MYn&-uP{*Ux=?Fqxhi z_S}2U@1Aq-Ip;n;=3i5;ys9{V@=)RYKbDu52i6D?6CuP$$cgTlbG9V4V&l}CQ^U_z zwY>L1o9l=9Fa7A{uDPierC{!|-8tlqy3y5`eRwQo`3{QEQh3DUTE%@RxWGD$19)SLX-$!$=w|)hFc7f|o=Z=*eEZbfQw!%K z4k^lZSZ67VuRk(2GVC3m*yA}mA@VE!c737FGPQ0eE?AW9^&Ih))sK!%PL$O*?QvK8 z1}6`Rtec1D93i#$dL~CEM9a1M5_mfHDGPxhKF+aldi_5mqOqfq1zxPnGV~7D=T7@| z+_(dI%`xBT#NKhw*pN8F;z{Pe#|0nfb{%tKW88j#`E|riaNCHxpJfj+pC*ISxEb(w zh?A3D3HR_S9Fx6AgwRc{WbkXNF!&A{Jhe*PH~cucBoqXOh75kw59CG&+%?3}rXVs~ z2;q+Duv<9tALy8XGLI`6JP~LxjJ?xgaN7E1F_7c0hXInW~~ zuOe>71Sj*qgt)F%;67TOUS6&Y0hHTGhV2>}{Bj7~7g_dI=6^ukL#x2Oi?}m{qxBne zEFH@DGbBzPQY$$g4YoHO(x9Bo zN(N=LR>F-3JLVG;N6JdZNH5QY0IrcsXZ|JTn~=ZH?H6jG%CQ67s#UvKNlFKK7TvN) zPt?LMJJR8KwOBo>O9Wj5Q{4Ws3)&85L#91XJ;|adD-|mYlW8 z)Wd_^KYBfnjyZs8SCUaR%YN<9R=?q_eJ#w`ZSZ)q72a^h##lI3Kj@U2P`Al|VUdVwCn6IvoKyBb`jRm4>Is;@K0~>HWkxOS7Ii?#J z5`2qk6r}tkDx1S8|BFhmRD!407Ts>>r7FE}qPA#y9m`~*xQlT$?(;@DlDU6+|3N3~ zS-2xmNtGjSnxMH;e(&KY2|iDCq8&jb(OP=R8SQ@}36zE72a>O~3`im*k_11hcf}s& zA|4z1^6*G5Vrd3*dS(+f=}gcImFRAri7m|Wd9G0#^H%1(?}VNEUtoSO^KHzvty_hi z&$B>IcP;O@K9+0W2NEQOSJ+KHEU6BstbVDL`RPGzs^WgRkev{No^08J6eQu42# z!gQCW3ZbOz#jw%}8LlL)=mH~LLD_-A25X`8Mng>ZL>=7IkXI$|9@?Ikm^0#I+-I`z zxI8rHMzfTKPECsQh1N#f7TOR*GU0lUez$Tn^n{BVtw~19w^?=W<*~9}ZQOUkRAZ{s z-16&YmU{y&M@h@fwc~*9`p>$s2b!$wjSH*8{3L3ZXdb)Bfs0KWlKmJNIXbO~6u9Dc zI{a$<=w4P7xpNXBv)M4VAMy0b(0|aTO*{d5n$wj8INqF6lt{*qD8Jj*XzCnIpo@my z$9&s0aUv`>r*4U6rJN6U5wV$@GLyC3-%X_#y^DJ;C~vV%@8q652xWXl;Iq7jfk8+5 zZd6DQLCTY;tj0egIUPCS3Y6icoCLpZu_|@&rC7v? z+Kyhutt~Ya;!;Ovn8?#g0wPI~e{%n4kNiw$x#FR@wy@zcL(r2CbXSzJJgAn0h=>i$ zh`fZf(hgtD^6ZqmR93kxMY%>rgiS{#hQcfzXaYV_6XJh8|7zF8u9@2TgXPzo&Of}j z4!m8JCc%&D9#wL*)X0G3azOOt#leT&+v0P0hJhHW)aTVm^GbDxt<=ApRjQAD%Akc^ zJctF(ekCx56#}K&O@vVx+=61yXdt} zZ)Zf%eU-%u<2p?~Z@{_)c%ODlhNh2kV1@)CdS>b5q^>#r1)(@TSh G2K*0qN;T~O delta 6075 zcmbVQdr*|u6~7-Wfkm(@EFb#-7KP;@K4Kb81Qk#o0p+m>D4@8Du8-Ct;UP_;F2op% zk03dJI8)o`H0`95PLon*(mz^bY$s{{NmFOi>15hzOk+%9Z7YfCw2p?J^L_VxS(aVc zpOak!lrwT0W%7+mpDezgE z5IHD%!Xm`UOd%8;4`vAwz~>x3zqHv3F8E%kgQgpYDv!Oq_v*UXr17=)*Z=t41ZB-@ zTkjG+1s^g?euU`!{vw4WMMW)@D~p=^`~AK?|I(Gq?w9(Dm+xpZG=0@HfHoih^o*Me zX&mno!m*2`I>$6j(W3U@D~*YEkKJp6D=sxojCjv}0^>2I6Z2#DC`vILG%Zi5_x1K3 z7~I#rXM?Y=U)bZ1yfN{L>2Unm-R8KW+coP;#_laktLg3;=wDt_w_!(xziVKRI9(dk zvlbO ze^>Gk5jP;m!MFob_L$^kk8Ov+1q1`%N8nHt1_^gOO5FG6#07*PgClbSg}92iC!@rj zj1qSW{c98^HAZIML&wyxM04Q=b=aIZE@NOWgV6?fG)l)OrsH(;p-n?89-R)<-ooL= zqQtd@#mVJy6aEbyp9u@pggj&ge6L*St>z(=L*Y00l4?x`qn zA0X~n7#ut1G6cx+;V?i>^=YXiMu!(sxSk2deOrgkiQA6{c2oxWkebVJca)BKan;hl zHjRbBE8%p_<+wMDW1c%Ib(rX>XG3w2uBNJwOX&*a|B&NrmEhU20{p65?USN;$OldO z%iC4(nj;SyRTEe|3GjxRtM*Hn897(9Y9n|yFV-M=>AC8#gd`y6F8Uop(2+act!@oc zpO@q6O@^93X*B!iQhi-lSK7XuO-EIYJg=ZmoBb1;8&24h5`QRf0DrA#v3eZQcsCGa z^p0HIV@;acZ+AnjBPmglv--AZ;@9nNl@4}tL9B-NjxdUKwZ z>K{1^)H5jN5EwG0TZqeWt8{9y`nt3*Z>Q$Kk7_!sSWPhyO={|i*E1AF`4*I`IdCI$ zNzBnKuw@m;jpC)}kFX`nZAwHajAp&541+Vv0mH7xO-o61reZ0SWvj-^#JTK4IpE03 zfb|utSbCfXE5KXX=*`B7L^V3Y)k^vZdl|1?8qH9CjLN!5$}dpa#Y(VLS&-ZMskDz9Bg?W!l-Yku6AWgn190aq?Hg3_#X-61 zgoc{rbk%VF@=>HD4&H7!r@uT7TZ;Bcxj z;M8Pls62d#a-gVgVTys_N-TiRx`j4FtO#XFQF#BPz}dQms|{r*nxPM9XS-D^Ih}Sy z@%Ze$fn`otJKN(sNJI--0F!l2E1kbY1bR4DQ{+H)z1kS8P}@!OaI3}e>8n+RW^tG_ zCQ=05rHD8WTu~fTyj0L5>y{{_{_A)|IO+?BTfCJJW1zZSb^P*GJ68E@_;z5ph`*7+h+n z4O!lp3Lmr=L|mBBGiD=$@QV(seRkWQcaZJ-ww27*su#C;6^Gt4;Wq4{?Z+{ymzvYT z+37UT?B+7~LFYE5P(xUDWQIX-?54$>5lRq!`C{>*FM2XQMD+3L?;Y@qRq%;#nVG&v zbd0+o$!jZh;fTlp(F>`$sPs-0*|HLd6Fj-;-&frs=&FGP;%o_z<4CBZ6}hX>8Nnhq>AO8+VO8l9H;Ksw-o}cDT~D s(!N__!+#qd+G%NjSR&R-ZhWB@NQi5hnRQ?NPTq2iM*wod5s; diff --git a/Content/AdvancedLocomotionV4/Blueprints/GameModes/ALS_GameMode_SP.uasset b/Content/AdvancedLocomotionV4/Blueprints/GameModes/ALS_GameMode_SP.uasset index c2ce701c821f14c0cb8187fda69879788d3ac87e..d81d5a2b4d32576dcf105628293b2502f449c36d 100644 GIT binary patch delta 5333 zcmcIodvKG-5kDCjzc3cIB){R9d;PRK9DqFushftHI!;{v$awtHyEmfkz}xll&hD41o37q$UVc39)X&eY0bb_E ztv^23l=EV3SjK^iPmc(5hMNnPST-K|Lv6zwvtB$AJ2VjA@ku@i-s(De<+|m-?WocD z$EwfPn(~0x)gFFrO?_66JGo+Lcw>%H3%rwNLg?a65~68gW$y5W zX}-)E&;!oqXhMz|2+=^>Xe4ANlm$?V4n2Kn-^KykGoLQHs%ss+0`NFO`Dsv4dnk<7 zkl&ngYG6WAP_VM5q+o^U6a}w1x5PAG!3pvF-tiEx87Bav6ng)j`vNu&!UB@5Dvy7H z0z+)W)3CVDs`n~p~8uF}DP7NKA4Sk*0VZ|dyyiZXfXS2t~b{yItOt?rfjTrzPO zfAC%y%C~oky#g6KyLUT%EwWr$P>a+l2iW3!{*TYoYmpaYBS3x?SSWeSHnOtN8L^yJ zg_x)zB#vIv=#p^b=C!nYy4~`;>iU*d#SW|8PSO`z{!aIX^e8Z}9o8y!07hptNF5@n&WPUyam9IxgNXKbGv0$hL#Ev+42T}9(od3~>??7K6JatHPTU2tf+QhS`(j!Y-$Jhd^Z$e~u z(P49(p^b4wR^I}|p&%O=r!!!T5ER)Q6ltFn`3ua`6BOwUinu04Zh$r^DB_+JxejAA zL6MH2h!_;v8WiycMf!pw^^+ohhE>bskZo*#uv!}wSr-&p9~9XT6ln{JY(yl7T~q#* zZDFknsQ0ntggde}f?p0)}m3}z@@ZaXcE(Q88J27PvDCfuwEw9$|>i(tyfoX)ehqXl!i2?UP9HH#ENf2fb2nFuX@ zHPpDabh|{8#n~siJ>75>&7dQCODf*5%X;0C2kzKLxCFdzp zX2YNlV~{JiN*-~gnwd??6_CpjSf+X-nF7*(u3|x>Ab0nRcEJOgU%fXTN9A<5NrhxPD@AB)HjXUGA(^$8Vw2}_uC0ofh z*vvvwOC-_-J&AOZd9QDtt<~mF?)KaOKQJeQf8wMBTv1<(m z-Ukq)5^2K7uK~oPhSaE51mhElzHQPsEmqsgr-ijAXu*tzUP3BTD}ORnasi${q$+y8 zQ15G1JMhv~33Cn-*Q*$e#^ot&d@`#vsUU(FCP-Y+sdmW%Rug<*p*xX$+@@J-pA@i~ z8(z!$HLT|T$7d>1iCPgQ1fb2+*nGz4Pa3|O9;Tp4#naSp7hH;QNhy<>327-olSaRY ziq|wiJ0)=`)5|6C(S@{zHtX_omZ=?rhXTnT6@&~{aZ?|vOGw3ef~(AkN%o!pk?1=Q zQs?Wuedqrp{VPBkiEp8Q5s|>0t3Z>0n0NV};tnxNXLSUtAGLcPdWaq>)ET&WC^#<0 zN&*pn;iBPufk{lahNLUuhM0~<%+EIYM}7%W&7_oSTI3M93p~Ev%DKTegAWHUXQF%p zzX$#SLl!ZRM+7&T3oA>&$2=CK0B@)aVq*0KXTU+tiZN2HS?3RI6#ehl1IhI9)}t<7 z*_{&08}}}){?mh|5p(*HPu?mr`@ITEvvGYu+!TJ^@VSxTD^o%LPWc^q2OL?-Kz^{f zBZ-Xxd>;HJiu9->alci{Vl`Khq4ptIGZ}&oK$@tdQUypOJzmt6xRCX@J^Xwso|y5$ z(Ba6O19`S*uhosrSaJNd#k94!GIt8JzOr$ic6>We^G7B3^fy{hpDER87SrcSD<605 zV9T^<+A9R#VFMIk#cs8iChrV03zHDiIlP!I<i~t4DBoJ0(vqyn`fs$NpbcE8+_t8x?b25Rwp1lst^WZ|=SUl=r1zWo6v@f0?aSN)gE Oo3-!1na@KD2mA|fMd*_N delta 4318 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 z00ck)1V8`;KmY_l00ck)1V8`;KmY_l00ck)1V8`;KmY_l00ck)1V8`;KmY_l00ck) z1V8`;KmY_l00ck)1V8`;KmY_l00ck)1V8`;KmY_l00ck)1V8`;KmY_l00ck)1V8`; zKmY_l00ck)1V8`;KmY_l00ck)1V8`;KmY_l00ck)1V8`;KmY_l00ck)1V8`;KmY_l z00ck)1V8`;KmY_l00ck)1V8`;KmY_l00ck)1V8`;KmY_l00ck)1V8`;KmY_l00ck) z1V8`;KmY_l00ck)1V8`;KmY_l00ck)1V8`;KmY_l00ck)1V8`;KmY_l00ck)1V8`; zKmY_l00ck)1V8`;KmY_l00ck)1V8`;KmY_l00ck)1V8`;KmY_l00ck)1V8`;KmY_l z00ck)1V8`;KmY_l00ck)1V8`;KmY_l00ck)1V8`;KmY_l00ck)1V8`;KmY_l00ck) z1V8`;KmY_l00ck)1V8`;KmY_l00ck)1V8`;KmY_l00ck)1V8`;KmY_l00ck)1V8`; zKmY_l00ck)1V8`;KmY_l00ck)1V8`;KmY_l00ck)1V8`;KmY_l00ck)1V8`;KmY_l z00ck)1V8`;KmY_l00ck)1V8`;KmY_l00ck)1V8`;KmY_l00ck)1V8`;KmY_l00ck) z1V8`;KmY_l00ck)1V8`;KmY_l00ck)1V8`;KmY_l00ck)1V8`;KmY_l00ck)1V8`; zKmY_l00ck)1V8`;KmY_l00ck)1V8`;KmY_l00ck)1V8`;KmY_l00ck)1V8`;KmY_l z00ck)1V8`;KmY_l00ck)1V8`;KmY_l00ck)1V8`;KmY_l00ck)1V8`;KmY_l00ck) z1V8`;KmY_l00ck)1V8`;KmY_l00ck)1V8`;KmY_l00ck)1V8`;KmY_l00ck)1V8`; zKmY_l00ck)1V8`;KmY_l00ck)1V8`;KmY_l00ck)1V8`;KmY_l00ck)1V8`;KmY_l z00ck)1V8`;KmY_l00ck)1V8`;KmY_l00ck)1V8`;KmY_l00ck)1V8`;KmY_l00ck) z1V8`;KmY_l00ck)1V8`;KmY_l00ck)1V8`;KmY_l00ck)1V8`;KmY_l00ck)1V8`; zKmY_l00ck)1V8`;KmY_l00ck)1V8`;KmY_l00ck)1V8`;KmY_l00ck)1V8`;KmY_l z00ck)1V8`;KmY_l00ck)1V8`;KmY_l00ck)1V8`;KmY_l00ck)1V8`;KmY_l00ck) z1V8`;KmY_l00ck)1V8`;KmY_l00ck)1V8`;KmY_l00ck)1V8`;KmY_l00ck)1V8`; zKmY_l00ck)1V8`;KmY_l00ck)1V8`;KmY_l00ck)1V8`;KmY_l00ck)1V8`;KmY_l z00ck)1V8`;KmY_l00ck)1V8`;KmY_l00ck)1V8`;KmY_l00ck)1V8`;KmY_l00ck) z1V8`;KmY_l00ck)1V8`;KmY_l00ck)1V8`;KmY_l00ck)1V8`;KmY_l00ck)1V8`; zKmY_l00ck)1V8`;KmY_l00ck)1V8`;KmY_l00ck)1V8`;KmY_l00ck)1V8`;KmY_l z00ck)1V8`;KmY_l00ck)1V8`;KmY_l00ck)1V8`;KmY_l00ck)1V8`;KmY_l00ck) z1V8`;KmY_l00ck)1V8`;KmY_l00ck)1V8`;KmY_l00ck)1V8`;KmY_l00ck)1V8`; zKmY_l00ck)1V8`;KmY_l00ck)1V8`;KmY_l00ck)1V8`;KmY_l00ck)1V8`;KmY_l z00ck)1V8`;KmY_l00ck)1V8`;KmY_l00ck)1V8`;KmY_l00ck)1V8`;KmY_l00ck) z1V8`;KmY_l00ck)1V8`;KmY_l00ck)1V8`;KmY_l00ck)1V8`;KmY_l00ck)1V8`; zKmY_l00ck)1V8`;KmY_l00ck)1V8`;KmY_l00ck)1V8`;KmY_l00ck)1V8`;KmY_l z00ck)1V8`;KmY_l00ck)1V8`;KmY_l00ck)1V8`;KmY_l00ck)1V8`;KmY_l00ck) z1V8`;KmY_l00ck)1V8`;KmY_l00ck)1V8`;KmY_l00ck)1V8`;KmY_l00ck)1V8`; zKmY_l00ck)1V8`;KmY_l00ck)1V8`;KmY_l00ck)1V8`;KmY_l00ck)1V8`;KmY_l z00ck)1V8`;KmY_l00ck)1V8`;KmY_l00ck)1V8`;KmY_l00ck)1V8`;KmY_l00ck) z1V8`;KmY_l00ck)1V8`;KmY_l00ck)1V8`;KmY_l00ck)1V8`;KmY_l00ck)1V8`; zKmY_l00ck)1V8`;KmY_l00ck)1V8`;KmY_l00ck)1V8`;KmY_l00ck)1V8`;KmY_l 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�GhIUyt20Un6VgL)@+gFIe8`>}zuvFT=y{i7@ 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 z009sH0T2KI5C8!X009sH0T2KI5C8!X009sH0T2KI5C8!X009sH0T2KI5C8!X009sH z0T2KI5C8!X009sH0T2KI5C8!X009sH0T2KI5C8!X009sH0T2KI5C8!X009sH0T2KI z5C8!X009sH0T2KI5C8!X009sH0T2KI5C8!X009sH0T2KI5C8!X009sH0T2KI5C8!X z009sH0T2KI5C8!X009sH0T2KI5C8!X009sH0T2KI5C8!X009sH0T2KI5C8!X009sH z0T2KI5C8!X009sH0T2KI5C8!X009sH0T2KI5C8!X009sH0T2KI5C8!X009sH0T2KI z5C8!X009sH0T2KI5C8!X009sH0T2KI5C8!X009sH0T2KI5C8!X009sH0T2KI5C8!X z009sH0T2KI5C8!X009sH0T2KI5C8!X009sH0T2KI5C8!X009sH0T2KI5C8!X009sH z0T2KI5C8!X009sH0T2KI5C8!X009sH0T2KI5C8!X009sH0T2KI5C8!X009sH0T2KI z5C8!X009sH0T2KI5C8!X009sH0T2KI5C8!X009sH0T2KI5C8!X009sH0T2KI5C8!X z009sH0T2KI5C8!X009sH0T2KI5C8!X009sH0T2KI5C8!X009sH0T2KI5C8!X009sH z0T2KI5C8!X009sH0T2KI5C8!X009sH0T2KI5C8!X009sH0T2KI5C8!X009sH0T2KI z5C8!X009sH0T2KI5C8!X009sH0T2KI5C8!X009sH0T2KI5C8!X009sH0T2KI5C8!X z009sH0T2KI5C8!X009sH0T2KI5C8!X009sH0T2KI5C8!X009sH0T2KI5C8!X009sH z0T2KI5C8!X009sH0T2KI5C8!X009sH0T2KI5C8!X009sH0T2KI5C8!X009sH0T2KI z5C8!X009sH0T2KI5C8!X009sH0T2KI5C8!X009sH0T2KI5C8!X009sH0T2KI5C8!X z009sH0T2KI5C8!X009sH0T2KI5C8!X009sH0T2KI5C8!X009sH0T2KI5C8!X009sH z0T2KI5C8!X009sH0T2KI5C8!X009sH0T2KI5C8!X009sH0T2KI5C8!X009sH0T2KI z5C8!X009sH0T2KI5C8!X009sH0T2KI5C8!X009sH0T2KI5C8!X009sH0T2KI5C8!X z009sH0T2KI5C8!X009sH0T2KI5C8!X009sH0T2KI5C8!X009sH0T2KI5C8!X009sH z0T2KI5C8!X009sH0T2KI5C8!X009sH0T2KI5C8!X009sH0T2KI5C8!X009sH0T2KI z5C8!X009sH0T2KI5C8!X009sH0T2KI5C8!X009sH0T2KI5C8!X009sH0T2KI5C8!X z009sH0T2KI5C8!X009sH0T2KI5C8!X009sH0T2KI5C8!X009sH0T2KI5C8!X009sH z0T2KI5C8!X009sH0T2KI5C8!X009sH0T2KI5C8!X009sH0T2KI5C8!X009sH0T2KI z5C8!X009sH0T2KI5C8!X009sH0T2KI5C8!X009sH0T2KI5C8!X009sH0T2KI5C8!X z009sH0T2KI5C8!X009sH0T2KI5C8!X009sH0T2KI5C8!X009sH0T2KI5C8!X009sH z0T2KI5C8!X009sH0T2KI5C8!X009sH0T2KI5C8!X009sH0T2KI5C8!X009sH0T2KI z5C8!X009sH0T2KI5C8!X009sH0T2KI5C8!X009sH0T2KI5C8!X009sH0T2KI5C8!X z009sH0T2KI5C8!X009sH0T2KI5C8!X009sH0T2KI5C8!X009sH0T2KI5C8!X009sH z0T2KI5C8!X009sH0T2KI5C8!X009sH0T2KI5C8!X009sH0T2KI5C8!X009sH0T2KI z5C8!X009sH0T2KI5C8!X009sH0T2KI5C8!X009sH0T2KI5C8!X009sH0T2KI5C8!X z009sH0T2KI5C8!X009sH0T2KI5C8!X009sH0T2KI5C8!X009sH0T2KI5C8!X009sH z0T2KI5C8!X009sH0T2KI5C8!X009sH0T2KI5C8!X009sH0T2KI5C8!X009sH0T2KI z5C8!X009sH0T2KI5C8!X009sH0T2KI5C8!X009sH0T2KI5C8!X009sH0T2KI5C8!X z009sH0T2KI5C8!X009sH0T2KI5C8!X009sH0T2KI5C8!X009sH0T2KI5C8!X009sH z0T2KI5C8!X009sH0T2KI5C8!X009sH0T2KI5C8!X009sH0T2KI5C8!X009sH0T2KI z5C8!X009sH0T2KI5C8!X009sH0T2KI5C8!X009sH0T2KI5C8!X009sH0T2KI5C8!X z009sH0T2KI5C8!X009sH0T2KI5C8!X009sH0T2KI5C8!X009sH0T2KI5C8!X009sH z0T2KI5C8!X009sH0T2KI5C8!X009sH0T2KI5C8!X009sH0T2KI5C8!X009sH0T2KI z5C8!X009sH0T2KI5C8!X009sH0T2KI5C8!X009sH0T2KI5C8!X009sH0T2KI5C8!X z009sH0T2KI5C8!X009sH0T2KI5C8!X009sH0T2KI5C8!X009sH0T2KI5C8!X009sH z0T2KI5C8!X009sH0T2KI5C8!X009sH0T2KI5C8!X009sH0T2KI5C8!X009sH0T2KI z5C8!X009sH0T2KI5C8!X009sH0T2KI5C8!X009sH0T2KI5C8!X009sH0T2KI5C8!X z009sH0T2KI5C8!X009sH0T2KI5C8!X009sH0T2KI5C8!X009sH0T2KI5C8!X009sH z0T3ul;Knd*d#T(VQ5x*aSSL5i4cu!Q=)WQT6VpJ&lh#@u^A8y*aLjNKz#FMDQgaz; zt@MMuQ)l1ZCjHzCJ(G_c(DBdl2_5Rn7#^9yX`G^sSm~XeKddMxdyKbx?!?grsX4{D zOS6xG~d^O zG8N9R{+6m%ZKrB%#MXy4E}XmdgUoyCesXBT2gf%KO(R|#snyHah>>+X=8c$hu<7KF zuWX$-b?K{x#_}BPXB4n`4nD84Ux1* z?$cHk#iOm1QHb2v(IsjqiE8;-lXn;PeQ;&R$nCl9y`fRV?o<3~)fp=L{+}#P=_&Is zs(1Don=@wgZ!>q_8^3QmnrhG*PEokvVq33<)3$8weoao(zSDPHwDk4QzCT3K%c#La zdkktAqVCe-X{(AN_gVH0Zjs9SQ!o2z+NfmDGwW9-O?x!v#L!43vaMf*!KB%Lpp`|( zk#*~FU-ixGkTq@JU0?6$a_9b|DHSd-`=T~_sk|0GS^2cj(C&{lZ{GjH;^!t(Wy?rq z2<*q5p@ezYmE{XU@>;l}ERiX>wrsMPTB9<4z~iHwYRIUA-2OBW)3EZ7 z+zvAKdarr78|O-`Mvhy|t8FS=T&0fK!I5}pl#FCrhp8RzDOz;t?WwbRb%;y*=+;*{ zT=nPmU#y?q^X>~j{$c7>aqp}cFzDxqe>{C3fBnEOkMzj-=v~86D}>ba^_@?jx#h?7 z4R4M*91X2&%%vt$gs41Gm1bq&@po_{8H9Z}~r#Y*34@ z6tZY9j~9GgG@-63=03isO`EJ!yFdQeuN!wguspxKCZy<&8|!BOw`10~Yu4x4Q#vWuUoKqPM@Fi#hRDq zKfHW`tVR%>z2Zt&k8`p(675?ie2SbP*6$Slm10Q~>lcZot5~{;B}FW$V)2M2Lo64H zWQVk zSZGqCp;#J;rLkC=h^47m=u-bUu~6$DFP0O;LK7k^!leDCddg z{O;MKz2~P68<(A*;~mzgV4QcfH^2D&KG|c6&QI-q+29QC=z`wfao)Vam-SZ@(NDHG zIMtcXMsjrG5r=Ab^<@Eq&V)CG@u}Vp5Jk$6#p3Cu+qjsCa;1y({nDoe}oKQDYu`I{%+}W zspt$Pmnwa=R2+$S?$P2XcS}FWyGQQf1o3kFe9ko}h1@{`>+dZr$}K7u>QVL5rHp#I zWR4R7-3znFj8slDl$HCx>nl16AN_P0F=$Fn+!{#X{%@6x&FvIu)WsrzP6l#ZL2ZkE z>6{?P2)J;jy?@<*uKV(_maBT*`*iBOwO!BK&c~-rObxD8LZ0npEw~BmQx72=A6e}| zI1=xCi@Flw&M;%uLJJS%qMhlYn=ng2O-C*mMUEDrM9HL0iP*F@;*vM3>2mADLPHa+=7Of+h-xO}}D# zBPLy*+11uW_otzW^eq!uH*KQK>TaSC-Ycsm9o?m}6|3zmLK6kfo3bmWXHjDHo<)22 z?CBb^j&8Ipd%#YlD@)v{3+9DXOqHK>fGwl~ge@fJ zVpJNK7vje*tM*_QPjuP1n}~TKRe8q(DcC}4Q%nOkaGPLtdeZ87it7%@S28{47xkpw5NWm78ClPzFh3wiw z@5XM-Z?a}!`qR(6voXBrydQYHXOiT@7Sd=i8`wg`qlE?~@OU!jg)|^fOD=xt2h5!E zJ|kDo-6t3(0Av~G#bnXwh-}vEu^ZVYI7H`guKy+dSwva}H*}xVe9HxO?U(cC zKmB~hy_e@)H>ytTFj?xFNI^c@A}g-YqFYnCIt z3+(G7Ho}K)@PRF4(A2ZxUw)Z7GqU$%mnL0#!H0X>@M)}%23ts@!E8b&M?5>NlEt&r zfrp9&54=-f&F|FLfY}b%Lizzotiu+Pb9t4&5`isb&{WG&<9nn&c2$qbKfiuW+8v)v z;_+S|4YrU*gW13qA|5TIMDR|%24c13foG>Bh=6B0Zs8tTfRVOhNy-KHGird6JLF6PKM{6mFGOP^Sy%kJl^Z0!4}eJFq;}|3x#mf0k)8;3fv>B{FSLo zY$5ut(DhsPcM~JMTmN>HOXh`Y04dl)`k`B_o7&f~g$$%_t=sLHHYYxjIqiqj|Lk&m z>=QiR>!ZOI(r7T78f*)N@Q*FQ7E)CKTd2m{LN#Ev!zH#*4Il+uNI!Iob=X3NHv>$+ zwYYg}kFGn?UhezUq-)oI^w8ATc)ZsGg)OAfU^cLYhzD#TRTZ#>U<+y8L+NkmI||rB zrF7Lb%Ml*WPU~n{l5)X)*CY0nx#Rc98b!D7b@ekH(&v8J>CKn_{pJv##yXgIr(VKf zHn4>V2y7u$7O;h23(5W=;Dx@UfGre&tF2g$@UVq+v@A)%7SfSw_x_r1ejEI3pXXZn z687EMWfPyqx+t)PBn)N)TZn+b7E)yaTd2m{Lip~q;Vy#d_l0TzDcmEIqZNCwg$(L8 zy+`)kpF6yRKE0{;JmtZOzpXfKC6D(^l6>4F(`Yao*h0huwveg{*g`el7ODYH!C+oU z>w*KnmLojog#w)LyinkeL{<2=S@%racwg3W|MYzB>DwQudx@_LkM}y5u!STHW&>M@ zfWQ_~WdU0Vwvg-}0$%7l3fMvcxY`PAA$(uRAPL^&v(NGKLN}bZ|Md;NPqLnQvB`{y zPmhh@j5uTRF)yUiU^cLYh(`+zO2F*K-)7Z-;QK;S7y-|8+@cZQ1=sMH7c$&MFug}s z14!W>S>U|WR!q-6yi;!=H757keGjy%@3}ARV2|*W{eB+r_0eDpX*8G(Y$4(STS!#} z=7lgXq;(IazoG9aFfUX}S6#Cl;ay-~AF;QiLO1xp7BXmR+=l1cp7Y4O9t*=t>dpH5 zr(8ab_0eDpX*8Hk=;T=Ke}eMAp@x&+MfL6%*f2Fr8nF>_rsg|x99O*9}TvUMuXYZU|R^^ zTGR_$w{F^Fz!uU`QddJKe;VOkU<=iNJ3lV5g=zpP*g}T$)wE}WEo30|fw%9UCtf=7 z;%zG${U^Tu7x>$(8lNVNiR~ZS=Jn7G2Gu?<1Y3w3*5I4=7_fy5q?FLfAGVNzt*HuO z3)v+FTgVA1d|yaM>+o|0UtWGnZoiG^ytXgwh9Ph8c(03sXQw3$W)r%>0Je~dHb(-E zlJ}#^wM0*{6Djmf1Y1aQ4|t)Ize{YP8t~N|m)JrzfD~+@z=^7@nA+Ev7c!7)Kd0pz z7o0nz=ghHF-rU|R1AnJp<5TWv9QuJ4wvdV&worubv`kqdH&P9+_n3YpOqW<)WucCi z88nj-K9+~!j1}7ENW62MjFcx68#BkeP!JL04(1oW6gBjssSUsOXh`Y04dB1$&-jZ%nKQ;GSf@SmBat-wy5Rzo_X6IeCwaB58-cc zXcEG_5T8mxK3jw>WC#yAd2&0_Y(C*^86iF>OV~oNg-8^zh2*JmSo&-fDzJql5%w%c zco#g6k9i@31!8(7a>PhEo)`Ko=fb7`*K1IZ)o&*sTJ-im+jyj7&5@6JA&myJ!MqUh zfGwn|0^b)Z(9RC!GwBC;rsEc#7c#K2B;|s8WO!casE_cW8+`D*km2lmdT{IX6Z+Qc zxxstE>Ih{DzAvQl!Mu<`C#9Qg5yBQynZOo;EmV4PXls0mgl^n&$-EG3A=pBS;+J|4 zOlFq|$C|Gz3GwZM3hz+6XI^N+i17G_hBnDq`(FLmrc8fwGgnD}dShPbNOf`5{=5*r zwWt@iZr${X{1ka^<6DbNE3_lL3+`vsfG-HT#1^Unr0~2DpQq9{?b$FdWFXaa-fMgI zHfY)7?uZXJH|%=ieAq%NAj}IHbW*y>3TYvC@dW^$7t(;>?~#>iMO!oNjd736fXb2- z?vd$enUaDnq@zTumZV&vDPM|yZYX4L(K>!!=)@PBPC4BA#jNEEKkd3`SBHH((&>R> zUPz880E`+Y5aEUF1=Y{aR(6Rfx(C9@UzrV}h@#3W){X4MJ z&KpkW@gBBNS^I~!m`&)qIM_leW!OTng-8fT>7Du-Fv7zYQag&$AIsSe7d(Tezw6^t z`x^5?rE*f&zKxzRe!$^%8FxSV^PN{b{q|fQ@Ac6zFQn06Hn4?=M++$tzWm1XLK+Y} zFC>K#@Jz=om)s+REo6VT!}T+0xJMQ^@3a-uvk$hAfz-0QUW+^agYM}Il(bdb?p$^W zkN5g$u!S@l%m%g)@qjI)s-kN5ah7VzQZO$>ATTc^<>1zDE!F_55w?)j5PPtN43@s> zcc)Vyd}!4zJ;!+-`gBp#ksmkxo5y=5Nj_{LjRv!UEkrzE3#qDrEmWYL9m;3Y5AsZV zW0%Ye)qp30U2>1C29Sa+WH|p!&pylx8A$cW*`ELV))%ri{C-Qym#3xe=kZ=24YrU* zgW13qA|9}XR8_zhf-R(V52e4M?qyO5xar&v_iySk zf9I&}d%vxp%%`y~3g(3*3}ypch=9NrQe^>K2)2;y9|B(JI||rB0l3X3NJq<( z6l@_Ksq_#2&hJ`s@ZxF92ej!i+4BIO#=0o5g(M7S16zoIz!p+v0b8iX+d?(qDHxa7 zLN$OC?vcsSiappucApo@D=bRb_3W$tw$17IZ{C5^zT@$pNs^CyWEu@-Q-f`x5PrM{ zwveg{*h0sEE#yntyQfLFy?gd_b?N)huCaw&PYSk>HdqCIVGG%{g}!~^wXBam_4i%1 z|Lyx{A837$$NKxC2qrq%yuq_nA56Qt6QdI$4sK(nuHQ!Uwva}H*}xVe9M@ zfWQ_~WdU0Vwvg-}0$%7l3fMvcxY~;42oGCGN6V5FY#|+~b>IDOc)NP*F23)k@O5?G zIBp=H#=0o5g(M7S16zoIz!p+v0b2;RknA4!M&@NWx$?u!RT+Y#~(^xJOnXPmj-}ALN<##_q9&x`|PqmK0i+$QrPf&nAND1*NgZ zq3ax*E|LIyROo_(-|45Zo(=(Xv;ahG^jo%ztlJ`;L9%%`zF8s>#G8qB5! z+d?7i=wS<~s(>wY4A?@h|Lg0nv4vbu3bv4b=oag+h2&EX6<*R@{&4Y=pAP!H&!e|> z?Edc!Z*Af6UJn$ukVb>qz!oANu!U4rz!rinq;(IazoG9aU<;MfRo5&>c$eIF<#|Sz z&NX6Q$e^jo59Xhn_r@(zH86tj8q8r$@ym#l*#=#iqta zC8nmw#Kom0XJln&WW*=MB`Nyist2|Bx!R)zmik})HKp#XHC|5>nTmZGQQg~0hD8X! zk0=`XEVdh{dlhBG_a~1|-tUZCAhN-47`$K%qm@6pB4m$IKp zDRt46CjYnQ>W24B?6Jyw==0`7f9_AUD0OuEAmCE9HSLyygPM3|deoEwzd+rdHRgVm zcRe-Gw_Ww*Pf5vb`Xei1d%N7{<9M`>*EQdlLPRwF6L%5~%A!yzi*DG5sVN zpL}*@)6(8jep(xFOwA{L%uL(E^`kAdjncIJ+Ar0Y(vV*^9fdRB;B-_kN<;N6n~u|n zfO3vkU#6kZvgv3Kmo@l!6qk?5nxYh?PHO|PomRR}TcfmGR^nMUoQ_H7hL(ea*ze`zb9gwC^~va6WV#TBtl!7Sa;sLq08( zp39)mpN>uWQ5fx~d}*QMQvRIJ31Xd=j3prG;2piiI5QCziAjS7OQ> zP7~|2oGO;n#lrdM%TDWjTz%PTo$E_%xa_n}j*hD@JFRoO=*v#)%u`=>T4xUWveP;p zx34HH`NW1Cm7U5;$DsY3r_kRHTEa!&s+}{W|B2}oha9D&h59v3oBIA;>q|eABAf! zkVgvdA&#`@(uw+6r=xPRzC}8!o2;LCI<6m|gSvF0e%9%zbbOAMO-CWjL!XDbPJ!zA zM(3O^9k-w8yT}EnqxzB7Xp!l52;VXt*N@H{T6F0|{m7MHPD)3ihWgR*h>I*E#URJq zrS;=JM0Y$YK1i3Yf^sfb>&JbROqU^iDktgC z$EDPK+E-dX?!$D)t1z9Y-wV`sbl!_}bS$o)>G5Ryy}*5-Ojlt!_3cO6)|HdEly|)C z`ucGnD$~*NDojW9<33hbPRn#$KkkENI^t4cI;s`-(LdaOS?Z?m&lVSe2WGv|W7}04 zV~RnpwB5vp+V0vuUkbG&IU3*fE=>7FZt^2WY(aJ@n{{a-{eJz$gm{rnb%LSl*p&6j zZ6#T*BuW1d=|^yco+9gu%mP=4fD6q6Ul#!#WT3H%Vqlg<4mu#^$w%kB10$jFSLtF~ePyzB|y!pn-Y3yXuUyY*h0De7UTAgdpC`SC=NJj3S@FK3W$`$jhtCm&>U7K5-;kqzmXFO)H10 z2VQ5N^3t!1ZOw&~_eFiXiL!1lr@Uex_Y`H$ zGfGS4Vqd>b`^2KTQ1InEC`V}*?hs=xEi~?`Wt4{#*HpoCR~qktjV96r*3;#BhVb?4 zB97+t$F6*Tp&pNpA@kLAVVqN=BhtK@uDmi$AU&0l_R*qW4|RF@7$V=Y8aB@R>B_51 z6I8|>y7JQcktnY&UriITtUiI27S$QbE7R!h+aPV|@+~`u90EOvHe}~Z5oJ^R2j0Wm z5$cXI8lW=KBGQ*BdxqQ&s&@&FOzR5%B##n&h{i*f9hO} zuqRUsz1f5Nj?K#pOwRaaa$Vs{)n?3&u0T{rmoS`N?}G6?ytyMr7MthUO+;rp#ykVF zzGTO7o*CZZ*<JKq2KVDIUjUT$~$6L0M@TCi+Pt22a`dULXiibb)>_CJq7aKW^SY4eCbh>6F5 z{jck5WE`LBADH1`|3DYeN@9RrEZGmhpV%iYM75_Ey%A!6qULS>xy0=oU&4sH?sYz z?@QHuWtH?NYrf|ik3x>iw8v1Ujxv6$Tl{J~&PQdDKYaM08@2sPvS0CwKdgDvN^RTp zxN0tUAOkJEpdeCoE?j6JuA;M@WWk?~K8zH{XGJN>0es#;|@rY9I*|T4(CuvOV z_e~N%9+5FAv6)!viKA&}ASsbtsS@?!Qi*B|@ncjXpBJouqY~e^!J{T+IspZ7h6cs) zZlgl^I7$~SKUQvFf3mj!nKgbzbwwW4JO^KSk!UP+35k98P zN{na_A^Hlb#K5s-nNF0-ikjllau5n4_sSYSc|y4!)mOUsHJ{?YvS-iZw|lg0vA?Y1 zO82V~Wd2%Y(H5nOs}s>cD6WA}oKRa>c-`>&4Z?)t!Wz^SY71|mM5t;Ds~Z-fJ(fsn zt1Hz;*+q!EFLiY4;&47xkl(=P(e`!m$HfY_x2)RIMc_9AB&)5C&{(P3h-z82akyk3 zAS?SF?)MHXl}DAWZB$zzok0zO{YLe0e)2d0RT=iPY9kiO;~VQFrVh&)EBf<{Bi zu~ZebU8)LwIE4roXnlh!I<57n;XE1{Rq@7(vf_Kg2h zzj_oVsBVZK|CJtX{|rCXI>?^k7EYS&SL1zix90QyA7+)mpY13$5&iJ_F3ZFFeOZ2W zmCIF*9Yrlf?I&78YM08X`0Dv+U)>ZcH?<$dV`pqZ&7Ki$My^~tg!W4tj_sKy5BMp% z^36?}&$e0@S!Xqne&p!VX}*YOuxEUW7A&}Hp4cy3Ir%h*5Pd^n1ZgNnkcMG(8Z;E6 zNJG(22+Jj$?UpcMyHKs-#9ceKSxUDl`?`X_`67%)8LmI=FXNIX`L%7?9vSzm+oU7f zKS?Z|1f>X(LnET|In?+Mwn24bdHyn>`7H(DUF@0GcItp3Yl!9_8>kKO4bVl_A z_8UeQ&ditPS6BJ?;z&Au2<1fhC|n#rh5S0wh^KXO`t}r?#-pk2thXXWsbxEd*QqCZ ziF#oX^wEy6dSPM0HV}Qk#G~1h>LJSeIdH2-+bu0L^*G!z=_06su4TdnyV91S1C(tU z4wr`x)PV`h>yto_%p?sh6O>M#zkzg|pV@vs&J0;MK91a9LCb_|0tu8trdG*_Dwi|j z)~zEfd@dy-z85S}P^5 z4`=cQ%Z4=>G=>_<8`DX`&#du?LkedgZ#Gs2wUl<{TIP&U_>3q$CzNnua|_!goVs4& z%ttW_^_{ZHLw=xC0fPL@&>vc`peWtvg3qtKA$-$_U)qiMwcUu{*p2v|-H1Qfjd;jz z#KU$Y{>N^_|JsfCo85@N+l~0A-H3nNjrgzKh;*vjl3BRjh!J)p*0URt`gL1nY-BfL z6T1y{Vtcz0JKBv%7N9LX zo?|y+XS)%**o_!vH)4$4h;fF9UeU#n^Q*r!{_9+{T#wi7qt!5Fh}<(z`VFLir}UM( zvNQv@jIhXqS(&^VLSJGW8v;&M= z%Q*Dt4X2hx`$B}p^w@oKA?gwQqLFUY>!chNO1|F6^H@(8pzA}`d z!W%F$e!%0FV4ngwbFPCu?et#aQFBF$s2CXDQEZWM(y(tr(+HZwIa2y^&RT|2k_EQ7y32C$)4)&dSH36xXbus)_QoGb;DK& zn{XIas?(@GR?hjbfU=^theTnD{|xm$31wE@od@g|g?opP4Q^GnjD003n%(ku%1lp4 z6cz@{SmnqAK&3B3kC8si|8K!szox8=K-a_P0Yh>!N-i(CZMe)3eHekQ^$PnlWf=)# zc}YQN>@d$?w+--!3{{6w^4Lw9%`8T zQTQ$s&shmLRZ*Dd-`j?Jh%mV$eSYyoC*KUhRYjofTys^yHlI)QVIEZ#;-@MKgUu%? zq7P#^@oZ@CC4OyJPt1l25S1R>s%*E2QAKNsz?@a}4+fZ@*3Jd_%i}y+L@VuEky)e#mKf~9* z3CsQJF8`&t{uLmO>h-TjZ3*3|f^q(+wg}t6?2G29$~cc+Sk*V~q(}_HV`b@V{HiDn zcT%9RQgNwkJkIZ0;nza0#yBrP9K~^-TV%j0twlV8(IQ8;MY#86Uz7%xmn+T@ekajC z6z9lMK1by9y=<}I91#RuagKbw+OHM`=ZK2IMI*cT)EdSSSDhnDPqfIr8$T&{OansOpnnL7r@w)+-wNqQ7%8xcw{T$)BA>6@sM~ismJAjc&6Zur9C|8xnMZDRnwk+NS z)G*Mm`ehL)tQ1J)jB0$hs+3^aHSK9zUrC~TKS;@~($%BL{DQ#8a4&CgkAJt`riK4ECD|;un?!D{%mQx}0pG|&7|RjnoiudxdEa;LwL1R9yfYp@_}x(P z8TjjDPR0@SJ(-Eo3-b;iv^ctboy?if9Qd{H-IKo){cbn0h!3BU?@JlvG{cN~jl4}S zzq;q##=m|azHj1kV}_=GC79~Uf9Jqh{I$k%^Y+S|^m(t=56@f>)9{z6k-OvS$^efn zHh-s0IY|UumOFY(p0`iIxZL~^{f1ue%_)vimdON%r62fi{-1J3XX*3jTUcA%9O~bG zqq0*&k~H+QT9npQN6F50^tZW=Zno0VZK8a&MMqRu$2vN7(Si>WW^U-cA?okDMz`6V z?odauA<_|*of?v)Vbqan4|0oD%lm3k%Trw)xBUG4Raf-fxiIVQ>laV|;HJe_8e6{1 z-x=3>5UuY>8=IRq%v%^8<-F~i$UY^|hlmzbsPxp7w%h$yt9GB{q}{I*BZq0fOgTBG zdiU|!A8+5au+P)S)&2Z~{;za%Of}k^>OM)&*fW<)l}b;bY*W3>it6nlqe?kBrn+hG z8y7C_er~@fa!!1;|L(%)9aFU!?;KI3(i14#RDD)dCp)29!>t^utK)Vb_w+k2EZn^> zbJ6JyzwUYJ*ZUo}dnLxFa?d6zJvF86cAsR`?o*t!yJa6mIXR~K_VT=c_a{8q)3lj;SVwh$@wyK-s1`#fs`( zA)`t;Ii~u{;hC)te*1pL%J7bh69?V%rDLi|A)-p9Cs4Mj-eE;`YRITkPL8Q|d3gKO zK8Y{&xi2zl!?pkU;akU4lS4$6N>89{Q@zuQ>NF=*hlFA-X87>oDc5h=-|dG>lDaCP zn2RxHc#WtMxu99B8HaW(Y5RXqWp3*9Si?HI{HJTt4y2e~BoG|OLfLZZim(fA{It); z#5;B_`F2!^Q7Emo!zxM(u~N>ZSE#I6Dm*p4ZJpd@rIYDSbYf}MP)?4auDma=$AjZv z?>;^0)6X+udlw_ADfZhbJE(2 z=XHLg!3&P5hDxhcdIDve>NG2=_k@fp<>Z*E_kr`S@z0&pW6Gh86Axvq33E)<;=0C> zR;ly^$~M*MR#fkGLbZlp&r)3-w|m#7CmfpbV~@-^pYA?wT*QnM9Jjm0m6zGPeYw}O zRC;Pk+wFe0RlCn{((Z$-=G-VJ$5b2Et3UaJyV|ARdHzf5iWkmLbxbu>S6)Ux$+PoQj5onb|FwiBwBJpkq8nCg?=pF3{+ z-#tCk6W^KrO7D}S98(R|^(>X1K-s1`(~9aGCsb?Ol^4NrER^rM_59`SncY*Lep1;p z@9P#17==>Nl~<_jE-E}Vy=|S$veLgOUpcqM(!l)tlo%fGt0 z5o$$OUa_IN=S8I_P`0VgwxT*WWK=09$5gi-_gDX~Cynbj|JkLD)^BR_pku0`y7HpZ z6DZqM=U7pl=Y(nvzeb?CI&Sx;AL!ZUlS7%APptoH=;zJrcXizE7JZbXYXmAiHKpx# zzt5`O?|0JfmVFfENN}3?_JS%(SUvL&f4?bM~KcJcPoQj5oohvPe#od& zPL8Qw_|BOp{crUP8BaYMf7zvtznkuuYN)OesPqKNHr07nR3C6c)$$sFa&kj%Evy~qFM_PyiB z*$LlfG+yGk-7T(S9QFKEdTL7B?LObC-51uPcBi^JZuduS9sT{p=yy}^i|Bsk-M+j( z9Jjm0eM3j>PNk=&wB7CxShf2iC+%L_u3ia_W1$?Ju(0caiT~^EoAu)PX;%!}X%tFD zSFaYc$BynAP~oZRZR=!#l};8r(Mb&-7pSg|oBh;-H@y|N<<`vkas66OS-LvX*z6Tu zU&mS8*>u!DQ0b{DZMXYEt9D=Fq}?sA2q-7VRP%rD_Tl}{ZSu?+f7OlKo|w1FG1XAb zT2Sc;lx?butf($^LbZmUO;lIM?f%E0vGd2BvLJKve>*ixC_eEt$L(%0uj1%zqS8}S z+HUv7R_(s57PULo)p5IDux#Rr%jR6uYw3A=pBr@QI6Z)!fJAKzEkO`DQ&m=Qmb}fQH$E0>gu@N zTjjnm{h$4PdoNpj{_^EHw|(Ha-7RMP9JM=@o|@8jyDzh9_mxiCJ=^M83(Cnc)v&_P zPjB4t(~NuW%4zxT*#p}-rfM=g->;L-0qt<$Fx7N@Wnps!rMO3W@>xKZwtnSYCerhPfcmN z-B($)`x+ zhDxhcdIDve>KZGm4~2{><>Z*^>`C)|UnL*zw`o(~mVLi%+rTkZ3v1SqR;ly^$~M)t zR#YDj8CA;3G1VUTKU}bcZxR_Z4Bhxka2yL|&m(`G{?KuMUHtS#J4ZK~J@8$lP%0XK zLv{91;i>6u>*OITojfXXv;EDXkmy9IId&SsajcX5nVBChZXKREW9xU54y}#a;Z!G~ z>QAWf)bzG>^01Xo9y=O3p>Lb1-!~)8RJlKqnFTToU4KGw9P4C5+wBcwURu|8L!;zZ zI(&Y4xKo{2T<<#?cc}2x^tN^Kh?P#(JJCrEzuu?1I&SujFOO{cTgP7g9_sl0%;V4c zs*TfT57p&96`oqscC$Zf)$AK;QL|HB9XI<@|JCj446B>@+(PeXbp~B=wXxaD`2=E_ z515(1p5|!El*&#GX>9eDnyse%A$_i&vQq45DiV=nODymzDfP1K{a}Sj(-9zOe_fVnX+$FMo*gaIPb`O2hstR8P}%MtD*5iA;&%^~0{2jP!97&QxQEJ% z?xAvnd#JqR9x8?Ip|Zn0REpd~Wv6?n6uXDYF85Fw>mDjEyNAj+_fXmG9xCJAL**6s zP`S}PR9l@|t_7OssY)`$gr+1wEUcC?4dF7sV+z@E)uscwEh zkDfs+*S#}-S>I7T9_umX#+lE*ygt=ue1yFzr)nrxE*mwWckYOh#pchg)1)Rj{j=Y+ z{SN&IXS-bIH~e7J1HUcLSn6jcftRml7IKqJGB!CvEHKKGwqFl$?Wr6pW30QqfW08y_@y?bq z5>4or>nz$$2?)Gg^>bU48^}T|H*lLQiK)2y%LvTMqL3e@{wpH~9g04j;*LUIn`TkS z-rd|$$Op{}xp2V(mlX0N^FoT|c1Iz74bx4VTWB@K9nIarypRhQw01`!eID~d#>U3F zqmatA=7rq5r?)E#8Ri>rUdR#R4?ep>lfG%@g;c~F^VL{L9(mZ$HydQc7yD9DWMI7X z*$Xp&_w!aU`qOhn?3s$?v2F=Q%`1pC^5O8TC%Nt=uJ7=;YRAUuX3@D0Z7Hwx@C+W`f(AdgT;nL76U+X{vM}iCZ;ZH;VtRXy0wbjH%=U4GRIYmFP_utu@78BY z=Q*hdz9po7W&4bYK8s`yV0t46zI5i6Ptfgu=CU3drbY~uY11RbK^b6 z+VNbNLR~*gF{@x~esOkgerSiY309S(K*yCUJgwP>pU$|r$MXjo?p^3f2=YecT zrmyDMj!Ykuu^pMdv0^(ieR{-p&dZ=Ay!LDXoMx_SAWX{D$2z&FlaK>llx=_7rt`Y zQ_iN@U-Qzstg2-%Oew4EI|Z`;Le`s+^P>O^OVJRNl*pAp+i*mlVp79T6tU@?Am>+q zbwr7~sabTBNLAglko-6?D@m<_@ktAQOvCw;7Oz`9X~8(Zl9ad%70$QG_yLb~!afCP zE%5Bzk9IEqVMgj*>8B^0ddrH=9WipTS zsqa!9b-b5do_cxD^gfxF^%$I-lpLLw6_b^f7!w^Aot2Or6P+0oml+$En30wkn;tzl zCMGF1HYP1KGb$z~E+Zo*IW99sY$qjVB*iAjC1qVQHhWlMZcZO>(a1}^!^Y+m=N9A- z9uVC=#v3&_p-)C)MtpL7Ong>cY(i{QQhHWGLR?gIT2e-GLVS8uY;0nbnTwVIM&BfU zoN+&=6Z?~*VzVgN%vY1ftG`iknF(15nF(SmR@)JjO70e3obDJ=QK?aJF(MKDGdiU* zZxBQ(h08sn$vojVPV=ixCw`8X&B)T^%ip%#yd1GSKioIK&-*KU6=AxJsn;;=G8OBn znlIMm#N_0pn0TS{n5gvB%!H)q*r=?Gw3yVi)Wr1U^x%f&hGroceGWJH$DUaIN;6fg zN@riHUn!dvnVgUootl-Ln2@Q{TiI2kNO`+# ztiaZ>CsswdNA02&B{DB0VqG5Q8{lEphrVYWQS-$blMtH}pAel97b7$qpPm>aF7mR3 za^n*cV>861Q$TIT6&9z_H^!6O$DUX{VHt}^TfVxU>;0@T7x%2gYra@B#dUf@Oj2T8 zR#HNAQe0wsR$^9sW@=n?db;RmlVJw141;{Xq8Y!-mCds>vHGv{R8FkRW5{OpC?9;%~!RU*G*5($cT?iO-jy+jfsy-OidS;Wl0I~@u_0cfHfPeRSq%w!7~KoxFX^EAU<0HUsebut4+*rs|7Jh= zigI<8RDXmGkD(QH(Y6M(lf)EttXA8=^Bo=JHt(04rQVlvHRyqil9C~reD~1w8G~c+ zYYsa^TbO>$fp4FN>=^^ouQ?pOM;%BITu(Nb0?#yrMyd3AJS&p#g&$$19)s`XL8(Vx zsV7&zQhnl()&1Po5&l9Blxn5a>q0X6x2%4pPJ&Wtusj0qIlFZ94~wyu7qPKHuzmr_I1r?#nnrA~oTq13>{fDi+}C1L$S3q9*z&DZ{SK&eowbETeA z{Yt$PN`+FLE0tc@tmZ!TE+`dBb*|LYs$Z#7q14)?)FC06Pd&Z*l{yVdtzAkD&9#4I z^(%EclnSLfAN|j$ex=?Gr9!FBmD;ZQm3j}9TDz1QntN1dR=-m3g;HymQU`_PimH9} zD|H5x3Z*(9{X0~@QfES`wM(g?x%Tf^{Ysq$rPeN`hGz6XtNN8X8%nKRN)64-KYf?9 zn(wC0fl_OiQbW_Ho?ZP)y$?!-Qk`E>om2fvoeQPbE~SQMKK0z{SL!?{wRR~rG^2m# z>R0OhP%4z_eDpuB`jt8#O08W=4b6ONm+DvQ15j%1Qfg@I)bp!fsSBV~DAoDsA65NI zT?nPtE~SQM=0CdnmAVK@tzAkD&FCLf{YqU7rPeN`hGv#3w)&O21WK)4N)1h)8dv>F zT?(Z_sm`yc;;Ub&%b-*!)wxm=s$Z$gp;Rc`W|$}lIsP#GUD~EXkL8x@T>1_Ds;hv$!e7k~BCmo9RE;&4N?Tj5 z;>y{{e=380j#70MTu}WgSPd1Z?H4i?9O1vGabfjKmnZ*FveaOR0lH@?DK?)vwfbP%4z_e2y)p z`jz?+lnSLfSE{G_mHIH0TDz1Qnky=rCavZxsz;zyDAjqNnpXWveH2QCQk^T6CK{`` zPkjtZtzAkD%`=M`)vwg`P%4z_yid)nex+`JQjbZc_7&|)?hnmV0%F_}t|;_uEV-b- zd&SPyW`UHFv*8C%D!ltU@Zi)AF>R-$Pc0nzLC*u1ny^}*&?`>A~o@rHYO6j=X*CkxNF){j;j5*nnZ$9%<(`$_NZov(B zyjU@`cZ_+p|CGsWH}`g{YR|H&Hl=i2?NjgDF!{5S=JcI1A@{=0V-ANKt8FFom?-ml zJC?cMs@}7$>P;yf*W35_V@odl;M^W7SN?d;!AWm7aa8Z<5Z3zzt9s9|syC%{T<s}!}p#gb^dc;RL9xv9o5@H=Z@R^MXP$>XH{=X>A2p1AD;DkhsMMEJ@M*q-L_qK z)7g&d9UH>-e#xrdbFJ!4DIM4Q!1w1~KeOHVURzrf_ZWF!msDfDt-3XfYCG=Mc34$= zo>jFerQ>RUetr13y&En{+qmNP`yTAHYps)N$C)uxn=t36@S!FoyY z<1gOY?TSA0Z_LhjQtkK zz9j6Yo|8w0zxP*cr~OWQcFmz9*2m=>+PC5~|UNNe1f(;z-IW zJ3n`{nmDqkSZt3e$jvYAOvT9=nO&HjQ|v7)YT9V{*!&ziKxFPPkuEnUJ1=hn9bd~? z7qv^IsFXOa2p*O@e7LvJo1Y`fTr{#^Y~CmNBTH(T8lwe}Vc&(867j%?aU zv_j#8;*pf8Ecy6?!ckPl+~UY#1tK?5x^gP7^p?5_nxJ@4JPo#7Dk&&%y$Bp5Q)b9W zJYhf`iRu8mKmw3#goy#0e-ov=r5&>=W8}cQhf*KYhqGVW@18S zLR@rmMrKA_LSj-zQbJsEY3nVQh|Cq8dv)IdBtJ~ z8!?gw02&L#NbAkZQ-^^O-h6Lic3$L|v4vv_io8XgDbDEZ36c2)#brlMb=1twj}(4n zQI7Zj*?SA({q$kFUP*`Zjx<Px>rPtZf<{dNNK64#{Kv&SY?2>Pf%E}zpr0-kiSnQ zpWvV{pU@zmpzu-w;eKHOmBQU5#K&6Ve?!avbHhoT%>U|evgx12p^)IPkYKN{Qhwn9 z{(j;90iglD-lY72{sG>B{$Zv3-P&?y!6DN7zNG1W2I1`872@=hgu26^9&Ni*3rJe- z0-1JX*(Bj4qU8M%Z6ka1>6<&EW6$m#`}Q7GB6rok)C|4)MfN5k?a?!L+YTKfB}o@7 z>fO<^L&r`a2nl}gj%`Wd<)rP~_E0C5!k}HxzMXUTQP8IdQgwiW19SIm*M$VUPwv7X zl4Rz5GcGmn)-AG+6anqX#6dvGqVtA!i|pR6ZM$wA^HMML=+UuTkrKH>U72^cLB&%h z<3l9gD*0yF@Y<&zs~r#t@g6;Uc=qcNDTzLC*tVM#EH2_;V$YPxy0<0m@6%7d4q&=u zCY0hnm7B7N_j3Q~9RCZLac1WORyMZV?H>%|o#Gate*YH$vs7@1 zcbK<#CBNWGl+Km>LIVPErNEF%fuSLOf!=;@vh@}g>mxPAh4732Mb1Bo+x3S_^=@u~ z<94eT*6M$a>YM&)E&m18`<3zu3-u2O@$&^T!~H@ll?n~7M6;w6*?53gkhkg^dH-vs z;VGuMl!$Eqk~F-Yc%P%}M%(s$MQGsFMUO|<@_~l#4x0I@iy-WOyshYhBjotyFl>*uK^9wFTQR3?p z=;Q4dfdnu`B#mN_ZR)OYHa5A@BjT5>WxZl+J<_C1o?%8`UQms1cU|# z`ULt1`2~1aDis(U65uA=%>SxdJU;&atQKWcMgINm23VcAzFU>pCsHrSzyI`u>s_Dw zW1q%-L8cDm-%{7FzyIkK zIP~(3LDj-0e~Os&zQl@*^4~hkzuoHRzYRpF<;ee}EB|(@pMUe_``8!%?oIj9yZ`7- z5ykx2H~&_SGLoeJwTq>DH1=$y%mA_;6B$Fv})r0(t)4j#f5znENdM{gU*JRk9}LC& z1IzvyANms`aew?TLvfP$+u#3`$^8%3P+ZC&a*Atw%kww#gMWV)5~~p_BV6zO{hQC2 zvGa?4GcH~h|Cf`DChabAW^5-1mkba!wggTDs2lQ?FN_~btLhq-y)0^mZ z^?G`J4*A(YZ^+R|Z_Mk>IGU?R3%#Y@ilepOCiZB{H{0tSI6A7|o%r2}zdGp=>Jh>3 z2tAUci{4p3t^cZD*Kg>z^_%)N{epg2->fgzC+Y_8HPP$nHTCKowfJ3&qpn(!YfTN+ zN@O)n)LLXEEm?=GMUJ+tr=2?5vJN@g#jdHNTAi$^qkdO^qQBMMjCh8-@kxK9KV}Vk z^m+PFy$5Hjtyk8=IV$T_cvR!4&PwE{!{L&O$i=k^k&4KrxspgLzTftbm9*ixNJbta zpSWiUjkHEiqo7fQBcGAYNMU?N9y|5f`XD}A2ig_&5Osv=mDEaPEwYlDdJP`6l}toO zq8mAy{vnU%dJA=kG+f$|HMkC;FGq2stWnLVV>IBXWrP`lMs6f=UEipWMniR=Sza&8 zQJ$j$M<{EFTS*nYYV0~{{Yf5;u$3mrq$!7M1ung`Rk{(qwE1I2^^J~3lrhlI4bA9l zbTe8Q;YML2p>a-MsQ2eQq0kOcN1$Gsql{Wh1*8(n5vH_Lm34?t#6mUT~_;?6j3W9?FZ2rN$C|&NqHE z#v8+o&PFg+aUBWtgsW0|alM#2O6qd>upVDt^;hc<-H0?~6_x(5j5vMB8blLu9?}9i zh+WDm#7|o4vlZn<#sa9%h5lq?tTDi7V&peo>05N0@B8b8^n7}Ly`Wy0Lsn8;_td?R ziL4@kRfr_YA&FpR87}**jub==F3S`jb$N!1zSx5tE%Z51UdUsfF$YP^Fvg*SXrq-; z3L7}6kKr?Ap`J_6spr=7=y`cwP_3j0t0!yCl}5^8qhc3f_-a)=wT99~J*5lr zi>9nWB+w#O1})LcRQML^v*CRvb}+^m0{^Xyaz9Fhq`dqoO&9L3>=wRLw5eo#TrB(F6serUmgvFC<_p@tgSpiJWwo8XbBdI z)w{GVYY>!bu1|sgg&ZRP8EAhvUf9m4Zj>~V8<(Kp9ckv(Q|oEsGK;viP+zLA(0|g`>g)8M zIo9f{$tjld`Yb*%juj4Jr32AUS7b01pPP#0rzzy?YqT+HV*3S*^dRsF>~9b}27xy| zpiFsep*nhQ%DP3?{W#BXxSgc`h^4H6(nfu|zDwV)AJUKLNBMb>W1qfT-vO4b*H@`E zOaWDf@y))RAwr)3*P|8c41@b9;!jm02Sv*HOMjq0 z)nAdpe9%AYpY>1b@lJoOKhqzvmaBZ~5P8K0eHmw+jFp&3po=~Lv>V7V0Ke~!?YAZm zsA~8s`ny@H$!A2`F3O{@tGQ@%gZ>Mdn$W$Y{|?oU`gc8{k<>_Oq(O5TvEIx^24v^~ ziX||RABQhKRKh4mPL-V%CBvIv>G#pa zQEXuiXPS%@2V=e6z}wN-z!-iGGc2Pg^egebb z0l5za_a!cuhGIObhj4Gj)DJ3y%nE}HbxS8CLjTa?=|Q1 zdC}SgLHPkag z&_`Zu<2xK&K>{1`>@oOuq+W}2L}3F%`TlUMurs_=Bp*&{Ji~jgBe7>lJ3f|_MNuw? zl0yF+x#Zt>~UGeue5i=)E#N7+(!{GZ9B(js)g+UU|(rt|F10taKWd(33NU;0bBK z^;>w-QuN=C9Ka9iq4-TB>>v^y=y+iadeyMuPUNAouC7?YWrBJ4O;-&WyDMzkvQ7lABM;CTh4 zUk97-gzWo6ceF7@WkS=iogvtDe^xRaO)p2E$BZk+V|a5jlbUJG%+M@gdYV3FDKpS4 zZIl}&rAV-`OMsV?R`|cF>PrjjtEM-?KO?bx8|_Yj;u7q63v%AUx7OfC ztFW`3==!Pg-AIjeJ)s*0oqA?tvz6J->|{oo-OR3L7c;_aZ?-m@@J>~;JS!+@ro$3` z=es-5z$l`d(9cX>a|!>ShV`{1vbI6;QvVG_M>F`GQ2zxjix2HKc5xg+4d0J<&=d)>;bs$;?-*e>ZX+fsKW$tojc4KZBUslsqyg_%9mhrtDArdoif> z3!Go(_|-Viw;y74Sq@OKRvOaU);7)SWl1?Zna4-fG2 z+-60yh1tg(WllF2LU*0H-rQ(z;8dFD9R8K~9%TkEd5hD|JAh7T|9eynQIqWEB!P#`jKwpeI4r1ZIBp*%o^n3!lrO zxrt*7$41t%mh~(#=b?iM@UJ8P_V{Bk8p~{c10j!azHwMzEn-MA<1W}gjclqmnS5&f zxfV{2ApMs{M4^^wq8BTesdTUpbeE`d)%a%QF)LtI{n7AjbD8;*`Lns16~s|rhWuxl zld;Gle5Nass)_v4k-h89M&s|wcF;}ERv z1Qv{@5?`U>+7@(o-gs~10NI+DQJjA=v_$u-%{4qk|4S5g(f)9}FbeBy077`1If(^N z(BKB7KL9QJlP^h5H=npypPC}2{!}}yg<_S}!2g=8p%zkTi7iH}NHdp;Y?-kh`8_ex znO=B)C#-uomOdM8FM{qOq&^qUr<;?|%y4Ai8}DlZCI*6kY0WR_Za=<13WTdl9CbIY z>6`QkWF28x{#WgqwnG#AuLAvQe4+|#Xo#JP&$(FJYliKmH(uz+hAeFFxsk?C%qKHh?Jo;meQg z^A(=A4BTr;#~_{lOgpSC(uSe`CJKQi`|1Y@^@D0pVwGeeUHR@Pa-Cm@6Rb#0++2H+~@eI`850+1aqxwYsG{#F%e<|EcKP!v=LOZ4{(?)2KS{tIzQ0PhpFb%(x zdVB#tf21POkwsr6fvup?E#n1tkchk@jhRtpJo&(-!dQ9%e&J?5x@UN%-@3UdxJZkdLsR%wo{v~4c1y}QScrE^(j!C&x(I0&)Kb_{{rmaKm$66 zxC|>i1Rh^E?sE25tmB)JfasPSj7fvMJ@}mri~nxCC0_gn^$k!Tf@W(F^O76CQ!Or~ zr{0eKTn_!6c2--fjnR5)jkJMCdlbibsLUZ--A3F$i{G4P4GWRMAoMVl)h&jf?b!2i z-n*jK@raeYHr^SZ(aa}~_r^=Ija%sb0H`sC^Y*~6g29CP)ZZ~=2-BgmnYCXg=3ZCU`y=lRKnBCn9KQ1q9Ues=6L`NTD{xrhBt9`)q2em^v7uz2HQJ<^e1bBwANZRtsC~&7d=bum#~`VwzHVR^skbLm=ipnFpg+q;YO zmuusp-%hKkb%47lm4A&<`QJLc{S4B4jg?*F`D~=q4oqwZ9z=nPf)gS!S&P)06Y-gO ztVDc9`nO||Wp8SU>g1X^$Tsd_c`NDE^rjCRK>zZi_M7$#+8>MWchnkc?G)Ay;9KMP z{xb0TAXY3(_aWIm(O?gF&B7wf-;C4VR9e2i8X zL!${XDjbd^Le^A|I-rUxZ)y*{D5&;BGCe@?R>bizB%g;`_XU;a4tidr=zBJ#f0kW$ z*YBbI&CnmKX<9F>v(^!r4uprXNctxbQ*h=P6;2Xzx7XO!Lg?3~-VdZsD^F*tEWgX} zvpm_HM9vy2cM;h%XPtFeMu0s6q^rk7REFMdQf&VU*0)|;4El`&fyQVWS{sKgug2C+lP|nA zl7R9#i6U8`e;Q2a!nq3(LGps5IqCRhi9Ir_>O2Rp<>mdt90homnI6~|dSaL9Law1d zDEo*_$u~;ULyo6E(#~u9h`TGa`Pv+9HV?tJrJ&AXGVQ0v7b7JoUYJU!7%TV)7EMB< zrJXP62o62_DAHW{7yn%nUW&~?|i4vb(fCgUZ~Hc#_U7HsgC96C*$~_ z-P6u#`?0^DwV$+=Jiq~{Zw2da8gGbinV{`$1`*i;h;*;Og5g+xacHN6ZbG^jU+6Es zr_1;jI?wf&Jf6|pd&2Lhs?&If>h3sJw-VlmL0$GR%d=0B1K4e+dsGcN?$wKbFj-G5ar0YTU@(s$bq4E%)mj3E>?CUqEU8GNc z7C$>hzw9tN-v!z&LGMDn9f%)H-#RzA_g#BRzI#qP3e|lahqRO0MQtViej9twgv2XC zxdjzo1esnCarP?S*A3gs0q>vT`5BaNK=G`ib(CE8AaeeNp7S>1%X-!4UQB0eD&19s zOrryNZWwz*h1fkv3iAA}UDqy<^B(6ojU`;u9%;+*_t!>h(eJzo?Nji$2l;M=;?GcAg@-K!Uw;H;CgW?P$T2kPi_YX(b)g=>o`LKi z#V6`M!uu|`z$u%`kWwPsTQ#6)d7-DxJ{nNc#YKK8t_dKpRi6!Vmg4Jw6&r zNrs)33RC*PB|yLcaH=AxP!-IqixoEo$6JHl9YD!Q^x7TVG!5B{mwl>^Y8BnlS|93@ zX!PgcJuygh3Vt+~nsEj4mi>jjXy7Csb_E-hp8FemvTjH~`oS3$8WaYnyoms1j0&nN z{AUSB?C1)0K|b4%J$TuhlNEGCYhBSrZ#rYLhvXoG80r<-SDA-RuVe*V(EUETvZu&t zuA+m-`U`aMRY@QS!P*UiH6b36xkiDhJSonN$NS7V%W-sFe zI=BkfJpzTq2I6cmCs^&WfIwnVMMYmMpds-|EWky-w~Bf(Ml1Y8_JLhTOSOvj*ra$x z6e}2rHw83-*FkPrELVu3Y0etjDO-r5S12nGJeYY*AO)wv1hY z_`(QuFatbZ1rqJX2hJ-Dc!B)gi2<3gz2fM-BAnMl+a0j<-dMWq@r@+Qn@Ej27p<=) z*E>M9^c?>a`VHZ|rlKB7yp|~n*G!GfGSo#AEz}Bnfd>wVD0`60@j{`0LFxY`JAp~C zy+j$`HPNp)^=2hFZ;iyImpG36aRGY= zYsm0+(h)dHw7*2Y@r1h7-Aqr;(H7~-oLem@g+RA7`9di*X(Uq}Wz-s~@NNUv*#TT0 zfCR>1gNtM7Um^xPhx_Dcz6jJSgYzB1R)@-QHk74%e~3Kx68zpLvwusbm6(b>8{LXB z(o@5}8bQB0GA|E3f3l?#WUKP6bc2H#$Rq@{O%gFTZs><~%kA|qXjg7i{)9RUfEI=coxC%C2K7+0}if&{&B4T1<0Qs*_XxNI#S7wqh{QKg-J%8h#qiJa_MlmZOtA@U;5+2>7h@f zhq;J8>RPi4JT*Z2!D!nDj`PwV$xMGNJvpOm;w6`w`|xFbmC#djBru5VYz7{%od|Ff z=_euT`=I$2`1okLIMOY;kHpi`8!Am_tQB(B**BO0Y?OxpXXB(32eozsu=Z?}Oqc^M?7r{M~%T@rFk?tf~&OEsc~5LOnG!laQ@` z*S>4+R7~;tD>W)kQXwMtp#tWYb=s$iAj@U;qCk?>O;&-23SG9dSO`X^{U)gDr--P7)KJYf|d zkVR@Hkcwg@)md>LGLm^z0H?^m;t}x!$grd6%dEui9@DEWj-5x*onDWIpF=yhsWk-0ErB));G|HN~1> zjkGk@(ax%2ML<6soGE~vC4%?o)Fqeck({DNI>vE=itUnii(2J9TF8Knl*SJ`krz%Q z0-S(;LV6t)KwJZ_KS&4A15a;;y)QP8n=j1_a9$674XDnyR#`t=o2+%#5^I{}u!81R zd$6YhmX!n9e?{YWRE2g}+pF!SPqa(hL%n*OTJ0u!_@t#k0zRy_6&5gwI`cU66A^Jk ziFCt|{%PE6s6dO6Vvy!8%;5HT+A5^+ZF$%?RsTMMjh)^Y2Sb<=ue{chc04ZB#;7;Avl67Bn;`y_M+9?%^* z0neMYHFO7-sACyjf(^WO3~P9V1X7`?GRgu*69W%n{|Q0<%J}{`JpUS9VNZ4;hT(Hp z%!F16tDzNb&4Kz!>yGuxdS`vGzF03=!ErP(!x~~W!Ja%7_fNE|RK>r*@p8H&v*?gc z*QW7v9)GV#2B(m~Yb`07@+U8e!~z$Qh2JCg6r@Ac1>fHa<|e`O+TeGa%$sI%E6{3V z4MW@ett-}ZE1n(CPHZQ!-Rx)9WowVM)EaNq!=CbjcCXR!8K|s->)F~=x(KV3z0oJxYLduqHX3qGqqJ3kBhN>g4=u6 zCo74a#!hdivs2oitoul0y*1mahUaI(@*ZIG2cYiiObyqD(jC+2Q4gn6IEfXkMKY(c zkIz~?X6MJKWRO-zFKMR9ClVayPeri zV81{jd#n{!Fp)NyE`71X*xW)SJ{qcnwBA}2{lUIGvv_3&yA@lof$L}>1r`tt25Dp= zTc`oQ>AA^yBB8$t{fqotvJbn-ybb*ze0(%sciehtx!D=*ymoFozn#tYu)iRYlh$U- zA5{B{W>0edB~TwpPp~(g(GGNHJFq{}UF*+!CZLnG_{BxgDIxkQM;sgg0&FDz`=IBd zLl;4Ixt^Ve`0Rc)H-{2guY-GjR!eKBwahvO{djf;JD**^F3cJ-Vh69StJXfN2=V3_ z81oBOHWlgvwI0xIt~FtAqPf;WYtJslU~Lq(xQacKbNE1f;$aZENI&Z04f;89zbxdt z9msFjka2uB3bP|+67POB-SPg$mT4`r4qCU7e>yvlUC=Iy1ajJG?eFO1w3U-+bCZtL zT4X!|UOTfVQqqMs>pJ$A%FYGtqDUYgc97hDiv-fpkv@gyr6WB+ z>!dY>awV;zR)I&bRz<5vkGdNY7>iGC0Eff^GeEyKwdq*uuoGmTsmc6W(2-w6|MsW~GDCI>o3^_!AvuOWHgTr%v(WIaK6 zU<~=jEfByLj2~vL!~!2!-z^U$P{c0AQ5;`LY(KSx`!#4@NAmUI*ON4;qh;a9s^w$_-n>>Fi|C0D zOv3^X;DPV7)F5UxV&E`p@qHjreCpjAR67&#z$;{41+jqMOokjJ_GcmAh_uEL^G<{P zZpsIW+g`R0^gZnN)@ktl2RyC`+V+C$ELu7(B}Zy4la@;>rUjvaCalhe{!iHHHSI0* zi;xL+AP=8U7vL83^OAcXL^^xNp?(NCjaK>u@e5-gw~ z@~?{h^&$?<#QzS1)SsbWoNBQp2t1K0>@YFdUFBeH(7;@Fu6yY?Q+k2szph40bHSyN%HG`eZ4^#h&egHor+ zhrdE!a-inqKx3!^cC!oc0Sxq}#}_4r}BgyFk2`mOGx8 z5l={l{YNV9vula9&&d60^yBC!tm1ui0xd1}?~VUA#6C14&=T9GIut4j`|(-T}lC-5fyr;KzQ z>(E#IfjrRVg%z08h+#_T26?Eb)y&eZxz-N6;F0wfKS)Xz@Y-sGhv$P=ckKgOe~ATr zjCRBJGsW6oBgOqVcI-BTzSqfs;z7S4vtw1Uz&`Zk=8^@RK>`U?9nbi1 zCfZNgzzZ|8!lBXDa_ay{_?T!E&;Dk;u6N+#Ti{pV%ur#)v!DS+B{7+&xj zUQiq_=xa?S79A(|d2YQ2jh!ENb5y+PT9P-5ODr=2Z$1?w|GHv>O&g1NrfL`@ZUb>iY2aAzBy_p7QwK9K*UCI>D|w<450 zyaRd2NcvGf(~Z4FE|w)0iDpoV-lYFfoNOeTTIiJdnQWkn)x-J$9qh2qlaD_lE2;_Z zm(q$uwGiI!sreCeYmjwF%pC>hFJ`ZBH`LD)`5uw|eTDy&GV=W;z+q8mgaz=>0O9e~j)wko_crzVsvtu!0~u2X(Q-p2VVQOtl{-8h+Pvu=CW4 zUc@r`Aa9MF=pagA@l&j@0$4o6nnmV$!ukzMYz4(SS}h)uYjq;hTI>qXz}wfO^FvIk zT%{&_Ol9~%`$84&POXrF4vAb5CS4KfNmK<3BH1&VsC@A{@hAs<_YTCvb@bib@q-2` zBRpriSw*ax)PphTU_YLC!Rkzg*`7&=2rzyyTu(&bD?qw^VBICMt*6NRBT|n~ZJtO^ z%#oCQJsCZb6xcy}Iwl2KLs`0~tyNcGJ`wQ>E67ew96?UL4Kz-L4kA=V`p`^|6}A8g zW)TgJk`qKD>u9o{;UL_PNPHcc@L_7;+jzQ5+R5mBq^9;y1J|jcnw&Kxpj!QkC&p(r zsaQjPGQv=D;x5GGABl;Vl?+1Zf=(hLzcg|)kvLFU;U_bnRTV3o2p0ar3S?*zG7GvWLsr-UOq|Z{ zz(o)-H~q+dbOp{(75HL>z-?G+f2SsYHd#bY=>(?`RW|?vWMO zU_wxGLa7SsTLX#5Yw*Lh)IIyCelBsYxA;~%_!NCs!MB^M-LQ^y+?tZ_l?U^R>ACrY z)ap+_gR6YY)uXuyGRYd!A*+h4U?ASGnW&JQ&QK?^lB3imKE%T*=KepT(RebFjn;nb z>^FFLi-n~{k3RTxBk1;^!(ri7L(ph6{?!`U2J>z~bdXek5BI;Jt7F*8As)x^lj~|f zS^5LA0u4miM{SUmxfKmGyl>OS`1feb?6U?}^g7xl#K zg>)q%ou}6y!i@MzVnHIy8y_&O>3HEII8Q{+vk+KPi=1)*`wO$xUhfv-+75b*Ka=H8 zV+Fm?M`chq4;JtZiCuvHc2Hss`1}(nxgAMdU$EE;G{q9gSQ>RHfh1vu}Hv?r6%Y*jm3=cp|&(BV7G-!jkOusd512^3|u zZu;-gIt0ztAoP5^XDRF0Mt*!Ata8Ung7JiLaPW|bP>?(gHzqm@4afDsJO+;Ind6^upUnVXej{=}#@24&HCOq0A4LC5H|Yme8lQat!rX?o#Io;N65cbQa)pW^Khr1mnQ-pHDjJ&p zOje#(vri#p)`^Vg}q`@t{;c@ zrR+M41r_?kZ3l86**C3AKROKSEk_?M5QOr9auF~fH-4H~QBS7u`Xhe!QXOxID{g2c z9iQ>kTcG2g*d=;Flq!f7RAK_ilO3BU46&Agm3Cz(N3Fe(FR=GwsPsKTMm~Q3+tZyO_v^3g(Muxu`Ya0eSL?Z3FM1``kbcNHbidstaoJ>XMM$8V=dy*~74AvR;%05xIc`*6sZpu{~o9L)@qOMM9+{WwXV{@I+w;-TrtYxK! z--ODx-r!BoutXz26#5T>{!I{YCVtie>Op)n8)r!o%k^jU`U1PYPnLFzn0SY0zw^o) zB=Jp)hx}##NGNB7au&Xu3pNuujh@VM~ ztMnNs;Nx}CR|(FMQgQtiX$#*^@#;HJzD{r8DvvwFhUZxOC%8|9giia(FShewoZR2A`_|_Y!^FL6i6R z^K&?r9OO2%1=WQ5b^dyU2E@k_BPEe{4!)His>M0v4ia8GywPJh^lxK*^XM9^rF*}H z4)V|Jpe@8BAX$c1RaxeHhC@X9l&f7cSL zJSqn~7lPjsP?ftR1d&PkV|jl3ER6();N?@GHw$^sVl9)gI+@4rPc7e^95#pX4&+@) zuP*}nrO;pESS%IV^0-e=^fvOpiT>{)5!tJXhsC7>3G(9Oa_zWK7HYxdCgph+z$>x> ze_eLU~-<2dD z^7{qW_z8STiHGIJN4;XXlz9f3tEd8I$<^e6P?tMsc4VwYnPv8Ef|R~9{{!TP>{q|e~=C7O80@dj&gJUq8z!B7ro4)YL+!8)DsvoL%b9Eqv*D@ zfD6gLQmc6O9=!PkMcJbjj7xxI1Y5FU}TmQ(i4qRIW*EEC=@`u!_9+ zVqI)343zVshnX2)lR3|?vBxJSF7JT7+lcmZwQzfK&@!w#7gUmA2ZCo(i>2dm-5Vnp zXZ4152+?1z)^ANz?uz7k@`xZlH%Et6IEN2*A$#5Fb&+>PIwu8~-TFk9aYId$UZAIR zos8om{cX8gdM>$?LF8$U4VHmBiR+osaTb2(f!_kq6-x_1;&OL{`h2o29@CplTqkB3 ztiBh2%QURe_e76b(PUD+5&eP?G@TVce@2`;NTgYXy{!ZDcG1_^0rso_{U%}ogIGZ; za=>uT;EhieRet4zjRj#DA;`PB;<^=?Vpn37P7W-0gZKgI4JBiU;&q8#{(Lhhh?s<^ z(F*NXLgyI_nUz1qp6WuTJI27T%sH)OEpq3EIlLx!ZjgHh$Yf~)c$9e+xf4)To{NRK zG%Yh@QP3L7IVKXZ<=zuB`8}5WwXe!xgFz9wqegP5zt%cqe{#2xbjs2Xf;2Pvu4Hn9 z@VSXple3^cm!GrA!ezeIpw8`zEy&!C+~KDgGLcy|xfg}ZX&FdrJQQVKa50(U68M-! z)-)Vlv}dJKL&!XE0`^-UX#MHgg(LrT#(p;N`3)RDv+{YoC-cxP(V8!|ni1c532I)@dNDcR1NWcl9-X3_{}ZbpN^aQ! z+18`4(FJKtWmQ|LWsb1ha)O`xvCK_;axprYfn`kQF_Y&qpZOE?HsP^5_{>gzZ)OF{ zS=Bi5hn}1-1n-gixqKsjT%+!dQuNap?~wihsI1_OF-Wr`nw7g-wZaxA!_Pi&;3{jp zPcAAm*r)jPF3v6U&r5l%qp+t=oUa_x&j~)uZudoM zM!C8o0RDykKF+rQyBUpcJL1Dt@u)^Tmwtjw`aGkjAn5dwiCY&^9K%ChQr@g6i^uLo zJ_qpQ{XCcIaTVtjn~H)L$({;=8j1BcR00>NpG`VdWkK3cRO|Z`(oAQq13?Oz-VTR; zUskje+jz-7OG;KM*8wEwer0c&{kVcu4nc7@yzW(83vGD__uG-k3T$UOHq;O9>k<9D zk$wgc`!)10Q^Aig+7V^58?LM3SEI!VSW_R?S`A%=;MM)n>wfA;cPQs2G8CgC%fs_z z#z%G@uA+&f97i|~L02ftdUhcXnZuupO^yN&BySEUA{8Tkq#-MPjr?WGWDGfWFf)@M z(d~X@HJeXcRKkssep&MSTC98l=YFE6!b|*!ish*Z{8&d8CXU}@4;Pt2Ie}%${a*IN zwanvhLGCO0-V6|AIGXPQ^{VLJ8{C!rEuQ|7Sp9^!J%UJI4*9=hl6DtJHyJyX`%=_L zR&r;fI$*(Ec>F*eEfZ!nIjZ8ZrC5!4&F{pCGg!wF>hyhz_Gb8Ah16$)LZd*;KG>3r z8(-qB)PpkL^p)5t)rdjNmwPS!4vqC_TJFoz3!JD)mf}g4QW>wA3x{9W&6F%Pn z#4L{<(u0{#75yXF+g=qb*1`8e_#ThWEo9dj&TFGbsYVNfdl`w*$ytFbdM4NVz)fDX ze}(TaRni)$qD&|mLVn^zFtYd&{yyt@kW+oEwJlTJbD(h`$=jF~ioya?CC>?qdZKMYvy-TUjgmxzM zP#7ev!1ed#vE`RYe*?BRT1A(3SZYb)yHqSC$RWnU-%GW>QjKWYl$}1gzAG2@_Y}EF z#9oc1OIILJ9Oq%XN)acrw9-qjwh%5~8v;b0#0 zZNA?KOU=u7zG#X0T^CJm!_Jdo^JSo1ooSD9_+VPNzm45*2H)h4K4Vmb?Mz&(1z+B9 zoeiE7LH7-L;tOhmH`Iobo8~~T;#n<-Uagszl`E6aKw~k!FV~9I;oB+6vR`1I+2O>1 z!mn6BMr7{I=f(Td8{b*eX}o+99v%bjfkfq&U`#04RRMG-@%<}l875rrvz~-V-;>X^K+Z8pyd!yU z0dlVg*!X(RH5gwljh()vp81t?cyPv+=w&rFc$-;^uXy5naPKCc--6u7Ds+(<)+%UC z=EywI^-I?NE74^S9Xjbx?xII}mU#PGlli4U@~5t3DRZ#-rqC~lB|YN&Ymk3$Bv=Bw zdqyR91$;`1r8LBkrxP1?Bk%L{1b^kT+rXGvNUJw;lwMa^rSbG+HSgf_JiWnf^d?s_ zx8s`NlKH6{R0^rF`%v&Dnlt_k4-FLm35@&T*D6q>D`yk>AK~CO7LWvOh2w*Rc~9c| z8Wqvz>r+|3^dqDrAk%}A&&oAUGR1Y2uIw825@yrapU%GVLi(fI(Zg+e0vYj&y4ctc zWCaJoe7W0I9wz6XV#zDuU+zock9U3tAH`l%aOU!Sqb>0>8co|^i*%&>s0^htvMho` zGb)Y0fWldN!avg!oymU27fgF{<-F(yrvezL!GCx*O4HT6Ow>7@qgy&V1#PchZ5FdM~;^`6Stc33gOcL45 zESOAo{D2fzU;!7gzLdnjYIxmfcy;ZYHzfZrPb^77_Ae1&BKY4GI#pGs;JWK#5#(E( zHAx*SccGN}BagzBgk+K8W4GA}IEA%sMCw!F+SUfKf7g$nvYR!FF0o7we9^LE%`LFl zAMuiB=XEr#MUXx4)$HzNAU>gshdj%gm z$JF3{_J>y~&WEvE-k0619!$;jXC>p9E!vFqpMYkCky|9(FC$)xKWAcUaTs-X1Z$|s z8d9?c$%5tT!BKcpXYq1@TvXqbx_R=u2!>aG0+ic0d29j5zOrMhwskp=5^M(B7Y0*&u53{9NZ^^`>Jps zL#)_O)PB!?bsi?BPSWw&$?Vu1`dvMVaDiAuT0=U{a+e|-tMfzGpXqL#QuB$6nFgG} zy$dEmaU%XTgJTj}9>y+SfA%jUp&kMC-t6m*W>0SoYrajLo)e30iRa8D(w$*yUeGk3 zx)$LP*RNknz#?6DpgY8;qrl@V?D$-P^PkwA9II@baSDzh>=BRS7>%84 z?9}&SUau>%?}-IO^WF@kv>!zH5bO6*PW zdLm88^fG}8JE%q)5wBc#Y?uenHv6Q#)ofxvUvvm_5iZc_y2$#j?xp4A=fELWZn+qRmTG!Apa#uUq`wk;~sEn zL3u2+CSYe{cs^47JrS)hVNdfA`SlB^7es?Hu{@P1b_mOR!OUnXvaVe8T(UE*7Q!{R zHF$(DFHxB5kCV~=JxvEvqcf1iIEgQEpD;ZB1RPCf5~)A(?*q5P(EMc3WgdH|bNKxu zk2%=;G7xwdpT14Jm)$s-799wxtfD&j4Zr)2-y{)bD_<3$ghTtYJ8`W!HEmQ+XS}myJZbjq2GBwRe6MkNc{n zNAF=^wosQjnaf1(@1UMsrC3lMS(p~D%&dMhuFq)08XEGKpPASEhDR&}9lbzl2VjGg3&9Ml}Ue9{=fj`HIZKrvh;^$fHO{Ud9;_ul(>#FE|5ZT#Etp1AP-9ufW zCs%07746B8cv)m$kEvO?e^x7=h45Np^9GpEkL)O(aS*R*LYzyeKP8XZ&tCN}&^-d( zi(t}S;+pgVpY!t>w*HZhTnaq42>D1|Y~CQM{REa=QF>2j`$g_aKkIAZTaY&c(ZpqY`(z7P@0b$@18C#(V)No_2y8+E`~ z{CyMI(seSoMA%#r_?9a|Hqx?83W&QAyHwvn^lVHa4a7bVxP zL=9ITyOt`V0XwrB@wA8R4JYLa^nCDL7&J=D{?je?C8yIFu7IcB0RtwI;kt4y$pKt< zpRGcs-UNCPMC&Lr!G0WajoxtVWhP#;o=AFzEd3+3Lssg=(o_z0>8i^$z@4b0x2jItBub^84k?cOmJy$M4^BFrp za^I0l#v$VJ6r|sXnmYvuaFBD#{W7D7pK`@`B+}?lt>wB0t6ZJE5}Ip4*Udxsc>(ck~sUzfYuB(!tLOUM)nyjFVFVt%zYq`In zM!q9=8H(XCl4x5OiS%MdWGt(gOYD>T@J`_Gp6vaEVlf`ZD>Bnv@IQr&NbVmzSmnVn zV2W!_VF%JV0o}8FPOiwlOHKY7sVAjQ%1s;(q-#-|v&o&k;_jC@m6?!fP@H7^-=056 zN?uuv8c(JlWSVjv+B=QEKEQIGput;Y=|_<80&Fab?5z^LglwR|3u4<5YOB>CvBaLa z;PP6K@i_SONy`lWv?kBoi1lZL`=NN#TcZRBJIy>|eqjEgDpOcvnZd~bPL`+UiKK#^ z4)p`jyGxXiPMfNto znq~OxDAw(ozldRv{iET{-u`qZV&9v2t!i9_HHJwzxu&cJwTzDcEQ9xRP=5{O#B_vH zg1zynOm5O0ko{+yK2`(HTo4@m1n!?B``t`Vwv06_LlT>b4Ht-eiRc=H@!5&0Z&8Rm zViGtPAAIY<6@aHqnZc^A_@8chBKu}|(@3hjE!2b8nb~nuSF&d!|4PR**Bwi@^Zsb! zuw1WGoNkIcu}CIxb~CHC4k>J+<~zWO?owrB0-+jWrHir3_@I4H?D{w2Ock!m`iY5T zcc$QKF_S%(`I7+RL|d$SyyE^mnb{|1X(coa9vV==3i!8 zQd@RptrDU4;k&<+876~sxr)00{*wtENN@HK?@z(^q$2Sl>ZBkeexfP@xu1tzrFN63 zFV{yEBu=yeA6(N%f$Z$fVMjS7@ogYig`8#jCKpqPZMphuD)T>K%JvL$vz65Mzhd_v zh!ttTjhs-=2LJJm=Xmu2D(@*+U`u!_g$1T27C%#azc*OLE$X6I#NzZ&uLw$u?2lu^ z1wh=<*uKpEwC65)zrcM;rk~`Rv{B4oEw!qksm|caMC!hs*x3zrHE|L&pMm~fI`Y4d z_|QdF7mfw{!~?yljyxf>*U|$>H@;vr0S92%8@{*DJNU!BL5MV78`!LmSkRG;N zs~C@(>^+n}s#%r{#Nzn#{MN+YC>!u#J8vN{hz71B%++g zf{tR78;L!Wk$pFOuLixIB4j|WPJjnEke&R?AGxjw@$SvCu#decb6ySR6 zkxb#=QCFk2X8w5&*S+n9_I0Lz&vX5k+*`dC7!-+oZKOOKJ*-6zTd;?t`G?D7&7#d4YmeroAl3h&H=|tz`x-dG%vh408Fca{N(z2*N)!|Rxyj5=SNUkc8+>Lp)P(cUDcda_qk(Oa4!d zqDZhTo+El_52u5$#-SkcaDGQaI|7fE>B~~cUZ~6e1R*`-VtlJ6--t$UKNJ6@M_rEG zE`|)|p2FJ!+@19Tv+rK$eKgl!oMz(OU0wf?k1MeQHa(#DcG$Ga~_qgvt zwC#yibU^Nn(N9IF%k-&C;HD=6%lvl`yt}BcC(nEX_44R_4Efw$CYeH*rdwd11MN#d zeJu8Vo+}?xbL~x_UB(W!%W)l07F*`iQo~PXwThDHA{d0P4Jye086tNBsfmSFKtjdP zd^W{-b}YU)epri@>hQh}FL?{~((pc-jQSRnT;;g>dM+OS-7L{ zc0;?F-P&$!hj1NOQaYxt86~;OJgf3#x!Pa;R|)x_f5Nbh(#XaWnz^AbpD2XC1>@}z zs-oYBzrJJ6)kS>+*Z(9Z(spLj@+eqegzKz_GiiL2Yrl%vmFyOFH@mMr(2lmFcwWx_ zPH*HjRk}>YeIatERy9p=EKTN90{H1m-BSz=$#k1cy~~tAIFjjxb<8F&xTyA~$|3pD z-1XqPk%Z~NPF!59FL|C``LEQnzY))#g6Zz` zUDF}y+{j!ypfX)i7%9j!O$b_VMfZ0UIJ=X`@R2AJ0`+lN-3_Sw5aoX`cXEe;oJ`tl zT={p^N@4riZQ*<_ln>e`?KAcfdmqn#L;^Rd*pJaEkt@y5umYL5|D+`(!*i{`)qyRB zK3wx!P4I~Rbg!2Z5wEIiU&F}j$1yE;gZpaufweJQ`}>G14XT3kORS6N-52V^?8WwO z`=Wi9Io&EY86B8L(%pT`@a3%PUmEIaywa_WR9Ej*gl30NdC5yuF4L6 z%Qfb%-brFGCOcN|5AKA6yi(O^xhGhU&s7xd}{V4T!bJOP11=_JGZexnV~<3+LFlNXjDtJleHjuK;Y(m(14)}H11k`i2F^aIzqy|8lH)$PIde5gOO zQ#nPP5T~Bg!fEX^acVhboI*}==aIeD{*8*^620ADCwkip4q?HkLV=H%-$QMo($Z{1J+g`pAbLmiN<9HNHT(LWEPjm z=f8sUUgY%Musgw<1oSUk;qhCz!YV6Ojm}jSx2-gGMZ3E_&E9YSuBcaa+Bm(PXh(NU zr?1n&sg4z7a9%+FV{8vA?kbjGG~N{2J=iCZJMGLs=WEHpj?+67>gnhqg%aUydc?<= z8O}wFm+Lw%o5{#5qsZtlT8W4<9l*Ms*nBdls8bD!{hi^?SdNjbp^H-&TS%|y3)0EG zO-hj4RKe0)5mkB<(T9-LGt}wfG=#qJztff}CN9RiJ?lVYr zHl~vM$UUAmlK)9B!XZohO=*Lt8ZHLk!InEtgbJ4pUh}~Z!yQ>7+uHy>VOm;Pp zex-fh{%YsP+S@srGv1lwEOk~mi&()(Y@m@-+DYd;vA5V2$RXGT2iIg~Y%E#0+}mjl zT<^r*j$-ffKd!uhx>RMwi8PJjegbHJ1>KkA{xV}g`?ti|HdNCmxw10A?qbgZUEkQ* z@w7I`d!n<@S?z3e);m8rbDc3*LPPZL;XEJ~$@Ob;N1qrvX7azhY*2KM;pJzk1g?T} zzmwUxYC^fgQ8nVMNtb3feJZj1Zd~7ZmMctyLHo7XeJ;D6Jp#V&*=d{rY<`e4!C4ID z9nMZ?yR+7r?~HPKIrSZHCy8?%{E;r@c)FD9vGDz5-RGfsi|qeCbYIXjeFx|6R6-f) zM0vw~U8;)VOiUl6SC*At^4;E|0-R(b&Pe+gyeSx&spm)y3h(FWX+YkV((x<%3c zc=8-~>Y9GsPvn(V1izbQpN4x+Y-|uVzs}hQ?TgM8=e%>o*@FB>I31l(V!<17foZnf zL+3uVUQ#7txpSo-Htxw@WMLvqUii*QoRf~Z+{>>n8Ky>Gb~E?6aR+(YQP-U|Q*d47 zFs^HLx65MrYtemrry^b+gT?Q0&N|ne+s-ZLl5@=2iadro?ZMxSSpRN&f_)t8{z9#q z1DZkTHN&ZiTSInAE$*!)zAt%RXZkt65$zjtcbi|izeFuN z#@=IpunS?~gPhsO{shz?IFFtC&Q+do#r`d)r4#6+aUK%?$Jn>vJq^5iaeld5U46P` zwV)J?v;&bu3D)3+OvkX6sL&)G>ie|zkF zm2&{OKXjfuFP$gOO)Ovw^i90N&q?9ju{RK#We++JUHJ<1_cjJoEXI2TjC$avvozba+HH5AZ%sdZe;Zdcm$fx}v;ES}hwbUk5_Esnc?Rvz9Iw&9IcFOf ztP%gb$$+leYxsN$Y%Bn7YtyM|jdiy{0u7*4nOdq8R_Cp_FOB@=Gjg~1u}tV6qo0+X zJ-eag*=}T8L#U_|QQ5@Ud+jf_52!Z=tU2!7ao##^L*fr{8}c3-xDd;~&`%2btf30Y zgx!@#^Y!3bq~Dxpb?`I!zkfvgavw*z$8vdItB>^$0(<3Zl@C<*jp!>JCF7||#&H_o zuTN!h+D;DYc6Fv8{R`0iulZ55o>v_|9_$Z zlCOd0%Yn4s(3U$rm*AP~7|H+5(1o05I&uF>toO~}ddhTI|17TM&11JA+qsVKRUz8W zLHfTTb+;kOhNR@-Hsl3=?*)s8VE=;tcd{#L=m5Iz zCM)(?6X}Tc&BFTc(9bJP*0Y$q3*;j5ETNN7jLL3>{m{-vbdN^+hq1l)PQoE6hIsIZ z2mNc#L89PrapNHV&2s03@)qac! zB2>)8Dk65(C@sAmiO_@?AqYb4UA0>}rMB3rbltW_>AG!o-QL^V-*LZx{rY|w4G*uJ zb6(^5dcMwi9hy{zEReq+Xuvnx2GGcBw0xi)4gmjtqK;F`sBqw4c5Q4|(+zZ*l%g@84CWd546GQKij8+$a@FuSr7-l_XN0qLjWSLGsv$;K$hhMFwYS6Z>kB< z{#@Yq=YaP8OWOy=FPCv3LoDMj;0LEcBrc>S14IU+{Y9Mx`N!_fySs9C*BSi_AO&VP|c73}+v22%Hc2>cJo z?)Cur2f+9ZfQAr2o_7)G-T>e;e}Kq)9ON5a0P|`Cyk7>G6-8iu1psaT27KEIu*Mx= z{nu&VX(B-TclA#!<2xAtt_P|F9*78jOY%Ptpbhj)2dwx(u-XuSGeiL2zkBc5Za>l8 zDg*@l!~|%cFJSR=0PfiBuObb0EbMZMe84c6fc|3D!1`1Gt5OK$|4TgtvJ5({8R+^G z;B|k|#4{u^_5%I?@}CF11tK5~Xo&TH5$MK$^A86)rVhp~1>^}`_!r3j3ve30fv(rP zm3keZmpG7XrGbiIH#jHu8FW~~fJ#OsV0VN8t9SBJ13>)hR9_HH$HDp={O5hI0K~Nf zM*Icn;GPU2;D0^>Z#WNLtp)Ec9QY_@kbm5x8Ug*&17rNZx!?QW-2V&4{(n8CcPnVS z(ZL&3D>Ff*@(wtcCj_e11hBQM6;v|z0nDESIED?7ZFy7kfcM>@9t7wriN*mMI1Xmu z4e&wVX@Ai^18w{Rtp80QKMNobN18hA3&_cLqr3r_e|4aFa$p7|!20iYbl+Whc_1AL z{IDAseL6t=U7%9?e;pNe^ZXki&zA>z{#lUmY+O`o@Y{M*3)9ifGSIj#ZGRzO+j)O`j}7Yv*aJqd6RAMn}AppJD8$X^HR?*gJpE6AxuK(==r#NRxCx^Do9i@@(b z1HNw=Sj2r0mCC_;3k4aVCdj}isLua+`(4ko+t*(QjCi+y^lk@XL*Nzcfb>A1d07B+ zTnCu*17P-0V2{RbUzJI~FdYOL-#Nf*J_Eh2{s$Pf3NWG%0DB$*F(wsc9d%$8?tpa= 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 W?#U27C<7jRFh&A|F8~L@gDRfQEgic6