Martin,
FOnlineSession settings has nothing to do with the behavior of the server. It is used to register your server with the online subsystem, like setting the game mode, map name, … so people can find it when using the FOnlineSessionSearch.
The behaviour of the server is usally configured trough the ini settings.
UCLASS(Config = Game)
class AMyGameMode
{
public:
UPROPERTY(Config)
int32 MyMatchTime;
};
For listen servers u can add a UI screen to configure the server and save the settings before launching the map with “listen” option. Once loaded the behaviour will be loaded from the ini like it would do with the dedicated server.
The main difference between dedicated server and listen server is how u register the online session with the online subsystem.
For dedicated servers the the AGameSession class provides a function “RegisterServer” (which is only called when running dedicated servers)
For listen server u most likely want to call it before launching the map to be sure registeration completed, because the session must be registered before u start playing.
When u run the listen server, the local player is registered with the session when launching the game, so if u did not wait for it to complete u can’t be registered.
Here is example of how i use the online subsystem for both dedicated and listen server: (based on both how ShooterGame and UT deal with online sessions)
CreateGameSession, StartGameSession, EndGameSessions are functions that implement the online subsystem API
void ASwatGameSession::InitOptions(const FString& Options)
{
Super::InitOptions(Options);
// Cache the game mode
SwatGameMode = GetWorld()->GetAuthGameMode<ASwatGameMode>();
if (SwatGameMode)
{
MaxPlayers = SwatGameMode->MaxPlayers;
SessionName = GameSessionName;
}
}
void ASwatGameSession::HandleMatchHasStarted()
{
StartGameSession();
}
void ASwatGameSession::HandleMatchHasEnded()
{
EndGameSession();
}
void ASwatGameSession::PostLogin(APlayerController* NewPlayer)
{
Super::PostLogin(NewPlayer);
UpdateGameSession();
}
void ASwatGameSession::NotifyLogout(APlayerController* PC)
{
Super::NotifyLogout(PC);
UpdateGameSession();
}
This part is called on dedicated servers only:
void ASwatGameSession::RegisterServer()
{
TSharedPtr<const FUniqueNetId> UserId;
auto OnlineSubsystem = IOnlineSubsystem::Get();
if (OnlineSubsystem)
{
auto IdentityInterface = OnlineSubsystem->GetIdentityInterface();
if (IdentityInterface.IsValid())
{
UserId = IdentityInterface->GetUniquePlayerId(0);
}
}
CreateGameSession(UserId, SwatGameMode->GetClass(), GetWorld()->GetMapName());
}
For the listen server i also have the GameInstance::Host method which register the server and call the ServerTravel on completion
void USwatGameInstance::HostGame(FString InTravelURL)
{
UE_LOG(LogSwatGameInstance, Log, TEXT("Starting game (URL: '%s')"), *InTravelURL);
... code removed for parsing map name, options ...
// Parse the game mode
const auto GameMapsSettings = GetDefault<UGameMapsSettings>();
FString GameName = GameMapsSettings->GetGlobalDefaultGameMode();
if (UGameplayStatics::HasOption(MapOptions, TEXT("Game")))
{
GameName = UGameplayStatics::ParseOption(MapOptions, TEXT("Game"));
}
// Load the game mode
GameName = AGameMode::StaticGetFullGameClassName(GameName);
UClass* GameClass = LoadObject<UClass>(nullptr, *GameName, nullptr, LOAD_NoWarn | LOAD_Quiet, nullptr);
if (!GameClass)
{
UE_LOG(LogSwatGameInstance, Warning, TEXT("Failed to start the game: GameMode '%s' not found"), *GameName);
return;
}
// Validate the game class
if (!GameClass->IsChildOf(ASwatGameMode::StaticClass()))
{
UE_LOG(LogSwatGameInstance, Warning, TEXT("Failed to start the game: GameMode '%s' is not a SWAT game mode"), *GameName);
return;
}
// Parse the online game option
bool bIsOnlineGame = UGameplayStatics::HasOption(MapOptions, TEXT("Listen"));
// Make sure we cant play single player games online
if (bIsOnlineGame && GameClass && !GameClass->GetDefaultObject<ASwatGameMode>()->bIsOnlineGame)
{
UE_LOG(LogSwatGameInstance, Warning, TEXT("Failed to start the game: GameMode '%s' can not be played online"), *GameName);
return;
}
... code removed for parsing game options and some more validations ...
// Check if we are playing an online game
if (bIsOnlineGame)
{
// Start the game session
auto const SwatGameMode = GetWorld()->GetAuthGameMode<ASwatMenuMode>();
if (SwatGameMode)
{
TravelURL = InTravelURL;
auto const SwatGameSession = Cast<ASwatGameSession>(SwatGameMode->GameSession);
if (SwatGameSession)
{
OnCreateGameSessionCompleteDelegateHandle = SwatGameSession->AddOnCreateGameSessionCompleteDelegate_Handle(FOnSwatCreateGameSessionCompleteDelegate::CreateUObject(this, &USwatGameInstance::OnCreateGameSessionComplete));
SwatGameSession->CreateGameSession(LocalPlayers[0]->GetCachedUniqueNetId(), GameClass, FPackageName::GetLongPackageAssetName(FullMapName));
... see shooter game example for loading screen, game state and offline game ...
}
}
}
else
{
....
}
}
void USwatGameInstance::OnCreateGameSessionComplete(FName SessionName, bool bWasSuccessful)
{
auto const SwatGameMode = GetWorld()->GetAuthGameMode<ASwatGameMode>();
if (SwatGameMode)
{
auto const SwatGameSession = Cast<ASwatGameSession>(SwatGameMode->GameSession);
if (SwatGameSession)
{
SwatGameSession->ClearOnCreateGameSessionCompleteDelegate_Handle(OnCreateGameSessionCompleteDelegateHandle);
}
}
if (bWasSuccessful)
{
GetWorld()->ServerTravel(TravelURL, true);
}
else
{
//@todo: SHOW_ERROR_DIALOG
}
}
edit:
The reasson the “delayed” online session registeration for dedicated server does not matter much is before u don’t have to register any players online when launching the game (local player)
Only player registeration is when remote players join … so only after the server before visible, which means the online registeration completed.