// 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 DeltaSeconds) { Super::Tick(DeltaSeconds); SetHUDTime(); CheckTimeSync(DeltaSeconds); PollInit(); } void ABlasterPlayerController::OnPossess(APawn* InPawn) { Super::OnPossess(InPawn); if (const ABlasterCharacter* BlasterCharacter = Cast(InPawn)) { SetHUDHealth(BlasterCharacter->GetHealth(), BlasterCharacter->GetMaxHealth()); } } void ABlasterPlayerController::ReceivedPlayer() { Super::ReceivedPlayer(); if (IsLocalController()) { ServerRequestServerTime(GetWorld()->GetTimeSeconds()); } } void ABlasterPlayerController::CheckTimeSync(float DeltaSeconds) { TimeSyncRunningTime += DeltaSeconds; if (IsLocalController() && TimeSyncRunningTime > TimeSyncFrequency) { ServerRequestServerTime(GetWorld()->GetTimeSeconds()); TimeSyncRunningTime = 0.f; } } float ABlasterPlayerController::GetServerTime() { if (HasAuthority()) return GetWorld()->GetTimeSeconds(); return GetWorld()->GetTimeSeconds() + ClientServerDelta; } 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->AnnouncementMessage; if (bHUDValid) { const FString AnnouncementText("New match starts in:"); BlasterHUD->Announcement->AnnouncementText->SetText(FText::FromString(AnnouncementText)); BlasterHUD->Announcement->AnnouncementMessage->SetText(FText()); BlasterHUD->Announcement->SetVisibility(ESlateVisibility::Visible); } } ABlasterCharacter* BlasterCharacter = Cast(GetPawn()); if (BlasterCharacter && BlasterCharacter->GetCombat()) { BlasterCharacter->bDisableGameplay = true; BlasterCharacter->GetCombat()->FireButtonPressed(false); } } 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::ServerCheckMatchState_Implementation() { ABlasterGameMode* GameMode = Cast(UGameplayStatics::GetGameMode(this)); if (GameMode) { LevelStartingTime = GameMode->LevelStartingTime; WarmupTime = GameMode->WarmupTime; MatchTime = GameMode->MatchTime; CooldownTime = GameMode->CooldownTime; MatchState = GameMode->GetMatchState(); ClientJoinMidGame(MatchState, WarmupTime, MatchTime, CooldownTime, LevelStartingTime); } } void ABlasterPlayerController::ClientJoinMidGame_Implementation(FName StateOfMatch, float Warmup, float Match, float Cooldown, float StartingTime) { LevelStartingTime = StartingTime; WarmupTime = Warmup; MatchTime = Match; CooldownTime = Cooldown; MatchState = StateOfMatch; OnMatchStateSet(MatchState); if (BlasterHUD && MatchState == MatchState::WaitingToStart) { BlasterHUD->AddAnnouncementOverlay(); } } void ABlasterPlayerController::ServerRequestServerTime_Implementation(float TimeOfClientRequest) { const float ServerTimeOfReceipt = GetWorld()->GetTimeSeconds(); ClientReportServerTime(TimeOfClientRequest, ServerTimeOfReceipt); } void ABlasterPlayerController::ClientReportServerTime_Implementation(float TimeOfClientRequest, float TimeServerReceivedClientRequest) { const float RoundTripTime = GetWorld()->GetTimeSeconds() - TimeOfClientRequest; const float CurrentServerTime = TimeServerReceivedClientRequest + 0.5f * RoundTripTime; ClientServerDelta = CurrentServerTime - GetWorld()->GetTimeSeconds(); } 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() + 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::SetHUDHealth(float Health, float MaxHealth) { BlasterHUD = BlasterHUD == nullptr ? Cast(GetHUD()) : BlasterHUD; bool bHUDValid = CharacterOverlay && CharacterOverlay->HealthBar && CharacterOverlay->HealthText; if (bHUDValid) { const float HealthPercent = Health / MaxHealth; BlasterHUD->CharacterOverlay->HealthBar->SetPercent(HealthPercent); const 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 = CharacterOverlay && CharacterOverlay->ScoreValue; if (bHUDValid) { const FString ScoreAmount = FString::Printf(TEXT("%d"), FMath::FloorToInt(Score)); BlasterHUD->CharacterOverlay->ScoreValue->SetText(FText::FromString(ScoreAmount)); } else { bInitializeCharacterOverlay = true; HUDScore = Score; } } void ABlasterPlayerController::SetHUDDefeats(int32 Defeats) { BlasterHUD = BlasterHUD == nullptr ? Cast(GetHUD()) : BlasterHUD; bool bHUDValid = CharacterOverlay && CharacterOverlay->DefeatsValue; if (bHUDValid) { const FString DefeatsAmount = FString::Printf(TEXT("%d"), Defeats); BlasterHUD->CharacterOverlay->DefeatsValue->SetText(FText::FromString(DefeatsAmount)); } else { bInitializeCharacterOverlay = true; HUDDefeats = Defeats; } } void ABlasterPlayerController::SetHUDWeaponAmmo(int32 Ammo) { BlasterHUD = BlasterHUD == nullptr ? Cast(GetHUD()) : BlasterHUD; bool bHUDValid = CharacterOverlay && CharacterOverlay->WeaponAmmoValue; if (bHUDValid) { const FString WeaponAmmoAmount = FString::Printf(TEXT("%d"), Ammo); BlasterHUD->CharacterOverlay->WeaponAmmoValue->SetText(FText::FromString(WeaponAmmoAmount)); } } void ABlasterPlayerController::SetHUDCarriedAmmo(int32 Ammo) { BlasterHUD = BlasterHUD == nullptr ? Cast(GetHUD()) : BlasterHUD; bool bHUDValid = CharacterOverlay && CharacterOverlay->CarriedAmmoValue; if (bHUDValid) { const FString CarriedAmmoAmount = FString::Printf(TEXT("%d"), Ammo); BlasterHUD->CharacterOverlay->CarriedAmmoValue->SetText(FText::FromString(CarriedAmmoAmount)); } } void ABlasterPlayerController::SetHUDMatchCountdown(float CountdownTime) { BlasterHUD = BlasterHUD == nullptr ? Cast(GetHUD()) : BlasterHUD; bool bHUDValid = CharacterOverlay && CharacterOverlay->MatchCountdownText; if (bHUDValid) { if (CountdownTime < 0.f) { BlasterHUD->CharacterOverlay->MatchCountdownText->SetText(FText()); return; } const int32 Minutes = FMath::FloorToInt(CountdownTime / 60); const int32 Seconds = CountdownTime - Minutes * 60; const 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->AnnouncementText && BlasterHUD->Announcement->CountdownText; if (bHUDValid) { if (CountdownTime < 0.f) { BlasterHUD->Announcement->CountdownText->SetText(FText()); return; } const int32 Minutes = FMath::FloorToInt(CountdownTime / 60); const int32 Seconds = CountdownTime - Minutes * 60; const FString CountdownText = FString::Printf(TEXT("%02d:%02d"), Minutes, Seconds); BlasterHUD->Announcement->CountdownText->SetText(FText::FromString(CountdownText)); } }