Search Unity

  1. Megacity Metro Demo now available. Download now.
    Dismiss Notice
  2. Unity support for visionOS is now available. Learn more in our blog post.
    Dismiss Notice

How to update a gameobject at other clients

Discussion in 'Editor & General Support' started by wvd_vegt, Apr 7, 2009.

  1. wvd_vegt

    wvd_vegt

    Joined:
    Jan 15, 2009
    Posts:
    48
    Hi,

    Can anybody give me a small C# sample of how to update a network object (where the original can be shifted around by a fps).

    I came as far as the following C# code (MyAvatar is a cube packed as a prefab and located in the Resources directory):

    Code (csharp):
    1.  
    2. using UnityEngine;
    3. using System;
    4. using System.Diagnostics;
    5. using System.Collections;
    6.  
    7. public class ServerScript : MonoBehaviour {
    8.  
    9.     public void OnServerInitialized() {
    10.         GameObject avatar = Resources.Load("MyAvatar") as GameObject;
    11.  
    12.         Vector3 baseposition = new Vector3(10,1,10);
    13.  
    14.         GameObject go= Network.Instantiate(avatar, baseposition, transform.rotation, 0) as GameObject;
    15.         go.name = "server_object";
    16.     }
    17.    
    18.     public void OnConnectedToServer() {
    19.         networkView.RPC( "RequestOwner", RPCMode.Server );
    20.  
    21.         GameObject avatar = Resources.Load("MyAvatar") as GameObject;
    22.        
    23.         Vector3 baseposition = new Vector3(10,1,10);
    24.  
    25.         GameObject go = Network.Instantiate(avatar, baseposition, transform.rotation, 0) as GameObject;
    26.         go.name = "client_object";
    27.     }
    28.    
    29.     public void OnGUI () {
    30.         if (GUI.Button (new Rect (10,10,100,50), "Start server")) {
    31.                
    32.             Network.InitializeServer(32, 25000);           
    33.         }
    34.         if (GUI.Button (new Rect (10,70,100,50), "Connect")) {
    35.  
    36.             Network.Connect("127.0.0.1", 25000);       
    37.         }
    38.     }
    39. }  
    40.  
    When i execute this code each client gets it's own avatar but it can only be pushed in its own world (remote does not show up a thing).

    From the documentation, it seems like Network.Instantiate sets up everything and does the synchronizing automatically.
     
  2. cyb3rmaniak

    cyb3rmaniak

    Joined:
    Dec 10, 2007
    Posts:
    162
    It does, but you still need to define what data you want to send over the net...
    Read this and focus on the part called "Choosing data to send".

    The network view has to observe something to sync it with the other clients. So if you want to transfer the position and rotation to the rest of the clients, you can probably just set up the Observed property to observe the Transform component of MyAvatar. Oh, and set the "State Synchronization" property to either "Reliable Delta Compressed" or "Unreliable".
    If I'm not mistaken, this will work as is.

    If you want to do more fancy stuff, you can set the Observe property to watch a script and then from inside the script use OnSerializeNetworkView():
    Code (csharp):
    1. void OnSerializeNetworkView(BitStream stream, NetworkMessageInfo info)
    2.     {
    3.         // Always send transform (depending on reliability of the network view)
    4.         if (stream.isWriting)
    5.         {
    6.             Vector3 pos = transform.localPosition;
    7.             Quaternion rot = transform.localRotation;
    8.             stream.Serialize(ref pos);
    9.             stream.Serialize(ref rot);
    10.         }
    11.         // When receiving, buffer the information
    12.         else
    13.         {
    14.             // Receive latest state information
    15.             Vector3 pos = Vector3.zero;
    16.             Quaternion rot = Quaternion.identity;
    17.             stream.Serialize(ref pos);
    18.             stream.Serialize(ref rot);
    19.             transform.localRotation = rot;
    20.             transform.localPosition = pos;
    21.         }
    22.     }
    23.  
    Also, check out the network examples.
     
  3. wvd_vegt

    wvd_vegt

    Joined:
    Jan 15, 2009
    Posts:
    48
    Thanks a lot!

    The Network View did the trick. I set the Observed property to Transform and that did it.

    And I noticed that I created the cube inside the OnServerInitialized() which was wrong!

    After calling it (btw why is it called twice?) the client can connect but the remote object is not created (at least so it seemed). If i create it later (for now in a GUIbutton) all works as expected.

    Last question: how to set Observed to a scripts' .

    Code sofar:
    1) OnSerializeNetworkView is not used,
    2) Observed is set to Transform of the Prefab,
    3) I'm also not sure about the ownercode working. The Jscript sample had @RPC but that does not work in C#:

    Code (csharp):
    1.  
    2. using UnityEngine;
    3. using System;
    4. using System.Diagnostics;
    5. using System.Collections;
    6.  
    7. public class ServerScript : MonoBehaviour {
    8.  
    9.     private NetworkPlayer networkPlayer;
    10.     private int currentPlayerID;
    11.     private GameObject avatar;
    12.     private GameObject go;
    13.  
    14. //Debug Code
    15.    
    16.     public static DateTime FirstTick = DateTime.Now;
    17.    
    18.     public static void Trace() {
    19.         _Trace(new StackFrame(1, true).GetMethod().ToString(), null);
    20.    }
    21.    
    22.     public static void Trace(string msg) {
    23.         _Trace(new StackFrame(1, true).GetMethod().ToString() , msg);
    24.    }
    25.    
    26.     public static void _Trace(string method, string msg) {
    27.         string Duration = ((TimeSpan)(DateTime.Now - FirstTick)).ToString();
    28.         Duration = Duration.Substring(0, Duration.Length - 4); //Removed some detail (msec resolution).
    29.         if (msg==null || msg.Length==0) {
    30.             print (Duration + ": "+method);
    31.         } else {
    32.             print (Duration + ": "+method + " - " +msg);
    33.         }
    34.    }
    35.  
    36. //Debug Code
    37.    
    38.     // Use this for initialization, called after Awake().
    39.     public void Start () {
    40.         Trace();
    41.     }
    42.    
    43.     // Update is called once per frame.
    44.     public void Update () {
    45.       //
    46.     }
    47.  
    48.     //Put global code here (whats put outside of functions in JScript.
    49.     public void Awake () {
    50.         Trace();
    51.     }
    52.    
    53.     public void OnServerInitialized() {
    54.         Trace();
    55.    
    56.         //Where does this end up?
    57.         //UnityEngine.Debug.Log("OnServerInitialized");
    58.     }
    59.    
    60.     public void OnConnectedToServer() {
    61.         Trace();
    62.     }
    63.    
    64.     public void OnGUI () {
    65.         if (GUI.Button (new Rect (10,10,100,50), "Start server")) {
    66.             Trace("Start Server");
    67.                
    68.             Network.InitializeServer(32, 25000);           
    69.         }
    70.        
    71.         if (GUI.Button (new Rect (10,70,100,50), "Connect")) {
    72.             Trace("Connect");
    73.  
    74.             Network.Connect("127.0.0.1", 25000);       
    75.         }
    76.  
    77.         if (GUI.Button (new Rect (10,140,100,50), "Create")) {
    78.             Trace("Create");
    79.  
    80.             GameObject avatar = Resources.Load("MyAvatar") as GameObject;
    81.  
    82.             Vector3 baseposition = new Vector3(10,1,10);
    83.  
    84.             go = Network.Instantiate(avatar, baseposition, transform.rotation, 0) as GameObject;
    85.             go.name = "server_object";
    86.         }
    87.  
    88.         if (GUI.Button (new Rect (10,200,100,50), "Move")) {
    89.             Trace("Move");
    90.  
    91.             go.transform.Translate(0,0,1);
    92.        
    93.             //Network.Connect("127.0.0.1", 25000, "HolyMoly");     
    94.         }
    95.     }
    96.    
    97.     public void RequestOwner(NetworkMessageInfo info)  {
    98.         Trace();
    99.         networkView.RPC( "SetOwner", info.sender, info.sender );
    100.     }
    101.  
    102.     public void SetOwner(NetworkPlayer a_owner)     {
    103.         networkPlayer = a_owner;
    104.         currentPlayerID = int.Parse( networkPlayer.ToString() );
    105.        
    106.         Trace("Current PlayerID = "+currentPlayerID.ToString());
    107.     }
    108.    
    109.     void OnSerializeNetworkView(BitStream stream, NetworkMessageInfo info) {
    110.       // Always send transform (depending on reliability of the network view)
    111.       if (stream.isWriting)
    112.       {
    113.          Vector3 pos = transform.localPosition;
    114.          Quaternion rot = transform.localRotation;
    115.          stream.Serialize(ref pos);
    116.          stream.Serialize(ref rot);
    117.       }
    118.       // When receiving, buffer the information
    119.       else
    120.       {
    121.          // Receive latest state information
    122.          Vector3 pos = Vector3.zero;
    123.          Quaternion rot = Quaternion.identity;
    124.          stream.Serialize(ref pos);
    125.          stream.Serialize(ref rot);
    126.          transform.localRotation = rot;
    127.          transform.localPosition = pos;
    128.       }
    129.    }  
    130. }
    131.  
     
  4. cyb3rmaniak

    cyb3rmaniak

    Joined:
    Dec 10, 2007
    Posts:
    162
    Glad it helped you.
    About the OnServerInitialized() running twice - it shouldn't. I think you have some confusion here about instantiation, and because of it you think it runs twice.
    Network.Instantiate() creates your game object on all connecting clients. It also buffers it so that new clients will receive this object too.
    So when you had the Network.Instantiate both in OnServerInitialized() and in OnConnectedToServer(), it ran once when you started the server, and then once again when the client connected to it. Each time, it created a new instance of the object. When the client connected, it first received the buffered call from the server to create the object (1st instance of the object), and then it ran the code in OnConnectedToServer() and created a new instance both on the client, and on the server. It also buffered it, so the next client that will connect will receive two buffered calls and will create one of its own.

    About ownership - in Unity, when you use Network.Instantiate the owner of that object is the client that ran the function. Lets say you connect to a server and you need to create your character. You (as a client) run Network.Instantiate and it will create an instance of your character on all the other clients and on the server. From now on, whenever someone will run networkView.owner or networkView.isMine, the owner of that object will be you (the client that created it). I'm not sure about this, but I think you cannot change ownership from a script. There are other solutions for that (that don't use Network.Instantiate).

    About RPC - "@RPC" is the syntax in Javascript. in C# it's "[RPC]".

    And the reason OnSerializeNetworkView() is not used in your code is because your network view is observing the Transform component. If you want to use it, either change the observing property of the existing network view to observe the script that has the OnSerializeNetworkView() function in it, or create a new network view on the same game object that observes it. Obviously, the sample script I posted already handles position and rotation, so you don't need both the OnSerializeNetworkView() and the observing of Transform. They both do the same thing, just in two different ways. (Oh, and the script doesn't handle the scale as it is).