diff --git a/Elistria_Calling/Content/MAIN_CONTENT/Magick_System/Spells/Gameplay_Abilities/LIGHTNING/GA_FieldOfLightning.uasset b/Elistria_Calling/Content/MAIN_CONTENT/Magick_System/Spells/Gameplay_Abilities/LIGHTNING/GA_FieldOfLightning.uasset index b54e88b..6ee052f 100644 --- a/Elistria_Calling/Content/MAIN_CONTENT/Magick_System/Spells/Gameplay_Abilities/LIGHTNING/GA_FieldOfLightning.uasset +++ b/Elistria_Calling/Content/MAIN_CONTENT/Magick_System/Spells/Gameplay_Abilities/LIGHTNING/GA_FieldOfLightning.uasset @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:d2bd69f4a88946d2668008b9c0fa6804cba5ec02106ffb4b1836a009e082455e -size 73513 +oid sha256:ec7acca3cc5a79abffc8a30e613d81b02891ac2d3435248a81829c095c8017aa +size 61461 diff --git a/Elistria_Calling/Elistria_Calling.uproject b/Elistria_Calling/Elistria_Calling.uproject index d9417c2..e37bc22 100644 --- a/Elistria_Calling/Elistria_Calling.uproject +++ b/Elistria_Calling/Elistria_Calling.uproject @@ -10,7 +10,8 @@ "LoadingPhase": "Default", "AdditionalDependencies": [ "GameplayAbilities", - "Engine" + "Engine", + "EnhancedInput" ] } ], diff --git a/Elistria_Calling/Source/Elistria_Calling/Elistria_Calling.Build.cs b/Elistria_Calling/Source/Elistria_Calling/Elistria_Calling.Build.cs index cbd6e72..d3ca392 100644 --- a/Elistria_Calling/Source/Elistria_Calling/Elistria_Calling.Build.cs +++ b/Elistria_Calling/Source/Elistria_Calling/Elistria_Calling.Build.cs @@ -8,7 +8,7 @@ public class Elistria_Calling : ModuleRules { PCHUsage = PCHUsageMode.UseExplicitOrSharedPCHs; - PublicDependencyModuleNames.AddRange(new string[] { "Core", "CoreUObject", "Engine", "InputCore","GameplayAbilities", "GameplayTags", "GameplayTasks" }); + PublicDependencyModuleNames.AddRange(new string[] { "Core", "CoreUObject", "Engine", "InputCore","GameplayAbilities", "GameplayTags", "GameplayTasks", "EnhancedInput","TargetingSystem" }); PrivateDependencyModuleNames.AddRange(new string[] { }); diff --git a/Elistria_Calling/Source/Elistria_Calling/Private/ElistriaAbilitySystemComponent.cpp b/Elistria_Calling/Source/Elistria_Calling/Private/ElistriaAbilitySystemComponent.cpp index 5aaeef4..f687cc3 100644 --- a/Elistria_Calling/Source/Elistria_Calling/Private/ElistriaAbilitySystemComponent.cpp +++ b/Elistria_Calling/Source/Elistria_Calling/Private/ElistriaAbilitySystemComponent.cpp @@ -3,3 +3,59 @@ #include "ElistriaAbilitySystemComponent.h" +#include "PlayerGameplayAbilitiesDataAsset.h" + +void UElistriaAbilitySystemComponent::ServerActivateAbilityByInputID_Implementation(FGameplayAbilitySpecHandle Handle,int32 InputID) +{ + TryActivateAbility(Handle); +} + +void UElistriaAbilitySystemComponent::GrantAbilitiesFromDataAsset(const UPlayerGameplayAbilitiesDataAsset* AbilitiesDataAsset) +{ + if (!AbilitiesDataAsset) return; + + for (const FGameplayInputAbilityInfo& AbilityInfo : AbilitiesDataAsset->GetInputAbilities()) + { + if (AbilityInfo.IsValid()) + { + FGameplayAbilitySpec AbilitySpec(AbilityInfo.AbilityClass, 1, AbilityInfo.InputID); + FGameplayAbilitySpecHandle SpecHandle = GiveAbility(AbilitySpec); + InputIDToAbilitySpecHandleMap.Add(AbilityInfo.InputID, SpecHandle); + } + } +} + +void UElistriaAbilitySystemComponent::AbilityLocalInputPressed(int32 InputID) +{ + if (FGameplayAbilitySpecHandle* HandlePtr = SlotToAbilityHandleMap.Find(InputID)) + { + if (GetOwnerRole() < ROLE_Authority) + { + ServerActivateAbilityByInputID(*HandlePtr, InputID); + } + TryActivateAbility(*HandlePtr); + } +} + +void UElistriaAbilitySystemComponent::EquipAbility(TSubclassOf NewAbility, int32 SlotIndex) +{ + if (!NewAbility) return; + UnequipAbility(SlotIndex); + + FGameplayAbilitySpec Spec(NewAbility,1,SlotIndex); + FGameplayAbilitySpecHandle SpecHandle = GiveAbility(Spec); + SlotToAbilityHandleMap.Add(SlotIndex, SpecHandle); + + OnAbilitiesChanged.Broadcast(this); +} + +void UElistriaAbilitySystemComponent::UnequipAbility(int32 SlotIndex) +{ + if (FGameplayAbilitySpecHandle* HandlePtr = SlotToAbilityHandleMap.Find(SlotIndex)) + { + ClearAbility(*HandlePtr); + SlotToAbilityHandleMap.Remove(SlotIndex); + + OnAbilitiesChanged.Broadcast(this); + } +} diff --git a/Elistria_Calling/Source/Elistria_Calling/Private/ElistriaEnhancedInputComponent.cpp b/Elistria_Calling/Source/Elistria_Calling/Private/ElistriaEnhancedInputComponent.cpp new file mode 100644 index 0000000..4d5b4b3 --- /dev/null +++ b/Elistria_Calling/Source/Elistria_Calling/Private/ElistriaEnhancedInputComponent.cpp @@ -0,0 +1,15 @@ +// Fill out your copyright notice in the Description page of Project Settings. + + +#include "ElistriaEnhancedInputComponent.h" + + + +void UElistriaEnhancedInputComponent::ClearAbilityBindings() +{ + for (uint32 Handle : AbilityActionBindings) + { + RemoveBindingByHandle(Handle); + } + AbilityActionBindings.Empty(); +} diff --git a/Elistria_Calling/Source/Elistria_Calling/Private/MagickPlayerController.cpp b/Elistria_Calling/Source/Elistria_Calling/Private/MagickPlayerController.cpp index 343b571..87d9712 100644 --- a/Elistria_Calling/Source/Elistria_Calling/Private/MagickPlayerController.cpp +++ b/Elistria_Calling/Source/Elistria_Calling/Private/MagickPlayerController.cpp @@ -3,6 +3,7 @@ #include "MagickPlayerController.h" +#include "ElistriaEnhancedInputComponent.h" #include "MagickPlayerState.h" void AMagickPlayerController::OnPossess(APawn *InPawn) @@ -10,8 +11,65 @@ void AMagickPlayerController::OnPossess(APawn *InPawn) Super::OnPossess(InPawn); UE_LOG(LogTemp, Display, TEXT("OnPossess")); AMagickPlayerState* PS = GetPlayerState(); + UElistriaAbilitySystemComponent* ASC = PS ? PS->GetAbilitySystemComponent() : nullptr; if (PS) { PS->SetupAbilityActorInfo(); + if (ASC) + { + ASC->OnAbilitiesChanged.AddDynamic(this,&AMagickPlayerController::OnAbilitiesChanged); + } + } +} + +void AMagickPlayerController::OnAbilitiesChanged(UElistriaAbilitySystemComponent* ASC) +{ + RebindAbilityInputs(); +} + +void AMagickPlayerController::SetupInputComponent() +{ + Super::SetupInputComponent(); + if (UElistriaEnhancedInputComponent* EIC = Cast(InputComponent)) + { + if (InputAbilitiesDataAsset) + { + EIC->BindAbilityActions(InputAbilitiesDataAsset, this, &AMagickPlayerController::AbilityInputPressed); + } + } +} + +void AMagickPlayerController::AbilityInputPressed(int32 InputID) +{ + if (AMagickPlayerState* PS = GetPlayerState()) + { + if (UElistriaAbilitySystemComponent* ASC = PS ? PS->GetAbilitySystemComponent() : nullptr) + { + ASC->AbilityLocalInputPressed(InputID); + } + } +} + +void AMagickPlayerController::BeginPlay() +{ + Super::BeginPlay(); + if (UInputMappingContext* IMC = InputMappingContext) + { + if (UEnhancedInputLocalPlayerSubsystem* Subsystem = ULocalPlayer::GetSubsystem(GetLocalPlayer())) + { + Subsystem->AddMappingContext(IMC, 0); + } + } +} + +void AMagickPlayerController::RebindAbilityInputs() +{ + if (UElistriaEnhancedInputComponent* EIC = Cast(InputComponent)) + { + EIC -> ClearAbilityBindings(); + if (InputAbilitiesDataAsset) + { + EIC->BindAbilityActions(InputAbilitiesDataAsset,this,&AMagickPlayerController::AbilityInputPressed); + } } } diff --git a/Elistria_Calling/Source/Elistria_Calling/Private/PlayerGameplayAbilitiesDataAsset.cpp b/Elistria_Calling/Source/Elistria_Calling/Private/PlayerGameplayAbilitiesDataAsset.cpp new file mode 100644 index 0000000..68702b5 --- /dev/null +++ b/Elistria_Calling/Source/Elistria_Calling/Private/PlayerGameplayAbilitiesDataAsset.cpp @@ -0,0 +1,44 @@ +// Fill out your copyright notice in the Description page of Project Settings. + + +#include "PlayerGameplayAbilitiesDataAsset.h" + +UPlayerGameplayAbilitiesDataAsset::UPlayerGameplayAbilitiesDataAsset(const FObjectInitializer& ObjectInitializer) + : Super(ObjectInitializer) +{ + // Constructor implementation +} + +const TSet& UPlayerGameplayAbilitiesDataAsset::GetInputAbilities() const +{ + return InputAbilities; +} + +#if WITH_EDITOR +void UPlayerGameplayAbilitiesDataAsset::PostEditChangeProperty(FPropertyChangedEvent& PropertyChangedEvent) +{ + Super::PostEditChangeProperty(PropertyChangedEvent); + + const FProperty* Property = PropertyChangedEvent.Property; + if (Property && Property->GetName()==GET_MEMBER_NAME_CHECKED(UPlayerGameplayAbilitiesDataAsset, InputAbilities)&& !InputAbilities.IsEmpty()) + { + TArray InputAbilitiesArray = InputAbilities.Array(); + for (int32 i = InputAbilitiesArray.Num() - 1; i >= 0; i--) + { + const int32 PrevIndex = i - 1; + if (InputAbilitiesArray[i]==InputAbilitiesArray[PrevIndex]) + { + InputAbilitiesArray.RemoveAtSwap(i); + } + } + InputAbilities.Reset(); + + for (int32 i=0; i NewAbility, int32 SlotIndex); + + UFUNCTION(BlueprintCallable) + void UnequipAbility(int32 SlotIndex); + + void RefreshInputBindings(); + + DECLARE_DYNAMIC_MULTICAST_DELEGATE_OneParam(FOnAbilitiesChanged, UElistriaAbilitySystemComponent*, ASC); + UPROPERTY(BlueprintAssignable) + FOnAbilitiesChanged OnAbilitiesChanged; + + void GrantAbilitiesFromDataAsset(const UPlayerGameplayAbilitiesDataAsset* AbilitiesDataAsset); + virtual void AbilityLocalInputPressed(int32 InputID) override; + +private: + TMap InputIDToAbilitySpecHandleMap; + + UPROPERTY() + TMap SlotToAbilityHandleMap; + + void ServerActivateAbilityByInputID_Implementation(FGameplayAbilitySpecHandle Handle, int32 InputID); }; diff --git a/Elistria_Calling/Source/Elistria_Calling/Public/ElistriaEnhancedInputComponent.h b/Elistria_Calling/Source/Elistria_Calling/Public/ElistriaEnhancedInputComponent.h new file mode 100644 index 0000000..5b7fe51 --- /dev/null +++ b/Elistria_Calling/Source/Elistria_Calling/Public/ElistriaEnhancedInputComponent.h @@ -0,0 +1,39 @@ +// Fill out your copyright notice in the Description page of Project Settings. + +#pragma once + +#include "CoreMinimal.h" +#include "EnhancedInputComponent.h" +#include "PlayerGameplayAbilitiesDataAsset.h" +#include "ElistriaEnhancedInputComponent.generated.h" + +/** + * + */ +UCLASS() +class ELISTRIA_CALLING_API UElistriaEnhancedInputComponent : public UEnhancedInputComponent +{ + GENERATED_BODY() +public: + template + void BindAbilityActions(const UPlayerGameplayAbilitiesDataAsset* InputConfig, UserClass* Object, FuncType Func); + + void ClearAbilityBindings(); + +private: + + TArray AbilityActionBindings; +}; +template +void UElistriaEnhancedInputComponent::BindAbilityActions(const UPlayerGameplayAbilitiesDataAsset* InputConfig, UserClass* Object, FuncType Func) +{ + if (!InputConfig) return; + + for (const FGameplayInputAbilityInfo& AbilityInfo : InputConfig->GetInputAbilities()) + { + if (AbilityInfo.IsValid()) + { + BindAction(AbilityInfo.InputAction,ETriggerEvent::Triggered,Object,Func,AbilityInfo.InputID); + } + } +} \ No newline at end of file diff --git a/Elistria_Calling/Source/Elistria_Calling/Public/MagickPlayerController.h b/Elistria_Calling/Source/Elistria_Calling/Public/MagickPlayerController.h index d8b2030..d2e3d06 100644 --- a/Elistria_Calling/Source/Elistria_Calling/Public/MagickPlayerController.h +++ b/Elistria_Calling/Source/Elistria_Calling/Public/MagickPlayerController.h @@ -3,7 +3,11 @@ #pragma once #include "CoreMinimal.h" +#include "PlayerGameplayAbilitiesDataAsset.h" #include "GameFramework/PlayerController.h" +#include "InputMappingContext.h" +#include "EnhancedInputSubsystems.h" +#include "ElistriaEnhancedInputComponent.h" #include "MagickPlayerController.generated.h" /** @@ -13,7 +17,25 @@ UCLASS() class ELISTRIA_CALLING_API AMagickPlayerController : public APlayerController { GENERATED_BODY() - - + virtual void OnPossess(APawn* InPawn) override; + + UFUNCTION() + void OnAbilitiesChanged(UElistriaAbilitySystemComponent* ASC); + +public: + UPROPERTY(EditAnywhere, BlueprintReadOnly, Category="Input") + TObjectPtr InputAbilitiesDataAsset; + + UPROPERTY(EditAnywhere, BlueprintReadOnly, Category="Input") + TObjectPtr InputMappingContext; + + virtual void SetupInputComponent() override; + + UFUNCTION() + void AbilityInputPressed(int32 InputID); + + virtual void BeginPlay() override; + + void RebindAbilityInputs(); }; diff --git a/Elistria_Calling/Source/Elistria_Calling/Public/MagickPlayerState.h b/Elistria_Calling/Source/Elistria_Calling/Public/MagickPlayerState.h index 70bfbcd..6670e30 100644 --- a/Elistria_Calling/Source/Elistria_Calling/Public/MagickPlayerState.h +++ b/Elistria_Calling/Source/Elistria_Calling/Public/MagickPlayerState.h @@ -33,4 +33,7 @@ protected: UPROPERTY(Replicated) TObjectPtr ManaSet; + +private: + }; diff --git a/Elistria_Calling/Source/Elistria_Calling/Public/PlayerGameplayAbilitiesDataAsset.h b/Elistria_Calling/Source/Elistria_Calling/Public/PlayerGameplayAbilitiesDataAsset.h new file mode 100644 index 0000000..32f5655 --- /dev/null +++ b/Elistria_Calling/Source/Elistria_Calling/Public/PlayerGameplayAbilitiesDataAsset.h @@ -0,0 +1,72 @@ +// Fill out your copyright notice in the Description page of Project Settings. + +#pragma once + +#include "CoreMinimal.h" +#include "Engine/DataAsset.h" +#include "Abilities/GameplayAbility.h" +#include "PlayerGameplayAbilitiesDataAsset.generated.h" + +/** + * + */ +class UInputAction; + +USTRUCT() +struct FGameplayInputAbilityInfo +{ + GENERATED_USTRUCT_BODY() + + UPROPERTY(EditAnywhere, Category = "GameplayInputAbilityInfo") + TSubclassOf AbilityClass; + + UPROPERTY(EditAnywhere, Category = "GameplayInputAbilityInfo") + TObjectPtr InputAction; + + UPROPERTY(VisibleAnywhere, Category = "GameplayInputAbilityInfo") + int32 InputID; + + bool IsValid() const + { + return AbilityClass && InputAction; + } + + bool operator==(const FGameplayInputAbilityInfo& other) const + { + return AbilityClass == other.AbilityClass && InputID == other.InputID; + } + + bool operator!=(const FGameplayInputAbilityInfo& other) const + { + return !operator==(other); + } + + friend uint32 GetTypeHash(const FGameplayInputAbilityInfo& Item) + { + return HashCombine(GetTypeHash(Item.AbilityClass), Item.InputID); + } + + FGameplayInputAbilityInfo() + : InputID(INDEX_NONE) + { + } +}; + +UCLASS() +class ELISTRIA_CALLING_API UPlayerGameplayAbilitiesDataAsset : public UDataAsset +{ + GENERATED_BODY() + +protected: + UPROPERTY(EditAnywhere, Category = "AbilitySystem") + TSet InputAbilities; + +public: + UPlayerGameplayAbilitiesDataAsset(const FObjectInitializer& ObjectInitializer = FObjectInitializer::Get()); + + const TSet& GetInputAbilities() const; + +#if WITH_EDITOR + virtual void PostEditChangeProperty(FPropertyChangedEvent& PropertyChangedEvent) override; +#endif +};