Fling to the Finish: Online Multiplayer & Matchmaking


Network Architecture Overview

The game uses the Photon Unity Networking (PUN2) API to manage its online multiplayer systems. I worked on making a robust system for connecting players with each other. The game lets players create & join rooms using room codes, or they can invite their friends (or join them).

A master client (or host) controls all of the physics objects in the game, including their own player characters. Non-master clients (non-hosts) control only their own player characters and sync every other object to the host. The host syncs other player characters to their owner clients.

Each room has a set of unique properties that are set using a Hashtable. This ensures that players only connect to rooms that have the games that the players wish to play (for example: finding campaign matches instead of races, etc.)

If there are too many objects being synced at a given time, then the game can run into packet loss issues. I resolved this issue by using network culling – only syncing objects that the client is immediately affected by. PUN’s approach for this is a concept called “interest groups”. Objects that are synced can be put into specific interest groups. My system works in the following manner:

  • At the start of a level, the host and non-hosts only listen to the main interest group
  • At the start of a level, the host starts the level only sends data to the main interest group
  • Once a non-host enters or leaves an interest group region, they notify the host about this change
  • If the host is notified of an interest group entry event, then the host starts sending data for that interest group, if it wasn’t already. Simultaneously, the non-host that entered this interest group begins listening to sync data inside this interest group
  • If the host is notified of an interest group exit event, then the host stops sending data for that interest group ONLY IF there are no more non-hosts listening to that interest group. Simultaneously, the non-host that exited this interest group stops listening to sync data inside this interest group
  • Non-hosts only receive data for the interest groups they are interested in, host only sends data for the interest groups that have at least one active listener

PUN2 only allows for matchmaking within the region that the client is connected to. This is very limiting, especially for a small game like Fling. The ideal way to get around this scenario would be to query a list of open rooms in all regions via a server that connects to different regions at regular intervals and checks if there are any open rooms. The game would then (while matchmaking) get a list of all such open rooms from the server and connect to one of them.

Unfortunately, due to our very limited resources, hosting a server for this purpose was out of question. To tackle the region restriction for matchmaking issue, I devised a solution where the game client would itself connect and cycle through each available region and try to find open rooms. If a game isn’t found after one complete cycle, the game would then start hosting a room for ~30 seconds in the region of best latency. After ~30 seconds, the client would restart a cyclic search through all regions. This process repeats until a match is found or the player stops match search.

The order of connectivity to all regions in this search differs based on which region the player is closest to. Each region has an ordered list of regions, each farther than the last. By using this approach, the algorithm ensures that it finds the best possible game for the player with the least amount of latency. In essence, this works somewhat similarly to a matchmaking system that would slowly expand its region radius over time to aid in finding a match.

Reiteration: high level overview of private games and matchmaking algorithm

Race vs Campaign matchmaking

Since players can choose to either find a partner for playing campaign (2 players max) or find a match to race against up to 7 other players, the game supports matchmaking into both modes. If a match in the desired mode isn’t found within a specific time, the user is prompted if they would like to expand matchmaking to find a match in either mode. As mentioned previously, I used Hashtable based room properties that aid in this.

Rigidbody Syncing

The game is very chaotic. Teams can interact with each other, and their ropes can get tangled. Teams also interact with many different obstacles in the game. Every single one of these objects is physics based. While many obstacles share similarities, many others are very unique ones. As such, each unique obstacle needs to be carefully studied and worked on to ensure that it syncs up properly over the internet.

I worked on writing the netcode to ensure proper syncing of many of these obstacles over multiple iterations, and maintaining proper sync of more complex interactions such as player-obstacle interactions, obstacle-obstacle interactions, and chained events that result due to these complex interactions. I also worked on writing netcode to ensure proper syncing of player movement and rigidbody physics.

This gets especially complicated when a team is shared over the network (that is, one character in the team is controller by player A on computer 1, and the other character in the team is controller by player B on computer 2). To maintain the same feel of the character controller, each client owns their half of the team and controls its physics, then sends that data over to the other half so it can sync those values on its side. The other half does the same for its own half of the team. P1 (character 1) and half the rope are owned by one client, and the other half of the rope and P2 (character 2) are owned by the second client, as demonstrated below:

P1 = = = = = = = | = = = = = = P2

This system then goes a level deeper, by placing a percentage based system on ownership (self-applied physics) vs synced physics. What this means is, that the further away a rope link from a player, the less they have control over it, and the more they sync its value from their partner player. The syncing vs self-physics calculation then looks something like this:

Blend of how much each player controls their rigidbody (shown in their own color) vs how much they sync it

Separate Chinese Servers

The game works on separate servers for the Chinese Mainland region. Players in this region cannot connect to the ROW (rest of world) regions and players in ROW cannot connect to Chinese Mainland. This is done to make sure that all players have a good online experience without any connectivity issues.

I ensured that players in the all regions would get put in the correct servers despite using the same build for Steam. This was done by using separate packages for the Chinese Mainland players. By doing a simple package install check through Steam, the game is able to identify which region a player should be put into.