Search Unity

Simplest network serialization - OnSerializeNetworkView

Discussion in 'Multiplayer' started by nopcode, May 20, 2011.

  1. nopcode

    nopcode

    Joined:
    Apr 29, 2011
    Posts:
    67
    I'm trying to figure out how Unity "does networking", and have gotten nowhere with the examples.

    I have a separate Client and Server project. Both are nothing - the server listens, and the client connects. However, what I expect to have happen is that OnSerializeNetworkView gets called, and they do not.

    The server's "output_log.txt" file shows that the client does connect successfully, but beyond that - nothing. The client should serialize the value "1984" to the server, but neither the client nor the server calls OnSerializeNetworkView. So obviously I'm missing a part. Server is built and run by itself, and the client I've run from within Unity. Run in the background is turned on both both.

    I'm attaching both projects, and including the code inline here:

    Server:
    Code (csharp):
    1. using UnityEngine;
    2. using System.Collections;
    3.  
    4. public class NetworkListenerServer : MonoBehaviour
    5. {
    6.    void Start()
    7.    {
    8.       Network.InitializeServer(25, 12000, false);
    9.    }
    10.  
    11.    void OnPlayerConnected(NetworkPlayer player)
    12.    {
    13.       Debug.Log("********* Player connected from " + player.ipAddress + ":" + player.port);
    14.    }
    15.  
    16.    void OnPlayerDisconnected(NetworkPlayer player)
    17.    {
    18.       Debug.Log("********* Clean up after player " + player);
    19.       Network.RemoveRPCs(player);
    20.       Network.DestroyPlayerObjects(player);
    21.    }
    22.  
    23.    // This apparently never gets called???
    24.    void OnSerializeNetworkView(BitStream stream, NetworkMessageInfo info)
    25.    {
    26.       Debug.Log("********* OnSerializeNetworkView");
    27.       if (stream.isReading)
    28.       {
    29.          int value = 0;
    30.          stream.Serialize(ref value);
    31.          Debug.Log(value);
    32.       }
    33.    }
    34. }
    35.  
    Client:
    Code (csharp):
    1. using UnityEngine;
    2. using System.Collections;
    3.  
    4. public class ClientScript : MonoBehaviour
    5. {
    6.    public int someValue;
    7.    NetworkViewID viewID;
    8.  
    9.    void Start()
    10.    {
    11.       Debug.Log("Connecting...");
    12.       Network.Connect("127.0.0.1", 12000);
    13.    }
    14.  
    15.    void OnConnectedToServer()
    16.    {
    17.       Debug.Log("Connected to server");
    18.    }
    19.  
    20.  
    21.    void OnDisconnectedFromServer(NetworkDisconnection info)
    22.    {
    23.       if (info == NetworkDisconnection.LostConnection)
    24.          Debug.Log("Lost connection to the server");
    25.       else
    26.          Debug.Log("Successfully disconnected from the server");
    27.    }
    28.  
    29.    // This never gets called???
    30.    void OnSerializeNetworkView(BitStream stream, NetworkMessageInfo info)
    31.    {
    32.       Debug.Log("OnSerializeNetworkView");
    33.       // write a value that we know what it will be
    34.       if (stream.isWriting)
    35.       {
    36.          int value = 1984;
    37.          stream.Serialize(ref value);
    38.       }
    39.    }
    40. }
     

    Attached Files:

  2. JRavey

    JRavey

    Joined:
    May 12, 2009
    Posts:
    2,377
    OnSerializeNetworkView serializes a network view. Your projects don't have network views. Also, those network views should have identical NetworkViewID values, otherwise it wouldn't know which network view was talking to which.

    Also, each NetworkView must have an owner, that owner can write to the bitstream, everybody else reads from it.
     
    Last edited: May 20, 2011
  3. nopcode

    nopcode

    Joined:
    Apr 29, 2011
    Posts:
    67
    The client does, and the Observed is set to the ClientObject, with Unreliable as the synchronization type. I've tried setting the NetworkViewID and they didn't do anything - how are you suggesting I set them?
     
  4. JRavey

    JRavey

    Joined:
    May 12, 2009
    Posts:
    2,377
    I honestly cannot tell what you are trying to accomplish. It looks like you want to have an object which exists on both servers with different scripts, but if you set up that object on the server with a network view, it needs to have a NetworkViewID of the client instance of that object. What you are attempting isn't impossible, but you have to make sure you are allocating proper networkviewIDs.

    Normally, one would either use Network.Instantiate, or use an RPC to request the creation of something and then pass along the NetworkViewID to be manually assigned.
     
  5. nopcode

    nopcode

    Joined:
    Apr 29, 2011
    Posts:
    67
    In simplest terms, I want to know what it takes to get OnSerializeNetworkView to get called, both on the client side, and on the server side. Right now, it's not getting called on either (server because the client's OnSerializeNetworkView is never called; client because...?)

    Put another way, what the sample code is expected to do is continually spit out "1984" to the server, continually broadcasting that message.
     
  6. nopcode

    nopcode

    Joined:
    Apr 29, 2011
    Posts:
    67
    Okay, I modified the client project to send an RPC command to the server. Right off the bat, it's screwy that I need to duplicate the function signature in the client code when it's never going to be called. The server project code has an RPC function that create a new object from a prefab. Both the server script and the prefab script have OnSerializeNetworkView - neither get called. The client's OnSerializeNetworkView still never gets called. I do see over and over in both output logs "Sending generic state update, broadcast on, view ID 'SceneID: 1 Level Prefix: 0'". All three objects - client, server, prefab - have NetworkView components.

    All the client needs to be doing is send messages to the server. From my understanding, OnSerializeNetworkView should be getting called at a constant rate as long as I have the Network View set up as unreliable. The problem still remains that OnSerializeNetworkView is not getting called. What does it take/require that OnSerializeNetworkView is called on the client side?




    View attachment $NetworkClientTest.zip View attachment $NetworkServerTest.zip
     
  7. nopcode

    nopcode

    Joined:
    Apr 29, 2011
    Posts:
    67
    I was able to figure out why the OnSerializeNetworkView never gets called. Several posts and Q&A topics had asked the same thing, and pretty much nobody was clear on what needs to be done, other than "drag the script over". The samples show that the script attached to the GameObject is being observed, so ergo, there must be a way. There was a mention in passing to "drag the name of the script", which made no sense.
    What this person was referring to is the Component name in the Inspector - drag this into the Observed slot (aside: you can do this with any component attached to the GameObject, and yes you can have multiple Network Views that observe different components). I've attached pictures inline to show this so that others who have gotten confused will understand better, because neither the documentation nor M2H's pdf discusses this at all, which is a major failing. The resource picker for the Observed slot only lets you pick the GameObject, not its sub-components.

    Image 1: the Observed slot that needs corrected
    $Step1-observedslot.jpg

    Image 2: Select the component to drag to the slot
    $Step2-selectcompnentitem.jpg

    Image 3: drag to the slot
    $Step3-dragtoslot.jpg

    Image 4: and done
    $Step4-done.jpg
     
    trongcongkt likes this.
  8. appels

    appels

    Joined:
    Jun 25, 2010
    Posts:
    2,687
    As far as i can remember it is mentioned, thats how i learned it anyway.
     
  9. Dreamora

    Dreamora

    Joined:
    Apr 5, 2008
    Posts:
    26,601
    I think it was mentioned at least back in Unity 2 inside the manual on networking
    But the real way to learn basics on networking is reading the manual on networking while experimenting with the networking example which will teach you how to interact with it and see messes etc directly as it works out of the box for all the various scenarios etc
     
  10. nopcode

    nopcode

    Joined:
    Apr 29, 2011
    Posts:
    67
    Re: mention of dragging component to the observer slot.

    In the Network View documentation, under Choosing data to send, it says "You can select a Component from the drop-down, or you can drag any Component header directly to the variable". This is the only place I found that it mentions this, and the there is no "drop down" that I found. The picker doesn't select components, only game objects. Never would it occur to me (and others, apparently) that you can drag the component "title" header into a slot. This is one of those times when relying on the graphic drag-n-drop interface of Unity vs coding it fails without pictures; simple verbiage and code examples doesn't cut it.

    Other things that have apparently perplexed others that I also ran into regarding how OnSerializeNetworkView is called and it's order of operations. The ones who have been with Unity for a long time probably know this, but these are not documented clearly enough for the new users.

    OnSerializeNetworkView is NOT a two-way street. The flow goes from whom "owns the object" to the others. That's all that is said on the subject in the docs. There is a post buried that if you google-fu into it that explains "the owner of a NetworkView is the system that used Network.AllocateViewID() to create that views view id". The owner will always write, and never read; the others are listeners and never get to write back. So if you need some form of two-way, either RPC the values or use two separate NetworkViews, with the allocation of the view ids being done on each separate system.

    You CAN use separate and different objects on the client and server; I've attached two sample projects that do this. Probably not the best example in the world - have the server change its own view id based on the client is poor - but it shows how I got the view id issues results.

    "View ID SceneID: 1 Level Prefix: 0 not found during lookup. Strange behaviour may occur" - the server is sending our the view id to the client. Once you set the view id up this stops, but to prevent it in the first place I found that "Network.SetSendingEnabled(nView.group, false)" in the OnPlayerConnected and then "Network.SetSendingEnabled(nView.group, true)" after the view id has been changed solves that problem.

    Client project
    View attachment $NetworkClientTest.zip

    Server project
    View attachment $NetworkServerTest.zip
     
  11. PrimeDerektive

    PrimeDerektive

    Joined:
    Dec 13, 2009
    Posts:
    3,090
    Why are you maintaining separate projects for the client and the server?
     
  12. nopcode

    nopcode

    Joined:
    Apr 29, 2011
    Posts:
    67
    Depending on the application, this is exactly what you will want to do. If you need to control things and have separate data acquisition and reaction control, you simply do not want any random Joe User to become a server.
     
  13. PrimeDerektive

    PrimeDerektive

    Joined:
    Dec 13, 2009
    Posts:
    3,090
    Sure, but I'd probably use a different networking library then. The built-in networking is kind of designed around the client and server using the same project; without a lot of working-around (and a very unintuitive development process), having separate projects basically breaks the ability to use RPC's, and you'll probably run into a lot of mismatched view ID's and other issues down the road.
     
  14. nopcode

    nopcode

    Joined:
    Apr 29, 2011
    Posts:
    67
    Absolutely. But in order to make that determination, I had to do the ground work that showed that Unity's networking is not suitable for a typical client/server model (separation of data and presentation). It might be useful for very limited design, but making Unity act as a pure server, as you pointed out, is not what it's designed for. Plus others have commented somewhat on the overhead of RPC's so using them as a solution is iffy.

    Fortunately, there exists other libraries that can be used, but for what we're designing towards, we're going to re-use some of our existing networking code and put .NET wrappers around the interfaces.
     
  15. PrimeDerektive

    PrimeDerektive

    Joined:
    Dec 13, 2009
    Posts:
    3,090
    I hear good things about Lidgren. Are you making a game? Just curious :)
     
  16. BLarentis

    BLarentis

    Joined:
    Mar 12, 2012
    Posts:
    3
    Thank you nopcode for those images. Saved my day !
     
  17. altair2020

    altair2020

    Joined:
    Mar 6, 2011
    Posts:
    48
    Hi everyone,

    Nopcode feeling your frustration here...

    I am struggling to understand the network aspects of Unity.

    I done these tutorials and they work:

    http://codesynergy.wordpress.com/unity-networking-tutorial-in-c/

    my next step would be to create a Authoritative server for my game and its proving a nightmare to understand.

    Can anyone advise of a C# networking tutorial that is not 85$ in the asset store ?

    Cheers,

    J.