Master Server Kit Guides

From gamevanilla wiki
Jump to: navigation, search

Guides

This section provides general guidelines on how you can approach some common use cases with Master Server Kit.

Integrating Master Server Kit on your game

In order to integrate Master Server Kit on your game, you will need to create three new scenes (one for each of the servers you will be running):

  • The master server scene, containing a game object with the Master Server component.
  • The zone server scene, containing a game object with the Zone Server component.
  • The game server scene, containing a game object with the Game Server component.

These scenes may be empty (even with no camera), apart from the appropriate kit component, because you will be running them in headless mode (meaning no graphics nor input).

On the game client side, you will need to use the client API to communicate with these servers. The included demo is a complete example on how you can implement this functionality.

Integrating Master Server Kit with a game using the Network Manager component

If you have experience with UNET, you are probably familiar with the Network Manager component. This component provides useful functionality for managing the network state of a multiplayer game and central to it are the concepts of offline and online scenes.

On the game client side, you can leave your Network Manager game object as it is, but you need to make sure you check the Use Network Manager option in the Client API game object and replace Unity's matchmaker calls in code with the appropriate calls available in the Client API. On the game server side, you will need to:

  • Add a Network Manager game object that derives from MasterServerNetworkManager (instead of the regular NetworkManager), a custom subclass that makes everything work in concert with the kit.
  • Add a reference to your game server scene as the offline scene and to your game scene as the online scene in you MasterServerNetworkManager component.
  • Check the Use Network Manager option in your Game Server component.

We are going to walk through the steps needed to do this in the accompanying demo.

  • Open the GameClient_Start scene and check the Use Network Manager option in the ClientAPI game object.

demo_network_manager_1.png

  • In the same scene, create a new game object called "NetworkManager" and add a Network Manager component to it. Set the appropriate offline and online scenes and the player prefab.

demo_network_manager_2.png

  • Open the GameServer scene and check the Use Network Manager option in the GameServer game object.

demo_network_manager_3.png

  • In the same scene, create a new game object called "NetworkManager" and add a Master Server Network Manager component to it. Set the appropriate offline and online scenes and the player prefab.

demo_network_manager_4.png

Finally, please remember to add the game scene to your game server build. In the accompanying demo, this means to edit the Builder script located in Demo/Scripts/Editor so that the game server build looks like this:

public static void BuildGameServer()
{
    var levels = new string[] {
        "Assets/MasterServerKit/Demo/Scenes/GameServer/GameServer.unity",
        "Assets/MasterServerKit/Demo/Scenes/GameClient/GameClient_Game.unity"
    };
    BuildPipeline.BuildPlayer(levels, "Builds/GameServer.exe", buildTarget, buildOptions);
}

Note how we have added both the offline and online scenes that are required in games using the Network Manager component.

Now, if you build all the binaries you should be able to run everything as usual but with the difference that the game connection will be managed via the Network Manager.

Please note that if your Network Manager has a custom, advanced configuration you will also need to do this.

Using an advanced configuration in the Network Manager

If you are using a Network Manager in your game that has a custom, advanced configuration like the following example:

network_manager_advanced_configuration.png

You will also need to open the NetworkSettings class and customize it in order to match the Network Manager's configuration. Following with the previous example, the changes would look like this:

public static class NetworkSettings
{
    public static NetworkClient CreateNetworkClient(int numPlayers = 8)
    {
        var client = new NetworkClient();
        var config = new ConnectionConfig();
        config.AddChannel(QosType.ReliableSequenced);
        config.AddChannel(QosType.Unreliable);
        config.AddChannel(QosType.Unreliable);
        client.Configure(config, numPlayers);
        return client;
    }

    public static void ConfigureServer(int numPlayers = 8)
    {
        var config = new ConnectionConfig();
        config.AddChannel(QosType.ReliableSequenced);
        config.AddChannel(QosType.Unreliable);
        config.AddChannel(QosType.Unreliable);
        NetworkServer.Configure(config, numPlayers);
    }
}

This is required by UNET in order to avoid the following error when trying to combine connections with different configurations:

Log: Channel configuration mismatch
UNet Client Disconnect Error: CRCMismatch

Implement filtered matchmaking

A common use case in games with matchmaking is being able to:

  • Create games with a certain set of attributes.
  • Find games with a certain set of attributes.

This functionality can be easily implemented with the generic property system available in the kit. All game servers have a set of properties that can be used to define metadata about the servers themselves (a property is a key-value pair, with both the key and the value being strings). This can be used when creating a new game:

var properties = new List<Property>()
{
    new Property { name = "GameType", value = "A" }
};
ClientAPI.CreateGameRoom(client.username, 2, password, properties, (ip, port) =>
{
    // Success.
    // ...
},
error =>
{
    // Error.
    // ...
});

This will create a new game room with the "GameType" = "A" property.

And also when finding existing games, which is particularly useful for implementing filters over the matchmaking results:

var includeProperties = new List<Property>()
{
    new Property { name = "GameType", value = "A" }
};
var excludeProperties = new List<Property>()
{
};
ClientAPI.FindGameRooms(includeProperties, excludeProperties, games =>
{
});

