Multiplayer Seamless Travel

The game I’m currently working on it is my first, and so I had to learn now pretty much everything from 0 that is related to gaming engine. Right now I’m done with the main menu and everything related to creating an account, the ability to update it, and connecting to the server that controls the interaction with the database (not the server that is created for players to join and load maps…), which actually doesn’t have much to do with the game engine (beside mostly the UI), and my programing knowledge was actually really useful for this part.

Now from what I read on the internet you can have two ways of travel between maps, seamless and non-seamless travel, the first one being recommended, and so I’ll use that one. I’ve read the basic documentation about this and I understood what it should do in the background (how you’ll load a between map to remove the old and load the new one, and that you can keep some actors).

But I still have some questions to make sure I understood it right, and to get some help:

  1. In that documentation it says that the GameMode (which I know is available only on the server side) gets carried over to the new map. Now this also raised two questions:
    1.1. Does this mean that for all maps I should use just one GameMode (Level -> Selected GameMode) instead of having a different one for each of them, as a new one won’t be created when the new map is loaded so it would be useless, or maybe it would actually create some problems if you have a different ones?
    1.2. Because the GameMode contains the GameState as well as PlayersState, does this mean that they will also be carried over, and new ones won’t be created with the new map? This actually is important as you have some information inside PlayerState and/or GameState that you would want to keep and other to reset/remove.
  2. Because of the transition map, does that mean that if you want to have a loading screen, inside that map is where you should show the UI, and not show/create any environment elements on the map? Or instead of an UI to give the players access to roam around until the new map is loaded? Like you have in Assassin’s Creed games, that void world where you can move around.
  3. Will the players be transported to the new map when their system is done loading the new map? Or they will be transported to the new map when all players are done loading the new map? This is good to know because if they are send when their system is done loading the map, then not all the players are on the new map yet, and you should add a “wait for everyone to be done loading” thing. Or does it wait for everyone to load into memory the new map, and only then everyone is sent to the new map? This can be a little hard to test on the same PC using standalone.
  4. Can someone link me a good YouTube video where they explain how this process is done? I’m a person that learns a lot faster by example and not reading theory, and so when I’m working on it and I get stuck, I’ll have a material to compare how I’ve done with that.
3 Likes

Edit: Also read my next post as I changed some things of how I’m doing what I said in this post

So far from my testing I noticed the following (they may not be accurate, and so corrections are welcomed):

1.1: Yes, you should use the same GameMode for all the maps that you use seamless travel to load them.

1.2: From my testing the variables values that I added inside GameMode, GameState, PlayerState (which were set to replicated) didn’t carry over to the new map, but that wasn’t the case with PlayerController, here the variable value did carry over after servertravel X was called. Inside the basic documentation it says that the GameMode should be carried over by default, but in my case it didn’t, so maybe you need to set something for them (GameMode, GameState, PlayerState) to carry over. I’m using UE5, and maybe they changed that behaviour in this version, as the documentation link says 4.27, or maybe they simply forgat to implement this too, as they did with other stuff in 5.0 (like with set style at runtime for some UI elements, which they said will be fixed in 5.2).

2: The way that seamless transition work is that any widgets on screen will stay there even when a map is changed. An easy way to remove them is to call Remove All Widgets in Event BeginPlay of the map. But here I found a problem. On normal maps the Event BeginPlay is called as expected, but when the transition map is loaded, that event doesn’t get triggered. Maybe that is a bug or just how it was made, I can’t say. As a simple test I added a create widget in Event BeginPlay but the widget didn’t showed, and so as an additional test I added only a print string in that event, and it didn’t get called/showed.

3: I can’t say for sure just yet, as the only tests I’ve done were on the same PC with multiple standalone versions of the game. I’ll try later a test with a different PC and see what happens. I can say that on the same PC, all players were send to transition map at the same time, and from transition map to the new map all at the same time.

4: I didn’t found a really good video to share, but I can say that there isn’t really all that much to it. Just make sure that inside your GameMode you have Use Seamless Travel checked, and inside your Project Settings -> Maps & Modes -> Default Maps -> Advanced -> Transition Map (for UE5, in UE4 I think those settings may be different as layout) you set the transition map. That is a map where everyone is send so that the old map is removed from memory, and the new map is loaded into memory. This means that the transition map should be something really small, with not much activity to not impact map switching time. Then when you want to load a new map use the node Execute Console Command and for the String you need to write servertravel followed by a space, and then the name of the new map, and for Specific Player set Get Player Controller 0. And be careful at what information is carried over to the new map, and which you need to set/reset.
Example:

As I said in the beginning, the information may not be accurate so do your own testing to be sure.

2 Likes

A small update for my previews statement:

For my game I created a parent actor for GameMode and then also a parent actor for GameState, PlayersState, PlayerController and then added them as defaults for the parent GameMode.

Doing this helps me A LOT with organization for each map when it comes to these actors. Inside the parent actor for each of them, I have only the functions that are used on ALL of the maps. For example:

  1. On all of the maps you spawn a character, and so inside PlayerController I have a function that spawns the character based on the character and skin the player selected (in my case the game is MP, so you have a character selection section);
  2. Each player has a nickname on all of the maps, and so I added that inside PlayerState as a variable as well as a functions that sets that variable on Event BeginPlay;
  3. On each map I have an area where players are spawned before they are ready to start, and so I have the default area actor saved inside GameMode as only the server handles the player spawn, and that actor is added on map Event BeginPlay and using Switch Has Authority to know if the map is loaded on the server host or a normal player, and when a player is done with loading he/she is spawned at that actor location until a “Start” event is triggered.

And then for each of the maps I’m creating a child to the parent actor, and inside them I’m adding functions related to one map. For example you have a map with traps, and you handle what happens with the player when he/she triggers one inside MapXPlayerController (move player to start/checkpoint, kill player, stun the player…), but then you have a different map without any traps, so you don’t need those functions and so they won’t show inside your event graph or inherited variables/function list.

Because now for each map I use a different GameMode (but with same parent), the Event BeginPlay is called for each of the main actors (Mode, State, Controller), but because I have the functions related to all the maps inside the parent, it isn’t a problem as you’ll call the parent Event BeginPlay and that will handle the common part of the BeginPlay (so you don’t need to write it again or copy/paste), after which you add what you need for each of the maps.

image
(Right click Event BeginPlay for the menu)

The part with using a parent actor is useful for a lot other things as well, in case of characters for example, maybe you have X of them melee and Y of them ranged, then make a parent for all of them which has the common info (health, speed, damage… variables, functions, UI elements like HP bar…), then from that parent make 2 children, one MeleeParent and one RangedParent which contains common variables/functions related to only that type of character, and then from those two, you have the actual characters with parent one of those two types.

As mentioned before, I’m just a beginner, and maybe something I said is wrong, or it can be optimized better. But these are a few of my observations that I wanted to share.

1 Like