diff --git a/Source/Blaster/PlayerController/BlasterPlayerController.cpp b/Source/Blaster/PlayerController/BlasterPlayerController.cpp index ff10229..ee231cd 100644 --- a/Source/Blaster/PlayerController/BlasterPlayerController.cpp +++ b/Source/Blaster/PlayerController/BlasterPlayerController.cpp @@ -22,6 +22,8 @@ void ABlasterPlayerController::Tick(float DeltaSeconds) Super::Tick(DeltaSeconds); SetHUDTime(); + + CheckTimeSync(DeltaSeconds); } void ABlasterPlayerController::OnPossess(APawn* InPawn) @@ -34,15 +36,56 @@ void ABlasterPlayerController::OnPossess(APawn* InPawn) } } +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::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() { - const uint32 SecondsLeft = FMath::CeilToInt(MatchTime - GetWorld()->GetTimeSeconds()); + const uint32 SecondsLeft = FMath::CeilToInt(MatchTime - GetServerTime()); if (CountdownInt != SecondsLeft) { - SetHUDMatchCountdown(MatchTime - GetWorld()->GetTimeSeconds()); + SetHUDMatchCountdown(MatchTime - GetServerTime()); } - + CountdownInt = SecondsLeft; } @@ -54,7 +97,7 @@ void ABlasterPlayerController::SetHUDHealth(float Health, float MaxHealth) BlasterHUD->CharacterOverlay && BlasterHUD->CharacterOverlay->HealthBar && BlasterHUD->CharacterOverlay->HealthText; - + if (bHUDValid) { const float HealthPercent = Health / MaxHealth; @@ -136,7 +179,7 @@ void ABlasterPlayerController::SetHUDMatchCountdown(float CountdownTime) { int32 Minutes = FMath::FloorToInt(CountdownTime / 60); int32 Seconds = CountdownTime - Minutes * 60; - + const FString CountdownText = FString::Printf(TEXT("%02d:%02d"), Minutes, Seconds); BlasterHUD->CharacterOverlay->MatchCountdownText->SetText(FText::FromString(CountdownText)); } diff --git a/Source/Blaster/PlayerController/BlasterPlayerController.h b/Source/Blaster/PlayerController/BlasterPlayerController.h index c4be8a6..61ddfb8 100644 --- a/Source/Blaster/PlayerController/BlasterPlayerController.h +++ b/Source/Blaster/PlayerController/BlasterPlayerController.h @@ -18,6 +18,7 @@ public: virtual void Tick(float DeltaSeconds) override; virtual void OnPossess(APawn* InPawn) override; + virtual void ReceivedPlayer() override; // Sync with server clock as soon as possible void SetHUDHealth(float Health, float MaxHealth); void SetHUDScore(float Score); @@ -25,12 +26,33 @@ public: void SetHUDWeaponAmmo(int32 Ammo); void SetHUDCarriedAmmo(int32 Ammo); void SetHUDMatchCountdown(float CountdownTime); + + // Synced with server world clock + virtual float GetServerTime(); protected: virtual void BeginPlay() override; + void CheckTimeSync(float DeltaSeconds); void SetHUDTime(); - + + // Sync time between client and server + + // Requests the current server time, passing in the client's time when the request was sent + UFUNCTION(Server, Reliable) + void ServerRequestServerTime(float TimeOfClientRequest); + + // Reports the current server time to the client in response to ServerRequestServerTime + UFUNCTION(Client, Reliable) + void ClientReportServerTime(float TimeOfClientRequest, float TimeServerReceivedClientRequest); + + // Difference between client and server time + float ClientServerDelta = 0; + + UPROPERTY(EditAnywhere, Category = Time) + float TimeSyncFrequency = 10.f; + + float TimeSyncRunningTime = 0.f; private: UPROPERTY()