Multiplayer Shootout

Choose your OS:

MultiplayerExample_Header.png

The Simple Blueprint Multiplayer showcase is a game built entirely in Blueprints and UMG UI and is an example of how you might use Blueprint's Session Nodes to facilitate multiplayer in your game. It has a Main Menu, a Server List, and a simple map with a Scoreboard on the HUD. Clicking Play at the Main Menu will host a session and load the gameplay map. Other players can then click Find games to see a list of all hosted games on a new menu screen, where clicking on one of the found games will attempt to join it. If there are any errors, a dialog is displayed and the user is returned to the Main Menu.

This game is also an example of how to manage state using a GameInstance Blueprint. The GameInstance is a convenient place to do this, since it persists between map loads, and is also the object that receives error events. Most of the session calls and menu transitions in this sample game are handled in the GameInstance.

In its current state, this document covers the Online Session Nodes and their implementation for hosting, discovering, joining, and leaving multiplayer games. This document will be updated to reflect the gameplay aspect of shooting and hitting other players, dying/respawning, and scoring at a later date.

Starting/Playing the Game

This section covers how to start and play the game itself and provides a breakdown of the game's components.

If you are new to mulitplayer testing inside Unreal Engine 4, you may want to review the Testing Multiplayer documentation.

To load up the game:

  1. Open the Game/Maps folder and the MainMenu map.

  2. With the MainMenu map open, click the down arrow next to the Play button and set the Number of players to 2.

    SettingNumberOfPlayers.png

    The Run Dedicated Server option may cause issues with correctly displaying the Server List and is a work-in-progress.

  3. Click the Play button to launch the game.

  4. When the game launches you will be presented with the following screens.

    twoWindows.png

    Above we are playing in New Editor Windows set to 640x480 each, which you can set in the Advanced Settings... option.

    If you are doing testing over a network and not a local multiplayer game like above, use the Standalone Play Mode and join games or have others join your hosted game. Attempting to run a networked game through the PIE (Play In Edtior Modes) currently is unstable and is in the process of being addressed.

A breakdown of the Main Menu is outlined below.

MainMenu.png

Option

Description

1

Start and host the game from the current game window.

2

Display the Server List screen with all active games where you can choose a game to join.

3

Quit the game.

4

Toggle the connection mode between LAN games or Internet games.

Once you have selected to host or join a game, you will enter the gameplay area as seen below.

InGame1.png

In the upper-left hand corner of the screen (in the yellow box) you will see some text which is for your player character's name. In the green box to the right of the player character name is your current score. As players join the game, the box in the upper-left will become updated to reflect the current amount of players in the game and their current score.

TwoInGame.png

The player names depicted above are currently being taken from a LAN game. When using a service like Steam, the player's Steam names will be displayed here instead.

Once you have a game hosted, click the Find games button on a second player to display the Server List.

ServerListWindow.png

After a moment to search for games, the currently active games will be displayed in the list. In this window, from left to right, the name of the server is displayed along with the number of players in the game and the current ping for the game session. In the lower left corner of the screen you can click the Refresh button to update the list or click the Back button to return to the Main Menu. Clicking on a name in the list will attempt to join the server and spawn you in the game.

Once you are in the game, you must click the Left Mouse Button to signal you are ready.

1Ready.png

When clicking to ready-up (Server or Client), text will be displayed in the upper-left corner of the screen indicating that player is ready.

After readying-up, you can then use the controls below to play the game.

Control

Description

Right Mouse Button

Draws the weapon (hold to keep the weapon drawn).

Mouse

Enters Aim Mode where moving the mouse allows you to aim the weapon.

Left Mouse Button

Fires the weapon.

Middle Mouse (Wheel Up/Down)

Reloads when not in Aim Mode.

Q

Brings up the in-game pause menu (resume or leave the game).

The objective of the game is to shoot the other player, which will give you a point and cause the other player to respawn. Each player is given 6 shots, which you can reload (one-by-one) using the Middle Mouse (Wheel Up/Down).

Project Setup/Configuration

This section covers each of the assets that were created (or modified) in the Content Browser with a description of what each does. Several of the Blueprints and UMG UI assets communicate with (or have dependencies on) one another so if you are attempting to reproduce this project from scratch, it is best to create each of the assets needed then populate them later.

Each asset can be found in their respective folders in the Content Browser:

Game/Blueprints/Widgets

Name

Description

ErrorDialog

This is the UI screen that displays any error messages that occur.

HUD

