diff --git a/Content/Characters/(Shared)/Abilities/GA_Cast.uasset b/Content/Characters/(Shared)/Abilities/GA_Cast.uasset index e943730..3d593a2 100644 Binary files a/Content/Characters/(Shared)/Abilities/GA_Cast.uasset and b/Content/Characters/(Shared)/Abilities/GA_Cast.uasset differ diff --git a/Content/Characters/(Shared)/BP_Character.uasset b/Content/Characters/(Shared)/BP_Character.uasset index 0ed53e0..a8daf08 100644 Binary files a/Content/Characters/(Shared)/BP_Character.uasset and b/Content/Characters/(Shared)/BP_Character.uasset differ diff --git a/Content/Characters/(Shared)/Effects/GE_Cost_Stamina.uasset b/Content/Characters/(Shared)/Effects/GE_Cost_Stamina.uasset index da18624..5a37d3d 100644 Binary files a/Content/Characters/(Shared)/Effects/GE_Cost_Stamina.uasset and b/Content/Characters/(Shared)/Effects/GE_Cost_Stamina.uasset differ diff --git a/Content/Characters/Hero1/Abilities/Poison/GA_Hero1_Poison.uasset b/Content/Characters/Hero1/Abilities/Poison/GA_Hero1_Poison.uasset index f30c29b..6842526 100644 Binary files a/Content/Characters/Hero1/Abilities/Poison/GA_Hero1_Poison.uasset and b/Content/Characters/Hero1/Abilities/Poison/GA_Hero1_Poison.uasset differ diff --git a/Content/Characters/Hero2/Abilities/Ability1/GA_Hero2_Ability1.uasset b/Content/Characters/Hero2/Abilities/Ability1/GA_Hero2_Ability1.uasset index 4d98c01..834b348 100644 Binary files a/Content/Characters/Hero2/Abilities/Ability1/GA_Hero2_Ability1.uasset and b/Content/Characters/Hero2/Abilities/Ability1/GA_Hero2_Ability1.uasset differ diff --git a/Content/Characters/Hero2/Abilities/Ability2/GA_Hero2_Ability2.uasset b/Content/Characters/Hero2/Abilities/Ability2/GA_Hero2_Ability2.uasset index dcb0820..3f8658d 100644 Binary files a/Content/Characters/Hero2/Abilities/Ability2/GA_Hero2_Ability2.uasset and b/Content/Characters/Hero2/Abilities/Ability2/GA_Hero2_Ability2.uasset differ diff --git a/Content/Characters/Hero2/Abilities/Ability3/GA_Hero2_Ability3.uasset b/Content/Characters/Hero2/Abilities/Ability3/GA_Hero2_Ability3.uasset index 4ec5dbe..d0fd6b8 100644 Binary files a/Content/Characters/Hero2/Abilities/Ability3/GA_Hero2_Ability3.uasset and b/Content/Characters/Hero2/Abilities/Ability3/GA_Hero2_Ability3.uasset differ diff --git a/Content/Characters/Hero2/Abilities/Ability4/GA_Hero2_Ability4.uasset b/Content/Characters/Hero2/Abilities/Ability4/GA_Hero2_Ability4.uasset index 814c274..b513039 100644 Binary files a/Content/Characters/Hero2/Abilities/Ability4/GA_Hero2_Ability4.uasset and b/Content/Characters/Hero2/Abilities/Ability4/GA_Hero2_Ability4.uasset differ diff --git a/Content/Core/GameModes/BP_PlayerController.uasset b/Content/Core/GameModes/BP_PlayerController.uasset index 37f8c6c..22f8281 100644 Binary files a/Content/Core/GameModes/BP_PlayerController.uasset and b/Content/Core/GameModes/BP_PlayerController.uasset differ diff --git a/Content/Core/Hud/BP_Hud.uasset b/Content/Core/Hud/BP_Hud.uasset index 1b29adb..c3bb4ba 100644 Binary files a/Content/Core/Hud/BP_Hud.uasset and b/Content/Core/Hud/BP_Hud.uasset differ diff --git a/Content/Core/Hud/WBP_Status.uasset b/Content/Core/Hud/WBP_Status.uasset index a5b3ef8..441c16a 100644 Binary files a/Content/Core/Hud/WBP_Status.uasset and b/Content/Core/Hud/WBP_Status.uasset differ diff --git a/Content/__ExternalActors__/Maps/L_Default/2/KZ/3Y4PAKEW3L97J087BUDMVI.uasset b/Content/__ExternalActors__/Maps/L_Default/2/KZ/3Y4PAKEW3L97J087BUDMVI.uasset index b32da00..d021592 100644 Binary files a/Content/__ExternalActors__/Maps/L_Default/2/KZ/3Y4PAKEW3L97J087BUDMVI.uasset and b/Content/__ExternalActors__/Maps/L_Default/2/KZ/3Y4PAKEW3L97J087BUDMVI.uasset differ diff --git a/Content/__ExternalActors__/Maps/L_Default/5/88/NDHUEK1ROBM2RCW7ZU51MM.uasset b/Content/__ExternalActors__/Maps/L_Default/5/88/NDHUEK1ROBM2RCW7ZU51MM.uasset index b1ece1a..5d4d4f2 100644 Binary files a/Content/__ExternalActors__/Maps/L_Default/5/88/NDHUEK1ROBM2RCW7ZU51MM.uasset and b/Content/__ExternalActors__/Maps/L_Default/5/88/NDHUEK1ROBM2RCW7ZU51MM.uasset differ diff --git a/Content/__ExternalActors__/Maps/L_Default/6/U3/6O7DJ03I0JB041XHH0L21L.uasset b/Content/__ExternalActors__/Maps/L_Default/6/U3/6O7DJ03I0JB041XHH0L21L.uasset index a136afd..254293a 100644 Binary files a/Content/__ExternalActors__/Maps/L_Default/6/U3/6O7DJ03I0JB041XHH0L21L.uasset and b/Content/__ExternalActors__/Maps/L_Default/6/U3/6O7DJ03I0JB041XHH0L21L.uasset differ diff --git a/Source/CogSample/CogSampleCharacter.cpp b/Source/CogSample/CogSampleCharacter.cpp index 183a4d2..bb605f5 100644 --- a/Source/CogSample/CogSampleCharacter.cpp +++ b/Source/CogSample/CogSampleCharacter.cpp @@ -82,6 +82,15 @@ void ACogSampleCharacter::GetLifetimeReplicatedProps(TArray< FLifetimeProperty > DOREPLIFETIME_WITH_PARAMS_FAST(ACogSampleCharacter, Team, Params); } + +//-------------------------------------------------------------------------------------------------------------------------- +void ACogSampleCharacter::PostInitializeComponents() +{ + Super::PostInitializeComponents(); + + InitializeAbilitySystem(); +} + //-------------------------------------------------------------------------------------------------------------------------- void ACogSampleCharacter::BeginPlay() { @@ -117,19 +126,83 @@ UAbilitySystemComponent* ACogSampleCharacter::GetAbilitySystemComponent() const return AbilitySystem; } -//-------------------------------------------------------------------------------------------------------------------------- -ECogInterfacesAllegiance ACogSampleCharacter::GetAllegianceWithOtherActor(const AActor* OtherActor) const -{ - ECogSampleAllegiance Allegiance = UCogSampleFunctionLibrary_Team::GetActorsAllegiance(this, OtherActor); - switch (Allegiance) +//-------------------------------------------------------------------------------------------------------------------------- +void ACogSampleCharacter::PossessedBy(AController* NewController) +{ + COG_LOG_OBJECT(LogCogPossession, ELogVerbosity::Verbose, this, TEXT("Controller:%s"), *GetNameSafe(NewController)); + + if (InitialController == nullptr) { - case ECogSampleAllegiance::Enemy: return ECogInterfacesAllegiance::Enemy; - case ECogSampleAllegiance::Friendly: return ECogInterfacesAllegiance::Friendly; - case ECogSampleAllegiance::Neutral: return ECogInterfacesAllegiance::Neutral; + InitialController = NewController; } - - return ECogInterfacesAllegiance::Neutral; + + Super::PossessedBy(NewController); + + if (bIsInitialized == false) + { + InitializeAbilitySystem(); + } + else + { + //------------------------------------------------------------------------------------------- + // When possessing a NPC, we need to refresh the ability system actor info, so it knows about + // the new controller to be able to activate abilities. + //------------------------------------------------------------------------------------------- + AbilitySystem->InitAbilityActorInfo(this, this); + + //------------------------------------------------------------------------------------------- + // We might be possessed when in a middle of an ability. Currently we prefer to cancel it. + //------------------------------------------------------------------------------------------- + AbilitySystem->CancelAllAbilities(); + + if (UCogSampleCharacterMovementComponent* MovementComp = Cast(GetMovementComponent())) + { + MovementComp->PossessedBy(NewController); + } + } +} + +//-------------------------------------------------------------------------------------------------------------------------- +void ACogSampleCharacter::UnPossessed() +{ + COG_LOG_OBJECT(LogCogPossession, ELogVerbosity::Verbose, this, TEXT("")); + + if (UCogSampleCharacterMovementComponent* MovementComp = Cast(GetMovementComponent())) + { + MovementComp->UnPossessed(); + } + + Super::UnPossessed(); +} + +//-------------------------------------------------------------------------------------------------------------------------- +void ACogSampleCharacter::AcknowledgePossession(AController* NewController) +{ + COG_LOG_OBJECT(LogCogPossession, ELogVerbosity::Verbose, this, TEXT("Controller:%s - NewController:%s"), *GetNameSafe(NewController), *GetNameSafe(Controller)); + + //------------------------------------------------------------------------------------------- + // Set the controller otherwise when the player possesses a NPC, he would not be able to cast + // any ability. The ability system component needs to know the controller and therefore it + // needs to be set before calling InitAbilityActorInfo. + // See FGameplayAbilityActorInfo::InitFromActor + //------------------------------------------------------------------------------------------- + Controller = NewController; + + if (AbilitySystem != nullptr) + { + AbilitySystem->InitAbilityActorInfo(this, this); + } +} + +//-------------------------------------------------------------------------------------------------------------------------- +void ACogSampleCharacter::AcknowledgeUnpossession() +{ + COG_LOG_OBJECT(LogCogPossession, ELogVerbosity::Verbose, this, TEXT("OldController:%s"), *GetNameSafe(Controller)); + + Controller = nullptr; + + AbilitySystem->InitAbilityActorInfo(this, this); } //-------------------------------------------------------------------------------------------------------------------------- @@ -221,11 +294,6 @@ void ACogSampleCharacter::TryFinishInitialize() return; } - if (bIsAbilitySystemInitialized == false) - { - return; - } - if (HasActorBegunPlay() == false) { return; @@ -262,19 +330,6 @@ void ACogSampleCharacter::ShutdownAbilitySystem() AbilitySystem->ClearActorInfo(); } -//-------------------------------------------------------------------------------------------------------------------------- -void ACogSampleCharacter::PossessedBy(AController* NewController) -{ - Super::PossessedBy(NewController); - InitializeAbilitySystem(); -} - -//-------------------------------------------------------------------------------------------------------------------------- -void ACogSampleCharacter::OnAcknowledgePossession(APlayerController* InController) -{ - InitializeAbilitySystem(); -} - //-------------------------------------------------------------------------------------------------------------------------- void ACogSampleCharacter::SetupPlayerInputComponent(class UInputComponent* PlayerInputComponent) { @@ -420,6 +475,21 @@ void ACogSampleCharacter::Look(const FInputActionValue& Value) } } +//-------------------------------------------------------------------------------------------------------------------------- +ECogInterfacesAllegiance ACogSampleCharacter::GetAllegianceWithOtherActor(const AActor* OtherActor) const +{ + ECogSampleAllegiance Allegiance = UCogSampleFunctionLibrary_Team::GetActorsAllegiance(this, OtherActor); + + switch (Allegiance) + { + case ECogSampleAllegiance::Enemy: return ECogInterfacesAllegiance::Enemy; + case ECogSampleAllegiance::Friendly: return ECogInterfacesAllegiance::Friendly; + case ECogSampleAllegiance::Neutral: return ECogInterfacesAllegiance::Neutral; + } + + return ECogInterfacesAllegiance::Neutral; +} + //-------------------------------------------------------------------------------------------------------------------------- void ACogSampleCharacter::HandleDamageReceived(const FCogSampleDamageEventParams& Params) { @@ -435,11 +505,6 @@ void ACogSampleCharacter::HandleDamageDealt(const FCogSampleDamageEventParams& P { OnDamageDealt.Broadcast(Params); - if (ACogSamplePlayerController* PlayerController = Cast(GetController())) - { - PlayerController->OnPawnDealtDamage.Broadcast(Params); - } - #if USE_COG FCogDebugMetric::AddMetric(this, "Damage Dealt", Params.MitigatedDamage, Params.UnmitigatedDamage, false); #endif //USE_COG diff --git a/Source/CogSample/CogSampleCharacter.h b/Source/CogSample/CogSampleCharacter.h index 226f2ad..d896483 100644 --- a/Source/CogSample/CogSampleCharacter.h +++ b/Source/CogSample/CogSampleCharacter.h @@ -79,6 +79,8 @@ public: // ACharacter overrides //---------------------------------------------------------------------------------------------------------------------- + virtual void PostInitializeComponents() override; + virtual void BeginPlay() override; virtual void EndPlay(const EEndPlayReason::Type EndPlayReason) override; @@ -89,7 +91,11 @@ public: virtual void PossessedBy(AController* NewController) override; - void OnAcknowledgePossession(APlayerController* InController); + virtual void UnPossessed() override; + + virtual void AcknowledgePossession(AController* NewController); + + virtual void AcknowledgeUnpossession(); //---------------------------------------------------------------------------------------------------------------------- // IAbilitySystemInterface overrides @@ -215,6 +221,11 @@ public: int32 ApplyRootMotion(const FCogSampleRootMotionParams& Params); private: + + friend class ACogSamplePlayerController; + + UPROPERTY() + AController* InitialController = nullptr; //---------------------------------------------------------------------------------------------------------------------- // Inputs diff --git a/Source/CogSample/CogSampleCharacterMovementComponent.cpp b/Source/CogSample/CogSampleCharacterMovementComponent.cpp index c4ab62e..ac33e8b 100644 --- a/Source/CogSample/CogSampleCharacterMovementComponent.cpp +++ b/Source/CogSample/CogSampleCharacterMovementComponent.cpp @@ -305,3 +305,26 @@ bool UCogSampleCharacterMovementComponent::ClientUpdatePositionAfterServerUpdate return Result; } + +//-------------------------------------------------------------------------------------------------------------------------- +void UCogSampleCharacterMovementComponent::PossessedBy(AController* NewController) +{ + if (NewController != nullptr && NewController->IsPlayerController()) + { + bWasAvoidanceEnabled = bUseRVOAvoidance; + SetAvoidanceEnabled(false); + } + else + { + SetAvoidanceEnabled(bWasAvoidanceEnabled); + } +} + +//-------------------------------------------------------------------------------------------------------------------------- +void UCogSampleCharacterMovementComponent::UnPossessed() +{ + //--------------------------------------------------------------------------------------- + // Make sure the character doesn't keep his velocity while not controlled anymore. + //--------------------------------------------------------------------------------------- + ConsumeInputVector(); +} \ No newline at end of file diff --git a/Source/CogSample/CogSampleCharacterMovementComponent.h b/Source/CogSample/CogSampleCharacterMovementComponent.h index d311838..689dd58 100644 --- a/Source/CogSample/CogSampleCharacterMovementComponent.h +++ b/Source/CogSample/CogSampleCharacterMovementComponent.h @@ -5,12 +5,60 @@ #include "GameFramework/CharacterMovementComponent.h" #include "CogSampleCharacterMovementComponent.generated.h" +class AController; + //-------------------------------------------------------------------------------------------------------------------------- UCLASS() class UCogSampleCharacterMovementComponent : public UCharacterMovementComponent { GENERATED_BODY() +public: + + virtual void BeginPlay() override; + + virtual void TickComponent(float DeltaTime, enum ELevelTick TickType, FActorComponentTickFunction* ThisTickFunction) override; + + virtual float GetMaxSpeed() const override; + + virtual float GetMaxAcceleration() const override; + + virtual FRotator GetDeltaRotation(float DeltaTime) const; + + virtual void UpdateFromCompressedFlags(uint8 Flags) override; + + virtual class FNetworkPredictionData_Client* GetPredictionData_Client() const override; + + virtual bool ClientUpdatePositionAfterServerUpdate() override; + + virtual void PossessedBy(AController* NewController); + + virtual void UnPossessed(); + + UFUNCTION(BlueprintCallable) + void StartSprinting(); + + UFUNCTION(BlueprintCallable) + void StopSprinting(); + +private: + + bool bIsSprinting = false; + + bool bWasAvoidanceEnabled = false; + +#if USE_COG + + FVector DebugLastBottomLocation = FVector::ZeroVector; + + FVector DebugLastVelocity = FVector::ZeroVector; + + bool DebugIsPositionCorrected = false; + +#endif //USE_COG + + + //---------------------------------------------------------------------------------------------------------------------- class FCogSampleSavedMove : public FSavedMove_Character { public: @@ -29,7 +77,7 @@ class UCogSampleCharacterMovementComponent : public UCharacterMovementComponent ///@brief Sets up the move before sending it to the server. virtual void SetMoveFor(ACharacter* Character, float InDeltaTime, FVector const& NewAccel, class FNetworkPredictionData_Client_Character& ClientData) override; - + ///@brief Sets variables on character movement component before making a predictive correction. virtual void PrepMoveFor(class ACharacter* Character) override; @@ -37,6 +85,7 @@ class UCogSampleCharacterMovementComponent : public UCharacterMovementComponent uint8 SavedRequestSprint : 1; }; + //---------------------------------------------------------------------------------------------------------------------- class FCogSampleNetworkPredictionData_Client : public FNetworkPredictionData_Client_Character { public: @@ -47,30 +96,4 @@ class UCogSampleCharacterMovementComponent : public UCharacterMovementComponent ///@brief Allocates a new copy of our custom saved move virtual FSavedMovePtr AllocateNewMove() override; }; - -public: - virtual void BeginPlay() override; - virtual void TickComponent(float DeltaTime, enum ELevelTick TickType, FActorComponentTickFunction* ThisTickFunction) override; - virtual float GetMaxSpeed() const override; - virtual float GetMaxAcceleration() const override; - virtual FRotator GetDeltaRotation(float DeltaTime) const; - virtual void UpdateFromCompressedFlags(uint8 Flags) override; - virtual class FNetworkPredictionData_Client* GetPredictionData_Client() const override; - virtual bool ClientUpdatePositionAfterServerUpdate() override; - - UFUNCTION(BlueprintCallable) - void StartSprinting(); - - UFUNCTION(BlueprintCallable) - void StopSprinting(); - -private: - - bool bIsSprinting = false; - -#if USE_COG - FVector DebugLastBottomLocation = FVector::ZeroVector; - FVector DebugLastVelocity = FVector::ZeroVector; - bool DebugIsPositionCorrected = false; -#endif //USE_COG }; diff --git a/Source/CogSample/CogSampleLogCategories.cpp b/Source/CogSample/CogSampleLogCategories.cpp index 0cd8556..e18ff0d 100644 --- a/Source/CogSample/CogSampleLogCategories.cpp +++ b/Source/CogSample/CogSampleLogCategories.cpp @@ -8,12 +8,15 @@ #endif //USE_COG DEFINE_LOG_CATEGORY(LogCogAlways); + +DEFINE_LOG_CATEGORY(LogCogAbility); +DEFINE_LOG_CATEGORY(LogCogBaseAimRotation); DEFINE_LOG_CATEGORY(LogCogCollision); +DEFINE_LOG_CATEGORY(LogCogControlRotation); DEFINE_LOG_CATEGORY(LogCogInput); DEFINE_LOG_CATEGORY(LogCogPosition); +DEFINE_LOG_CATEGORY(LogCogPossession); DEFINE_LOG_CATEGORY(LogCogRotation); -DEFINE_LOG_CATEGORY(LogCogControlRotation); -DEFINE_LOG_CATEGORY(LogCogBaseAimRotation); DEFINE_LOG_CATEGORY(LogCogSkeleton); DEFINE_LOG_CATEGORY(LogCogTargetAcquisition); @@ -23,16 +26,19 @@ namespace CogSampleLog { #if USE_COG FCogDebugLog::AddLogCategory(LogCogAlways, "Always", false); + + FCogDebugLog::AddLogCategory(LogCogAbility, "Ability"); FCogDebugLog::AddLogCategory(LogAbilitySystem, "Ability System"); - FCogDebugLog::AddLogCategory(LogGameplayEffects, "Gameplay Effects"); + FCogDebugLog::AddLogCategory(LogCogBaseAimRotation, "BaseAimRotation"); FCogDebugLog::AddLogCategory(LogCogCollision, "Collision"); + FCogDebugLog::AddLogCategory(LogCogControlRotation, "ControlRotation"); FCogDebugLog::AddLogCategory(LogCogInput, "Input"); FCogDebugLog::AddLogCategory(LogCogPosition, "Position"); + FCogDebugLog::AddLogCategory(LogCogPossession, "Possession"); FCogDebugLog::AddLogCategory(LogCogRotation, "Rotation"); - FCogDebugLog::AddLogCategory(LogCogControlRotation, "ControlRotation"); - FCogDebugLog::AddLogCategory(LogCogBaseAimRotation, "BaseAimRotation"); FCogDebugLog::AddLogCategory(LogCogSkeleton, "Skeleton"); FCogDebugLog::AddLogCategory(LogCogTargetAcquisition, "Target Acquisition"); + FCogDebugLog::AddLogCategory(LogGameplayEffects, "Gameplay Effects"); #endif //USE_COG } } diff --git a/Source/CogSample/CogSampleLogCategories.h b/Source/CogSample/CogSampleLogCategories.h index 8d8da8e..48a0f05 100644 --- a/Source/CogSample/CogSampleLogCategories.h +++ b/Source/CogSample/CogSampleLogCategories.h @@ -1,12 +1,15 @@ #include "CoreMinimal.h" DECLARE_LOG_CATEGORY_EXTERN(LogCogAlways, VeryVerbose, All); + +DECLARE_LOG_CATEGORY_EXTERN(LogCogAbility, Warning, All); +DECLARE_LOG_CATEGORY_EXTERN(LogCogBaseAimRotation, Warning, All); DECLARE_LOG_CATEGORY_EXTERN(LogCogCollision, Warning, All); +DECLARE_LOG_CATEGORY_EXTERN(LogCogControlRotation, Warning, All); DECLARE_LOG_CATEGORY_EXTERN(LogCogInput, Warning, All); DECLARE_LOG_CATEGORY_EXTERN(LogCogPosition, Warning, All); +DECLARE_LOG_CATEGORY_EXTERN(LogCogPossession, Warning, All); DECLARE_LOG_CATEGORY_EXTERN(LogCogRotation, Warning, All); -DECLARE_LOG_CATEGORY_EXTERN(LogCogControlRotation, Warning, All); -DECLARE_LOG_CATEGORY_EXTERN(LogCogBaseAimRotation, Warning, All); DECLARE_LOG_CATEGORY_EXTERN(LogCogSkeleton, Warning, All); DECLARE_LOG_CATEGORY_EXTERN(LogCogTargetAcquisition, Warning, All); diff --git a/Source/CogSample/CogSamplePlayerController.cpp b/Source/CogSample/CogSamplePlayerController.cpp index a0e75f5..5d2db4f 100644 --- a/Source/CogSample/CogSamplePlayerController.cpp +++ b/Source/CogSample/CogSamplePlayerController.cpp @@ -1,7 +1,9 @@ #include "CogSamplePlayerController.h" +#include "CogDebugLogMacros.h" #include "CogDefines.h" #include "CogSampleCharacter.h" +#include "CogSampleLogCategories.h" #include "CogSampleTargetAcquisition.h" #include "Net/UnrealNetwork.h" @@ -12,7 +14,6 @@ #include "CogEngineReplicator.h" #endif //USE_COG - //-------------------------------------------------------------------------------------------------------------------------- ACogSamplePlayerController::ACogSamplePlayerController() { @@ -31,14 +32,115 @@ void ACogSamplePlayerController::BeginPlay() } //-------------------------------------------------------------------------------------------------------------------------- -void ACogSamplePlayerController::AcknowledgePossession(APawn* P) +void ACogSamplePlayerController::OnPossess(APawn* InPawn) { - Super::AcknowledgePossession(P); + COG_LOG_OBJECT(LogCogPossession, ELogVerbosity::Verbose, this, TEXT("")); - if (ACogSampleCharacter* PossessedCharacter = Cast(P)) + ACogSampleCharacter* OldControlledCharacter = Cast(GetPawn()); + + //---------------------------------------------------------------------------------------------------------- + // Case of pawn was possessed too early by the server before a join complete + //---------------------------------------------------------------------------------------------------------- + if (InPawn != nullptr && InPawn->Controller != nullptr) { - PossessedCharacter->OnAcknowledgePossession(this); + COG_LOG_OBJECT(LogCogPossession, ELogVerbosity::Warning, this, TEXT("Asking %s to possess pawn %s more than once. Pawn will be restarted! Should call Unpossess first if possible."), *GetNameSafe(this), *GetNameSafe(InPawn)); + InPawn->Controller->UnPossess(); } + + Super::OnPossess(InPawn); + + if (InPawn != nullptr) + { + //on server, the pawn are not possessed on begin play callback, need to do it here. + if (IsLocalController()) + { + SetControlRotation(InPawn->GetActorRotation()); + } + } + + ControlledCharacter = Cast(InPawn); + + if (InitialControlledCharacter == nullptr) + { + InitialControlledCharacter = ControlledCharacter; + } + + OnControlledCharacterChanged.Broadcast(this, ControlledCharacter.Get(), OldControlledCharacter); +} + +//-------------------------------------------------------------------------------------------------------------------------- +void ACogSamplePlayerController::AcknowledgePossession(APawn* NewPawn) +{ + COG_LOG_OBJECT(LogCogPossession, ELogVerbosity::Verbose, this, TEXT("")); + + ACogSampleCharacter* OldControlledCharacter = Cast(AcknowledgedPawn); + + Super::AcknowledgePossession(NewPawn); + + if (InitialControlledCharacter == nullptr) + { + InitialControlledCharacter = Cast(NewPawn); + } + + if (ControlledCharacter != nullptr) + { + ControlledCharacter->AcknowledgeUnpossession(); + } + + ControlledCharacter = Cast(NewPawn); + ControlledCharacter->AcknowledgePossession(this); + + OnControlledCharacterChanged.Broadcast(this, ControlledCharacter.Get(), OldControlledCharacter); +} + +//-------------------------------------------------------------------------------------------------------------------------- +void ACogSamplePlayerController::ControlCharacter(ACogSampleCharacter* NewCharacter) +{ + if (NewCharacter == nullptr || GetPawn() == NewCharacter) + { + return; + } + + //------------------------------------------------------------------------------------------- + // Unplug the current controller so it doesn't conflict with the newly assigned controller + //------------------------------------------------------------------------------------------- + AController* OldController = NewCharacter->GetController(); + if (OldController != nullptr) + { + COG_LOG_OBJECT(LogCogPossession, ELogVerbosity::Verbose, this, TEXT("%s unpossess %s"), *GetNameSafe(OldController), *GetNameSafe(NewCharacter)); + OldController->UnPossess(); + } + + //------------------------------------------------------------------------------------------- + // We will need to replug the initial controller of the character we currently control + //------------------------------------------------------------------------------------------- + ACogSampleCharacter* OldCharacter = Cast(GetPawn()); + + //------------------------------------------------------------------------------------------- + // Unpossess before possession to prevent a warning + //------------------------------------------------------------------------------------------- + COG_LOG_OBJECT(LogCogPossession, ELogVerbosity::Verbose, this, TEXT("%s unpossess %s"), *GetNameSafe(this), *GetNameSafe(GetPawn())); + UnPossess(); + + COG_LOG_OBJECT(LogCogPossession, ELogVerbosity::Verbose, this, TEXT("%s possess %s"), *GetNameSafe(this), *GetNameSafe(NewCharacter)); + Possess(NewCharacter); + + //------------------------------------------------------------------------------------------- + // Replug the initial controller on the old character. For example, replug the initial + // AI controller of an AI when the player finishes controlling it. This needs to be done + // after the Possess call. + //------------------------------------------------------------------------------------------- + if (OldCharacter != nullptr && OldCharacter->InitialController != nullptr && OldCharacter->InitialController != this) + { + COG_LOG_OBJECT(LogCogPossession, ELogVerbosity::Verbose, this, TEXT("%s possess %s"), *GetNameSafe(OldCharacter->InitialController), *GetNameSafe(OldCharacter)); + OldCharacter->InitialController->Possess(OldCharacter); + } +} + +//-------------------------------------------------------------------------------------------------------------------------- +void ACogSamplePlayerController::ResetControlledPawn() +{ + ControlCharacter(InitialControlledCharacter.Get()); } //-------------------------------------------------------------------------------------------------------------------------- @@ -46,13 +148,22 @@ void ACogSamplePlayerController::Tick(float DeltaSeconds) { Super::Tick(DeltaSeconds); - if (TargetAcquisition != nullptr) - { - TArray TagretToIgnore; - FCogSampleTargetAcquisitionResult Result; - TargetAcquisition->FindBestTarget(this, TagretToIgnore, nullptr, true, FVector2D::ZeroVector, false, Result); - SetTarget(Result.Target); + TickTargeting(DeltaSeconds); +} + +//-------------------------------------------------------------------------------------------------------------------------- +void ACogSamplePlayerController::TickTargeting(float DeltaSeconds) +{ + if (TargetAcquisition == nullptr) + { + SetTarget(nullptr); + return; } + + TArray TagretToIgnore; + FCogSampleTargetAcquisitionResult Result; + TargetAcquisition->FindBestTarget(this, TagretToIgnore, nullptr, true, FVector2D::ZeroVector, false, Result); + SetTarget(Result.Target); } //-------------------------------------------------------------------------------------------------------------------------- diff --git a/Source/CogSample/CogSamplePlayerController.h b/Source/CogSample/CogSamplePlayerController.h index 840bf3d..9b18046 100644 --- a/Source/CogSample/CogSamplePlayerController.h +++ b/Source/CogSample/CogSamplePlayerController.h @@ -2,15 +2,17 @@ #include "CoreMinimal.h" #include "AbilitySystemInterface.h" -#include "CogSampleDamageEvent.h" #include "GameFramework/PlayerController.h" #include "CogSamplePlayerController.generated.h" class UCogSampleTargetAcquisition; +class ACogSampleCharacter; //-------------------------------------------------------------------------------------------------------------------------- DECLARE_DYNAMIC_MULTICAST_DELEGATE_ThreeParams(FCogSampleTargetChangedEventDelegate, ACogSamplePlayerController*, Controller, AActor*, NewTarget, AActor*, OldTarget); +DECLARE_DYNAMIC_MULTICAST_DELEGATE_ThreeParams(FCogSampleControlledCharacterChangedEventDelegate, ACogSamplePlayerController*, Controller, ACogSampleCharacter*, NewCharacter, ACogSampleCharacter*, OldCharacter); + //-------------------------------------------------------------------------------------------------------------------------- UCLASS(config=Game) class ACogSamplePlayerController : public APlayerController @@ -23,22 +25,53 @@ public: virtual void BeginPlay() override; - virtual void AcknowledgePossession(APawn* P); + virtual void Tick(float DeltaSeconds) override; - virtual void Tick(float DeltaSeconds); + //---------------------------------------------------------------------------------------------------------------------- + // Control + //---------------------------------------------------------------------------------------------------------------------- + virtual void OnPossess(APawn* NewPawn) override; + virtual void AcknowledgePossession(APawn* NewPawn) override; + + UFUNCTION(BlueprintCallable) + void ControlCharacter(ACogSampleCharacter* NewCharacter); + + UFUNCTION(BlueprintCallable) + void ResetControlledPawn(); + + UPROPERTY(BlueprintAssignable) + FCogSampleControlledCharacterChangedEventDelegate OnControlledCharacterChanged; + + //---------------------------------------------------------------------------------------------------------------------- + // Targeting + //---------------------------------------------------------------------------------------------------------------------- void SetTarget(AActor* Value); AActor* GetTarget() const { return Target.Get(); } + UPROPERTY(BlueprintAssignable) FCogSampleTargetChangedEventDelegate OnTargetChanged; - UPROPERTY(BlueprintAssignable) - FCogSampleDamageEventDelegate OnPawnDealtDamage; - private: + //---------------------------------------------------------------------------------------------------------------------- + // Control + //---------------------------------------------------------------------------------------------------------------------- + + UPROPERTY(BlueprintReadonly, meta = (AllowPrivateAccess = "true")) + TWeakObjectPtr ControlledCharacter = nullptr; + + UPROPERTY(BlueprintReadonly, meta = (AllowPrivateAccess = "true")) + TWeakObjectPtr InitialControlledCharacter = nullptr; + + //---------------------------------------------------------------------------------------------------------------------- + // Targeting + //---------------------------------------------------------------------------------------------------------------------- + + virtual void TickTargeting(float DeltaSeconds); + UFUNCTION(Reliable, Server) void Server_SetTarget(AActor* Value); diff --git a/Source/CogSample/CogSampleRootMotionParams.h b/Source/CogSample/CogSampleRootMotionParams.h index ab97d02..dc870d4 100644 --- a/Source/CogSample/CogSampleRootMotionParams.h +++ b/Source/CogSample/CogSampleRootMotionParams.h @@ -15,16 +15,16 @@ struct FCogSampleRootMotionParams public: UPROPERTY(EditAnywhere, BlueprintReadWrite) - AActor* Instigator; + AActor* Instigator = nullptr; UPROPERTY(EditAnywhere, BlueprintReadWrite) - AActor* Causer; + AActor* Causer = nullptr; UPROPERTY(EditAnywhere, BlueprintReadWrite) TSubclassOf Effect; UPROPERTY(EditAnywhere, BlueprintReadWrite) - FRotator Rotation; + FRotator Rotation = FRotator::ZeroRotator; UPROPERTY(EditAnywhere, BlueprintReadWrite) bool IsAdditive = false;