Servers and Matchmaking

When a user joins a space, they are automatically put into a server. Each server has a maximum user capacity: when a server reaches that limit, a new server is created for additional users to connect to.

The toolkit provides granular control over server instancing. You can customize the server capacity or disable it altogether to limit the total number of concurrent participants to a fixed value. Through scripting, you can create a complex matchmaking system. For example, you can:

  • Group users into servers that match game types
  • Group admins into a single server by default.
  • Make a lobby waiting area where users can select their destination
  • Allow users to have private voice conversations by teleporting them to private servers.

Users are able to switch between servers through our core UI, but creators can customize and enhance the functionality using scripting.

Overview

The maximum server size is 50 players per server. There are no limits to how many servers your space can have. The default server size (if you don’t change anything in your project settings) is 16 players.

You can set basic server instancing settings on your Space Package Configuration. When a user joins a space for the first time, they will enter a server with these initial settings. The system will always try to fill servers before sending users to more empty servers.

Space package server property settings

Switch server UI

Server instancing can be disabled altogether. If disabled, the space always only has 1 server, and will only allow concurrent user capacity to the specified setting. Users who attempt to join while the server is at capacity will get a message explaining that the space is at capacity and will not be allowed to join the space. When this feature is turned off, matchmaking features are not available.

Note

Spaces published before Toolkit version 0.80 (Oct 4, 2023) will have a server size of 50. This can be changed by the space creator when publishing a new update to the space. Spaces published after version 0.80 have a default server size of 16.

Server Properties

The following configuration properties are available for each server.

PropertyData TypeDescription
Is HostboolHost instances are considered the “main” or “leader” instance. Today, the only difference is that when you add content to the space from within the Spatial app, only the host instance will save those changes. In the future, we may use the host server as the source for cross-server replication.
Is OpenboolUsers can only join servers that are open
Is VisibleboolServers that are set to invisible don’t show up in the “Switch Server” menu, and users will not be elected to randomly join them. You can use invisible servers as private servers, or for in-progress PVP games that should not allow additional participants.
CapacityintThe maximum capacity of users that can join a server. The platform maximum is set to 50 but this can be configured to any value between 2 and 50.
PropertiesPair<string, VALUE_TYPE>Properties are used to store arbitrary data for a server, and can also be used for matchmaking. VALUE_TYPE can be a int, bool, or string.

Scripting Access

C# API

The INetworkingService provides access to server properties and server management.

Visual Scripting API

Action Nodes

NodeDescription
Get Space Participant CountReturns the number of participants in the current space (sum of all servers)
Get Server Participant CountReturns the number of participants in the current server
Get Total Servers CountReturns the total number of servers active for the current space
Get/Set Server OpenSet/Get server open state; Servers that are closed are not accepting new participants
Get/Set Server VisibleSet/Get server visible state; Servers that are not visible are not shown in the instance switcher UI and won't be randomly selected when joining a space
Get/Set Server Max ParticipantsModify or retrieve the maximum number of participants allowed in the current server
Get/Set Server PropertiesModify or retrieve custom properties for the current server; Properties are used to store arbitrary data for a server, and used for matchmaking
Teleport To New ServerTeleport the current user to a new server (create new server with the requested properties)
Teleport Actors To New ServerTeleport the given list of actors to a new server with the requested matchmaking filters
Teleport To Best Match ServerTeleport the current user to the best match server based on the given matchmaking filters

Trigger Nodes

NodeDescription
On Connected ChangedTriggered when the current user connects or disconnects from the current server
On Space Participant Count ChangedTriggered when the number of participants in the current space changes
On Server Participant Count ChangedTriggered when the number of participants in the current server changes

Examples

Tip

Check out our Matchmaking Template for a fully implemented example of a matchmaking/lobby system!

Matchmaking is the concept of finding a best match server for a given user. Through scripting, developers can customize this behavior to fit their experiences.

Finding matches is done by using Server Properties and specifying which properties need to match. Server properties are limited to string, boolean, and integer values.

