Book Image

Unity Multiplayer Games

By : Alan R. Stagner
Book Image

Unity Multiplayer Games

By: Alan R. Stagner

Overview of this book

Unity is a game development engine that is fully integrated with a complete set of intuitive tools and rapid workflows used to create interactive 3D content. Multiplayer games have long been a staple of video games, and online multiplayer games have seen an explosion in popularity in recent years. Unity provides a unique platform for independent developers to create the most in-demand multiplayer experiences, from relaxing social MMOs to adrenaline-pumping competitive shooters. A practical guide to writing a variety of online multiplayer games with the Unity game engine, using a multitude of networking middleware from player-hosted games to standalone dedicated servers to cloud multiplayer technology. You can create a wide variety of online games with the Unity 4 as well as Unity 3 Engine. You will learn all the skills needed to make any multiplayer game you can think of using this practical guide. We break down complex multiplayer games into basic components, for different kinds of games, whether they be large multi-user environments or small 8-player action games. You will get started by learning networking technologies for a variety of situations with a Pong game, and also host a game server and learn to connect to it.Then, we will show you how to structure your game logic to work in a multiplayer environment. We will cover how to implement client-side game logic for player-hosted games and server-side game logic for MMO-style games, as well as how to deal with network latency, unreliability, and security. You will then gain an understanding of the Photon Server while creating a star collector game; and later, the Player.IO by creating a multiplayer RTS prototype game. You will also learn using PubNub with Unity by creating a chatbox application. Unity Multiplayer Games will help you learn how to use the most popular networking middleware available for Unity, from peer-oriented setups to dedicated server technology.
Table of Contents (14 chapters)
Unity Multiplayer Games
Credits
About the Author
About the Reviewers
www.PacktPub.com
Preface
Index

Setting up a dedicated server model


Many games allow players to host their own dedicated servers, as separate applications from the game client. Some games even allow players to modify the behavior of the server through scripting languages, allowing player-run servers to employ novel behaviors not originally designed into the game.

Let's see how we can set up a similar system in Unity. I will not be covering modding, although readers can look up Lua scripting in Unity—there are a number of resources on the topic.

Servers in Unity

Most games have a specialized "server" build, which contains much the same code as the client, designed to run as a dedicated server. This allows the server to process the same logic as the client.

Unity, however, does not directly support this concept out of the box. Unity Pro does allow builds to be run in "headless mode", which runs the game without initializing any graphics, resources, but the server runs the exact same code as the client. The game must be designed to operate in both server and client mode.

To do this, we'll take advantage of a compiler feature known as "conditional compilation". This allows us to wrap code in special tags which allows us to strip out entire sections of code when compiling. This way, our server-only code will only be included in server builds, and our client-only code will only be included in client builds.

Compiler directives

The first thing we will do, is figure out how the application knows whether it is a client or a server. We will use a compiler directive to do this.

If you are using Unity 4, you can go to Edit | Project Settings | Player and under Other Settings is a section that allows you to define these.

However, for any version prior to Unity 4, you'll have to define these yourself. To do this, create a new text file in the Assets folder and name it smcs.rsp. Open Notepad and type:

-define:SERVER

This creates a global symbol define for your C# scripts. You would use the symbol like this:

#if SERVER
  //code in here will not be compiled if SERVER isn't defined
#endif

You might consider writing an editor script which replaces the contents of this file (when compiling for the client, it would replace SERVER with CLIENT, and vice versa). It is important to note that changes to this file will not automatically recompile, when changing the file you should save one of your scripts. Your editor script might do this automatically, for example it could call AssetDatabase.Refresh( ImportAssetOptions.ForceUpdate ).

Now that we can detect whether the application was built as a server or a client, we'll need some way for the server to act as autonomously as possible. The server should have a configuration file which allows the user to set, for example, network settings before the server runs. This book will not cover how to load the configuration file (XML or JSON are recommended), but once these are loaded the server should immediately initialize and register itself with the Master Server using the data in the configuration file (for example, server name, maximum connections, listen port, password, and so on).

Setting up a server console without Pro

Usually, a game server is a console application. This is nearly possible in Unity if you have purchased a Pro license, by appending the -batchmode argument to the executable (actually, Unity does not create a console window, instead the game simply runs in the background). If you do have Pro, feel free to skip this section. However, if you own a free license, you'll need to get a bit creative.

We want the server to use as few resources as possible. We can create a script that turns off rendering of the scene when running in server mode. This won't completely disable the rendering system (as running in command line would), but it does significantly reduce the GPU load of the server.

using UnityEngine;
using System.Collections;

public class DisableServerCamera : MonoBehavior
{
#if SERVER
  void Update()
  {
    // culling mask is a bitmask – setting all bits to zero means render nothing
    camera.cullingMask = 0;
  }
#endif
}

This script can be attached to a camera, and will cause that camera to not render anything when running on the server.

Next we're going to set up a console-type display for our server. This "console" will hook into the built-in Debug class and display a scrolling list of messages. We'll do this via Application.RegisterLogCallback.

using UnityEngine;
using System.Collections;
using System.Collections.Generic;

// contains data about the logged message
struct LogMessage
{
  public string message;
  public LogType type;
}

public class CustomLog : MonoBehavior
{
  // how many past log messages to store
  public int MaxHistory = 50;

  // a list of stored log messages
  private List<LogMessage> messages = new List<LogMessage>();

  // the position within the scroll view
  private Vector2 scrollPos = Vector2.zero;

  void OnEnable()
  {
    // register a custom log handler
    Application.RegisterLogCallback( HandleLog );
  }
  void OnDisable()
  {
    // unregister the log handler
    Application.RegisterLogCallback( null );
  }

  void OnGUI()
  {
    scrollPos = GUILayout.BeginScrollView( scrollPos, GUILayout.ExpandWidth( true ), GUILayout.ExpandHeight( true ) );

    //draw each debug log – switch colors based on log type
    for( int i = 0; i < messages.Count; i++ )
    {
      Color color = Color.white;
      if( messages[i].type == LogType.Warning )
      {
        color = Color.yellow;
      }
      else if( messages[i].type != LogType.Log )
      {
        color = Color.red;
      }

      GUI.color = color;
      GUILayout.Label( messages[i].message );
    }

    GUILayout.EndScrollView();
  }

  void HandleLog( string message, string stackTrace, LogType type )
  {
    // add the message, remove entries if there's too many
    LogMessage msg = new LogMessage();
    msg.message = message;
    msg.type = type;

    messages.Add( msg );
    
    if( messages.Count >= MaxHistory )
    {
      messages.RemoveAt( 0 );
    }
    // scroll to the newest message by setting to a huge amount
    // will automatically be clamped
    scrollPos.y = 1000f;
  }
}

Now the user can see the debug information being printed as the server runs—very useful indeed.

You should strive for as much code reuse as possible in fact, if your game allows players to host a game from inside the client, most of the same code will already work with a few minor differences:

  • As previously mentioned, the server starts up automatically with a configuration loaded from the user-editable files (unlike the client).

  • The server does not spawn any player objects of its own, unlike the client.

  • The server does not have any UIs or menus to display to the user beyond the log dump. Beyond starting up the server and shutting it down, there is zero interaction with the server application.