UE4 Starting Sessions with a Specific Map

There seems to be a chicken and egg scenario when it comes to Maps in a GameLift solution. This seems like a really fundamental aspect of the solution that I can’t seem to find any documentation on.

The question is: How do you start a session with a specific map? There are 2 scenarios.

New Instances

For instances that have not yet been started. The solution would seem to be, as part of StartGameSessionPlacement, if GameLift looked through GameProperties for special keys and added them to an instances startup parameters. I can’t find any evidence or documentation of this. Am I missing it? Is this an actual thing/feature that exists? Are the keys documented anywhere?

Existing Instances

In the case of already existing auto-scale instances that are not yet activated, we need a different solution. For instances in this category, it seems that the expectation is that we should transition the server to the new map before calling ActivateGameSession.

The fundamental problem is: How do we preserve the GameLift state during this transition? GameMode is not preserved on level transition, seamless travel or not. And different maps have different GameModes, so the expectation should always be that GameMode will go away on travel (because it does and there’s literally no changing that). Where does that leave GameLift and its current state waiting for ActivateGameSession to be called?

Since the entry point for GameLift is GameMode, the only way to preserve any data across map changes would be:

  1. Stuff it into the GameInstance and perform seamless travel (could be any arbitrary data)
  2. Pass it via URL parameter to the new map (only valid for strings)

How do we save/restore the GameLift state across map/gamemode transitions?

So I am using a plugin for UE4 but I think it should be applicable. This is a very basic explanation. What you should do is create what you can call a “Decicated server entry gamemode” It’s a gamemode specifically for handling what level to load. It will be your default dedicated server gamemode. When you create your gamelift session give it a game property of the level name, then in this Dedicated Server entry mode when constructing process parameters, have it get that game property of the level string, and just open the level with that string.

This ignores the state of GameLift, how are you preserving it across map loads? Are just re-initializing it a 2nd time? Are you tearing down all of the bound lambdas and rebinding them?

I just reinitialize a 2nd time. It’s the only way I could get it to work. It doesn’t seem to cause issues for me.

Honestly i am by no means an expert, perhaps there is a better way to do it,but this is how I got mine working.

I just changed my implementation and moved all of the GameLift stuff to GameInstance. IMO this is how it should have been designed. Proxy a few calls from the GameMode over to there, GameLift stays alive, seamless travel to change maps, no double init of GameLift.

The problem with this is that the GameLift object isn’t a UPROPERTY and it isn’t tied to the lifecycle of any UE4 type in any way. So you are in-effect initializing 2 completely separate GameLift instances.

This is probably pretty easy to see if you print a message during the HealthCheck. You’ll see a message printed in 1-minute increments from the time of the first init as well as 1-minute increments from the time of the 2nd init.

Would this show 2 servers running in metrics? or would it only be noticable from printing during health check? I haven’t noticed any issues with multiple servers running

I didn’t see 2 servers running in the metrics. But I did see all of our instances had 2 health checks running 1-10 seconds apart, which tipped me off that there was an issue. I don’t trust a darn thing that it’s doing behind the scenes since I can’t see the code.

In my searching around, I did find another call that escaped my notice until now:
InitSDK returns a value of type InitSDKOutcome and there’s another call InitSDKWithExisting that takes an InitSDKOutcome.

I’m guessing this is how they intended on picking up the SDK state. You’d need to squirrel that into the GameInstance and seamless travel to use it.

Hmm this could actually be what’s causing a seperate issue for me. I’m getting this bug where on multi-location fleets in non-home region locations whenever a player joins or leaves, it causes a big lag spike. Are you using a plugin for gamelift or coding it yourself?

I’m using the GameLiftServerSDK plugin provided by amazon. It’s on-par with all of the other amazon SDKs that I’ve used - outdated and incorrect documentation combined with sample code that’s not suitable for production.

Nice. So you found a way to open specific levels you said earlier? can you explain it briefly? I wonder how different it would be with my plugin or if I would even be able to do it. I just have blueprint node idk if I could do whatever method you’re doing for it. Lol sorry didn’t mean to make this about my problem. I’m reading your message again, I’m not sure what you mean by proxy a few calls over to the game mode

Are you storing the level in a player’s game instance, then when he joins the gamelift session, he sends the level string from game instance to the gamemode, then the gamemode loads the new level with that string with seamless travel?

This is for dedicated servers. So it all happens before any player connects.

The process begins in the callback that you bind to OnStartGameSession

In that callback, I’m pulling out the GameProperties from the GameSession object and looking for a property that has a key called “map”. I previously stuff this parameter in when I request a new game session from a client.

If I find that key, I set a bool in the GameInstance that indicates we’re waiting for map travel to complete. I then begin seamless travel to the new map. Then in GameMode PostSeamlessTravel, I call into GameInstance to let him know that we’ve arrived, this then calls ActivateGameSession to complete the GameLift flow.

By Proxy calls, I mean that in GameMode, PreLogin calls into GameInstance to handle calling AcceptPlayerSession on the GameLift object.

Hmm ok so that’s similar to what I’m doing, I think I just need to use seamless travel and remove the code to initialize a 2nd time. Hmm ok I should probably also change my accept player session to be called pre-login, mine is post login. Hmm ok ty for this info. Good luck.