// Fill out your copyright notice in the Description page of Project Settings. #include "BlasterPlayerController.h" #include "Blaster/Character/BlasterCharacter.h" #include "Blaster/Components/CombatComponent.h" #include "Blaster/GameMode/BlasterGameMode.h" #include "Blaster/GameState/BlasterGameState.h" #include "Blaster/HUD/Announcement.h" #include "Blaster/HUD/BlasterHUD.h" #include "Blaster/HUD/CharacterOverlay.h" #include "Blaster/HUD/DebugWidget.h" #include "Blaster/PlayerState/BlasterPlayerState.h" #include "Components/ProgressBar.h" #include "Components/TextBlock.h" #include "GameFramework/GameMode.h" #include "Kismet/GameplayStatics.h" #include "Net/UnrealNetwork.h" void ABlasterPlayerController::BeginPlay() { Super::BeginPlay(); BlasterHUD = Cast(GetHUD()); ServerCheckMatchState(); } void ABlasterPlayerController::GetLifetimeReplicatedProps(TArray& OutLifetimeProps) const { Super::GetLifetimeReplicatedProps(OutLifetimeProps); DOREPLIFETIME(ABlasterPlayerController, MatchState); } void ABlasterPlayerController::SetDebugMsg1(FString Key, FString Value) { bool bHUDValid = BlasterHUD && BlasterHUD->DebugWidget && BlasterHUD->DebugWidget->DebugMsg1; if (bHUDValid) BlasterHUD->DebugWidget->DebugMsg1->SetText(FText::FromString(Key.Append(Value))); } void ABlasterPlayerController::Tick(float DeltaTime) { Super::Tick(DeltaTime); SetHUDTime(); CheckTimeSync(DeltaTime); PollInit(); CheckPing(DeltaTime); if (DebugWidget) { SetDebugMsg1(TEXT("GetWorld()->GetTimeSeconds(): "), FString::Printf(TEXT("%02f"), GetWorld()->GetTimeSeconds())); SetDebugMsg2(TEXT("GetServerTime(): "), FString::Printf(TEXT("%02f"), GetServerTime())); SetDebugMsg3(TEXT("ClientServerDelta: "), FString::Printf(TEXT("%f"), ClientServerDelta)); SetDebugMsg4(TEXT("LevelStartingTime: "), FString::Printf(TEXT("%f"), LevelStartingTime)); SetDebugMsg5(TEXT("CountdownInt: "), FString::Printf(TEXT("%d"), CountdownInt)); } } void ABlasterPlayerController::CheckPing(float DeltaTime) { HighPingRunningTime += DeltaTime; if (HighPingRunningTime > CheckPingFrequency) { HighPingRunningTime = 0.f; PlayerState = PlayerState == nullptr ? GetPlayerState() : PlayerState; if (PlayerState) { UE_LOG(LogTemp, Warning, TEXT("Ping: %f"), PlayerState->GetPingInMilliseconds()); if (PlayerState->GetPingInMilliseconds() > HighPingThreshold) { HighPingWarning(); PingAnimationRunningTime = 0.f; } } } bool bHighPingAnimationPlaying = BlasterHUD && BlasterHUD->CharacterOverlay && BlasterHUD->CharacterOverlay->HighPingAnimation && BlasterHUD->CharacterOverlay->IsAnimationPlaying(BlasterHUD->CharacterOverlay->HighPingAnimation); if (bHighPingAnimationPlaying) { PingAnimationRunningTime += DeltaTime; if (PingAnimationRunningTime > HighPingDuration) { StopHighPingWarning(); } } } void ABlasterPlayerController::SetDebugMsg2(FString Key, FString Value) { bool bHUDValid = BlasterHUD && BlasterHUD->DebugWidget && BlasterHUD->DebugWidget->DebugMsg2; if (bHUDValid) BlasterHUD->DebugWidget->DebugMsg2->SetText(FText::FromString(Key.Append(Value))); } void ABlasterPlayerController::SetDebugMsg3(FString Key, FString Value) { bool bHUDValid = BlasterHUD && BlasterHUD->DebugWidget && BlasterHUD->DebugWidget->DebugMsg3; if (bHUDValid) BlasterHUD->DebugWidget->DebugMsg3->SetText(FText::FromString(Key.Append(Value))); } void ABlasterPlayerController::SetDebugMsg4(FString Key, FString Value) { bool bHUDValid = BlasterHUD && BlasterHUD->DebugWidget && BlasterHUD->DebugWidget->DebugMsg4; if (bHUDValid) BlasterHUD->DebugWidget->DebugMsg4->SetText(FText::FromString(Key.Append(Value))); } void ABlasterPlayerController::SetDebugMsg5(FString Key, FString Value) { bool bHUDValid = BlasterHUD && BlasterHUD->DebugWidget && BlasterHUD->DebugWidget->DebugMsg5; if (bHUDValid) BlasterHUD->DebugWidget->DebugMsg5->SetText(FText::FromString(Key.Append(Value))); } void ABlasterPlayerController::SetDebugMsg6(FString Key, FString Value) { bool bHUDValid = BlasterHUD && BlasterHUD->DebugWidget && BlasterHUD->DebugWidget->DebugMsg6; if (bHUDValid) BlasterHUD->DebugWidget->DebugMsg6->SetText(FText::FromString(Key.Append(Value))); } void ABlasterPlayerController::SetDebugMsg7(FString Key, FString Value) { bool bHUDValid = BlasterHUD && BlasterHUD->DebugWidget && BlasterHUD->DebugWidget->DebugMsg7; if (bHUDValid) BlasterHUD->DebugWidget->DebugMsg7->SetText(FText::FromString(Key.Append(Value))); } void ABlasterPlayerController::CheckTimeSync(float DeltaTime) { TimeSyncRunningTime += DeltaTime; if (IsLocalController() && TimeSyncRunningTime > TimeSyncFrequency) { ServerRequestServerTime(GetWorld()->GetTimeSeconds()); TimeSyncRunningTime = 0.f; } } void ABlasterPlayerController::ServerCheckMatchState_Implementation() { ABlasterGameMode* GameMode = Cast(UGameplayStatics::GetGameMode(this)); if (GameMode) { WarmupTime = GameMode->WarmupTime; MatchTime = GameMode->MatchTime; CooldownTime = GameMode->CooldownTime; LevelStartingTime = GameMode->LevelStartingTime; MatchState = GameMode->GetMatchState(); ClientJoinMidgame(MatchState, WarmupTime, MatchTime, CooldownTime, LevelStartingTime); } } void ABlasterPlayerController::ClientJoinMidgame_Implementation(FName StateOfMatch, float Warmup, float Match, float Cooldown, float StartingTime) { WarmupTime = Warmup; MatchTime = Match; CooldownTime = Cooldown; LevelStartingTime = StartingTime; MatchState = StateOfMatch; OnMatchStateSet(MatchState); if (BlasterHUD && MatchState == MatchState::WaitingToStart) { BlasterHUD->AddAnnouncementOverlay(); } } void ABlasterPlayerController::OnPossess(APawn* InPawn) { Super::OnPossess(InPawn); ABlasterCharacter* BlasterCharacter = Cast(InPawn); if (BlasterCharacter) { SetHUDHealth(BlasterCharacter->GetHealth(), BlasterCharacter->GetMaxHealth()); } } void ABlasterPlayerController::SetHUDHealth(float Health, float MaxHealth) { BlasterHUD = BlasterHUD == nullptr ? Cast(GetHUD()) : BlasterHUD; bool bHUDValid = BlasterHUD && BlasterHUD->CharacterOverlay && BlasterHUD->CharacterOverlay->HealthBar && BlasterHUD->CharacterOverlay->HealthText; if (bHUDValid) { const float HealthPercent = Health / MaxHealth; BlasterHUD->CharacterOverlay->HealthBar->SetPercent(HealthPercent); FString HealthText = FString::Printf(TEXT("%d/%d"), FMath::CeilToInt(Health), FMath::CeilToInt(MaxHealth)); BlasterHUD->CharacterOverlay->HealthText->SetText(FText::FromString(HealthText)); } else { bInitializeHealth = true; HUDHealth = Health; HUDMaxHealth = MaxHealth; } } void ABlasterPlayerController::SetHUDShield(float Shield, float MaxShield) { BlasterHUD = BlasterHUD == nullptr ? Cast(GetHUD()) : BlasterHUD; bool bHUDValid = BlasterHUD && BlasterHUD->CharacterOverlay && BlasterHUD->CharacterOverlay->ShieldBar && BlasterHUD->CharacterOverlay->ShieldText; if (bHUDValid) { const float ShieldPercent = Shield / MaxShield; BlasterHUD->CharacterOverlay->ShieldBar->SetPercent(ShieldPercent); FString ShieldText = FString::Printf(TEXT("%d/%d"), FMath::CeilToInt(Shield), FMath::CeilToInt(MaxShield)); BlasterHUD->CharacterOverlay->ShieldText->SetText(FText::FromString(ShieldText)); } else { bInitializeShield = true; HUDShield = Shield; HUDMaxShield = MaxShield; } } void ABlasterPlayerController::SetHUDScore(float Score) { BlasterHUD = BlasterHUD == nullptr ? Cast(GetHUD()) : BlasterHUD; bool bHUDValid = BlasterHUD && BlasterHUD->CharacterOverlay && BlasterHUD->CharacterOverlay->ScoreValue; if (bHUDValid) { FString ScoreText = FString::Printf(TEXT("%d"), FMath::FloorToInt(Score)); BlasterHUD->CharacterOverlay->ScoreValue->SetText(FText::FromString(ScoreText)); } else { bInitializeScore = true; HUDScore = Score; } } void ABlasterPlayerController::SetHUDDefeats(int32 Defeats) { BlasterHUD = BlasterHUD == nullptr ? Cast(GetHUD()) : BlasterHUD; bool bHUDValid = BlasterHUD && BlasterHUD->CharacterOverlay && BlasterHUD->CharacterOverlay->DefeatsValue; if (bHUDValid) { FString DefeatsText = FString::Printf(TEXT("%d"), Defeats); BlasterHUD->CharacterOverlay->DefeatsValue->SetText(FText::FromString(DefeatsText)); } else { bInitializeDefeats = true; HUDDefeats = Defeats; } } void ABlasterPlayerController::SetHUDWeaponAmmo(int32 Ammo) { BlasterHUD = BlasterHUD == nullptr ? Cast(GetHUD()) : BlasterHUD; bool bHUDValid = BlasterHUD && BlasterHUD->CharacterOverlay && BlasterHUD->CharacterOverlay->WeaponAmmoValue; if (bHUDValid) { FString AmmoText = FString::Printf(TEXT("%d"), Ammo); BlasterHUD->CharacterOverlay->WeaponAmmoValue->SetText(FText::FromString(AmmoText)); } else { bInitializeHUDWeaponAmmo = true; HUDWeaponAmmo = Ammo; } } void ABlasterPlayerController::SetHUDCarriedAmmo(int32 Ammo) { BlasterHUD = BlasterHUD == nullptr ? Cast(GetHUD()) : BlasterHUD; bool bHUDValid = BlasterHUD && BlasterHUD->CharacterOverlay && BlasterHUD->CharacterOverlay->CarriedAmmoValue; if (bHUDValid) { FString AmmoText = FString::Printf(TEXT("%d"), Ammo); BlasterHUD->CharacterOverlay->CarriedAmmoValue->SetText(FText::FromString(AmmoText)); } else { bInitializeCarriedAmmo = true; HUDCarriedAmmo = Ammo; } } void ABlasterPlayerController::SetHUDGrenades(int32 Grenades) { BlasterHUD = BlasterHUD == nullptr ? Cast(GetHUD()) : BlasterHUD; bool bHUDValid = BlasterHUD && BlasterHUD->CharacterOverlay && BlasterHUD->CharacterOverlay->GrenadesAmount; if (bHUDValid) { FString GrenadesText = FString::Printf(TEXT("%d"), Grenades); BlasterHUD->CharacterOverlay->GrenadesAmount->SetText(FText::FromString(GrenadesText)); } else { bInitializeGrenades = true; HUDGrenades = Grenades; } } void ABlasterPlayerController::SetHUDMatchCountdown(float CountdownTime) { BlasterHUD = BlasterHUD == nullptr ? Cast(GetHUD()) : BlasterHUD; bool bHUDValid = BlasterHUD && BlasterHUD->CharacterOverlay && BlasterHUD->CharacterOverlay->MatchCountdownText; if (bHUDValid) { if (CountdownTime < 0.f) { BlasterHUD->CharacterOverlay->MatchCountdownText->SetText(FText()); return; } int32 Minutes = FMath::FloorToInt(CountdownTime / 60.f); int32 Seconds = CountdownTime - Minutes * 60; FString CountdownText = FString::Printf(TEXT("%02d:%02d"), Minutes, Seconds); BlasterHUD->CharacterOverlay->MatchCountdownText->SetText(FText::FromString(CountdownText)); } } void ABlasterPlayerController::SetHUDAnnouncementCountdown(float CountdownTime) { BlasterHUD = BlasterHUD == nullptr ? Cast(GetHUD()) : BlasterHUD; bool bHUDValid = BlasterHUD && BlasterHUD->Announcement && BlasterHUD->Announcement->CountdownText; if (bHUDValid) { if (CountdownTime < 0.f) { BlasterHUD->Announcement->CountdownText->SetText(FText()); return; } int32 Minutes = FMath::FloorToInt(CountdownTime / 60.f); int32 Seconds = CountdownTime - Minutes * 60; FString CountdownText = FString::Printf(TEXT("%02d:%02d"), Minutes, Seconds); BlasterHUD->Announcement->CountdownText->SetText(FText::FromString(CountdownText)); } } void ABlasterPlayerController::SetHUDTime() { float TimeLeft = 0.f; if (MatchState == MatchState::WaitingToStart) TimeLeft = WarmupTime - GetServerTime(); // + LevelStartingTime; else if (MatchState == MatchState::InProgress) TimeLeft = WarmupTime + MatchTime - GetServerTime(); // + LevelStartingTime; else if (MatchState == MatchState::Cooldown) TimeLeft = WarmupTime + MatchTime + CooldownTime - GetServerTime(); // + LevelStartingTime; uint32 SecondsLeft = FMath::CeilToInt(TimeLeft); if (HasAuthority()) { BlasterGameMode = BlasterGameMode == nullptr ? Cast(UGameplayStatics::GetGameMode(this)) : BlasterGameMode; if (BlasterGameMode) { SecondsLeft = FMath::CeilToInt(BlasterGameMode->GetCountdownTime()); } } if (CountdownInt != SecondsLeft) { if (MatchState == MatchState::WaitingToStart || MatchState == MatchState::Cooldown) { SetHUDAnnouncementCountdown(TimeLeft); } if (MatchState == MatchState::InProgress) { SetHUDMatchCountdown(TimeLeft); } } CountdownInt = SecondsLeft; } void ABlasterPlayerController::PollInit() { /* if (BlasterHUD && BlasterHUD->DebugWidget == nullptr) { BlasterHUD->AddDebugWidget(); if (BlasterHUD->DebugWidget) { DebugWidget = BlasterHUD->DebugWidget; } } */ if (CharacterOverlay == nullptr) { if (BlasterHUD && BlasterHUD->CharacterOverlay) { CharacterOverlay = BlasterHUD->CharacterOverlay; if (CharacterOverlay) { if (bInitializeHealth) SetHUDHealth(HUDHealth, HUDMaxHealth); if (bInitializeShield) SetHUDShield(HUDShield, HUDMaxShield); if (bInitializeScore) SetHUDScore(HUDScore); if (bInitializeDefeats) SetHUDDefeats(HUDDefeats); if (bInitializeCarriedAmmo) SetHUDCarriedAmmo(HUDCarriedAmmo); if (bInitializeHUDWeaponAmmo) SetHUDWeaponAmmo(HUDWeaponAmmo); ABlasterCharacter* BlasterCharacter = Cast(GetPawn()); if (BlasterCharacter && BlasterCharacter->GetCombat()) { if (bInitializeGrenades) SetHUDGrenades(BlasterCharacter->GetCombat()->GetGrenades()); } } } } } void ABlasterPlayerController::HighPingWarning() { BlasterHUD = BlasterHUD == nullptr ? Cast(GetHUD()) : BlasterHUD; bool bHUDValid = BlasterHUD && BlasterHUD->CharacterOverlay && BlasterHUD->CharacterOverlay->HighPingImage && BlasterHUD->CharacterOverlay->HighPingAnimation; if (bHUDValid) { BlasterHUD->CharacterOverlay->HighPingImage->SetOpacity(1.f); BlasterHUD->CharacterOverlay->PlayAnimation(BlasterHUD->CharacterOverlay->HighPingAnimation, 0.f, 5); } } void ABlasterPlayerController::StopHighPingWarning() { BlasterHUD = BlasterHUD == nullptr ? Cast(GetHUD()) : BlasterHUD; bool bHUDValid = BlasterHUD && BlasterHUD->CharacterOverlay && BlasterHUD->CharacterOverlay->HighPingImage && BlasterHUD->CharacterOverlay->HighPingAnimation; if (bHUDValid) { BlasterHUD->CharacterOverlay->HighPingImage->SetOpacity(0.f); if (BlasterHUD->CharacterOverlay->IsAnimationPlaying(BlasterHUD->CharacterOverlay->HighPingAnimation)) { BlasterHUD->CharacterOverlay->StopAnimation(BlasterHUD->CharacterOverlay->HighPingAnimation); } } } void ABlasterPlayerController::ServerRequestServerTime_Implementation(float TimeOfClientRequest) { float ServerTimeOfReceipt = GetWorld()->GetTimeSeconds(); ClientReportServerTime(TimeOfClientRequest, ServerTimeOfReceipt); } void ABlasterPlayerController::ClientReportServerTime_Implementation(float TimeOfClientRequest, float TimeServerReceivedClientRequest) { float RoundTripTime = GetWorld()->GetTimeSeconds() - TimeOfClientRequest; SingleTripTime = 0.5f * RoundTripTime; float CurrentServerTime = TimeServerReceivedClientRequest + SingleTripTime; ClientServerDelta = CurrentServerTime - GetWorld()->GetTimeSeconds(); } float ABlasterPlayerController::GetServerTime() { if (HasAuthority()) return GetWorld()->GetTimeSeconds(); return GetWorld()->GetTimeSeconds() + ClientServerDelta; } void ABlasterPlayerController::ReceivedPlayer() { Super::ReceivedPlayer(); if (IsLocalController()) { ServerRequestServerTime(GetWorld()->GetTimeSeconds()); } } void ABlasterPlayerController::OnMatchStateSet(FName State) { MatchState = State; if (MatchState == MatchState::InProgress) { HandleMatchHasStarted(); } else if (MatchState == MatchState::Cooldown) { HandleCooldown(); } } void ABlasterPlayerController::OnRep_MatchState() { if (MatchState == MatchState::InProgress) { HandleMatchHasStarted(); } else if (MatchState == MatchState::Cooldown) { HandleCooldown(); } } void ABlasterPlayerController::HandleMatchHasStarted() { BlasterHUD = BlasterHUD == nullptr ? Cast(GetHUD()) : BlasterHUD; if (BlasterHUD) { if (BlasterHUD->CharacterOverlay == nullptr) BlasterHUD->AddCharacterOverlay(); if (BlasterHUD->Announcement) { BlasterHUD->Announcement->SetVisibility(ESlateVisibility::Hidden); } } } void ABlasterPlayerController::HandleCooldown() { BlasterHUD = BlasterHUD == nullptr ? Cast(GetHUD()) : BlasterHUD; if (BlasterHUD) { if (BlasterHUD->CharacterOverlay) { BlasterHUD->CharacterOverlay->RemoveFromParent(); } bool bHUDValid = BlasterHUD->Announcement && BlasterHUD->Announcement->AnnouncementText && BlasterHUD->Announcement->AnnouncementMessage; if (bHUDValid) { BlasterHUD->Announcement->SetVisibility(ESlateVisibility::Visible); FString AnnouncementText("New match starts in:"); BlasterHUD->Announcement->AnnouncementText->SetText(FText::FromString(AnnouncementText)); ABlasterGameState* BlasterGameState = Cast(UGameplayStatics::GetGameState(this)); ABlasterPlayerState* BlasterPlayerState = GetPlayerState(); if (BlasterGameState && BlasterPlayerState) { TArray TopPlayers = BlasterGameState->TopScoringPlayers; FString InfoTextString; if (TopPlayers.Num() == 0) { InfoTextString = FString("There is no winner."); } else if (TopPlayers.Num() == 1 && TopPlayers[0] == BlasterPlayerState) { InfoTextString = FString("You are the winner!"); } else if (TopPlayers.Num() == 1) { InfoTextString = FString::Printf(TEXT("%s won!"), *TopPlayers[0]->GetPlayerName()); } else if (TopPlayers.Num() > 1) { InfoTextString = FString("Players tied for the win: \n"); for (auto TiedPlayers : TopPlayers) { InfoTextString.Append(FString::Printf(TEXT("%s\n"), *TiedPlayers->GetPlayerName())); } } BlasterHUD->Announcement->AnnouncementMessage->SetText(FText::FromString(InfoTextString)); } } } ABlasterCharacter* BlasterCharacter = Cast(GetPawn()); if (BlasterCharacter && BlasterCharacter->GetCombat()) { BlasterCharacter->bDisableGameplay = true; BlasterCharacter->GetCombat()->FireButtonPressed(false); } }