5
\$\begingroup\$

I'm working on a very simple/basic client-server networking program, the basis of a future game I hope to create. Now the client program/project DOES successfully connect with the 'server program/project' (both completely separate). However when it comes to having the client send a request/command to the server. Well it doesn't send the command to the server, it executes it on the client.

I read about changing the 'Monodevelop' inheritance to 'NetworkBehaviour' so I did and it resulting in an error along the lines of;

Command xxx was sent to the server ...Debug.logerror(object So I seemed to have got half way there, it allegedly sent the command to the server, but the server did nothing with it. I don't know why.

Below are the relatively short programs I've got for my server and client and are pretty much the same, but if anyone can help me out I'd greatly appreciate it, as my University course didn't really go into Network Programming all that much;

Server Code

using UnityEngine;
using UnityEngine.Networking;
using System.Collections;

public class server : MonoBehaviour
{

    public string IP = "127.0.0.1";
    public int port = 25001;
    public int prevConns = 0;
    private int currConns = 0;

    public virtual void OnServerReady (NetworkConnection conn)
    {
        NetworkServer.SetClientReady (conn);
    }

    void OnGUI ()
    {
        if (Network.peerType == NetworkPeerType.Disconnected) {
            if (GUI.Button (new Rect (100, 100, 100, 25), "Start Client")) {
                Network.Connect (IP, port);
            }
            if (GUI.Button (new Rect (100, 125, 100, 25), "Start Server")) {
                Network.InitializeServer (20, port, false);
            }
        } else {
            //CLIENT - NOT NEEDED
            if (Network.peerType == NetworkPeerType.Client) {
                GUI.Label (new Rect (100, 100, 100, 25), "Client");
                if (GUI.Button (new Rect (100, 125, 100, 25), "Disconnect")) {
                    Network.Disconnect (250);
                }
            }
            if (Network.peerType == NetworkPeerType.Server) {               
                currConns = Network.connections.Length;
                GUI.Label (new Rect (100, 100, 100, 25), "Server");
                GUI.Label (new Rect (100, 125, 100, 25), "Connections: " + currConns);

                if (prevConns != currConns) {
                    if (prevConns < currConns) {
                        Debug.Log ("NEW CONNECTION");
                        prevConns++;

                    } else if (prevConns > currConns) {
                        Debug.Log ("Lost CONNECTION");
                        prevConns--;
                    }
                }

                if (GUI.Button (new Rect (100, 15, 100, 25), "Shutdown")) {
                    Network.Disconnect (250);
                }
            }
        }
    }

}

Client Code

using UnityEngine;
using UnityEngine.Networking;
using System.Collections;

public class connection : MonoBehaviour
{

    public string IP = "127.0.0.1";
    public int port = 25001;
    public GameObject player;

    public virtual void OnClientConnect (NetworkConnection conn)
    {
        ClientScene.Ready (conn);
    }

    void OnGUI ()
    {
        if (Network.peerType == NetworkPeerType.Disconnected) {
            if (GUI.Button (new Rect (100, 100, 100, 25), "Start Client")) {
                Network.Connect (IP, port);
            }
        } else {
            if (Network.peerType == NetworkPeerType.Client) {
                GUI.Label (new Rect (100, 100, 100, 25), "Client");
                if (GUI.Button (new Rect (100, 125, 100, 25), "Disconnect")) {
                    Network.Disconnect (250);
                }

                if (GUI.Button (new Rect (100, 150, 100, 25), "Send Cmd")) {
                    CmdSendCommand ();
                }

            }
        }
    }

    [Command]
    void CmdSendCommand ()
    {
        NetworkBehaviour.print ("HELLO");
    }
}
\$\endgroup\$
5
\$\begingroup\$

As per the documentation, [Command] and [ClientRpc] should be in a NetworkBehaviour, not in a MonoBehaviour. NetworkBehaviour's must be spawned using NetworkServer.Spawn(). Moreover you should use a NetworkClient Object to connect to the Server.

Take a look at this

Note: As of Unity 5.1 offline documentation is not up to date. Even some aspects of online documentation are misleading. This is the way I have implemented it.

using UnityEngine;
using UnityEngine.Networking;
using UnityEngine.Networking.NetworkSystem;
using System.Collections.Generic;

public class MatchMaker : MonoBehaviour
{
    public MatchManager matchManager;
    public string ip = "127.0.0.1";
    public int port = 2349;

    NetworkClient client;

    bool showGUI = true;
    bool isServer = false;
    int clientLimit = 1;
    int curretCount = 0;

    private static MatchMaker instance;

    public static MatchMaker Instance { get { return instance; } }

    public List<Player> players;

    const short PLAYER_SYNC_AFTER = 1203;
    const short PLAYER_SYNC_BEFORE = 1205;
    const short GRID_MESSAGE_X = 1240;
    const short GRID_MESSAGE_Y = 1230;
    const short PLAY = 1440;

    public int sizeX;
    public int sizeY;

    public static bool networkSpawn = false;

    void Awake ()
    {
        instance = this;
        players = new List<Player> ();
    }

    void OnGUI ()
    {
        if (isServer && networkSpawn) {
            if (GUILayout.Button ("Play"))
                Play ();
        }

        if (!showGUI)
            return;

        if (GUILayout.Button ("Host Game"))
            HostGame ();
        if (GUILayout.Button ("Join Game"))
            JoinGame ();
    }

    public void Play ()
    {
        matchManager.gm.BeginGame ();
        NetworkServer.SendToAll (PLAY, new EmptyMessage ());
        NetworkServer.ClearHandlers ();
    }

    public void HostGame ()
    {
        NetworkServer.Listen (port);
        NetworkServer.RegisterHandler (MsgType.Connect, OnClientConnected);
        NetworkServer.RegisterHandler (PLAYER_SYNC_AFTER, OnRecievePlayerAfter);
        // HACK Can Changer Server Side Players
        players.Add (new HumanPlayer (Color.green, "Host"));
        showGUI = false;
        isServer = true;
        sizeX = 15;
        sizeY = 10;
    }

    public void JoinGame ()
    {
        client = new NetworkClient ();
        client.RegisterHandler (MsgType.Connect, OnServerConnected);
        client.RegisterHandler (PLAYER_SYNC_AFTER, OnRecievePlayerAfter);
        client.RegisterHandler (PLAYER_SYNC_BEFORE, OnRecievedPlayerBefore);
        client.RegisterHandler (GRID_MESSAGE_X, OnGridSizeX);
        client.RegisterHandler (GRID_MESSAGE_Y, OnGridSizeY);
        client.RegisterHandler (PLAY, (NetworkMessage msg) => {
            matchManager.gm.BeginGame ();
            client.UnregisterHandler (MsgType.Connect);
            client.UnregisterHandler (PLAYER_SYNC_AFTER);
            client.UnregisterHandler (PLAYER_SYNC_BEFORE);
            client.UnregisterHandler (GRID_MESSAGE_X);
            client.UnregisterHandler (GRID_MESSAGE_Y);
            client.UnregisterHandler (PLAY);
        });                           
        client.Connect (ip, port);

        // TODO Cutomize Client
        players.Add (new HumanPlayer (Color.yellow, "CLient"));
        showGUI = false; 
    }

    void OnServerConnected (NetworkMessage msg)
    {       
        client.Send (PLAYER_SYNC_AFTER, new PlayerMessage{ color = players [0].color, name = players [0].name });
        Debug.Log ("Server Connected");
    }

    void OnClientConnected (NetworkMessage msg)
    {
        Debug.Log ("Client Connected");
        foreach (var player in players)
            NetworkServer.SendToClient (msg.conn.connectionId, PLAYER_SYNC_BEFORE, new PlayerMessage {
            name = player.name,
            color = player.color
        });

        NetworkServer.SetClientReady (msg.conn);

        curretCount++;
        if (curretCount == clientLimit) {
            NetworkServer.SendToAll (GRID_MESSAGE_X, new IntegerMessage { value = 15});
            NetworkServer.SendToAll (GRID_MESSAGE_Y, new IntegerMessage { value = 10});
            NetworkServer.SpawnObjects ();
            networkSpawn = true;
        }
    }

    void OnRecievePlayerAfter (NetworkMessage msg)
    {
        var playerMessage = msg.ReadMessage<PlayerMessage> ();
        players.Add (new NetworkPlayer (playerMessage.color, playerMessage.name));

        if (!isServer)
            return;

        foreach (var conn in NetworkServer.connections)
            if (conn != null && conn.connectionId != msg.conn.connectionId)
                NetworkServer.SendToClient (conn.connectionId, PLAYER_SYNC_AFTER, new PlayerMessage {
                name = playerMessage.name,
                color = playerMessage.color
            });
    }

    void OnRecievedPlayerBefore (NetworkMessage msg)
    {
        var playerMessage = msg.ReadMessage<PlayerMessage> ();
        players.Insert (players.Count - 1, new NetworkPlayer (playerMessage.color,         playerMessage.name));
    }

    void OnGridSizeX (NetworkMessage msg)
    {
        sizeX = msg.ReadMessage<IntegerMessage> ().value;
    }

    void OnGridSizeY (NetworkMessage msg)
    {
        sizeY = msg.ReadMessage<IntegerMessage> ().value;
    }

    public class PlayerMessage : MessageBase
    {
        public string name;
        public Color color;
    }
}

Here is My NetworkBehaviour for ClientRpc and Command

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

public class MatchManager : NetworkBehaviour
{
    public NetworkGameManager gm;
    public bool canSpawn = false;

    public void UpdateCell (int x, int y, LineDirection lineDirection)
    {
        if (isServer)
            RpcUpdateCell (x, y, lineDirection);
        else {
            CmdUpdateCell (x, y, lineDirection);
        }
    }

    [ClientRpc]
    public void RpcUpdateCell (int x, int y, LineDirection lineDirection)
    {
        gm.UpdateCell (x, y, lineDirection);
    }

    [Command]
    public void CmdUpdateCell (int x, int y, LineDirection lineDirection)
    {
        RpcUpdateCell (x, y, lineDirection);
        gm.UpdateCell (x, y, lineDirection);
    }
}
\$\endgroup\$
0
\$\begingroup\$

A little addendum to Sri Krishna Paritala's answer:

I've noticed that a [command] is executed only locally, if it is called from inside of a MonoBehaviour.Update() function. To get it executed on the server, it was required to call the [command] from the context of its NetworkBehaviour. In other words, what fixed it was:

  1. From inside the MonoBehaviour.Update() function, just set a local variable at the NetworkBehaviour class containing the [command].
  2. Execute the [command] from inside NetworkBehaviour.Update() if the variable from 1. is set.
\$\endgroup\$

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.