// 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/HUD/Announcement.h" #include "Blaster/HUD/BlasterHUD.h" #include "Blaster/HUD/CharacterOverlay.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::Tick(float DeltaTime) { Super::Tick(DeltaTime); SetHUDTime(); CheckTimeSync(DeltaTime); PollInit(); } 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->AddAnnouncement(); } } 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 { bInitializeCharacterOverlay = true; HUDHealth = Health; HUDMaxHealth = MaxHealth; } } 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 { bInitializeCharacterOverlay = 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 { bInitializeCharacterOverlay = 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)); } } 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)); } } 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->WarmupTime; if (bHUDValid) { if (CountdownTime < 0.f) { BlasterHUD->Announcement->WarmupTime->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->WarmupTime->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 = CooldownTime + WarmupTime + MatchTime - GetServerTime() + LevelStartingTime; uint32 SecondsLeft = FMath::CeilToInt(TimeLeft); if (HasAuthority()) { BlasterGameMode = BlasterGameMode == nullptr ? Cast(UGameplayStatics::GetGameMode(this)) : BlasterGameMode; if (BlasterGameMode) { SecondsLeft = FMath::CeilToInt(BlasterGameMode->GetCountdownTime() + LevelStartingTime); } } if (CountdownInt != SecondsLeft) { if (MatchState == MatchState::WaitingToStart || MatchState == MatchState::Cooldown) { SetHUDAnnouncementCountdown(TimeLeft); } if (MatchState == MatchState::InProgress) { SetHUDMatchCountdown(TimeLeft); } } CountdownInt = SecondsLeft; } void ABlasterPlayerController::PollInit() { if (CharacterOverlay == nullptr) { if (BlasterHUD && BlasterHUD->CharacterOverlay) { CharacterOverlay = BlasterHUD->CharacterOverlay; if (CharacterOverlay) { SetHUDHealth(HUDHealth, HUDMaxHealth); SetHUDScore(HUDScore); SetHUDDefeats(HUDDefeats); } } } } 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; float CurrentServerTime = TimeServerReceivedClientRequest + (0.5f * RoundTripTime); 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) { BlasterHUD->AddCharacterOverlay(); if (BlasterHUD->Announcement) { BlasterHUD->Announcement->SetVisibility(ESlateVisibility::Hidden); } } } void ABlasterPlayerController::HandleCooldown() { BlasterHUD = BlasterHUD == nullptr ? Cast(GetHUD()) : BlasterHUD; if (BlasterHUD) { BlasterHUD->CharacterOverlay->RemoveFromParent(); bool bHUDValid = BlasterHUD->Announcement && BlasterHUD->Announcement->AnnouncementText && BlasterHUD->Announcement->InfoText; if (bHUDValid) { BlasterHUD->Announcement->SetVisibility(ESlateVisibility::Visible); FString AnnouncementText("New match starts in:"); BlasterHUD->Announcement->AnnouncementText->SetText(FText::FromString(AnnouncementText)); BlasterHUD->Announcement->InfoText->SetText(FText()); } } ABlasterCharacter* BlasterCharacter = Cast(GetPawn()); if (BlasterCharacter && BlasterCharacter->GetCombat()) { BlasterCharacter->bDisableGameplay = true; BlasterCharacter->GetCombat()->FireButtonPressed(false); } }