This is the in-game Scoreboard which displays ScoreboardRow widgets containing all player names and scores.

InGameMenu

This is an in-game menu that allows players to leave the game and return to the Main Menu.

LoadingScreen

A simple loading screen that appears when attempting to join a game.

MainMenu

The Main Menu when the game is launched. Allows the player to Host, Join, or Quit the game.

ScoreboardRow

This widget is added to the HUD and contains a player's name and score.

ServerList

This is a menu that houses a list of ServerRow widgets that display all available games to join.

ServerRow

This widget holds an individual row of data related to active servers including Server Name, Number of Players, and Ping. This is passed to the ServerList widget.

Game/Blueprints

Name

Description

MyGameInstance

(Instance Blueprint) - Handles all transitional states from the Main Menu and sub-screens to/from gameplay as well as Error Events.

MyGameMode

(Game Mode Blueprint) - Holds all the Default Classes (Pawn, HUD, PlayerController, etc.) Also handles respawning players and what happens when a player first joins a gameplay session.

MyPlayerController

(PlayerController Blueprint) Sets up the in-game UI and allows the player to open the in-game pause menu.

MyPlayerState

(PlayerState Blueprint) Handles each player's score.

ProjectileBP

(Actor Blueprint) Is the projectile that each player can fire at each other attempting to cause damage.

State

(Enumeration) This is a list of all the possible states the game can be in.

Game/Gunslinger

Name

Description

Gunslinger_BP

This is the playable character in-game.

GunslingerTTP

Skeletal Mesh used with the Gunslinger_BP.

Gunslinger_AnimBP

Used to drive animations for the Gunslinger_BP.

Game/Character

Name

Description

Character_Parent

(Parent) Material used for the Gunslinger_BP.

Character_Instance

(Instanced) Material used with Gunslinger_BP.

Game/Fonts

Name

Description

ScoreFont

A font added and used with the Scoreboard widget.

Game/Maps

Name

Description

MainMenu

The default map that loads when the project/editor starts and contains the Front End display.

Level_01

This is the gameplay map that player's spawn into when hosting or joining a game.

Configuration Settings

In order to successfully host or connect to multiplayer games, there are some settings you will need to make to your DefaultEngine.ini file which can be found in the following location (for example): UnrealProjectDirectory/ProjectName/Config

ExampleLocation.png

Once you open it up, you will need to specify the OnlineSubsystem to use as well as the DefaultPlatformService that corresponds to your subsystem.

For example, you can play over a LAN by adding the OnlineSubsystemNull:

[OnlineSubsystem]
DefaultPlatformService=Null

Or you can play over Steam for example, using the OnlineSubsystemSteam:

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

[OnlineSubsystem]
DefaultPlatformService=Steam

[OnlineSubsystemSteam]
bEnabled=true
SteamDevAppId=480
bVACEnabled=0

[/Script/OnlineSubsystemSteam.SteamNetDriver]
NetConnectionClassName="OnlineSubsystemSteam.SteamNetConnection"

If you do use Steam, you will need some additional SDK and INI setup , refer to the link for more information.

Blueprint Walkthrough

In the following sections, we will walk through each of the various states of the game and look at the Blueprints that drive them.

Let us first take a look at the Startup sequence.

Startup

While in the MainMenu map, open the Level Blueprint.

Startup1.png

With the Level Blueprint open, you will notice a portion of script that indicates that "Game Logic Starts Here".

Startup2.png

This is an excellent comment as the game logic does indeed begin with this portion of script. Here we are saying when the game begins, get the game instance and Cast to the MyGameInstance Blueprint. Doing so allows us to access the Variables, Functions, and script inside it and in this case, calls a Function called Begin Play Show Main Menu (shown below).

Startup3.png

When Begin Play Show Main Menu is called, the first thing it does is run a macro that was created called IsCurrentState.

IsCurrentState Macro

Startup4.png

IsCurrentState checks to see if the In State (specified on the Macro Node) is equal to a variable called Current State (which is a variable that holds the current state the game is in). The Current State variable uses the Enumeration that was created called State that holds each of the states the game can be in.

Since the Current State is equal to the In State, the ShowMainMenuEvent custom event is called.

Startup5a.png

Startup5.png

The first thing that ShowMainMenuEvent does is run the IsCurrentState Macro to check the current state versus Playing, which if True would open the MainMenu level, but the game is currently in the Startup state and so returns a False value. This calls another macro that was created called TransitionToState.

TransitionToState Macro

