Lobbyist is a plugin for UE4 that makes it possible to host and join lobbies without loading into a lobby map — straight from the main menu.

Features

  • Improved player experience. Let players create and join sessions without leaving the main menu. No more annoying blocking-loads just to join a lobby.
  • Easy to use. Lobbyist provides a simple yet powerful framework for you to build upon in both Blueprint and C++.
  • Supported and tested. The plugin is actively used in a game live on Steam and Xbox, and will receive all the needed lifetime updates.
  • Multi-platform support. Lobbyist works seamlessly with multiple online subsystems (such as Steam, Xbox Live, etc.) and supports local testing for fast iteration during development.
  • Blueprint & C++ example projects. The provided example projects implement a fully-featured lobby system including a server browser, player kicking, chat and more that you can use as a base for your own game.
  • Source code & docs. Lobbyist comes with full, heavily commented source code and extensive documentation to help you get started quickly.

Lobbyist can be purchased on the Unreal Engine Marketplace. Feel free to join the Discord server if you have any questions. Try out the demo!

Download the demo


Why Lobbyist?

Connecting to a server in UE4 implies a blocking load during which the active level (i.e. the main menu level) is torn down, a connection is established with the server and a new level that supports network play is brought up. While this works great for normal gameplay, it can be cumbersome when dealing with lobbies or parties.

Lobbyist provides a flexible framework to manage lobbies without loading into a different level. It works by leveraging online beacons, a lightweight way to contact and interact with a server available in UE4.

The plugin allows you to to host and join a lobby straight from the main menu, including support for replicating data to all lobby members, traveling to the actual game and getting back to the lobby after the game is over.

To find out more about how Lobbyist and online beacons work, make sure to check out the reference section. Feel free to refer to it while browsing the usage section, exploring the example projects or developing your own game!

Limitations

There’s a major limitation to be aware of when working with Lobbyist and online beacons in general. Since no replicated world is ever set up when connecting to a server using beacons, actors like Pawn or Character—or, in general, actors that need to collide with each others or the world — won’t work as expected.

If you’re looking to have players interact with each other in a physical world while in the lobby, Lobbyist is not the right approach.


Usage

This guide explains the steps required to set up a basic lobby, from initial configuration to in-editor testing. Make sure to check out the available examples project for a fully featured lobby implementation that includes UMG UI, a server browser, chat system, player kicking and more.

Getting Started

Let’s go through a couple of preliminary steps.

1. Beacons configuration

All network communication in UE4 is handled by NetDrivers. Since Lobbyist uses beacons to communicate with a server, we’ll need to configure the BeaconNetDriver in DefaultEngine.ini:

[/Script/UnrealEd.EditorEngine]
!NetDriverDefinitions=ClearArray
+NetDriverDefinitions=(DefName="GameNetDriver",DriverClassName="OnlineSubsystemUtils.IpNetDriver",DriverClassNameFallback="OnlineSubsystemUtils.IpNetDriver")
+NetDriverDefinitions=(DefName="BeaconNetDriver",DriverClassName="OnlineSubsystemUtils.IpNetDriver",DriverClassNameFallback="OnlineSubsystemUtils.IpNetDriver")

[/Script/Engine.GameEngine]
!NetDriverDefinitions=ClearArray
+NetDriverDefinitions=(DefName="GameNetDriver",DriverClassName="OnlineSubsystemSteam.IpNetDriver",DriverClassNameFallback="OnlineSubsystemUtils.IpNetDriver")
+NetDriverDefinitions=(DefName="BeaconNetDriver",DriverClassName="OnlineSubsystemSteam.IpNetDriver",DriverClassNameFallback="OnlineSubsystemUtils.IpNetDriver")

Beacons will now use the built-in IP NetDriver (which is suitable for local testing) in both editor and game. If you plan to use Steam, you can use the following configuration instead:

