Search Unity

What it the right way to execute functions on the server and clients as well?

Discussion in 'Multiplayer' started by Sahkan, Nov 30, 2015.

  1. Sahkan

    Sahkan

    Joined:
    Mar 3, 2013
    Posts:
    204
    [ClientRpc] is only clients.
    I need something that will cause the function to run on the server and all of the clients. is there anything like that?

    What I'm doing right now is:

    Code (CSharp):
    1. [ClientRpc]
    2.     void Rpc_func()
    3.     {
    4.         func();
    5.     }
    6.  
    7.     void func()
    8.     {
    9.         //
    10.     }
    And calling both when I need to.
     
    Last edited: Nov 30, 2015
  2. Chom1czek

    Chom1czek

    Joined:
    Sep 19, 2015
    Posts:
    66
    Code (CSharp):
    1. [Command]
    2. private void CmdComand()
    3. {
    4.    RpcToClients()
    5. }
    6.  
    7. [ClientRpc]
    8. private void RpcToClients()
    9. {
    10.    Whatever you want it to do.
    11. }
    Im using something like that, I don't really like how it looks like but it works so :D
     
  3. moco2k

    moco2k

    Joined:
    Apr 29, 2015
    Posts:
    294
    Chom1czek, your example does not solve the task of running a same function on server and client because the code within the ClientRpc is executed on all clients, but not on the server. If you want the code to be run on the server, it will work on hosts only, where you have both server and client in one instance, but it won't run the code on dedicated servers.

    Sahkan, I think your intial approach of using another function call is quite fine. One could just call the function either from server-side (e.g. from a command) or client-side (e.g. from an Rpc). You could even pass a boolean flag like firedOnClient or something. I actually think yours is a clean and structured solution already. Currently, I don't know other UNET mechanics to achieve this yet, or why there even would be a need to have such. But maybe there are some reasons or use cases.
     
    Last edited: Dec 1, 2015
  4. DRRosen3

    DRRosen3

    Joined:
    Jan 30, 2014
    Posts:
    683
    Honestly, the way to approach something is entirely dependant on what exactly it is you're trying to do. Maybe it's something that has use call backs. Maybe it's something that can be done via an animation event. However, @Chom1czek 's approach does PARTIALLY solve the task...possibly...

    Code (CSharp):
    1. [Command]
    2. private void CmdComand()
    3. {
    4.    RpcToClients();
    5.    //CODE GOES HERE TO EXECUTE THE PROCESS ON THE SERVER.
    6. }
    7. [ClientRpc]
    8. private void RpcToClients()
    9. {
    10.    //CODE GOES HERE TO EXECUTE THE PROCESS ON ALL CLIENTS
    11. }
     
  5. Chom1czek

    Chom1czek

    Joined:
    Sep 19, 2015
    Posts:
    66
    Well I think I even seen some guy from Unity that said it's legit but if you got better ideas I like to check it out :)
     
  6. Velo222

    Velo222

    Joined:
    Apr 29, 2012
    Posts:
    1,437
    Can I ask a backup question along these lines? I've been trying to sync animations for awhile now, and the "Network Animator" script is not working as I thought it would. My unit's animations sync properly with the Network Animator if I uncheck "Local Player Authority" on my Network Identity script for the object. However, I need my objects to have Local Player Authority in order for them to be spawned and registered with different remote clients. The animations do NOT sync when Local Player Authority is checked, only when it is unchecked -- I don't know why this is.

    So using what you guys are discussing, I get the fact that a client needs to call a [Command] to execute a function on the server. However, where does the [ClientRpc] function need to sit? Should it be in a script only located on a server object? Or can it be called from the same object/script as the one that makes the [Command] function call?
     
  7. seanr

    seanr

    Unity Technologies

    Joined:
    Sep 22, 2014
    Posts:
    669
  8. DRRosen3

    DRRosen3

    Joined:
    Jan 30, 2014
    Posts:
    683
    @Velo222 I'll expand on my example/suggestion a bit more.

    Code (CSharp):
    1. public class PlayerInput : NetworkBehaviour
    2. {
    3.  
    4.      public Material thisMaterial;
    5.  
    6.      void Update()
    7.      {
    8.           if(Input.GetKey(Keycode.SPACE))
    9.                CmdChangeColor(); //This sends a request to the server to execute the "CmdChangeColor" function on the server.
    10.      }
    11.  
    12.      public void ChangeColor()
    13.      {
    14.           thisMaterial.color = new Color(255, 255, 255,255);
    15.      }
    16.  
    17.      [Command]
    18.      public void CmdChangeColor()
    19.      {
    20.           RpcClientChangeColor(); //This sends a message from the server to all connected clients that have THIS GameObject and tells them to execute all code inside the "RpcClientChangeColor" function.
    21.  
    22.           ChangeColor(); //This executes the "ChangeColor" function on the server ONLY.
    23.      }
    24.  
    25.      [ClientRpc]
    26.      public void RpcClientChangeColor()
    27.      {
    28.           ChangeColor(); //This executes the "ChangeColor" function on the client ONLY.
    29.      }
    30. }
    All this code exists in a single script on the Player GameObject. When the player presses the SPACE BAR the Command portion is executed on the SERVER, which in turn sends a message to all connected clients to execute the ClientRpc portion.
     
    Last edited: Dec 1, 2015
    Velo222 likes this.
  9. Velo222

    Velo222

    Joined:
    Apr 29, 2012
    Posts:
    1,437

    Okay thank you. I'm getting a clearer picture. :)
     
  10. Sahkan

    Sahkan

    Joined:
    Mar 3, 2013
    Posts:
    204
    Thanks for everyone who tried to help. I guess I will stick with my method for now.
     
  11. DRRosen3

    DRRosen3

    Joined:
    Jan 30, 2014
    Posts:
    683
    What do you mean everyone who tried to help? I gave you the answer in my first post.
     
  12. Arisjan94

    Arisjan94

    Joined:
    Mar 10, 2018
    Posts:
    1
    I realize this post is very old, but I had this problem too and wanted to contribute. Isn't the server also considered a client?
     
  13. Ellernate

    Ellernate

    Joined:
    Aug 25, 2017
    Posts:
    81
    I just use SyncVar hooks if it's something like changing a color. This way all you have to do is call the function on the server, and it will also do the same thing on all clients. Plus it's buffered so it works on future clients, very simple!

    Code (CSharp):
    1. [SyncVar(hook="SetColor")]
    2. public Color32 MyColor;
    3.  
    4. public override void OnStartClient()
    5. {
    6.     SetColor(MyColor);
    7. }
    8.  
    9. public void SetColor(Color32 color)
    10. {
    11.     MyColor = color;
    12.     GetComponent<MeshRenderer>().material.color = MyColor;
    13. }
     
    Last edited: Mar 22, 2018
  14. Joe-Censored

    Joe-Censored

    Joined:
    Mar 26, 2013
    Posts:
    11,847
    I wouldn't normally write nonsense like this, but if you run DoSomething() the method something() will be called on the server and all clients no matter who is calling it, as long as if a client it has the proper authority over the object to issue commands.

    Code (csharp):
    1.  
    2. public void DoSomething()
    3. {
    4.     if (isServer)
    5.     {
    6.         something();
    7.         RpcDoSomething();
    8.     }
    9.     else
    10.     {
    11.         CmdDoSomething();
    12.     }
    13. }
    14.  
    15. [ClientRpc]
    16. void RpcDoSomething()
    17. {
    18.     something();
    19. }
    20.  
    21. [Command]
    22. void CmdDoSomething()
    23. {
    24.     something();
    25.     RpcDoSomething();
    26. }
    27.  
    28. private void something()
    29. {
    30.     Debug.Log("something is done");
    31. }
    32.  
     
  15. Zoroastrian

    Zoroastrian

    Joined:
    Mar 8, 2017
    Posts:
    10
    I'm testing with the example of incrementing a value one unit every time. If the server calls the function, the value is incremented twice.