Difference between revisions of "Master Server Kit Guides"
(→If you are using the high-level API) |
(→If you are using the high-level API) |
||
Line 162: | Line 162: | ||
- Modify the StartListening method of the GameServer class of the Master Server Kit to look like this: | - Modify the StartListening method of the GameServer class of the Master Server Kit to look like this: | ||
− | + | <nowiki> | |
− | + | if (useNetworkManager) | |
− | + | { | |
− | + | webGLServer.Listen(gameServerIp, gameServerPort); | |
− | + | webGLServer.RegisterHandler(GameServerNetworkProtocol.RequestGameServerRegistration, OnGameServerRegistrationRequested); | |
+ | webGLServer.RegisterHandler(BaseServerNetworkProtocol.SendPlayerData, OnPlayerInfoReceived); | ||
− | + | DontDestroyOnLoad(gameObject); | |
− | + | var networkManager = NetworkManager.singleton as MasterServerNetworkManager; | |
− | + | Assert.IsTrue(networkManager != null, "A Master Server Network Manager was not found."); | |
− | + | networkManager.gameServer = this; | |
− | + | networkManager.networkAddress = gameServerIp; | |
− | + | networkManager.networkPort = gameServerPort + 1000; | |
− | + | networkManager.StartServer(); | |
− | + | } | |
+ | </nowiki> | ||
You also need to remove the conditional in the GameServer's Update method: | You also need to remove the conditional in the GameServer's Update method: | ||
− | + | <nowiki> | |
− | + | //if (!useNetworkManager) | |
− | + | { | |
− | + | webGLServer.Update(); | |
+ | } | ||
+ | </nowiki> | ||
Of course, the Network Manager objects (both on the server and the client side) need to have the useWebSockets flag enabled. | Of course, the Network Manager objects (both on the server and the client side) need to have the useWebSockets flag enabled. |
Revision as of 13:35, 16 May 2022
Contents
GuidesThis section provides general guidelines on how you can approach some common use cases with Master Server Kit. Integrating Master Server Kit on your gameIn 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):
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 componentIf 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:
We are going to walk through the steps needed to do this in the accompanying demo.
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. You also want to make sure the game client build contains your game scene in the same way as the game server build does. 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 ManagerIf you are using a Network Manager in your game that has a custom, advanced configuration like the following example:
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 matchmakingA common use case in games with matchmaking is being able to:
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 supportVersion 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 APIIn 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 APIIn 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, you can try the following unofficial and unsupported hack to work around it: - Modify the StartListening method of the GameServer class of the Master Server Kit to look like this: if (useNetworkManager) { webGLServer.Listen(gameServerIp, gameServerPort); webGLServer.RegisterHandler(GameServerNetworkProtocol.RequestGameServerRegistration, OnGameServerRegistrationRequested); webGLServer.RegisterHandler(BaseServerNetworkProtocol.SendPlayerData, OnPlayerInfoReceived); DontDestroyOnLoad(gameObject); var networkManager = NetworkManager.singleton as MasterServerNetworkManager; Assert.IsTrue(networkManager != null, "A Master Server Network Manager was not found."); networkManager.gameServer = this; networkManager.networkAddress = gameServerIp; networkManager.networkPort = gameServerPort + 1000; networkManager.StartServer(); } You also need to remove the conditional in the GameServer's Update method: //if (!useNetworkManager) { webGLServer.Update(); } Of course, the Network Manager objects (both on the server and the client side) need to have the useWebSockets flag enabled. You will also need to change all the occurrences of gameServerPort below this code to gameServerPort + 1000 (or a different offset number you choose). This is a bit of a hack and therefore not pretty; as you can see I create the actual game server at gameServerPort + offset address to work around the limitation in the high-level API. But it will get the kit working with WebGL builds (please note that only WebGL clients will be able to play). Creating your own server/client addon and network messagesMaster 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 argumentsA 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:
The zone server can be passed the following arguments:
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. |