diff --git a/Source/Blaster/Character/BlasterCharacter.cpp b/Source/Blaster/Character/BlasterCharacter.cpp index 2a4802a..41e1cce 100644 --- a/Source/Blaster/Character/BlasterCharacter.cpp +++ b/Source/Blaster/Character/BlasterCharacter.cpp @@ -171,21 +171,15 @@ void ABlasterCharacter::OnRep_ReplicatedMovement() TimeSinceLastMovementReplication = 0.f; } -void ABlasterCharacter::Eliminated() +void ABlasterCharacter::Eliminated(bool bPlayerLeftGame) { if (Combat) Combat->DropWeapons(); - - MulticastEliminated(); - GetWorldTimerManager().SetTimer( - EliminationTimer, - this, - &ABlasterCharacter::EliminationTimerFinished, - EliminationDelay - ); + MulticastEliminated(bPlayerLeftGame); } -void ABlasterCharacter::MulticastEliminated_Implementation() +void ABlasterCharacter::MulticastEliminated_Implementation(bool bPlayerLeftGame) { + bLeftGame = bPlayerLeftGame; if (BlasterPlayerController) { BlasterPlayerController->SetHUDWeaponAmmo(0); @@ -237,15 +231,36 @@ void ABlasterCharacter::MulticastEliminated_Implementation() { ShowSniperScopeWidget(false); } + + GetWorldTimerManager().SetTimer( + EliminationTimer, + this, + &ABlasterCharacter::EliminationTimerFinished, + EliminationDelay + ); } void ABlasterCharacter::EliminationTimerFinished() { ABlasterGameMode* BlasterGameMode = GetWorld()->GetAuthGameMode(); - if (BlasterGameMode) + if (BlasterGameMode && !bLeftGame) { BlasterGameMode->RequestRespawn(this, Controller); } + if (bLeftGame && IsLocallyControlled()) + { + OnLeftGame.Broadcast(); + } +} + +void ABlasterCharacter::ServerLeaveGame_Implementation() +{ + ABlasterGameMode* BlasterGameMode = GetWorld()->GetAuthGameMode(); + BlasterPlayerState = BlasterPlayerState == nullptr ? GetPlayerState() : BlasterPlayerState; + if (BlasterGameMode && BlasterPlayerState) + { + BlasterGameMode->PlayerLeftGame(BlasterPlayerState); + } } void ABlasterCharacter::Destroyed() diff --git a/Source/Blaster/Character/BlasterCharacter.h b/Source/Blaster/Character/BlasterCharacter.h index a3dc13b..c9632c2 100644 --- a/Source/Blaster/Character/BlasterCharacter.h +++ b/Source/Blaster/Character/BlasterCharacter.h @@ -11,6 +11,8 @@ #include "Sound/SoundCue.h" #include "BlasterCharacter.generated.h" +DECLARE_DYNAMIC_MULTICAST_DELEGATE(FOnLeftGame); + UCLASS() class BLASTER_API ABlasterCharacter : public ACharacter, public IInteractWithCrosshairInterface { @@ -33,10 +35,10 @@ public: void PlayThrowGrenadeMontage(); void PlaySwapMontage(); - void Eliminated(); + void Eliminated(bool bPlayerLeftGame); UFUNCTION(NetMulticast, Reliable) - void MulticastEliminated(); + void MulticastEliminated(bool bPlayerLeftGame); UPROPERTY(Replicated) bool bDisableGameplay = false; @@ -53,6 +55,11 @@ public: TMap HitCollisionBoxes; bool bFinishedSwapping = false; + + UFUNCTION(Server, Reliable) + void ServerLeaveGame(); + + FOnLeftGame OnLeftGame; protected: virtual void BeginPlay() override; @@ -244,6 +251,8 @@ private: void EliminationTimerFinished(); + bool bLeftGame = false; + // Dissolve effect UPROPERTY(VisibleAnywhere) UTimelineComponent* DissolveTimeline; diff --git a/Source/Blaster/GameMode/BlasterGameMode.cpp b/Source/Blaster/GameMode/BlasterGameMode.cpp index 6596d07..f732d65 100644 --- a/Source/Blaster/GameMode/BlasterGameMode.cpp +++ b/Source/Blaster/GameMode/BlasterGameMode.cpp @@ -93,7 +93,7 @@ void ABlasterGameMode::PlayerEliminated(class ABlasterCharacter* EliminatedChara if (EliminatedCharacter) { - EliminatedCharacter->Eliminated(); + EliminatedCharacter->Eliminated(false); } } @@ -112,3 +112,18 @@ void ABlasterGameMode::RequestRespawn(ACharacter* EliminatedCharacter, AControll RestartPlayerAtPlayerStart(EliminatedController, PlayerStarts[Selection]); } } + +void ABlasterGameMode::PlayerLeftGame(ABlasterPlayerState* PlayerLeaving) +{ + if (PlayerLeaving == nullptr) return; + ABlasterGameState* BlasterGameState = GetGameState(); + if (BlasterGameState && BlasterGameState->TopScoringPlayers.Contains(PlayerLeaving)) + { + BlasterGameState->TopScoringPlayers.Remove(PlayerLeaving); + } + + if (ABlasterCharacter* CharacterLeaving = Cast(PlayerLeaving->GetPawn())) + { + CharacterLeaving->Eliminated(true); + } +} diff --git a/Source/Blaster/GameMode/BlasterGameMode.h b/Source/Blaster/GameMode/BlasterGameMode.h index ff28489..6ef388f 100644 --- a/Source/Blaster/GameMode/BlasterGameMode.h +++ b/Source/Blaster/GameMode/BlasterGameMode.h @@ -3,6 +3,7 @@ #pragma once #include "CoreMinimal.h" +#include "Blaster/PlayerState/BlasterPlayerState.h" #include "GameFramework/GameMode.h" #include "BlasterGameMode.generated.h" @@ -26,7 +27,8 @@ public: virtual void PlayerEliminated(class ABlasterCharacter* EliminatedCharacter, class ABlasterPlayerController* VictimController, class ABlasterPlayerController* AttackerController); virtual void RequestRespawn(ACharacter* EliminatedCharacter, AController* EliminatedController); - + void PlayerLeftGame(ABlasterPlayerState* PlayerLeaving); + UPROPERTY(EditDefaultsOnly) float WarmupTime = 10.f; diff --git a/Source/Blaster/HUD/ReturnToMainMenu.cpp b/Source/Blaster/HUD/ReturnToMainMenu.cpp index 74b65c1..b369a71 100644 --- a/Source/Blaster/HUD/ReturnToMainMenu.cpp +++ b/Source/Blaster/HUD/ReturnToMainMenu.cpp @@ -3,6 +3,7 @@ #include "ReturnToMainMenu.h" #include "MultiplayerSessionsSubsystem.h" +#include "Blaster/Character/BlasterCharacter.h" #include "Components/Button.h" #include "GameFramework/GameModeBase.h" @@ -74,12 +75,35 @@ void UReturnToMainMenu::MenuTearDown() } void UReturnToMainMenu::ReturnButtonClicked() +{ + ReturnButton->SetIsEnabled(false); + + if (const UWorld* World = GetWorld()) + { + if (const APlayerController* FirstPlayerController = World->GetFirstPlayerController()) + { + if (ABlasterCharacter* BlasterCharacter = Cast(FirstPlayerController->GetPawn())) + { + BlasterCharacter->ServerLeaveGame(); + if (!BlasterCharacter->OnLeftGame.IsBound()) + { + BlasterCharacter->OnLeftGame.AddDynamic(this, &UReturnToMainMenu::OnPlayerLeftGame); + } + } + else + { + ReturnButton->SetIsEnabled(true); + } + } + } +} + +void UReturnToMainMenu::OnPlayerLeftGame() { if (MultiplayerSessionsSubsystem) { - ReturnButton->SetIsEnabled(false); MultiplayerSessionsSubsystem->DestroySession(); - } + } } void UReturnToMainMenu::OnDestroySessionComplete(bool bWasSuccessful) diff --git a/Source/Blaster/HUD/ReturnToMainMenu.h b/Source/Blaster/HUD/ReturnToMainMenu.h index d1601c1..272e790 100644 --- a/Source/Blaster/HUD/ReturnToMainMenu.h +++ b/Source/Blaster/HUD/ReturnToMainMenu.h @@ -20,8 +20,13 @@ public: protected: virtual bool Initialize() override; + UFUNCTION() void OnDestroySessionComplete(bool bWasSuccessful); + + UFUNCTION() + void OnPlayerLeftGame(); + private: UPROPERTY(meta = (BindWidget))