[/Script/Engine.GameEngine]
!NetDriverDefinitions=ClearArray
+NetDriverDefinitions=(DefName="GameNetDriver",DriverClassName="OnlineSubsystemSteam.IpNetDriver",DriverClassNameFallback="OnlineSubsystemUtils.IpNetDriver")
+NetDriverDefinitions=(DefName="BeaconNetDriver",DriverClassName="OnlineSubsystemUtils.IpNetDriver",DriverClassNameFallback="OnlineSubsystemUtils.IpNetDriver")
; Use the Steam NetDriver when running standalone
+NetDriverDefinitions=(DefName="GameNetDriver",DriverClassName="OnlineSubsystemSteam.SteamNetDriver",DriverClassNameFallback="OnlineSubsystemUtils.IpNetDriver")
+NetDriverDefinitions=(DefName="BeaconNetDriver",DriverClassName="OnlineSubsystemSteam.SteamNetDriver",DriverClassNameFallback="OnlineSubsystemUtils.IpNetDriver")

2. Enabling the plugin

Make sure Lobbyist is enabled in the Edit ➜ Plugins window.

A screenshot of the plugin panel in UE4, with Lobbyist enabled

If you plan to use the plugin from C++ don’t forget to list it in your build dependencies.

using UnrealBuildTool;

public class MyGame : ModuleRules
{
public MyGame(ReadOnlyTargetRules Target)
: base(Target)
{
// [...]
PrivateDependencyModuleNames.Add("Lobbyist");
// [...]
}
}

Configuring the classes

Lobbyist provides a set of base classes that you can extend to provide custom functionality, following the same approach of UE4 classes such as GameMode, PlayerState, etc. At a minimum, you’ll want to provide your own implementation of LobbyistHost and LobbyistClient.

The first class is equivalent to UE4 GameMode and is responsible for managing players and lobby rules. A LobbyistClient is used to establish a connection to the host and exposes a set of useful events related to the connection lifetime and status.

An in-depth description of all the available classes and their intended usage can be found in the reference section.

1. Creating the classes

Create a subclass of LobbyistHost in either C++ or Blueprint:

A screenshot of the Pick Parent Class dialog in UE4, with LobbyistHost selected
#pragma once
#include "CoreMinimal.h"
#include "LobbyistHost.h"
#include "MyLobbyHost.generated.h"

UCLASS()
class AMyLobbyHost : public ALobbyistHost
{
GENERATED_BODY()
}

Do the same for LobbyistClient:

A screenshot of the Pick Parent Class dialog in UE4, with LobbyistClient selected
#pragma once
#include "CoreMinimal.h"
#include "LobbyistClient.h"
#include "MyLobbyClient.generated.h"

UCLASS()
class AMyLobbyClient : public ALobbyistClient
{
GENERATED_BODY()
}

2. Configure Lobbyist to use the new classes

Lobbyist can be configured to use the new classes by navigating to the Plugins / Lobbyist section of the Edit ➜ Project Settings menu:

A screenshot of the Lobbyist settings dialog in UE4, configured to use the just created classes

Hosting a Session

Hosting a session with Lobbyist involves two steps: creating an online session for players to join, and starting up the host that will handle players as they join the session.

1. Creating an online session

UE4 provides a powerful way to manage online sessions by using the Online Subsystem, an interface that provides a common way to access online services such as Steam, Xbox Live, PSN and so on.

In this example we’ll use the Null subsystem which is suitable for local testing, but any other subsystem should work out-of-the-box. To configure the subsystem add the following to DefaultEngine.ini:

[OnlineSubsystem]
DefaultPlatformService=Null

[OnlineSubsystemNull]
bEnabled=True

If you plan to use Steam you can enable the Steam subsystem as well. This provides a flexible way to test things: UE4 will default to the Null subsystem when running the editor (or the game if Steam is closed), but will prefer the Steam subsystem when running the game.

[OnlineSubsystem]
DefaultPlatformService=Null
DefaultPlatformService=Steam

