Search Unity

How to handle both server and client actions simultaneously using UNET?

Discussion in 'UNet' started by asperatology, Sep 2, 2015.

  1. asperatology

    asperatology

    Joined:
    Mar 10, 2015
    Posts:
    981
    I am making a simple network program, and I aim to learn about server and client commands with a more direct approach of designing C# codes in a way where a script can handle both the server and the client actions (commands, functions, methods, etc.). I learned a few things from this documentation article here. So far, I understood how the client->server works, and how I should be designing my C# code. I may not be as clear on server->client, though.

    I still haven't figure out how client->server->client and server->client->server works.



    The picture shown above is a very simple project. I click on the cube, and it will turn red. I release the mouse button, and it will turn white. Here's the NetworkBehaviour codes for the Input Manager game object, which handles setting the cube to the color red or white when clicking on the cube. The Input Manager game object is placed on the same level as the Main Camera. The Cube is a prefab with a NetworkIdentity attached to it, and has been registered.



    Code (CSharp):
    1. using UnityEngine;
    2. using UnityEngine.Networking;
    3. using System.Collections;
    4. using System.Collections.Generic;
    5.  
    6. public class InputManager : NetworkBehaviour {
    7.     public List<GameObject> selectedObjects;
    8.  
    9.     protected void Start() {
    10.         this.selectedObjects = new List<GameObject>();
    11.     }
    12.  
    13.     protected void Update() {
    14.         if (Input.GetMouseButtonDown(0)) {
    15.             SelectOrder();
    16.         }
    17.         else if (Input.GetMouseButtonUp(0)) {
    18.             CmdClearColor();
    19.             RpcClearColor();
    20.             this.selectedObjects.Clear();
    21.         }
    22.         CmdMoveOrder();
    23.         RpcMoveOrder();
    24.     }
    25.  
    26.     public void SelectOrder() {
    27.         Ray ray = Camera.main.ScreenPointToRay(Input.mousePosition);
    28.         RaycastHit hit;
    29.         if (Physics.Raycast(ray, out hit)) {
    30.             this.selectedObjects.Add(hit.collider.gameObject);
    31.         }
    32.     }
    33.  
    34.     [Command]
    35.     public void CmdMoveOrder() {
    36.         for (int i = 0; i < this.selectedObjects.Count; i++) {
    37.             ServerMoveOrder(this.selectedObjects[i]);
    38.         }
    39.     }
    40.  
    41.     [ClientRpc]
    42.     public void RpcMoveOrder() {
    43.         for (int i = 0; i < this.selectedObjects.Count; i++) {
    44.             Renderer renderer = this.selectedObjects[i].GetComponent<Renderer>();
    45.             if (renderer != null) {
    46.                 renderer.material.color = Color.red;
    47.             }
    48.         }
    49.     }
    50.  
    51.     [Command]
    52.     public void CmdClearColor() {
    53.         for (int i = 0; i < this.selectedObjects.Count; i++) {
    54.             ClearColor(this.selectedObjects[i]);
    55.         }
    56.     }
    57.  
    58.     [ClientRpc]
    59.     public void RpcClearColor() {
    60.         for (int i = 0; i < this.selectedObjects.Count; i++) {
    61.             Renderer renderer = this.selectedObjects[i].GetComponent<Renderer>();
    62.             if (renderer != null) {
    63.                 renderer.material.color = Color.white;
    64.             }
    65.         }
    66.     }
    67.  
    68.     [ClientCallback]
    69.     public void ServerMoveOrder(GameObject obj) {
    70.         Renderer renderer = obj.GetComponent<Renderer>();
    71.         if (renderer != null) {
    72.             renderer.material.color = Color.red;
    73.         }
    74.     }
    75.  
    76.     [ClientCallback]
    77.     public void ClearColor(GameObject obj) {
    78.         Renderer renderer = obj.GetComponent<Renderer>();
    79.         if (renderer != null) {
    80.             renderer.material.color = Color.white;
    81.         }
    82.     }
    83. }
    84.  
    The code stops working on the client side, in the Update() code. I believed that [ClientRpc] and [Command] can be called one after another in the Update(), it's just that I am not sure how to design the C# code to make it happen.

    Could someone tell me what I need to do? And how to design the C# code to make client->server->client and server->client->server work?

    Thanks in advance.
     
  2. asperatology

    asperatology

    Joined:
    Mar 10, 2015
    Posts:
    981
    I simplified the test project and the code, and is currently aiming for SSCCE.

    Code (CSharp):
    1. using UnityEngine;
    2. using UnityEngine.Networking;
    3. using System.Collections;
    4. using System.Collections.Generic;
    5.  
    6. public class InputManager : NetworkBehaviour {
    7.     bool flag = false;
    8.     bool stuffFlag = false;
    9.  
    10.     protected void Start() {
    11.     }
    12.  
    13.     protected void Update() {
    14.         if (!this.flag) {
    15.             if (this.isServer) {
    16.                 Debug.Log("Server is calling the Rpc.");
    17.                 RpcToClient();
    18.             }
    19.             else {
    20.                 Debug.Log("Client is calling the Command.");
    21.                 CmdTest();
    22.             }
    23.         }
    24.     }
    25.  
    26.     [Command] //Client -> Server
    27.     public void CmdTest() {
    28.         Debug.Log("Calling on RPC");
    29.         RpcToClient();
    30.     }
    31.  
    32.     [ClientRpc] //Server -> Client
    33.     public void RpcToClient() {
    34.         Debug.Log("Success!");
    35.         this.flag = true;
    36.     }
    37. }
    38.  
    This is what the output log messages look like for both the server and the client. (Server is on the left, client is on the right)



    I don't understand the yellow message in the client's console, saying "Trying to send command for non-local player." I thought I did everything right, but I guess it's not.

    How would I fix this? Thanks in advance.
     
  3. asperatology

    asperatology

    Joined:
    Mar 10, 2015
    Posts:
    981
    I found a hint explaining what the yellow log message is telling me here. Now, the question is:
    • Should the [Command] calling on [ClientRpc] be called first? -OR-
    Code (CSharp):
    1. [ClientRpc]
    2. public void RpcCall() {
    3. }
    4.  
    5. [Command]
    6. public void CmdCall() {
    7.     RpcCall();
    8. }
    9.  
    10. public void firstSuggestion() {
    11.     CmdCall();
    12. }
    13.  
    • Should the [ClientRpc] calling on [Command] be called first?
    Code (CSharp):
    1. [ClientRpc]
    2. public void RpcCall() {
    3.     CmdCall();
    4. }
    5.  
    6. [Command]
    7. public void CmdCall() {
    8. }
    9.  
    10. public void secondSuggestion() {
    11.     RpcCall();
    12. }