Below, on the TransitionToState, the first thing it does is run the IsCurrentState Macro (1) to check the Current State versus the Desired State and if they are equal to each other an error is printed to the screen (2). If they are not equal to each other, the Switch on State node is executed (3) which gets the Current State and either runs a Function (if applicable) called Hide Widget (which hides the UI Widget currently being displayed) or runs a custom event called Destroy Session Caller (which destroys the session for the player who calls it).

Startup6.png

After the Switch on State is complete, the Current State is updated to reflect the specified Desired State.

After running the TransitionToState macro, we can continue with the ShowMainMenuEvent custom event.

Startup7.png

Above, the IsValid node (1) is executed which checks if the variable Main Menu is valid, which upon first run is not (if it were it would skip (2) and (3) above). Step (2) uses the Create Widget node to create the UMG Widget Blueprint called Main Menu and then promotes it to a variable (3) so that it can be accessed later without having to re-create it. In (4) the Set Input Mode UIOnly node is used to restrict input to UI only and in (5) the Main Menu widget is added to the viewport, displaying the Main Menu screen.

Startup8.png

Next we will look at what happens when you press Play to host a game.

Hosting a Game

After the Main Menu has loaded and you click the Play Button, inside the MainMenu Widget Blueprint, the following script is executed.

Play1.png

The OnClicked Event corresponds to the Button designated as the "Play" button on the Designer tab of the MainMenu Widget Blueprint. This event when fired, gets the game instance and Casts to the MyGameInstance Blueprint, allowing us to call a custom event inside it called Host Game Event.

Play2.png

The first thing HostGameEvent does is run a custom event inside the MyGameInstance Blueprint called ShowLoadingScreen.

Play3.png

When ShowLoadingScreen gets called, it runs the TransitionToState Macro (with the Desired State set to Loading Screen).

We then continue with the ShowLoadingScreen Event by running an IsValid check (1) below.

Play4.png

IsValid checks if the variable Loading Widget is valid, which upon first run is not (if it were it would skip (2) and (3) above). Step (2) uses the Create Widget node to create the UMG Widget Blueprint called Loading Screen and then promotes it to a variable (3) so that it can be accessed later without having to re-create it. In (4) the Loading Widget is added to the viewport with the Add to Viewport node and the Set Input Mode UIOnly node is called to restrict input to UI only during the loading screen (which at this point is displayed in-game).

Play5.png

After the Loading Screen has been displayed, the script jumps back to the HostGameEvent and the Create Session node.

Play6.png

On the Create Session node, the number of Public Connections (or players allowed to join the session) is set to 4. There is also a Boolean variable called Enable LAN which is plugged into the Use LAN input pin. This Enable LAN variable is used with the Play Mode Toggle on the Main Menu which will be discussed later in this document. If the session is successfully created, the Open Level node is used to open the map that will be used for the play session. If there are any failures, the OnFailure pin is executed and a created macro called DisplayErrorDialog is called.

DisplayErrorDialog Macro

The DisplayErrorDialog macro when called first executes the (1) TransitionToState Macro to transition to the Error Dialog state. After the new state has been applied, a custom event called Destroy Session Caller is executed (2) which destroys the session for the current player (this can be found on the Event Graph). Following the session being destroyed, the engine macro IsValid checks to see if the variable called Error Dialog (which points to the Error Dialog Widget Blueprint) is indeed valid.

Play7.png

Upon first run, the Error Dialog is not valid, if it were it would skip (1) and (2) below and go straight to (3).

Play8.png

Upon first run however, (1) above which uses the Create Widget node to create the ErrorDialog Widget Blueprint is executed. In (2), the ErrorDialog Widget Blueprint is promoted to a variable called Error Dialog (which can now be used the next time this macro is performed). In (3), the Function Set Message from inside the ErrorDialog Widget Blueprint is called which gets the message specified on the macro node and sets it as the message to display in the dialog box (yellow box below) while the Add to Viewport (4) displays the Error Dialog Widget Blueprint on screen and (5) uses the Set Input Mode UIOnly sets the input mode to only UI.

Play9.png

With no errors, the map specified in the Open Level node is loaded and the player enters Gameplay.

Joining a Game

From the Main Menu, clicking the Find games button will start the script inside the MainMenu Widget Blueprint below.

Findgames1.png

The OnClicked Event here is tied to the Button specified as the "Find games" button on the Designer tab of the MainMenu Widget Blueprint. When fired, the game instance is Cast to MyGameInstance Blueprint which allows us to access it and call the Show Server List Event inside it.

Findgames2.png

