Search Unity

Network Identity 'observers' don't match expectation

Discussion in 'Multiplayer' started by shiva-js, Jun 20, 2015.

  1. shiva-js

    shiva-js

    Joined:
    Oct 5, 2011
    Posts:
    31
    I have a scene object that doesn't list all my players in it's 'Observers' list. What defines which players are observers for an object? Is this different for scene objects versus dynamic spawned objects?

    I am not using NetworkManager, but my version of it is calling NetworkServer.SpawnObjects.
    I am trying to make a game with drop-in/drop-out, and so NetworkServer.SpawnObjects is called without all clients being connected. I expect this is my problem, but I would like some more information about how things are working behind the scenes.

    I am using 5.1.1f1
     
  2. seanr

    seanr

    Unity Technologies

    Joined:
    Sep 22, 2014
    Posts:
    669
    Objects spawned should be visible for new players entering.

    The list of observers for an object should only be different if you are using a component like NetworkProximityChecker that does custom visibility.

    You can can use NetworkIdentity.RebuildObservers() to update the observers for an object..
     
  3. shiva-js

    shiva-js

    Joined:
    Oct 5, 2011
    Posts:
    31
    Ok, so now things get interesting...
    I'm not using the NetworkProximityChecker, nor anything like it. Also, calling NetworkIdentity.RebuildObservers does not add all players to the observers list.
    If I were you, I'd probably be asking for a repro case right about now, so I'll look into making a nice simple one for you...
     
  4. shiva-js

    shiva-js

    Joined:
    Oct 5, 2011
    Posts:
    31
    Turns out I was wrong about the observers. The only player missing from the list is the one that is hosting (which I guess is ok). So my actual problem is that SyncVar and ClientRpc don't work on scene objects.
    I've attached a small project to repro the problem.
    - run the host in the editor and connect a standalone client
    - have the standalone client click the 'set owner' button
    - select the 'test scene object' in the editor hierarchy
    - switch inspector to debug mode and you should see that the last send time is still 0

    I tried creating a really really simple project to repro the problem, but at some point it starts working. I think my example is small enough that you should be able to find the issue, but let me know if you need anything else.

    Thanks
     

    Attached Files:

  5. seanr

    seanr

    Unity Technologies

    Joined:
    Sep 22, 2014
    Posts:
    669
    this is a known bug, it will be fixed in a patch release.
     
  6. shiva-js

    shiva-js

    Joined:
    Oct 5, 2011
    Posts:
    31
    That's great to know, but what exactly is the bug? Is it an issue with scene objects only? Can I get around this by dynamically creating my object for the time being?
     
  7. seanr

    seanr

    Unity Technologies

    Joined:
    Sep 22, 2014
    Posts:
    669
    yes, only scene objects.
     
    shiva-js likes this.
  8. shiva-js

    shiva-js

    Joined:
    Oct 5, 2011
    Posts:
    31
    Just curious if 5.1.1p1 was supposed to fix this issue? If it was, something is still broken. If it wasn't, I eagerly await the next one.
     
  9. seanr

    seanr

    Unity Technologies

    Joined:
    Sep 22, 2014
    Posts:
    669
    yes. it is fixed in that patch. Caveat, that it still doesnt work from inside OnStartServer(), which is a slightly different issue.
     
  10. shiva-js

    shiva-js

    Joined:
    Oct 5, 2011
    Posts:
    31
    I'm not using OnStartServer, I'm not even using NetworkManager. Can you double-check my repro please, I'm beginning to think that my issue remains unfixed. At the very least, could you elaborate on the bug you've fixed that you think I'm suffering from.
     
  11. seanr

    seanr

    Unity Technologies

    Joined:
    Sep 22, 2014
    Posts:
    669
    There are warnings building your project:


    I see 2 observers...

    upload_2015-6-24_17-10-10.png
     
  12. shiva-js

    shiva-js

    Joined:
    Oct 5, 2011
    Posts:
    31
    Thanks for looking. New SyncVar warnings are good, I missed those after upgrading. No warning for the RPC that is failing only when called within the property function though? Switching to a member function fixes all of my issues.
    Can you explain why the SyncVars and RPCs don't/can't work within a property function? I've read the docs and your blog on the topic, and saw nothing about these caveats.
     
  13. seanr

    seanr

    Unity Technologies

    Joined:
    Sep 22, 2014
    Posts:
    669
    the SyncVar setter system uses property functions, so setting syncvars inside property functions can lead to infinite recursion issues. If that is not in the docs, it should be. I will check.

    Actually ClietnRpc calls SHOULD work from within property functions, although it is strange to do that instead of a SyncVar hook function. That may be a bug.
     
  14. shiva-js

    shiva-js

    Joined:
    Oct 5, 2011
    Posts:
    31
    Hmm. I'm confused by the property function infinite recursion you mention. Surely the infinite recursion can only be caused by hook functions? If so, how does a property function affect this situation at all? I can't see a reason why property functions would lead to more infinite recursion than any other function. Maybe I'm missing a piece of the puzzle, please enlighten me.

    Have you considered adding something like 'Sync Var Reentrant Bits' to go along with 'Sync Var Dirty Bits' to do runtime testing for infinite recursion caused by hook functions? You could still get some false positives I suppose.

    The ClientRpc was an attempt to get something working, since the SyncVars were silently failing at the time. I agree that my use was a contrived example.
     
  15. seanr

    seanr

    Unity Technologies

    Joined:
    Sep 22, 2014
    Posts:
    669
    • user code sets value
    • property setter function is called
    • hook function is called
    • user code in hook function sets old value from new value
    • property setter function is called
    • hook function is called
    • ...

    I guess there are other potential solutions than just not processing property setter functions at all. Maybe we'll be able to find a better way to deal with this that allows setting in general property functions..
     
  16. shiva-js

    shiva-js

    Joined:
    Oct 5, 2011
    Posts:
    31
    I've found myself writing SetFoo functions due to the limitation anyway, and I could certainly achieve the same loop were I to make a similar mistake.
     
  17. Zullar

    Zullar

    Joined:
    May 21, 2013
    Posts:
    651
    This is creating problems for me as well. I follow on why setDirtyBit is not set during the syncVar's own hook function because this would cause infinite looping. But I have a completely separate property setter (a state machine) and when the syncVar is set in it's property setter it also does not call the syncVar hook.

    Code (csharp):
    1.  
    2. using UnityEngine;
    3. using System.Collections;
    4. using UnityEngine.Networking; //needed for NetworkBehavior
    5.  
    6. public class TestSyncVarHook : NetworkBehaviour
    7. {
    8.     private int _state;
    9.  
    10.     [SyncVar(hook="MyHook")]
    11.     public int syncVarTest;
    12.  
    13.     void Update ()
    14.     {
    15.         if(Input.GetKeyDown(KeyCode.Q))
    16.         {
    17.             state += 1;
    18.         }
    19.     }
    20.  
    21.     private int state //getSet property
    22.     {
    23.         get
    24.         {
    25.             return _state;
    26.         }
    27.         set
    28.         {
    29.             Debug.Log("Key Q Pressed: OldState=" + _state + "  NewState=" + value);
    30.             _state = value;
    31.             if(_state == 0)
    32.             {
    33.                 //Do something
    34.             }
    35.             else if(_state == 1)
    36.             {
    37.                 //Do something
    38.                 syncVarTest = 55; //This changes the syncVar value, but does not set dirty bit.  Why?
    39.             }
    40.             else if(_state == 2)
    41.             {
    42.                 //Do something
    43.                 syncVarTest = 66; //This changes the syncVar value, but does not set dirty bit.  Why?
    44.             }
    45.             else if(_state == 3)
    46.             {
    47.                 //Do something
    48.             }
    49.             else
    50.             {
    51.                 //Do something
    52.             }
    53.         }
    54.     }
    55.  
    56.     private void MyHook(int newValue)
    57.     {
    58.         Debug.Log("Hook Called: OldValue=" + syncVarTest + "  NewValue=" + newValue);
    59.         syncVarTest = newValue;  //I understand why this shouldn't set dirty bit, because it would cause infinite looping
    60.     }
    61. }
    62.  
     
  18. seanr

    seanr

    Unity Technologies

    Joined:
    Sep 22, 2014
    Posts:
    669
    this is fixed in 5.2 :(
     
    shiva-js likes this.
  19. Zullar

    Zullar

    Joined:
    May 21, 2013
    Posts:
    651
    Oooh awesome. Thanks.