[OnlineSubsystemNull]
bEnabled=True

[OnlineSubsystemSteam]
bEnabled=True
SteamDevAppId=480

You can use both Blueprint or C++ to create a game session. Feel free to do this wherever it works best for you: inside an actor, in the game instance, etc.

Session creation and management is quite limited in Blueprint by default. If you need additional control over sessions you should consider using the free and open-source Advanced Sessions plugin.

void ASomeActor::BeginPlay()
{
Super::BeginPlay();

const FUniqueNetIdRepl PrimaryPlayerId = GetGameInstance()->GetPrimaryPlayerUniqueId();
const IOnlineSessionPtr SessionInterface = Online::GetSessionInterface(GetWorld());

if (!PrimaryPlayerId.IsValid() || !SessionInterface.IsValid())
{
return;
}

FOnlineSessionSettings SessionSettings;
SessionSettings.NumPublicConnections = 8;
SessionSettings.bShouldAdvertise = true;
SessionSettings.bAllowJoinInProgress = true;
SessionSettings.bIsLANMatch = false;
SessionSettings.bUsesPresence = true;
SessionSettings.bAllowJoinViaPresence = true;

SessionInterface->CreateSession(*PrimaryPlayerId, NAME_GameSession, SessionSettings);
}

2. Starting the host

We’re now ready to initialize the host and wait for clients to join. This is done by calling the CreateLobbyHost function of the Lobbyist subsystem.

The Lobbyist Subsystem is the main entrypoint to most functionality. It provides methods to create and access both host and client and also provides access to the LobbyistState.

void ASomeActor::BeginPlay()
{
Super::BeginPlay();

const FUniqueNetIdRepl PrimaryPlayerId = GetGameInstance()->GetPrimaryPlayerUniqueId();
const IOnlineSessionPtr SessionInterface = Online::GetSessionInterface(GetWorld());

if (!PrimaryPlayerId.IsValid() || !SessionInterface.IsValid())
{
return;
}

FOnlineSessionSettings SessionSettings;
SessionSettings.NumPublicConnections = 8;
SessionSettings.bShouldAdvertise = true;
SessionSettings.bAllowJoinInProgress = true;
SessionSettings.bIsLANMatch = false;
SessionSettings.bUsesPresence = true;
SessionSettings.bAllowJoinViaPresence = true;

SessionInterface->CreateSession(*PrimaryPlayerId, NAME_GameSession, SessionSettings);
DelegateHandle_OnCreateSessionComplete = SessionInterface->AddOnCreateSessionCompleteDelegate_Handle(
FOnCreateSessionCompleteDelegate::CreateUObject(this, &ThisClass::OnCreateSessionComplete));
if (!SessionInterface->CreateSession(*PrimaryPlayerId, NAME_GameSession, SessionSettings))
{
SessionInterface->ClearOnCreateSessionCompleteDelegate_Handle(DelegateHandle_OnCreateSessionComplete);
}
}

void ASomeActor::OnCreateSessionComplete(FName SessionName, bool bWasSuccessful)
{
const UWorld* World = GetWorld();
if (const IOnlineSessionPtr SessionInterface = Online::GetSessionInterface(World))
{
SessionInterface->ClearOnCreateSessionCompleteDelegate_Handle(DelegateHandle_OnCreateSessionComplete);
}

if (bWasSuccessful)
{
if (ULobbyistSubsystem* LobbyistSubsystem = ULobbyistSubsystem::Get(World))
{
LobbyistSubsystem->CreateLobbyHost();
}
}
}

If you want the local machine to act as a listen server and participate in the session, make sure to create a client and connect to the local host. We’ll go over clients in detail in the next section.

// [...]

