#include "GasaCharacter.h" #include "AbilitySystemComponent.h" #include "Camera/CameraComponent.h" #include "Components/CapsuleComponent.h" #include "GameFramework/CharacterMovementComponent.h" #include "GameFramework/SpringArmComponent.h" #include "Kismet/KismetSystemLibrary.h" #include "AbilitySystem/GasaAbilitySystemComponent.h" #include "AbilitySystem/GasaAttributeSet.h" #include "Components/SkeletalMeshComponent.h" #include "Engine/PostProcessVolume.h" #include "Game/GasaGameInstance.h" #include "Game/GasaLevelScriptActor.h" #include "Game/GasaPlayerController.h" #include "Materials/MaterialInstanceDynamic.h" #include "Networking/GasaNetLibrary_Inlines.h" using namespace Gasa; AGasaCharacter::AGasaCharacter() { PrimaryActorTick.bCanEverTick = false; HighlightColor = FLinearColor(0.8, 0.32, 0.05f, 1.f); UCharacterMovementComponent* Movement = GetCharacterMovement(); Movement->bOrientRotationToMovement = true; Movement->bConstrainToPlane = true; Movement->bSnapToPlaneAtStart = true; Movement->RotationRate = FRotator(0.0, 400.f, 0.0); bUseControllerRotationPitch = false; bUseControllerRotationRoll = false; bUseControllerRotationYaw = false; USceneComponent* root_component = GetRootComponent(); USkeletalMeshComponent* mesh = GetMesh(); Weapon = CreateDefaultSubobject("Weapon"); Weapon->SetupAttachment(mesh, FName("WeaponAttach")); Weapon->SetCollisionEnabled(ECollisionEnabled::NoCollision); if (bAutoAbilitySystem) { AbilitySystem = CreateDefaultSubobject("Ability System"); AbilitySystem->SetIsReplicated(true); AbilitySystem->SetReplicationMode(EGameplayEffectReplicationMode::Minimal); Attributes = CreateDefaultSubobject("Attributes"); } // Replication bReplicates = false; bNetLoadOnClient = true; NetDormancy = DORM_Awake; NetCullDistanceSquared = NetCullDist_Medium; NetUpdateFrequency = 30.0f; MinNetUpdateFrequency = 5.0f; NetPriority = 2.0f; ACharacter::SetReplicateMovement(true); } #pragma region Ability System void AGasaCharacter::ApplyEffectToSelf(TSubclassOf GE, float Level) { UAbilitySystemComponent* ASC = GetAbilitySystemComponent(); ensure(ASC); ensure(GE); FGameplayEffectContextHandle Context = ASC->MakeEffectContext(); FGameplayEffectSpecHandle Spec = ASC->MakeOutgoingSpec(GE, Level, Context ); ASC->ApplyGameplayEffectSpecToTarget( * Spec.Data, ASC ); } void AGasaCharacter::InitDefaultAttributes() { UAbilitySystemComponent* ASC = GetAbilitySystemComponent(); ensure(ASC); ensure(DefaultVitalAttributes); ensure(DefaultPrimaryAttributes); ensure(DefaultSecondaryAttributes); FGameplayEffectContextHandle Context = ASC->MakeEffectContext(); Context.AddSourceObject(this); FGameplayEffectSpecHandle SpecPrimary = ASC->MakeOutgoingSpec(DefaultPrimaryAttributes, 1.0f, Context ); FGameplayEffectSpecHandle SpecSecondary = ASC->MakeOutgoingSpec(DefaultSecondaryAttributes, 1.0f, Context ); FGameplayEffectSpecHandle SpecVital = ASC->MakeOutgoingSpec(DefaultVitalAttributes, 1.0f, Context ); ASC->ApplyGameplayEffectSpecToTarget( * SpecPrimary.Data, ASC ); ASC->ApplyGameplayEffectSpecToTarget( * SpecSecondary.Data, ASC ); ASC->ApplyGameplayEffectSpecToTarget( * SpecVital.Data, ASC ); } #pragma endregion Ability System #pragma region GameFramework void AGasaCharacter::Controller_OnPawnPossessed() { NetLog("Controller confirmed possession."); // Do stuff here that you needed to wait for the player controller be aware of you for. BP_Controller_OnPawnPossessed(); if (Event_OnPawnReady.IsBound()) Event_OnPawnReady.Broadcast(); } void AGasaCharacter::ServerRPC_R_NotifyClientPawnReady_Implementation() { Event_OnPawnReady.Broadcast(); } #pragma endregion GameFramework #pragma region Highlight void AGasaCharacter::SetHighlight(EHighlight Desired) { HighlightState = Desired; } #pragma endregion Highlight #pragma region Pawn void AGasaCharacter::OnRep_PlayerState() { Super::OnRep_PlayerState(); } void AGasaCharacter::PossessedBy(AController* NewController) { NetLog("Pawn possessed."); AController* OldController; // APawn::PossessedBy { SetOwner(NewController); OldController = Controller; Controller = NewController; ForceNetUpdate(); #if UE_WITH_IRIS // The owning connection depends on the Controller having the new value. UpdateOwningNetConnection(); #endif if (Controller->PlayerState != nullptr) SetPlayerState(Controller->PlayerState); if (APlayerController* PlayerController = Cast(Controller)) { if (GetNetMode() != NM_Standalone) { SetReplicates(true); SetAutonomousProxy(true); } } else CopyRemoteRoleFrom(GetDefault()); } if (AGasaPlayerController* PC = Cast(NewController)) { PC->Event_OnPawnPossessed.AddUniqueDynamic(this, & ThisClass::Controller_OnPawnPossessed); } else { NetLog("Controller assigned to GasaCharacter is not derived from GasaPlayerController.", ELogV::Warning); NetLog("Controller: Name: " + NewController->GetName() + " Class: " + NewController->GetClass()->GetName(), ELogV::Warning); } // cont. APawn::PossessedBy { // Dispatch Blueprint event if necessary if (OldController != NewController) { ReceivePossessed(Controller); NotifyControllerChanged(); } } // ACharacter::PossessedBy { // If we are controlled remotely, set animation timing to be driven by client's network updates. So timing and events remain in sync. if (GetMesh() && IsReplicatingMovement() && (GetRemoteRole() == ROLE_AutonomousProxy && GetNetConnection() != nullptr)) GetMesh()->bOnlyAllowAutonomousTickPose = true; } #if 1 // if (bAutoAbilitySystem) // { // // Note(Ed): For the player character; this is manually called by the player controller in NetOwner_Ready() // AbilitySystem->InitAbilityActorInfo(this, this); // Cast(AbilitySystem)->OnAbilityActorInfoSet(); // // InitDefaultAttributes(); // } #endif } void AGasaCharacter::SetPlayerDefaults() { Super::SetPlayerDefaults(); } void AGasaCharacter::SetupPlayerInputComponent(UInputComponent* PlayerInputComponent) { Super::SetupPlayerInputComponent(PlayerInputComponent); } #pragma endregion Pawn #pragma region Actor void AGasaCharacter::BeginPlay() { Super::BeginPlay(); // TODO(Ed): Find out if this is the best spot todo this // There is also OnPossessed, PostInitializeComponents, etc... if (bAutoAbilitySystem) { // Note(Ed): For the player character; this is manually called by the player controller in NetOwner_Ready() AbilitySystem->InitAbilityActorInfo(this, this); Cast(AbilitySystem)->OnAbilityActorInfoSet(); InitDefaultAttributes(); } } void AGasaCharacter::Tick(float DeltaSeconds) { Super::Tick(DeltaSeconds); USkeletalMeshComponent* mesh = GetMesh(); switch (HighlightState) { case EHighlight::Disabled: { mesh->SetRenderCustomDepth(false); mesh->SetCustomDepthStencilValue(0.f); Weapon->SetRenderCustomDepth(false); Weapon->SetCustomDepthStencilValue(0.f); } break; case EHighlight::Enabled: { mesh->SetRenderCustomDepth(true); mesh->SetCustomDepthStencilValue(HighlightStencilDepth); Weapon->SetRenderCustomDepth(true); Weapon->SetCustomDepthStencilValue(HighlightStencilDepth); APostProcessVolume* PPV = Gasa::GetLevelActor(this)->GlobalPPV; TObjectPtr Blendable = PPV->Settings.WeightedBlendables.Array[0].Object; UMaterialInstanceDynamic* MID = Cast(Blendable); MID->SetVectorParameterValue("Depth Highlight Color", HighlightColor); #if 0 UCapsuleComponent* Capsule = GetCapsuleComponent(); UKismetSystemLibrary::DrawDebugCapsule(this , Capsule->GetComponentLocation() , Capsule->GetScaledCapsuleHalfHeight()^ , Capsule->GetScaledCapsuleRadius() , Capsule->GetComponentRotation() , HighlightColor , 0.f , 1.f ); #endif } break; } } #pragma endregion Actor