This will find all available game rooms with the "GameType" = "A" property.

WebGL support

Version 1.11 of the kit added experimental support for WebGL. What does this mean? The answer actually depends on whether you are using the low-level API or the high-level API of UNET.

If you are using the low-level API

In this case, your servers will be able to automatically accept both standard and WebGL incoming connections at the same time without further intervention.

If you are using the high-level API

In this case, you are using the Network Manager component. This means your servers can only accept one type of incoming connection (standard or WebGL) at the same time, but not both (this is by design according to the UNET developers). If you are interested in having WebGL support in this scenario, please reach us to the support email and we will be happy to provide more information about it (it requires a bit of trickery in the code that we prefer not to provide by default at this moment).

Creating your own server/client addon and network messages

Master Server Kit uses network messages extensively in order to implement the functionality it provides. In order to handle the network messages in independent, logically-grouped classes (as opposed to having them all in a single monolithic class), the concept of server and client addons is introduced. Addons provide a simple way of handling your custom network messages on the server and client side. These are the steps you need to follow if you want to implement your own addon:

1) Create a new network protocol class (see the NetworkProtocols folder for examples). This class will contain the unique identifiers of your network messages and their custom data classes:

public class YourGameNetworkProtocol
{
    public static readonly short CardPlayed = 1000;
    public static readonly short RollDice = 1001;
    public static readonly short GetScore = 1002;
};

public class CardPlayedMessage : MessageBase
{
    // ...
};

public class RollDiceMessage : MessageBase
{
    // ...
};

public class GetScoreMessage : MessageBase
{
    // ...
};

The kit's network protocols use identifiers in the low 100s range, so I just use a relatively higher starting number for the game to be on the safe side and avoid duplicate identifiers.

2) Create a new server-side addon to handle the logic of your game-specific messages:

public class YourGameServerAddon : ServerAddon
{
    protected override void RegisterNetworkHandlers()
    {
        NetworkServer.RegisterHandler(YourGameNetworkProtocol.CardPlayed , OnCardPlayed);
        // ...
    }

    protected override void UnregisterNetworkHandlers()
    {
        NetworkServer.UnregisterHandler(YourGameNetworkProtocol.CardPlayed);
        // ...
    }

    protected virtual void OnCardPlayed(NetworkMessage netMsg)
    {
        var msg = netMsg.ReadMessage<CardPlayedMessage>();
        if (msg != null)
        {
            // ...
        }
    }
};

3) Create a custom subclass of the GameServer class for your game that has the addon you just created:

public class YourGameServer : GameServer
{
    protected override void SetupDefaultAddons()
    {
        base.SetupDefaultAddons();
        gameObject.AddComponent<YourGameServerAddon>();
    }
}

4) Create a new client-side addon to handle the logic of your game-specific messages:

public class YourGameClientAddon : ClientAddon
{
    protected override void RegisterNetworkHandlers()
    {
        networkClient.client.RegisterHandler(YourGameNetworkProtocol.CardPlayed , OnCardPlayed);
        // ...
    }

    protected override void UnregisterNetworkHandlers()
    {
        networkClient.client.UnregisterHandler(YourGameNetworkProtocol.CardPlayed);
        // ...
    }

    protected virtual void OnCardPlayed(NetworkMessage netMsg)
    {
        var msg = netMsg.ReadMessage<CardPlayedMessage>();
        if (msg != null)
        {
            // ...
        }
    }
};

5) Create a custom subclass of the ClientAPI class for your game that has the addon you just created:

public class YourGameClientAPI : ClientAPI
{
    protected override void SetupDefaultGameClientAddons()
    {
        base.SetupDefaultGameClientAddons();
        var gameAddon = gameObject.AddComponent<YourGameClientAddon>();
        gameAddon.RegisterAddon(ClientAddonType.Game);
    }
}

Please note that this is just an example; you will usually not need to handle every message both on the server and on the client (because some messages only go from client to server, or vice versa).

Launching the servers with command line arguments

A useful feature of the kit is that the servers can be passed command line arguments to indicate the related IP addresses and port numbers. This avoids having to create new builds to change that data.

The master server can be passed the following arguments:

  • -ip IP_ADDRESS (e.g., -ip 127.0.0.1): The IP address the master server will listen to.
  • -port PORT_NUMBER(e.g., -port 8000): The port number the master server will listen to.

The zone server can be passed the following arguments:

  • -ip IP_ADDRESS (e.g., -ip 127.0.0.1): The IP address the zone server will listen to.
  • -port PORT_NUMBER(e.g., -port 9000): The port number the zone server will listen to.
  • -master-ip IP_ADDRESS (e.g., -master-ip 127.0.0.1): The IP address of the master server.
  • -master-port PORT_NUMBER(e.g., -master-port 8000): The port number of the master server.

The spawned game servers will be automatically configured to listen to the appropriate IP address and port based on the zone server's data.

When launching the servers with no command line arguments, the data to use will be the one specified in their respective components.