void ASomeActor::OnCreateSessionComplete(FName SessionName, bool bWasSuccessful)
{
const UWorld* World = GetWorld();
if (const IOnlineSessionPtr SessionInterface = Online::GetSessionInterface(World))
{
SessionInterface->ClearOnCreateSessionCompleteDelegate_Handle(DelegateHandle_OnCreateSessionComplete);
}

if (bWasSuccessful)
{
if (ULobbyistSubsystem* LobbyistSubsystem = ULobbyistSubsystem::Get(World))
{
LobbyistSubsystem->CreateLobbyHost();
if (ALobbyistClient* Client = LobbyistSubsystem->CreateLobbyClient())
{
Client->ConnectToSession();
}
}
}
}

Participating in a Session

For a client to be able to participate in a session we’ll need to join the session using the Online Subsystem and connect to the host.

1. Joining the session

First retrieve a list of all available sessions and select one to join. Feel free to do this wherever it works best for you: inside an actor, in the game instance, etc.

For the sake of this tutorial, we’ll assume that only one session is available (the one created by the host), but in a real world scenario there might be multiple sessions to choose from. These can be filtered to select the best one based on player preferences, available player slots or any game-specific criteria.

void ASomeActor::BeginPlay()
{
Super::BeginPlay();

const IOnlineSessionPtr SessionInterface = Online::GetSessionInterface(GetWorld());
if (!SessionInterface.IsValid())
{
return;
}

SessionSearch = MakeShared<FOnlineSessionSearch>();
SessionSearch->MaxSearchResults = 20;
SessionSearch->QuerySettings.Set(SEARCH_PRESENCE, true, EOnlineComparisonOp::Equals);

DelegateHandle_OnFindSessionsComplete = SessionInterface->AddOnFindSessionsCompleteDelegate_Handle(
FOnFindSessionsCompleteDelegate::CreateUObject(this, &ThisClass::OnFindSessionsComplete));
if (!SessionInterface->FindSessions(0, SessionSearch.ToSharedRef()))
{
SessionInterface->ClearOnFindSessionsCompleteDelegate_Handle(DelegateHandle_OnFindSessionsComplete);
}
}

void ASomeActor::OnFindSessionsComplete(bool bWasSuccessful)
{
const IOnlineSessionPtr SessionInterface = Online::GetSessionInterface(GetWorld());
if (!SessionInterface.IsValid())
{
return;
}

SessionInterface->ClearOnFindSessionsCompleteDelegate_Handle(DelegateHandle_OnFindSessionsComplete);

if (bWasSuccessful
&& SessionSearch.IsValid()
&& SessionSearch->SearchResults.Num() > 0)
{
SessionInterface->JoinSession(0, NAME_GameSession, SessionSearch->SearchResults[0]);
}
}

2. Connecting to the host

To connect to the host, create a client using the CreateLobbyClient function of the Lobbyist subsystem and call ConnectToSession:

// ...

void ASomeActor::OnFindSessionsComplete(bool bWasSuccessful)
{
const IOnlineSessionPtr SessionInterface = Online::GetSessionInterface(GetWorld());
if (!SessionInterface.IsValid())
{
return;
}

SessionInterface->ClearOnFindSessionsCompleteDelegate_Handle(DelegateHandle_OnFindSessionsComplete);

if (bWasSuccessful
&& SessionSearch.IsValid()
&& SessionSearch->SearchResults.Num() > 0)
{
SessionInterface->JoinSession(0, NAME_GameSession, SessionSearch->SearchResults[0]);
DelegateHandle_OnJoinSessionComplete = SessionInterface->AddOnJoinSessionCompleteDelegate_Handle(
FOnJoinSessionCompleteDelegate::CreateUObject(this, &ThisClass::OnJoinSessionComplete));
if (!SessionInterface->JoinSession(0, NAME_GameSession, SessionSearch->SearchResults[0]))
{
SessionInterface->ClearOnJoinSessionCompleteDelegate_Handle(DelegateHandle_OnJoinSessionComplete);
}
}
}

