Download

How to manage sessions and dedicated servers?

Hey everyone,

I’ve tried looking in every resource or example at disposal (UE souurce coode, UT, ShooterGame ecc…) to get an idea of how can I set up dedicated servers with my custom settings, but I still can’t get it :-(.

Here below I’ve expained how I believe this stuff works, please correct me because I am surely wrong on some points :slight_smile:

Session creation:
-Listen servers: there’s the need to set up some UI to be able to configure the FOnlineSessionSettings that will be used to create thesession
-Dedicated servers: the FOnlineSessionSettings are set up with the command line. (Like let’s say “MyPath\MyGameServer.exe ?Map=“MyMap”?GameMode=“MyGameMode”?MyMatchTime=20?MyUselessCustomSettings=“none””)

Making the FOnlineSessionSettings have an effect on the behavior of the server:
simple: IDK :smiley: -I’d need to set up map cycling in my case so i may need to know a bit more about this.

Filtering sessions:
I am pretty sure that here i just need to set up the right FOnlineSessionSearch’s QuerySettings. And they’d have to match with the FOnlineSessionSettings of the found FOnlineSessions.

Thanks in advance for anyone that’ll try giving me an helping hand on this. It is quite hard to always solve problems by myself with such a huge codebase.

Bye, Martin.

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.

Thank you a lot for taking the time to reply, man.
You were very helpful.