The ShowServerListEvent starts off by running the TransitionToState Macro (1) which sets the game state to Sever List. From there, the IsValid (2) check occurs against the Server List Widget Blueprint variable, where if valid uses the Add to Viewport (5) node to display the Server List menu onscreen. Upon first run however, the Server List screen needs to be created using the Create Widget (3) node, then promoted to a variable (4) before displaying it onscreen. Once the screen has been set to displayed, the Set Input Mode UIOnly node sets the input method to only UI.

During (5) above and before (6) and actually displaying the Server List Menu, additional script is executed inside the ServerList Widget Blueprint which is used to populate the Server List menu with any active games. As seen below inside the Server List Widget Blueprint, the Event Construct node is used and fired off when the Widget Blueprint is called to be constructed (created) and immediately executes a created macro called RefreshListMacro.

Findgames3.png

RefreshListMacro

The RefreshListMacro performs quite a few tasks, the first section of which is illustrated below.

Findgames4.png

Above when the macro is called, the first thing it does is set a Boolean variable called Refresh Button Enabled to False (1) which disables the Refresh Button and prevents the player from being able to press it. Next, a variable called Status Text is set to Searching... (2) and its Visibility is set to Visible (3) which allows the Widget holding the Status Text to be updated and displayed.

In (4) an array variable called Found Session Widgets, which is a collection of ServerRow Widgets used to populate the Server List, each one that exists is removed using the Remove Child (5) node. This is effectively removing any servers that are to be listed when the screen is displayed. In (6), the Found Session Widgets variable is also cleared removing any previously stored sessions, so that everything is wiped clean before performing a new search.

Next, the macro gets the game instance and uses the Cast To MyGameInstance node (1 below) in order to access whether Enable LAN is true or not (which is used when searching for sessions).

Findgames5.png

The Find Sessions node (2) is then used to discover any sessions that exist (which are output to the Results value). Also on this node, you can set the Max Results (number of search results to return). The results from the Find Sessions query are assigned and stored in an array variable called Found Sessions (3). A Branch is then performed (4) to check the Results, and if equal to 0, the True pin is executed (if not, the False is executed). If for any reason there is a failure when using the Find Sessions node, the OnFailure event is called and changes the Status Text that is displayed to Search failed (5), informing the user that the search for sessions did not complete.

Off of the Branch (4 in the previous image), if True (which means no sessions were found) the Status Text is set to No sessions found (7 below) and the Refresh Button Enabled variable is set to True (8) so that the player can press the Refresh button to attempt to search for sessions again.

Findgames6.png

If sessions are found, the Status Text Visibility is set to Collapsed (1) so that it is hidden from the player. A ForEachLoop node (2) is then used to take each of the Results found and, using the Create ServerRow node (3), create a Server Row Widget for each of them. These will be the individual rows of sessions found in the server list.

In (4), the Results are also added to the Found Session Widgets array before calling the Set Search Result Function inside the ServerRow Widget Blueprint (which used to generate the Server Name, Player Count, and Ping to be displayed). After setting the content to be displayed in the ServerRow Widget Blueprint with the Set Search Result node, the Add Child node (6) is used to add each of the ServerRow Widget Blueprints created to a Scrolling Servers scroll box that is displayed in the Server List menu.

After each of the sessions found has had a ServerRow widget created, populated and added to the Scrolling Servers widget, the ForEachLoop is completed and the Referesh Button Enabled variable is set to True (8).

After having run through the RefreshListMacro to search for sessions, any sessions found will be displayed in the Server List menu.

Findgames7.png

Clicking the Refresh button will run the RefreshListMacro again to search for sessions. Pressing the Back button will execute the ShowMainMenuEvent custom event (which is outlined in the Startup section).

Clicking on a server displayed in the server list will fire off the OnClicked event in the ServerRow Widget Blueprint (see below).

Findgames8.png

The OnClicked Event for a ServerRow Widget, gets the game instance and uses the Cast To MyGameInstance node in order to call the Join from Server List Event inside it. The SearchResult variable (which was generated as part of the RefreshListMacro ) is passed to the MyGameInstance Blueprint as well and allows the player to attempt to join the server that they clicked on.

The JoinFromServerListEvent inside the MyGameInstance Blueprint (pictured below), when called first performs the ShowLoadingScreen custom event outlined in the Hosting a Game section.

Findgames9.png

While the loading screen is being displayed, the Join Session node is used to attempt to join the Search Result provided from the ServerRow Widget Blueprint the player clicked on to attempt to join. If successful, the player will join the server they selected and spawn into that game. If there are any errors, the DisplayErrorDialog is run and the Error Message of Failed to join session is displayed.