void ASomeActor::OnJoinSessionComplete(FName SessionName, EOnJoinSessionCompleteResult::Type Result)
{
if (Result != EOnJoinSessionCompleteResult::Success)
{
return;
}

if (ULobbyistSubsystem* LobbyistSubsystem = ULobbyistSubsystem::Get(GetWorld()))
{
if (ALobbyistClient* Client = LobbyistSubsystem->CreateLobbyClient())
{
Client->ConnectToSession();
}
}
}

3. Next steps

The LobbyistClient class exposes several events that are triggered during the connection lifetime. You can use these events, for example, to update your UI accordingly.

  • ConnectedToLobby: called when a connection is first established.
  • DisconnectedFromLobby: called when the client is gracefully disconnected from the server (i.e. because the server was gracefully stopped, the client was kicked, etc.).
  • NetworkFailure: called when the client is disconnected from the server because of a network error.

Local Testing

A useful feature of Lobbyist that allows for fast iteration times is the ability to test your lobby locally, either directly from within the editor or by running multiple instances of the game.

Testing inside the editor

To test from within the editor simply launch two standalone clients:

A screenshot of the Play In Editor options dropdown, with the two standalone clients set up

You can create and join sessions in the editor just like you would when running a standalone or packaged version of the game.

In order to run multiple clients in UE 4.24 and previous versions of the engine you’ll need to turn off the Auto Connect To Server option in Edit ➜ Editor Preferences ➜ Play.

Testing standalone

To test standalone, simply launch multiple instances of the game. The easiest way to do this is by right-clicking your .uproject file and clicking on Launch game.

A screenshot of Windows Explorer, showing the context menu after clicking on the project file

Managing Lobby State and Players

Lobbyist provides a flexible and intuitive way to replicate both general lobby data and player-specific data.

Lobby state

All the global lobby data that needs to be replicated to remote clients should live inside the LobbyistState actor. This is equivalent to UE4 GameState and it’s spawned automatically by the lobby host when the lobby is started. It’s replicated to clients as soon as they join.

The default implementation provided by Lobbyist simply replicates a list of players. In order to provide custom functionality, you need to create your own LobbyistState subclass.

A screenshot of the Pick Parent Class dialog in UE4, with LobbyistState selected
#pragma once
#include "CoreMinimal.h"
#include "LobbyistState.h"
#include "MyLobbyState.generated.h"

UCLASS()
class AMyLobbyState : public ALobbyistState
{
GENERATED_BODY()
}

Finally, configure your LobbyistHost to use the new class.

A screenshot of the lobby host actor properties panel, configured to use the new lobby state class
#include "MyLobbyHost.h"
#include "MyLobbyState.h"

AMyLobbyHost::AMyLobbyHost(const FObjectInitializer& ObjectInitializer)
: Super(ObjectInitializer)
{
LobbyStateClass = AMyLobbyState::StaticClass()
}

Lobby players

Each player in the lobby is represented by a LobbyistPlayer actor. This is replicated to all remote clients and is the perfect spot to store player information. You can think of it as Lobbyist’s PlayerState counterpart.

The default implementation simply stores and replicates the player’s name, so you’ll likely want to create your own LobbyistPlayer subclass.

A screenshot of the Pick Parent Class dialog in UE4, with LobbyistPlayer selected
#pragma once
#include "CoreMinimal.h"
#include "LobbyistPlayer.h"
#include "MyLobbyPlayer.generated.h"

UCLASS()
class AMyLobbyPlayer : public ALobbyistPlayer
{
GENERATED_BODY()
}

Finally, configure your LobbyistHost to use the new class.

A screenshot of the lobby host actor properties panel, configured to use the new lobby player class
#include "MyLobbyHost.h"
#include "MyLobbyState.h"
#include "MyLobbyPlayer.h"

