(Feat) Add mulitplayer

This commit is contained in:
2026-08-03 10:30:47 +02:00
parent 41d6e6a7f3
commit a4cc59a411
41 changed files with 3418 additions and 125 deletions
@@ -10,6 +10,7 @@
#include "MainMenuWidget.h"
#include "MenuCameraSpot.h"
#include "ScreenFadeComponent.h"
#include "SessionSubsystem.h"
#include "SettingsMenuWidget.h"
#include "SurvivalGameInstance.h"
@@ -78,6 +79,18 @@ void AMainMenuPlayerController::BeginPlay()
ScreenFade->OnFadeFinished.AddDynamic(this, &AMainMenuPlayerController::HandleFadeFinished);
ScreenFade->FadeIn(OpeningFadeDuration);
if (USessionSubsystem* Sessions = GetGameInstance() ? GetGameInstance()->GetSubsystem<USessionSubsystem>() : nullptr)
{
Sessions->OnHostFailed.AddDynamic(this, &AMainMenuPlayerController::HandleHostFailed);
Sessions->OnJoinFailed.AddDynamic(this, &AMainMenuPlayerController::HandleJoinFailed);
// Revenir au menu depuis une partie laisse la session ouverte : elle
// resterait annoncee a tes amis alors que plus personne n'est dedans.
Sessions->LeaveSession();
UE_LOG(LogTemp, Log, TEXT("AMainMenuPlayerController : service en ligne [%s]."), *Sessions->GetOnlineServiceName());
}
}
AMenuCameraSpot* AMainMenuPlayerController::PickCameraSpot()
@@ -135,7 +148,7 @@ AMenuCameraSpot* AMainMenuPlayerController::PickCameraSpot()
return Chosen;
}
void AMainMenuPlayerController::StartSoloGame()
void AMainMenuPlayerController::StartGame()
{
// Le fondu est deja lance : on ignore le second clic plutot que d'empiler
// deux chargements.
@@ -162,6 +175,33 @@ void AMainMenuPlayerController::StartSoloGame()
ScreenFade->FadeOut(LeaveFadeDuration);
}
void AMainMenuPlayerController::HandleHostFailed(FText Reason)
{
UE_LOG(LogTemp, Warning, TEXT("AMainMenuPlayerController : session indisponible (%s), la partie se lance hors ligne."), *Reason.ToString());
// Sans session on ouvre quand meme en serveur d'ecoute plutot qu'en solo
// sec : l'ecart de cout est nul a un joueur, et ca evite d'avoir deux
// facons differentes de demarrer une partie a maintenir.
UGameplayStatics::OpenLevelBySoftObjectPtr(this, GameLevel, /*bAbsolute=*/true, TEXT("listen"));
}
void AMainMenuPlayerController::HandleJoinFailed(FText Reason)
{
UE_LOG(LogTemp, Error, TEXT("AMainMenuPlayerController : connexion impossible -- %s"), *Reason.ToString());
// Ici pas de repli : le joueur voulait rejoindre un ami precis. On le rend
// simplement a son menu, ecran remonte -- sans quoi un echec le laisserait
// devant un noir definitif, ce qui se lit comme un plantage.
PendingAction = EMenuPendingAction::None;
if (MainMenu)
{
MainMenu->SetVisibility(ESlateVisibility::Visible);
}
ScreenFade->FadeIn(LeaveFadeDuration);
}
void AMainMenuPlayerController::QuitGame()
{
// Une partie est deja en cours de chargement : la question n'a plus de sens.
@@ -287,9 +327,22 @@ void AMainMenuPlayerController::HandleFadeFinished()
{
// Le delegue se declenche aussi a la fin du fondu d'ouverture, ou il n'y a
// rien a faire : c'est PendingAction qui distingue les deux cas.
if (PendingAction == EMenuPendingAction::StartGame)
if (PendingAction != EMenuPendingAction::StartGame)
{
UGameplayStatics::OpenLevelBySoftObjectPtr(this, GameLevel);
return;
}
// C'est le sous-systeme qui ouvrira la map, et seulement une fois la session
// reellement creee : ouvrir avant donnerait une partie que personne ne peut
// rejoindre. Le cas d'echec passe par HandleHostFailed, qui charge quand meme.
if (USessionSubsystem* Sessions = GetGameInstance() ? GetGameInstance()->GetSubsystem<USessionSubsystem>() : nullptr)
{
Sessions->HostSession(GameLevel, USessionSubsystem::DefaultMaxPlayers);
}
else
{
UE_LOG(LogTemp, Warning, TEXT("AMainMenuPlayerController : USessionSubsystem introuvable, partie lancee hors ligne."));
UGameplayStatics::OpenLevelBySoftObjectPtr(this, GameLevel, /*bAbsolute=*/true, TEXT("listen"));
}
}