Gameplay

Before the player takes control of a character during gameplay, the character and game state need to be setup (or if joining a game, the game needs to be updated and told that a new player has joined). When clicking the Play button from the Main Menu or selecting a server from the Server List Menu to join, the first thing that occurs is a Post Login Event inside the Game Mode Blueprint which kicks off the setup process indicated below.

Gameplay1.png

When Event Post Login is fired, it first executes an engine macro called Switch Has Authority (1) which is used to check if the script is being executed on a machine that has Network Authority (on the Server) or if it is being executed on a Remote Machine (on a Client). Since this process occurs on the server for either hosting or joining games, the Remote pin leads nowhere but the Authority pin continues the Post Login script.

For another example on Switch Has Authority, see the Detecting Network Authority and Remote Clients in Blueprints page.

In (2), the PlayerState from the New Player is Cast to the MyPlayerState Blueprint, where the Player Number is set (3) and used to ensure that the order of players in the Scoreboard is displayed the same for all players (each new player that is added, is added to the Scoreboard list). After setting the player number, the New Player is also Cast to the MyPlayerController Blueprint so that the ClientPostLogin custom event is fired.

Gameplay2.png

Above, the ClientPostLogin Event has some properties assigned to it via the Details panel.

Gameplay3.png

Under the Graph section, the Replicates option is set to Run on owning Client and the Reliable checkbox is checked. Using these two options, we are stating that the script following this event is called by the server but executed on the owning client's machine only. The Reliable setting guarantees that this script will be executed and not lost due to heavy traffic (most replicated calls that handle cosmetic visuals are Unreliable to avoid network saturation, but in this case, we need this to occur so it is set to Reliable).

Now that we have identified where the script should occur, the Setup Ingame UI Function is called.

Gameplay4.png

This Function starts with a Branch (1) to check if the controller that is being targeted is a Local Player Controller and if it is, the Create Widget (2) is used to create the HUD Widget Blueprint. The HUD Widget is then promoted to a variable called HUD Widget (3) and the Add to Viewport (4) node adds the widget to the player's viewport. In (5), another Create Widget node used to create the InGame Menu Widget Blueprint which is promoted to the variable InGameMenuWidget (6) and can be used to call display the In Game Menu when the player presses the button needed to summon it.

At this point, the "login" process is complete and the setting up of the character itself occurs through the Character Animation Blueprint. Each of the character's movements states are defined and animations are set, which will not be covered here but if you would like to read more on Animation Blueprints, please see the Animation Blueprints documentation.

After the Character Animation Blueprint has been set up, the Level_01 map is opened. Inside this map, in the Level Blueprint, the follow script is called before the player actually spawns in the level.

level1LevelBlueprint.png

Above upon Event Begin Play for this map, the Cast To MyGameInstance node is called for the current game instance and from it, the Start Playing State Function is called. This function inside the MyGameInstance Blueprint changes the game state to Playing as shown below.

playingState.png

Once the state has been changed to Playing, the mouse cursor is locked to the game viewport with the Set Focus to Game Viewport node (3 in the previous image) and UI input is disregarded by using the Set Input Mode Game Only node (4 in the previous image).

Disconnecting from a Game

The process of disconnecting from a game is pretty straightforward and involves turning on/off from display some UMG Widgets and enabling the same start process that occurs when you first load up the game to return you to the Main Menu.

When Q is pressed during gameplay and the in-game pause menu is displayed, upon clicking the Leave Game option, the following process occurs inside the InGameMenu Widget Blueprint:

disconnectingGraph.png

Above, the Leave Button itself was clicked (1) so an Event is fired off which Casts to the MyPlayerController Blueprint (2) by getting the owning player. Inside the MyPlayerController Blueprint, the Function Hide in Game Menu (3) is called which is shown below.

hideingamemenu.png

This portion of script gets the variable In Game Menu Widget (which was created earlier and stored as a reference), then removes it from the screen with the Remove from Parent node. Following that, Set Input Mode Game Only is used to prevent the player from performing any other UI related input actions until we change the input mode again to allow for UI input.

The script then returns to the InGameMenu Widget Blueprint and the Cast to MyGameInstance node (4) which gets the current game instance and calls the Function inside it Show Main Menu Event, where the first thing that Function does is run the IsCurrentState Macro and the sections following it in the Startup section when first loading the game up.

disconnectingGraph.png