AMyLobbyHost::AMyLobbyHost(const FObjectInitializer& ObjectInitializer)
: Super(ObjectInitializer)
{
LobbyStateClass = AMyLobbyState::StaticClass()
LobbyPlayerClass = AMyLobbyPlayer::StaticClass()
}

Handling player login/logout

LobbyistHost provides some useful extension points that you can use to customize the login flow in both C++ and Blueprint.

  • PreLogin: called before processing the login request for a given player. Only available in C++.
  • ApproveLogin: approves or rejects the login request for a given player. Override this function if you want to prevent a login, i.e. because the lobby is full.
  • PostLogin: called after a player has been successfully logged in. This is the right spot to initialize the new player.
  • PreLogout: called when a player leaves the lobby.

The player login process involves multiple RPCs between the client and the host. A high level overview of the login RPC/event flow is available below.

A high-level diagram of the login flow
High-level overview of the login flow.

Starting the Game

When you’re ready to start the game, call the StartGame function on the host.

if (ULobbyistSubsystem* LobbyistSubsystem = ULobbyistSubsystem::Get(GetWorld()))
{
if (ALobbyistHost* Host = LobbyistSubsystem->GetLobbyHost())
{
Host->StartGame();
}
}

This will notify all the clients that it’s time to travel to the actual game and will fire the TravelToGame event on the host as soon as all clients confirm they’re ready to travel. You should use this event to travel to the level you want to play.

void AMyLobbyHost::TravelToGame()
{
Super::TravelToGame();

const bool bAbsolute = true;
GetWorld()->ServerTravel(TEXT("/Game/Maps/MyGameLevel?listen"), bAbsolute);
}

Remember to use the listen option if you want the host to act as a listen server.

Traveling to the game level will tear down the active world, destroying the lobby host and client actors. When the game is over and you want to get back to lobby, simply travel back to the main menu level, recreate the lobby host and reconnect the clients as appropriate.

Online sessions created/joined with the Online Subsystem persist across map changes, so re-creating or re-joining the active session isn’t necessary after traveling to a different level.


Example Projects

Lobbyist comes with an extensive example project (for UE 4.24 and up) that implements a fully featured lobby system, including:

  • A server browser from which players can create new lobbies and join existing ones.
  • A multiplayer lobby featuring a chat system, character selection, player kicking, ping visualization and more.
  • Traveling to the actual game and getting back to the lobby once the game is over.

There are two versions of the example project: one completely implemented in Blueprint and another one implemented in C++. Both projects feature the exact same functionality and use UMG widgets for their UIs. They can be easily used as a base for your own lobbies. A standalone demo version of the example project is also available for evaluation purposes.

Blueprint example projectC++ example project

Download the demo

Running the project

To run the example project simply launch two standalone clients inside the editor. Please refer to the Local Testing section for additional launch options and specific instructions for UE 4.24 and previous engine versions.

A screenshot of the Play In Editor options dropdown, with the two standalone clients set up

The project is set up to launch into the Menu level. After selecting or creating a lobby in the server browser, players can use the lobby to customize their character, chat and start the game. Starting the game will load the ThirdPersonExampleMap (from the Third Person Template available in UE4). The lobby leader can end the game by pressing ESC. After the game is over, players are moved back to the lobby.

Blueprint project structure

You can find all the Blueprint and UMG widgets inside the Blueprint folder in the content browser.

A screenshot of the Content Browser inside UE4, with the Blueprints folder highlighted
  • BP_GameInstance. Global game state management. Keeps track of the active session and persists character selection information to make sure the correct skin is applied to the player across map changes.
  • Menu
    • BP_MenuGameMode. Game mode used in the menu level, spawns the menu player controller.
    • BP_MenuPlayerController. Entry point for most menu functionality. Creates the menu widget and manages the UI. Handles callbacks from the UI to create and join sessions and updates the game instance accordingly.
    • BP_LobbyHost, BP_LobbyClient, etc. Lobbyist subclasses that handle all the lobby logic.
  • Game
    • BP_GameMode. Game mode used in the menu level, spawns the menu player controller.
    • BP_GamePlayerController. Manages the in-game UI.
  • UI. UMG widgets for both menu and game.

