Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Unity3d server auto discover, LAN only

I need to implement a game with a server in a local network, with no Internet access.

Provided that I can handle the connections and network communication between clients and server if they are connected, I'd like to know if there's a elegant way to make clients discover server's address at startup.


I'm providing my approach as an answer, in order to share the knowledge, but it would be nice to see if there is a more elegant/automatic approach.

like image 680
Alexandre Avatar asked Apr 19 '13 17:04

Alexandre


2 Answers

Clients will use a specific port to connect to the game server. I implemented a UDP multicast in a different port so clients can get server's IP.

The following code is for both server and client, written in Unity Javascript. On the server side, it will start sending multicast messages every second at port 5100. Clients will listen to the same port, until they detect a new message. Then they identify sender's IP and establish a client-server connection the Unity3d way.

private var server_port : int = 5000;
private var server_ip : String;

// multicast
private var startup_port : int = 5100;
private var group_address : IPAddress = IPAddress.Parse ("224.0.0.224");
private var udp_client : UdpClient;
private var remote_end : IPEndPoint;

function Start ()
{
    // loaded elsewhere
    if (station_id == "GameServer")
        StartGameServer ();
    else
        StartGameClient ();
}

function StartGameServer ()
{
    // the Unity3d way to become a server
    init_status = Network.InitializeServer (10, server_port, false);
    Debug.Log ("status: " + init_status);

    StartBroadcast ();
}

function StartGameClient ()
{
    // multicast receive setup
    remote_end = IPEndPoint (IPAddress.Any, startup_port);
    udp_client = UdpClient (remote_end);
    udp_client.JoinMulticastGroup (group_address);

    // async callback for multicast
    udp_client.BeginReceive (new AsyncCallback (ServerLookup), null);

    MakeConnection ();
}

function MakeConnection ()
{
    // continues after we get server's address
    while (!server_ip)
        yield;

    while (Network.peerType == NetworkPeerType.Disconnected)
    {
        Debug.Log ("connecting: " + server_ip +":"+ server_port);

        // the Unity3d way to connect to a server
        var error : NetworkConnectionError;
        error = Network.Connect (server_ip, server_port);

        Debug.Log ("status: " + error);
        yield WaitForSeconds (1);
    }
}

/******* broadcast functions *******/
function ServerLookup (ar : IAsyncResult)
{
    // receivers package and identifies IP
    var receiveBytes = udp_client.EndReceive (ar, remote_end);

    server_ip = remote_end.Address.ToString ();
    Debug.Log ("Server: " + server_ip);
}

function StartBroadcast ()
{
    // multicast send setup
    udp_client = UdpClient ();
    udp_client.JoinMulticastGroup (group_address);
    remote_end = IPEndPoint (group_address, startup_port);

    // sends multicast
    while (true)
    {
        var buffer = Encoding.ASCII.GetBytes ("GameServer");
        udp_client.Send (buffer, buffer.Length, remote_end);

        yield WaitForSeconds (1);
    }
}

Attaching this to your GameObject should do the trick.

like image 136
Alexandre Avatar answered Sep 27 '22 23:09

Alexandre


Here is a c# version Thanks

using System.Collections;
using UnityEngine;
using System.Net.Sockets;
using System;
using System.Net;
using System.Text;

public class OwnNetworkManager : MonoBehaviour
{

private int server_port = 5000;
private string server_ip;

// multicast
private int startup_port = 5100;
private IPAddress group_address = IPAddress.Parse("127.0.0.1");
private UdpClient udp_client ;
private IPEndPoint remote_end ;


void Start()
{
    // loaded elsewhere
    if (Loader.IsPC)
        StartGameServer();
    else
        StartGameClient();
}

void StartGameServer()
{
    // the Unity3d way to become a server
    NetworkConnectionError init_status = Network.InitializeServer(10, 
server_port, false);
    Debug.Log("status: " + init_status);

    StartCoroutine(StartBroadcast());
}

void StartGameClient()
{
    // multicast receive setup
    remote_end = new IPEndPoint(IPAddress.Any, startup_port);
    udp_client = new UdpClient(remote_end);
    udp_client.JoinMulticastGroup(group_address);

    // async callback for multicast
    udp_client.BeginReceive(new AsyncCallback(ServerLookup), null);

    StartCoroutine(MakeConnection());
}

IEnumerator MakeConnection()
{
    // continues after we get server's address
    while (string.IsNullOrEmpty(server_ip))
        yield return null;

    while (Network.peerType == NetworkPeerType.Disconnected)
    {
        Debug.Log("connecting: " + server_ip + ":" + server_port);

        // the Unity3d way to connect to a server
        NetworkConnectionError error ;
        error = Network.Connect(server_ip, server_port);
        Debug.Log("status: " + error);
        yield return new WaitForSeconds (1);
    }
}

/******* broadcast functions *******/
void ServerLookup(IAsyncResult ar)
{
    // receivers package and identifies IP
    var receiveBytes = udp_client.EndReceive(ar, ref remote_end);

    server_ip = remote_end.Address.ToString();
    Debug.Log("Server: " + server_ip);
}

IEnumerator StartBroadcast()
{
    // multicast send setup
    udp_client = new UdpClient();
    udp_client.JoinMulticastGroup(group_address);
    remote_end = new IPEndPoint(group_address, startup_port);

    // sends multicast
    while (true)
    {
        var buffer = Encoding.ASCII.GetBytes("GameServer");
        udp_client.Send(buffer, buffer.Length, remote_end);

        yield return new WaitForSeconds (1);
    }
}
}
like image 43
Orion Avatar answered Sep 27 '22 21:09

Orion