Saturday 4 April 2015

Multiplayer in Unity: Get connected

Introduction

The goal of this article is very simple; I have two computers in our living room and I want to find out whether I can create a Unity executable that will have these two computers communicate.

Setting up a server

The "server" is the instance of our app that can accept incoming connections.

I created a Server class. I initialise the server using Network.InitializeServer.
Used code as provided in API reference.
Added error handling code.
Seems to work.

Setting up a client

The "client" is the instance that will connect to the server.

I created a Client class. I initialise the client using Network.Connect.
There are endless variants of Network.Connect. The one I choose uses an IP and port (but read on; we're not staying with this)

It works. In fact, it works a bit too well because it still initialises successfully when the network is not initialised. Weird, I know.

How to choose the IP and port
  • The 'port' refers a communication channel. As a rule of the thumb don't use anything under 1000 (other applications and OS services may be using these). Of course the port should match between client and server.
  • 'IP' identifies a computer on the network.
    127.0.0.1 refers the local host. In other words this is connecting to the same machine we are running the client from. Often useful, but we hope to do better than that.
So, how to choose the IP? And why we need a master server

The answer is, let's not do this, as you probably do not have a stable IP address.
Not sure what this means? Don't have stable IP.
Didn't setup your internet connection yourself? Don't have stable IP.

From a functional point of view, the master server is a go-between the client and the server. Works like this:
  1. Server initialises.
  2. Server registers with master server
  3. Client fetches server info from master server
  4. Client connects to the server.
So, where is the master server you ask? Well, it's a service provided by Unity Technologies so I guess it is somewhere inside their bunker.

Note that the Unity master server is provided only for testing purposes. They're not actively preventing you from using it in a live game but they don't warrant uptime either.

IMPORTANT: You cannot setup a client AND setup a server AND access the master server within the same instance. It may be possible to run a client and server via localhost (or using stable IPs) but I haven't tried. To understand why it works like this, read here.

Registering to the master server

MasterServer.RegisterHost takes 3 arguments (API):
  • Game Type - this is a unique identifier for your game. You might use something like com.company.gamename just as a convention that's easy to remember.
  • Game Name - this is what most players think of as "room name". Again use whatever you like (there is probably a way to iterate room names but in practice this is not really necessary).
  • Description - frankly, I think this should be optional. Just put something there.
IMPORTANT: Call MasterServer.UnregisterHost before exiting (for example, inside OnDestroy() )

Client side: Fetching the host data via Master Server

The client uses 3 APIs to connect to the master server and retrieve a host:
I'm not sure about the advantage of polling for the host list. If you implement OnMasterServerEvent you will receive a notification when the host list has been received. A big advantage of doing it this way is that polling will keep busy with itself after an empty list has been received.

Then we connect using Network.Connect( HostData host, string password )


Troubleshooting Tips

Before getting into specific errors I encountered, note that it is useful to have a separate script reporting master server events. Said script will implement the following:
  • void OnFailedToConnectToMasterServer(NetworkConnectionError err)
  • void OnMasterServerEvent(MasterServerEvent e)
Why is this useful? Because these events are broadcast. So if you put them both in your client and your server script, every event will be broadcast twice, which adds to the general confusion.

Other methods that can help troubleshooting:
  • Use separate GameObjects that you attach your client/server script to. This way you can disable the one or the other and see what happens. This also provides a quick way to prepare a "server only" or "client only" build.
Common errors, and why they occur:

Error #1: Already connected to the master server, the server probably hasn't cleaned up because of an abrupt disconnection.

May occur as a result of trying to simultaneously start the client and server inside the same player.

Error #2: The connection request to ###.###.#.###:##### failed. Are you sure the server can be connected to?

May occur while running a client and server in the same app. As far as I could judge, Unity does not allow a client to be its own server (and vice versa).

Error #3The remote system is using a password and has refused our connection because we did not set the correct password.

May occur while running a client and server in separate instances, but the client did not set a password.

No comments:

Post a Comment