All the Blueprint logic — including graph, classes, functions, etc.  — is commented. Functions and variables have tooltips explaining what they’re used for.


Reference

How Lobbyist Works

Lobbyist leverages an alternative, lightweight way to contact a server and interact with it offered by UE4: Online Beacons. Since beacons can be used for a variety of network-related tasks — such as QOS tests, chat systems and more — the base implementation provided by the engine is reasonably generic and not exposed to Blueprint.

When using online beacons most of the standard UE4 classes — such as GameMode, GameState, PlayerController and PlayerState—can’t be used to manage the game because no world travel is ever performed and data flows through a beacon connection instead of a standard game connection.

Lobbyist provides its own set of classes to handle everything from initial player login to traveling to the actual game. Most Lobbyist classes are designed to be a direct counterpart of the ones provided by UE4 and, much like base engine classes, can be extended in either C++ or Blueprint to provide game-specific functionality.

A diagram showing the relationships between Lobbyist classes
Relationships between Lobbyist classes

Clients connect to a server on which a LobbyistHost is running. The LobbyistHost is equivalent to the GameMode and is responsible for managing connected clients, the player login/logout flow and lobby rules. Every time a player joins the session a new LobbyistPlayer (equivalent to the PlayerState) representing that player is spawned on the server and replicated to all clients through the LobbyistState, Lobbyist’s counterpart of the GameState.

For more information about beacons make sure to check out the official UE4 docs and this AnswerHub question.

An in-depth description of all the available classes is available below.

Class Cheatsheet

Below you can find a cheatsheet of all available classes, where they’re available (i.e. server and/or clients) and what they can be used for.

ClassDescription
Server
LobbyistServer

Listens for incoming connections from remote clients and notifies LobbyistHost when a client attempts to connect. Dealing directly with this class isn’t normally required, so it’s not exposed to Blueprint. Only ever exists on the server.

Inherits from: AOnlineBeaconHost.

LobbyistHost

Manages connected clients, governing the LobbyistState and the player login/logout flow. It’s equivalent to UE4 GameMode and only ever exists on the server.

Inherits from: AOnlineBeaconHostObject.

Server & Owner Client
LobbyistClient

Establishes and manages the connection with the server, joining all local players into the lobby. A server-side version of the actor will be spawned on the server as well when the connection is first established.

It’s a good place for RPCs that affect all players on a given machine. Similarly to PlayerController, it only exists on the server and the client that started the connection (owner client).

Inherits from: AOnlineBeaconClient.

Server & All Clients
LobbyistState

GameState counterpart. It’s spawned on the server by the LobbyistHost and replicated to all clients. It maintains an up-to-date list of players who are currently in the lobby and it’s the perfect spot to store global lobby data that needs to be replicated to all clients.

Inherits from: AInfo.

LobbyistPlayer

PlayerState counterpart. It’s spawned on the server when a player joins the lobby and replicated to all clients. It stores information about a specific player (by default, his name and UniqueNetId).

Inherits from: AInfo.


Help

Troubleshooting

The best way to find out what’s going on and troubleshoot issues is to turn on logging in DefaultEngine.ini. Useful log categories to turn on are LogLobbyist for Lobbyist specific debugging and LogBeacon for general beacon troubleshooting.

[Core.Log]
LogLobbyist=VeryVerbose
LogBeacon=VeryVerbose

Log categories can also be changed at runtime using the development console, accessed using the tilde ~ character by default:

Log LogLobbyst VeryVerbose
Log LogBeacon VeryVerbose

The output log can be shown inside the editor by selecting Window ➜ Developer Tools ➜ Output Log or by using the showlog command in standalone games. You can find more information about logging in the UE4 Community Wiki.

