This article was initially published on my Medium Page.
Lately, I have published a series of articles and videos about creating a real-time multiplayer game with Unity3D and Amazon GameLift. The feedback I received about them had been outstanding: a lot of developers downloaded my source code and made their own projects and games using Amazon services.
I received many messages and e-mails asking me for help as well. Let’s be honest: the architecture of a real-time multiplayer game that I always suggest is simple but contains a lot of distinct elements working together like the cogs in a well-oiled machine. A simple mistake and the whole architecture will fail. Furthermore, GameLift can sometimes be unfriendly; I personally had some hard times when trying to find the cause of an error or bug.
In this post, I will explore the common errors people have experienced and how to debug a GameLift game server.
Do you prefer watching a video instead of reading? Here you have:
5 Common Errors To Avoid
This is the architecture of a real-time multiplayer game I always suggest in my videos and articles:
And those are the 5 common mistakes related to the architecture I could identify:
1. AWS SDK for .NET
Numerous people asking me for help had trouble connecting to the Lambda function from Unity. Remember that Unity uses .NET Standard 2.1, and the Amazon documentation recommends downloading the AWS SDK for .NET here for Unity. If you download the wrong version or download it from elsewhere, some Amazon services won’t work correctly, including the Lambda calls.
2. Multiple Unity Desktop Clients
In my code, I have included a mechanism to avoid consuming the game server resources if the users minimize the application using the Unity functions OnApplicationFocus and OnApplicationPause. Some of you were trying to launch multiple Unity desktop clients and experienced server disconnections in the out-of-focus clients. In this case, please comment both functions or add a conditional compilation for the Unity editor in the AppController
class.
3. Client Proxy / Firewall / VPN
The connection between the Unity client and the game server is established thanks to the TCP and UDP networking. Ensure you don’t have any software or system that could block your TCP and UDP ports, like a proxy, firewall, or VPN.
4. Memory Provisioning for Lambda
I have been told that for the first connection after a long time to the Lambda function, an error is returned, and the player can not join the game. This is totally “normal”: this phenomenon is known as a cold start.
According to the cloud experts PluralSight, “A cold start occurs when an AWS Lambda function is invoked after not being used for an extended period of time, resulting in increased invocation latency.”. A Lambda function has a default timeout of 3 seconds; an error is returned if the execution time exceeds the function timeout.
To solve this slow invocation issue, Amazon recommends over-provisioning your Lambda function memory instead of the timeout to avoid unexpected costs.
5. GameLift Launch Path
Before creating your GameLift fleet, you need first to upload to GameLift a compressed archive (zip file) containing your Realtime script and dependencies. During the fleet creation, you will be asked for the launch path, in other words, the path of your Javascript code file within the zip file. For example, if you have no dependencies and have compressed the Javascript file directly, the path will be file.js
. If you have compressed a folder containing your Javascript file and dependencies, the path will be folder/file.js
.
if you want more insights about the Realtime script, please check my post about it:
Debugging a GameLift Game Server
Suppose that your Unity client runs great, and your Lambda function is called correctly, but a new game session can not be created, probably due to an error in GameLift. The first thing you must check is whether your game server is running correctly, thanks to the GameLift events and metrics.
Events & Metrics
In the GameLift console, click on your fleet and go to the Events section. This section collects all the log entries describing an event that involves GameLift resources. The GameLift documentation says the following: “In addition to tracking activity, event codes and messages can provide additional information for troubleshooting and debugging problems.”
If your fleet is running correctly, you should see the following main events showing up in this specific order: FLEET_CREATED
, FLEET_STATE_VALIDATING
, FLEET_STATE_ACTIVATING
, FLEET_STATE_ACTIVE
, FLEET_SCALING_EVENT
.
If you see critical messages like SERVER_PROCESS_TERMINATED_UNHEALTHY
during the fleet creation, something may be wrong with either the launch path (see previous section) or your Realtime script (wrong syntax or broken dependencies).
The last message of the successful fleet creation is a scaling message, meaning that your fleet has automatically scaled up, launching a new EC2 instance. If you go to the Metrics section, you can visualize it:
Your game server is running correctly!
Game Session Logs
Now, suppose that your game server is running correctly: your fleet has scaled up, and no critical messages have shown up during the fleet creation. You are able to execute multiple Unity clients at the same time, and the multiplayer feature works great. However, in some cases, you notice that for some actions you perform in the Unity client, your game server does not have the expected behavior and can even crash. Something is failing in your Realtime script, and you want to check the value of certain variables at a precise moment in time.
There is a simple workaround: you can write into the game session logs and then access them to see what happened.
Writing into the game session logs
Do you remember my previous article about talking with NPCs?
I will add a few lines of code in the Realtime script: when a player starts to talk with an NPC, I will write information into the game session logs. According to the GameLift documentation, there are 6 levels of server log messages; let’s try with 3 of them: info
, warning
, and error
.
We have written into the game session logs; now, let’s access them!
Accessing the game session logs
This part is a little bit tricky. As described in the GameLift documentation, when a game session finishes, the related logs are stored in an S3 bucket. There is no simple way to access those logs; the only way to achieve it is by using the GetGameSessionLogUrl API call to get the location of the logs. I will implement the API call in a Lambda function. I’m a Python guy so I will do it with Python, but it’s up to you to use your favorite language!
Remember that Lambda includes boto3, the official AWS SDK for Python, perfect! Checking the documentation of the boto3 function get_game_session_log_url, we can figure out that the function requires a parameter called GameSessionId
, described as “A unique identifier for the game session to get logs for.”. There is a slight confusion with the boto3 documentation and, more generally, with the whole Amazon documentation: we need the game session ARN, not the game session ID.
Building the Lambda function
Now we can write the function:
Before executing the function, we need to give the Lambda function the necessary permissions to access the game session logs. Go to the Lambda function role and add the following policy:
Reading the logs
Now, let’s execute the function! The answer will return a pre-signed URL of the location of the logs for the specific game session:
Note that a pre-signed URL is temporary: in this particular case, the URL is valid for 15 minutes after the request. Visit the URL with your favorite internet browser and download the logs. Our messages can be visualized!
Final Thoughts
Thanks for reading this post until the end! I really hope it helped you troubleshoot your real-time multiplayer game and understand more deeply how the game session logs work.
If you have any feedback or questions, feel free to reach out to me on my social networks:
See you in the next post!