setup
If you are using a version of Unity using Package Manager
you might need to add Multiplayer HLAPI
As of 2020-02-21 this is flagged as deprecated and won't work in the futur but still works fine now.
basics
The idea here is to setup a server<->client message bridge. We'll create a software to will manage the server side of things and another for client(s). Either the client or the server will be able to send messages. A "message" is any class that can be serialized and that inherit MessageBase (from UNET).
general notes
Because server and/or client must executed outside of unity (if both are launched on the same computer) you won't be able to see Debug.Log().
To that end I'm using a UI Canvas with a Text component attached. NwkTool is a static class where I store a way to display logs on screen. You can obviously replace all log() calls by whatever you like.
custom message
This is the class that will be serialized and sent through the network.
public class NwkMessage : MessageBase
{
public short messageId = 1000;
public string msg = "";
}
server script
The following unity component is the minimum requirement for the server side of things.
using UnityEngine;
using UnityEngine.Networking;
public class NwkServer : MonoBehaviour
{
short messageID = 1000;
int maxConnections = 4;
int port = 9999;
private void Start()
{
generateServer();
}
void generateServer()
{
// Unity have different Messages types defined in MsgType
NetworkServer.RegisterHandler(MsgType.Connect, OnClientConnected);
NetworkServer.RegisterHandler(MsgType.Disconnect, OnClientDisconnected);
// Our message use his own message type.
NetworkServer.RegisterHandler(messageID, OnMessageReceived);
var config = new ConnectionConfig();
// There are different types of channels you can use, check the official documentation
config.AddChannel(QosType.ReliableFragmented);
config.AddChannel(QosType.UnreliableFragmented);
var ht = new HostTopology(config, maxConnections);
if (!NetworkServer.Configure(ht))
{
NwkTools.log("No server created, error on the configuration definition");
return;
}
else
{
// Start listening on the defined port
if (NetworkServer.Listen(port)) NwkTools.log("Server created, listening on port: " + port);
else NwkTools.log("No server created, could not listen to the port: " + port);
}
}
void OnClientConnected(NetworkMessage netMessage)
{
NwkTools.log("someone just connected : " + netMessage.ToString());
}
void OnClientDisconnected(NetworkMessage netMessage)
{
NwkTools.log("someone left : " + netMessage.ToString());
}
void OnMessageReceived(NetworkMessage netMessage)
{
NwkMessage serialMsg = netMessage.ReadMessage<NwkMessage>();
NwkTools.log("Server::OnMessageReceived " + serialMsg.msg);
}
void OnApplicationQuit()
{
//make sure port is released on quit
NetworkServer.Shutdown();
}
/// <summary>
/// example of how to send a message to all clients
/// helper that you can call or plug to a button on ui
/// </summary>
public void pingClients()
{
NwkMessage msg = new NwkMessage();
msg.msg = "server ping !";
NetworkServer.SendToAll(msg.messageId, msg);
NwkTools.log("send to all client : " + msg.msg);
}
}
client script
Client will connect automatically to provided ip (property of the class). In this example the script connects right away so you'll need to have a server running before any instance of that script is launched.
using UnityEngine;
using UnityEngine.Networking;
using UnityEngine.Networking.NetworkSystem;
class NwkClient : MonoBehaviour
{
short messageID = 1000;
string ip = "localhost"; // <-- this must be replaced by server ip if client is on another computer
int port = 9999;
public NetworkClient client;
void Start()
{
generateClient();
connectToServer();
}
void generateClient()
{
var config = new ConnectionConfig();
// Config the Channels we will use
config.AddChannel(QosType.ReliableFragmented);
config.AddChannel(QosType.UnreliableFragmented);
// Create the client ant attach the configuration
client = new NetworkClient();
client.Configure(config, 1);
// Unity have different Messages types defined in MsgType
client.RegisterHandler(messageID, OnMessageReceived);
client.RegisterHandler(MsgType.Connect, OnConnected);
client.RegisterHandler(MsgType.Disconnect, OnDisconnected);
client.RegisterHandler(MsgType.Error, OnError);
}
private void connectToServer()
{
NwkTools.log("connecting to " + ip + ":" + port);
// Connect to the server
client.Connect(ip, port);
}
void OnError(NetworkMessage netMsg)
{
var errorMsg = netMsg.ReadMessage<ErrorMessage>();
Debug.Log("Error:" + errorMsg.errorCode);
}
void OnConnected(NetworkMessage message)
{
NwkTools.log("Client::OnConnected : " + message.msgType);
}
void OnDisconnected(NetworkMessage message)
{
// Do stuff when disconnected to the server
}
// Message received from the server
void OnMessageReceived(NetworkMessage netMessage)
{
// You can send any object that inherence from MessageBase
// The client and server can be on different projects, as long as the MyNetworkMessage or the class you are using have the same implementation on both projects
// The first thing we do is deserialize the message to our custom type
NwkMessage serialMsg = netMessage.ReadMessage<NwkMessage>();
NwkTools.log("Client::OnMessageReceived "+ serialMsg.msg);
}
public void pingServer()
{
NwkMessage msg = new NwkMessage();
msg.msg = "ping ?";
client.Send(messageID, msg);
NwkTools.log("sent to server : " + msg.msg);
}
}