A screenshot of the UE4 editor, with the Output Log entry selected in the Developer Tools menu

FAQ

1. Lobby host and/or client aren’t spawned correctly

This is most probably due to a configuration issue. Please double check that the required NetDriver configuration was added to DefaultEngine.ini. Common error messages you can see in the log in this case include:

LogNet: CreateNamedNetDriver failed to create driver from definition BeaconNetDriver
LogLobbyist: Error: Failed to initialize lobby host.
LogLobbyist: Error: Failed to initialize lobby client.

2. Why doesn’t Lobbyist implement put feature here?

The plugin is purposely kept as barebone as possible so that it can be used across a wide range of projects. Implementation of advanced features (i.e. chat systems, player kick, character selection, etc.) is demonstrated in the example projects — feel free to copy-paste as needed!

3. Is voice chat supported?

Yes, voice chat is supported. Lobbyist provides the low level connection voice channel implementation needed to replicate voice packets and relies on the OSS for actual voice processing and for features, such as muting, that are platform-dependent. To turn on voice chat add the following to DefaultEngine.ini:

[Voice]
bEnabled=true

[OnlineSubsystem]
bHasVoiceEnabled=true

For initial testing it can also be useful to disable the PushToTalk feature (i.e. to make sure voice works). By default Lobbyist uses the same bRequiresPushToTalk setting of the actual game, which can be changed in DefaultGame.ini:

[/Script/Engine.GameSession]
bRequiresPushToTalk=false

If needed, you can completely override this behavior by overriding ALobbyistHost::RequiresPushToTalk in either C++ or Blueprint.

Support

If you experience issues with the plugin that aren’t covered in the documentation, feel free to get in touch! The best support channel is the Discord server.

Alternatively, you can reach out to me on Twitter or by e-mail. Please allow at least a business day for me to get back to you.


Changelog

Version 1.4 (2 July 2021)
  • Added support for UE 4.27 and extended backward compatibility up to UE 4.22.
  • The Blueprint example project is now available on Github.
  • Fixed ALobbyistState::PlayerRemoved being called with an invalid (pending kill) player reference on remote non-owning clients.
  • Fixed GetNetMode incorrectly returning NM_Standalone in ALobbyistClient and ALobbyistState on remote clients.
  • Fixed a couple of cases where clients failed to be notified that login had failed on the host.
  • Cleaned-up ALobbyistHost::ProcessLogin and added a new C++ ALobbyistHost::LoginComplete event that’s called at the end of the login process.

Example projects have been updated to include a minor change required to make them work with Lobbyist 1.4. If you used an example project as the base for your own game the following changes are required to make it compatible with Lobbyist 1.4:

Blueprint changes required to make the example project compatible with Lobbyist 1.4
/Content/Blueprints/Menu/BP_LobbyPlayer.uasset
// Private/Menu/ExLobbyPlayer.cpp

void AExLobbyPlayer::BeginPlay()
{
Super::BeginPlay();

// Kickstart ping calculation on remote clients
if (IsNetMode(ENetMode::NM_Client))
if (IsNetMode(ENetMode::NM_Client) && IsLocalPlayer())
{
RequestPingUpdate();
}
}
Version 1.3 (17 May 2021)
  • New C++ example project.
  • Added an overridable OnDisconnected event as a direct counterpart to OnConnected to ALobbyistClient.
  • Fixed reason why a player failed to login not being returned to the client.
  • Fixed utility C++ templated getters not working, plus added a few new ones.
Version 1.2 (13 May 2021)
  • Improved connection code to handle cases where connection port is invalid when using the Null subsystem.
  • Example Project. Fixed character skin not being applied correctly when testing using “Play Standalone” option in the editor.
Version 1.1 (8 May 2021)
  • Fixed FLobbyistLoginResult not being API-exported.
  • Improved in-code documentation.
  • Minor docs and API improvements.
Version 1.0 (24 March 2021)
First public release.