Unreal Engine Multiplayer Tips

Luccas Schmigel
4 min readMar 20, 2021

--

These last 2 months I started developing a multiplayer project using Unreal Engine. At Carbon Zero we’re working hard to have our Beta launched as soon as possible. However, I decided to create a well structured ground in C++ rather than creating a Blueprints Prototype.
This article is a list of tips about Unreal Engine Multiplayer, mainly focused on C++, although many ideas can be applied in Blueprints.

1 Game Instance only exists for the current executable.
If you execute a local packaged game, then any reference to the Game Instance in your code will point to this packaged. Same if you refer to the Game Instance when on Server. It’ll point to the server Game Instance. It’s not possible to access other Game Instances other than the current executable. It doesn’t matter if your running a local package or a server packaged.

// will return this packaged game instance
UGameInstance* GI = GetGameInstance();

2 Game Mode only exists in the server.
When running the Server-Client model, the Game Mode will only exist in the Server. When trying to access the Game Mode in a multiplayer code it will return the server Game Mode. There’s only one copy. You don’t need to check if it’s running in the Server to get the Game Mode. However, if you check if it’s running locally, the Game Mode will return null. (you may need to cast to your game mode class to check this behavior).

#include "Kismet/GameplayStatics.h"// If trying to get Game Mode from a Client, it will return NULL 
if (GetLocalRole() < ROLE_Authority)
{
AGameModeBase* GM = UGameplayStatics::GetGameMode(GetWorld());
if (!GM) {UE_LOG(LogTemp, Warning,
TEXT("GM from Client is not Valid"));}
}

// If trying to get Game Mode from a Server, it will return valid
if (GetLocalRole() == ROLE_Authority)
{
AGameModeBase* GM = UGameplayStatics::GetGameMode(GetWorld());
if (GM) {UE_LOG(LogTemp, Warning,
TEXT("GM from Server is Valid"));}
}

3 Multicast purpose
is to execute the code on the Server and on all current connected Clients. However this will happen only if the function happens to be called on the server. So if your’re on a Client it’s common to first use a Server RPC that calls the Multicast function.

header

UFUNCTION(Server, Unreliable)
void SR_TestFunction();
void SR_TestFunction_Implementation();

UFUNCTION(NetMulticast, Unreliable)
void MC_TestFunction();
void MC_TestFunction_Implementation();

cpp

void APlayerController::SR_TestFunction_Implementation()
{
// code to be executed on the Server
// call the MultiCast function
MC_TestFunction();
}

void APlayerController::MC_TestFunction_Implementation()
{
// this code will be executed on the Server and on the all connected Clients
// MultiCast Code
}

4 Game Mode doesn’t replicate.
This behavior is linked to the fact it only exists in the server (item 2). To replicate values it’s recommended to use the Game State Class. For values that are game related. If you need to replicate Player related values, it’s recommended to use the Player State Class.
Just remember that any property inside those classes that you want to be replicated needs to be marked as replicated.

5 For Seamless Travel to work, it need to be actived in the Gamemode.
Also, you need to use a ClientTravel with Relative option or ServerTravel. If the current level is local, and you’re connecting to a server, the seamless travel is not possible. https://docs.unrealengine.com/en-US/API/Runtime/Engine/Engine/UWorld/ServerTravel/index.html

6 Seamless Travel enables you to copy properties and objects across maps.
Player Controllers are copied by default. Player States need to use Copy Properties. Other Actors need to be listed to be part of the seamless travel. You can copy properties inside the Player State using Copy Properties. However it’s only possible when using Seamless Travel.

header

FString StringTest;virtual void CopyProperties(APlayerState* PlayerState) override;
virtual void OverrideWith(APlayerState* PlayerState) override;

cpp
(APSBase in this example is the custom PlayerState)

APSBase::APSBase(const FObjectInitializer& ObjectInitializer) : Super(ObjectInitializer)
{
StringTest = "test";
}
void APSBase::CopyProperties(APlayerState* PlayerState)
{
Super::CopyProperties(PlayerState);
if (PlayerState)
{
APSBase* PS = Cast<APSBase>(PlayerState);
if (PS)
{
PS->StringTest = StringTest;
}
}
}

void APSBase::OverrideWith(APlayerState* PlayerState)
{
Super::OverrideWith(PlayerState);
if (PlayerState)
{
APSBase* PS = Cast<APSBase>(PlayerState);
if (PS)
{
StringTest = PS->StringTest;
}
}
}

7 Skeletal Meshes do not replicate.
If you change a skeletal mesh in the Server it will not automatically replicate the change to the clients. One way to solve this is to use a Multicast that changes the mesh and call the same change in all machines. Remember that the Multicast needs to be called from the Server. Another way is to use a RepNotify whenever the Mesh property changes as showed below.

Player Character header

UPROPERTY(ReplicatedUsing=OnRep_Head)
USkeletalMesh* HeadMesh;
UFUNCTION() void OnRep_Head();

Player Character cpp

void APCharBase::SetNewSKMesh(USkeletalMesh* NewMesh)
{
HeadMesh = NewMesh;
}
void APCharBase::OnRep_Head()
{
SKMeshHead->SetSkeletalMesh(HeadMesh);
}

This is a simple list that I hope can give some light to anyone starting to face the multiplayer coding challenges. If you have any questions feel free to ask. I can further detail any of the items listed.

Best,

--

--

Luccas Schmigel

Unreal Engine Dev at CarbonZerø and Teacher / Author of UE4 Class: Blueprints course and Epic Mega Grants winner.