Search Unity

Bizarre Network.Instantiate/destroy problem

Discussion in 'Multiplayer' started by AmazingRuss, Oct 29, 2008.

  1. AmazingRuss

    AmazingRuss

    Joined:
    May 25, 2008
    Posts:
    933
    I've been having a problem cleaning up objects instantiated by the server, and have narrowed it down to the following, which is run on the server:

    Code (csharp):
    1.  
    2. if( GUILayout.Button("BLARG!") )
    3. {
    4.     if(ps)
    5.         Network.Destroy(ps);
    6.     else
    7.         ps =
    8.             Network.Instantiate( Game.vehicle.Get(Game.config.startingVehicle),
    9.                                              new Vector3(0,5,0), Quaternion.identity, 0)
    10.                                              as GameObject;
    11.  
    12. }
    13.  
    This creates or destroys an object on the server every time the button is clicked. On the first connection, everything works perfectly. The object shows up and dissappears on the client and server as expected.

    However, if you disconnect the client and reconnect, the client creates all the objects that were created and destroyed on the server.

    If you create and destroy the object 10 times, and disconnect/reconnect the client, you immediately get 10 objects on the server and none on the client.

    My server has the following code, which I wouldn't think should be necessary, as the objects are being instantiated by the server....but I have it in there out of desperation.

    Code (csharp):
    1.  
    2.     void OnPlayerDisconnected(NetworkPlayer np)
    3.     {
    4.         Network.RemoveRPCs(np);
    5.         Network.DestroyPlayerObjects(np);
    6. }
    7.  

    If I connect multiple clients after a series of instantiate/destroys, each client gets the phantom objects.

    Anybody know why this is happening?
     
  2. ProtonOne

    ProtonOne

    Joined:
    Mar 8, 2008
    Posts:
    406
    Network.Instantiate boils down to an RPC call with the RPCMode of AllBuffered.

    So if on the server you Network.Instantiate an enemy (lets say a zombie), in the middle of a town, that zombie will be owned by the server. And you would expect that any person connecting to that server would see the zombie (even if they reconnect and disconnect many times).

    Do you really want the server to own all of the objects? (Authoritative server mode)

    If you don't mind letting the players own their objects, it is easier, and your line of code:
    Code (csharp):
    1. Network.RemoveRPCs(np);
    Will remove that players RPCs, including the Network.Instantiate RPC that would belong to the player.

    If you want to go the authoritative route, then it's best to not use Network.Instantiate and use Network.AllocateViewID() instead and manually assign your network view ids.

    They have an example of how to do that in the docs:
    file://localhost/Applications/Unity/Unity.app/Contents/Documentation/Documentation/ScriptReference/Network.AllocateViewID.html
     
    Miscellaneous likes this.
  3. seon

    seon

    Joined:
    Jan 10, 2007
    Posts:
    1,441
    Bottom line is....

    Network.Instantiate is buffered... but Network.Destroy isnt,

    So re-connecting players, or newly connecting players get the buffered call to instantiate the object, but never get the call to destroy it again.

    What you need to do is..

    Code (csharp):
    1. networkView.RCP("killObject", RPCMode.AllBuffered);
    2.  
    3. @RPC
    4. function killObject() {
    5.      Destroy(object you want destroyed);
    6. }
    Now the destroy gets called via a buffered RPC, so when people connect after the item is destroyed, there is a killObject call waiting for them to kill it off.

    yes, it seems like a pain, but once you get used to coding this way and thinking this way, it's a piece of cake :) Lemon Sponge cake :)

    Cheers :)
     
    Miscellaneous likes this.
  4. AmazingRuss

    AmazingRuss

    Joined:
    May 25, 2008
    Posts:
    933
    Thank you...that helps a lot!

    Any idea why Network.Destroy() isn't buffered? Doesn't seem to make sense.
     
  5. Aubrey-Falconer

    Aubrey-Falconer

    Joined:
    Feb 13, 2008
    Posts:
    438
    Fascinating!

    I ran into this problem a while ago, and finally ended up designing a very cludgy solution that relied on utilizing a new RPC channel for each object, and then clearing a whole channel when I wanted to remove an object.

    My question is whether there is any performance penalty for continually adding RPCs to your buffers.

    My multiplayer game has long been plagued by an extremely frustrating bug: all the connected players positions stop synchronizing after a while. When they create a new rpc call by, say, using the messaging console - all the other players see the message, but their vehicles stop moving on everyone else's screens. Could this be caused by some kind of networking buffer gradually filling up - or should I be looking elsewhere to isolate the problem?
     
  6. ProtonOne

    ProtonOne

    Joined:
    Mar 8, 2008
    Posts:
    406
    robur, are you using "Reliable Delta Compressed" state sync for your position rotation sync?

    If so, does the problem go away if you change it to unreliable?
     
  7. AmazingRuss

    AmazingRuss

    Joined:
    May 25, 2008
    Posts:
    933
    I wouldn't think the RPCs themselves use a huge amount of memory, but if you have to send them all every time a client connects there is going to be a burst of network traffic. If those RPCs are instantiating objects on the client, you could end up with a bunch of processor usage.

    The game I'm building will have run for weeks, so I could potentially end up with thousands of objects being instantiated and destroyed, so this becomes a problem. I'm writing my own object buffering system.
     
  8. Aubrey-Falconer

    Aubrey-Falconer

    Joined:
    Feb 13, 2008
    Posts:
    438
    Proton;

    I have experimented with both "unreliable" and RDC state synchronization, and the problem does occur a bit less when in unreliable mode, but it is still killing the game. Thanks for the suggestion though!


    AmazingRuss;

    Sounds like fun!
    My games should never run for more than a day or so, but I have noticed that very busy servers can take a while after you connect to them before things start happening - I will have to experiment with this more.



    P.S. The state sync code I am using is the C# one from Unity's networking example (with that green car driving around) - and it occasionally reaches the section of code that complains about the states array being out of order or something like that. Just wondering if this could be related to my problem? There were some comments in the code that it needed better error handling in that section, but that was the one script I have found that I haven't been able to fully comprehend yet :)

    (Very sorry for the vague references, but my main development computer is in to Apple for repairs right now, and I am running off my memory because I don't feel like digging out my source code archives to access them from my backup computer)
     
  9. ProtonOne

    ProtonOne

    Joined:
    Mar 8, 2008
    Posts:
    406
    Maybe you mean this code:

    Code (csharp):
    1. // Check if states are in order, if it is inconsistent you could reshuffel or
    2.             // drop the out-of-order state. Nothing is done here
    3.             for (int i=0;i<m_TimestampCount-1;i++)
    4.             {
    5.                 if (m_BufferedState[i].timestamp < m_BufferedState[i+1].timestamp)
    6.                     Debug.Log("State inconsistent");
    7.             }  
    I've seen that debug statement get triggered before, but do not remember why it happened. I would assume that it happens only with unreliable state sync (since the order of packets is not guaranteed). I actually disabled the interpolation and only use extrapolation, so I never get to that message anymore.

    Not sure what problem it would cause, but if it happened in RDC state sync mode, I imagine it could really mess things up.
     
  10. Aubrey-Falconer

    Aubrey-Falconer

    Joined:
    Feb 13, 2008
    Posts:
    438
    Yep - that is the code I was thinking of.

    Good idea on disabling the interpolation - that sounds like it may solve this problem. I will let you know once I get my computer back.
     
  11. Ethan

    Ethan

    Joined:
    Jan 2, 2008
    Posts:
    501
    You disable interpolation at all?
    Well doing only extrapolation may work, if your objects dont turn suddenly, right?

    currently i am extrapolating like that:
    Code (csharp):
    1. if(extraPolTime < maxExpolDur)
    2.   transform.position = bufferedState[0].pos + lastVelocity * (Network.time - lastNetUpdateTime) ;
    i'm mixing it with interpolation, but its still not really cool for my kind of action multiplayer game.
    (2 players starting right next to each other, and everyone sees himself right in front of the other on his own screen - just 1 meter perhaps, but thats not perfect)



    well to get back to the topic:

    in my game every player network.instantiates his own character,
    if player disconnects i just do
    Code (csharp):
    1. function OnPlayerDisconnected(player : NetworkPlayer)
    2. {
    3.     DeletePlayer(player);
    4.     networkView.RPC("DeletePlayer", RPCMode.Others, player);
    5.    
    6.     Debug.Log("Server destroying player");
    7.     Network.RemoveRPCs(player);
    8.     Network.DestroyPlayerObjects(player);
    9.  
    10. }
    i should go fine with this code, and i am going fine until someone gets disconnected because he kills the app without disconnecting from server, or pc crashed or what ever.

    now something strange happens:
    imagine 2 players on the server, one crashes, 1 is still on the server, now anotherone joins the server, and sees a uninitialized strange phantom player, which isnt in playerlist and NOT controlled by anyone.
    (everyone who now joins the server has this phantom player)

    now the really funny thing:
    if the one who was on the server when the other guy crashed is leaving the server - the phantom will be gone too for NEW connecting players.

    i am not 100 percent sure if this is how to get that bug, i hope anyone has an idea whats happening here.

    cheers

    gabriel
     
  12. Der Dude

    Der Dude

    Joined:
    Aug 7, 2006
    Posts:
    213
    I posted a version of the NetworkRigidbody script that uses an insertion sort algorithm to make sure the states in the buffer are in sync.

    I would advise you not to disable interpolation, when dealing with player characters as they are unpredictable.
     
  13. Nasuadax

    Nasuadax

    Joined:
    May 17, 2014
    Posts:
    1
    i solved it by using an RPC to create my objects on each client local. This means the server doesn't own it and I didn't set it to be a buffered command so new players will not get those items. Here you find another problem, new players don't see old items. I solved this by making the person who is the server check all the objects who are in the game at that moment and send them with an RPC to the new connecting player (this info you get from the OnPlayerConnected function) to make hem spawn the still existing old items.

    I also have the problem with the movement from the player not showing correctly (but this is different for each user i notice when trying with multiple clients) and this does not affect the making and deleting from those items. When you delete one of those items altough that player is currently bugged, he will still see it dissappear (in case of pickups it'll still be picked up altough payer is standing still somewhere else)

    i hope this was usefull, if you want any piece of code i used (i'm only starting programmer so prolly not good code, but does work), mail me @ mi_thom@hotmail.com