Some common examples of matchmaking scenarios include:

  • Game Types: I have two servers that have a property named GameType. One is GameType=Deathmatch and the other is GameType=CaptureTheFlag. When finding a game for a user, we can specify that we want to find a server where GameType is set to CaptureTheFlag when the user interacts with GUI in your space.
  • Skill Matching: To match users based on skill, you may define a server property Skill and map your in-experience skill value to an integer value, where 0 represents low skill and 1, 2, ... represent higher skill players. Now, when sending users to a matching server, specify that the Skill property should match your locally computed value. Note that skill-based matching is more suited when you have higher concurrent users in your space.

Matching a user through scripting

Using INetworkingService.TeleportToBestMatchServer you can move the local actor to a server that matches certain properties.

// Send the local actor to a server that has a property "GameType" set to "Deathmatch"
// If there is no match, a new server is created with these properties
SpatialBridge.networkingService.TeleportToBestMatchServer(
maxParticipants: 16,
serverProperties: new Dictionary<string, object> { { "GameType", "Deathmatch" } },
// Specify which properties we want to match when finding a server
serverPropertiesToMatch: new List<string> { "GameType" }
);
// Send the local actor to a server that has a property "GameType" set to "Deathmatch"
// If there is no match, a new server is created with these properties
SpatialBridge.networkingService.TeleportToBestMatchServer(
maxParticipants: 16,
serverProperties: new Dictionary<string, object> { { "GameType", "Deathmatch" } },
// Specify which properties we want to match when finding a server
serverPropertiesToMatch: new List<string> { "GameType" }
);

Grouping users by skill

Let's define a simple enum to represent the skill level of a user.

public enum SkillBucket : int
{
Newbie,
Intermediate,
Pro
}
public enum SkillBucket : int
{
Newbie,
Intermediate,
Pro
}

Then we may use the user's current XP to group them into a skill bucket and send them to a server that matches their skill level.

var userXPRequest = SpatialBridge.userWorldDataStoreService.GetVariable("xp", 0);
yield return userXPRequest;

// Calculate the user's skill bucket based on their XP
int userXP = userXPRequest.intValue;
SkillBucket skillBucket;
if (userXP < 100)
{
skillBucket = SkillBucket.Newbie;
}
else if (userXP < 500)
{
skillBucket = SkillBucket.Intermediate;
}
else
{
skillBucket = SkillBucket.Pro;
}

// Send the local actor to a server that has a property "Skill" set to the user's skill bucket
SpatialBridge.networkingService.TeleportToBestMatchServer(
maxParticipants: 16,
serverProperties: new Dictionary<string, object> { { "Skill", (int)skillBucket } },
serverPropertiesToMatch: new List<string> { "Skill" }
);
var userXPRequest = SpatialBridge.userWorldDataStoreService.GetVariable("xp", 0);
yield return userXPRequest;

// Calculate the user's skill bucket based on their XP
int userXP = userXPRequest.intValue;
SkillBucket skillBucket;
if (userXP < 100)
{
skillBucket = SkillBucket.Newbie;
}
else if (userXP < 500)
{
skillBucket = SkillBucket.Intermediate;
}
else
{
skillBucket = SkillBucket.Pro;
}

// Send the local actor to a server that has a property "Skill" set to the user's skill bucket
SpatialBridge.networkingService.TeleportToBestMatchServer(
maxParticipants: 16,
serverProperties: new Dictionary<string, object> { { "Skill", (int)skillBucket } },
serverPropertiesToMatch: new List<string> { "Skill" }
);

Detecting that a user as changed servers

You can use INetworkingService.onConnectionStatusChanged to get notified when a user disconnects and reconnects. If a full disconnect and reconnect has happened, it is likely that the user has switched server.

FAQ

What happens to network variables when switching servers or reconnecting?

When teleporting from one server to another, or during a temporary disconnect, all of the synchronized state (network variables) are reset to their initial state immediately. Upon re-establishing a connection to a server, the state is recovered from the server's current state.

Important

Any visual scripting variable marked as Synced will be reset to its initial value when the user switches servers or reconnects. All other visual scripting variables are not reset, it is your responsibility to reset them if needed.

This follows the same behavior as C# scripting, where any local state in class variables is not automatically reset when switching servers.