Professional loading state management for multiplayer environments
LoadSense Pro’s multiplayer synchronization ensures reliable, network-safe level transitions by coordinating loading states across all connected clients. Unlike traditional loading screens that only handle visual feedback, LoadSense Pro manages the entire multiplayer loading lifecycle.
In multiplayer games, level transitions are critical moments where synchronization failures can cause:
LoadSense Pro solves these challenges through its subsystem-driven architecture that operates at the game instance level, ensuring consistent behavior across all network topologies.
ILoadingScreenInterface// Subsystem manages global loading state
ULoadingScreenSubsystem* LoadingSystem =
GetGameInstance()->GetSubsystem<ULoadingScreenSubsystem>();
// Event delegates for multiplayer coordination
UPROPERTY(BlueprintAssignable)
FOnLoadingScreenStateChanged OnLoadingScreenStateChanged;
UPROPERTY(BlueprintAssignable)
FOnMapLoadingProgress OnMapLoadingProgress;
UPROPERTY(BlueprintAssignable)
FOnMapLoadingComplete OnMapLoadingComplete;
// LoadingScreenDataAsset configuration
MapName: "MultiplayerLevel"
LoadType: Asynchronous // Recommended for multiplayer
MinimumLoadingTime: 3.0 // Ensures synchronization window
// Server-side level transition
UFUNCTION(Server, Reliable)
void ServerRequestLevelChange(ULoadingScreenDataAsset* LoadingData)
{
// Validate request
if (!IsValidLoadingData(LoadingData)) return;
// Broadcast to all clients
MulticastStartLoading(LoadingData);
}
UFUNCTION(NetMulticast, Reliable)
void MulticastStartLoading(ULoadingScreenDataAsset* LoadingData)
{
ULoadingScreenSubsystem* LoadingSystem =
GetGameInstance()->GetSubsystem<ULoadingScreenSubsystem>();
LoadingSystem->LoadMapByDataAsset(LoadingData);
}
void AMyGameMode::BeginPlay()
{
Super::BeginPlay();
ULoadingScreenSubsystem* LoadingSystem =
GetGameInstance()->GetSubsystem<ULoadingScreenSubsystem>();
// Bind to loading events
LoadingSystem->OnMapLoadingProgress.AddDynamic(
this, &AMyGameMode::OnLoadingProgress);
LoadingSystem->OnMapLoadingComplete.AddDynamic(
this, &AMyGameMode::OnLoadingComplete);
}
UFUNCTION()
void AMyGameMode::OnLoadingProgress(float Progress, const FString& StatusMessage)
{
// Broadcast progress to all players
for (APlayerController* PC : PlayerControllers)
{
if (PC && PC->IsValidLowLevel())
{
PC->ClientUpdateLoadingProgress(Progress, StatusMessage);
}
}
}
Implement ILoadingScreenInterface on game actors to create custom synchronization logic:
// Player synchronization checkpoint
UCLASS()
class MYGAME_API AMultiplayerSyncPoint : public AActor, public ILoadingScreenInterface
{
GENERATED_BODY()
public:
// ILoadingScreenInterface implementation
virtual void SetLoadingProgress_Implementation(float Progress) override
{
// Custom logic for this sync point
if (Progress >= RequiredProgress && !bHasReportedReady)
{
bHasReportedReady = true;
ServerReportSyncPointReady();
}
}
protected:
UPROPERTY(EditAnywhere, BlueprintReadWrite)
float RequiredProgress = 0.8f;
bool bHasReportedReady = false;
UFUNCTION(Server, Reliable)
void ServerReportSyncPointReady();
};
// GameMode validation for client readiness
bool AMyGameMode::AreAllClientsReady() const
{
for (const auto& PlayerController : PlayerControllers)
{
if (AMyPlayerController* MyPC = Cast<AMyPlayerController>(PlayerController))
{
if (!MyPC->IsLoadingComplete())
{
return false;
}
}
}
return true;
}
// Delayed activation until all clients ready
void AMyGameMode::CheckForLevelActivation()
{
if (AreAllClientsReady())
{
// Safe to activate gameplay
ActivateGameplayForAllPlayers();
}
else
{
// Retry after short delay
GetWorld()->GetTimerManager().SetTimer(
ClientCheckTimer,
this,
&AMyGameMode::CheckForLevelActivation,
0.1f,
false
);
}
}
LoadSense Pro minimizes network traffic through:
// Configuration for high-latency environments
UPROPERTY(EditAnywhere, BlueprintReadOnly, Category = "Multiplayer")
float NetworkTimeoutGracePeriod = 5.0f;
UPROPERTY(EditAnywhere, BlueprintReadOnly, Category = "Multiplayer")
float MaxAcceptableLatency = 500.0f; // milliseconds
UPROPERTY(EditAnywhere, BlueprintReadOnly, Category = "Multiplayer")
bool bUseLatencyCompensation = true;
// Recommended settings for different scenarios
struct FMultiplayerLoadingConfig
{
// Fast local network (LAN)
static constexpr float LAN_MIN_TIME = 1.0f;
static constexpr float LAN_TIMEOUT = 10.0f;
// Internet play
static constexpr float ONLINE_MIN_TIME = 3.0f;
static constexpr float ONLINE_TIMEOUT = 30.0f;
// Mobile/high-latency
static constexpr float MOBILE_MIN_TIME = 5.0f;
static constexpr float MOBILE_TIMEOUT = 60.0f;
};
// Robust error handling for multiplayer scenarios
void ULoadingScreenSubsystem::HandleMultiplayerLoadingError(const FString& ErrorMessage)
{
UE_LOG(LogLoadingScreen, Error, TEXT("Multiplayer Loading Error: %s"), *ErrorMessage);
// Notify all connected clients
if (UWorld* World = GetWorld())
{
if (AGameModeBase* GameMode = World->GetAuthGameMode())
{
GameMode->BroadcastLoadingError(ErrorMessage);
}
}
// Attempt graceful recovery
ForceStopLoadingScreen();
OnMapLoadingProgress.Broadcast(-1.0f, FString::Printf(TEXT("Error: %s"), *ErrorMessage));
}
// Built-in metrics for multiplayer performance
USTRUCT(BlueprintType)
struct FLoadingPerformanceMetrics
{
GENERATED_BODY()
UPROPERTY(BlueprintReadOnly)
float TotalLoadingTime = 0.0f;
UPROPERTY(BlueprintReadOnly)
float NetworkSynchronizationTime = 0.0f;
UPROPERTY(BlueprintReadOnly)
int32 ConnectedClientCount = 0;
UPROPERTY(BlueprintReadOnly)
float AverageClientLatency = 0.0f;
};
| Issue | Cause | Solution |
|---|---|---|
| Clients stuck in loading | Network timeout | Increase NetworkTimeoutGracePeriod |
| Desynchronized states | Race conditions | Use MinimumLoadingTime > 2.0f |
| Loading never completes | Failed client validation | Check OnMapLoadingProgress delegates |
| Input mode conflicts | Rapid state changes | Verify ResetInputModeToGame() calls |
// Console commands for multiplayer debugging
UFUNCTION(Exec)
void Debug_ShowLoadingState()
{
ULoadingScreenSubsystem* LoadingSystem =
GetGameInstance()->GetSubsystem<ULoadingScreenSubsystem>();
UE_LOG(LogTemp, Warning, TEXT("Loading State: %d"),
static_cast<int32>(LoadingSystem->GetCurrentState()));
}
UFUNCTION(Exec)
void Debug_ForceCompleteLoading()
{
ULoadingScreenSubsystem* LoadingSystem =
GetGameInstance()->GetSubsystem<ULoadingScreenSubsystem>();
LoadingSystem->ForceStopLoadingScreen();
}
// Dedicated server configuration
void AMyGameMode::InitGame(const FString& MapName, const FString& Options, FString& ErrorMessage)
{
Super::InitGame(MapName, Options, ErrorMessage);
// Configure for dedicated server
ULoadingScreenSubsystem* LoadingSystem =
GetGameInstance()->GetSubsystem<ULoadingScreenSubsystem>();
if (LoadingSystem)
{
LoadingSystem->SetMinimumLoadingTime(5.0f); // Longer for server coordination
LoadingSystem->OnMapLoadingComplete.AddDynamic(
this, &AMyGameMode::OnServerLevelLoadComplete);
}
}
// Steam/EOS session integration
void AMyGameSession::OnSessionLoadingComplete(const FString& MapName)
{
// Update session properties
UpdateSessionSettings(MapName);
// Notify session service
NotifySessionReady();
// Enable player joining
SetJoinInProgressAllowed(true);
}
LoadSense Pro integrates with common monitoring solutions:
LoadSense Pro - Professional loading screens for professional games.
Need Help? Join our Discord Community or check the Documentation