Search Unity

  1. Unity 2019.1 is now released.
    Dismiss Notice

Unity Multiplayer My Compiled List of UNET Bugs/Issues

Discussion in 'Connected Games' started by Zullar, May 10, 2016.

  1. Zullar

    Zullar

    Joined:
    May 21, 2013
    Posts:
    595
    I've spent a lot of time working with UNET and thought I'd compile a list of bugs/issues that I've come across. Overally I think UNET will be good once it gets finished, but some issues at the moment. I hope this can help other players and also that a Unity developer can help straiten things out.

    I'll update this as I find new bugs or as things are fixed. Let me know if anything is incorrect.

    Also if anybody from Unity reads this I'll be happy to create reduced bare-bones code to replicate any of these issues for debugging.

    ***BUGS***
    1: [734257] UNET [Command] Does Not Work With Inheritance or Commands With the Same Name.

    https://issuetracker.unity3d.com/issues/commands-with-duplicate-names-call-wrong-command
    http://forum.unity3d.com/threads/command-inheritance-heirarchy-index-mismatch-bug.359772/

    2: [794443] UNET NetworkAnimator Broken With Multiple Animation Layers
    When using NetworkAnimator only the base layer[0] will sync to client. Other layers (like layer [1] or [2]) will not sync to client.
    https://issuetracker.unity3d.com/is...t-layer-animations-are-synced-through-network
    https://fogbugz.unity3d.com/default.asp?794443_l24atkuvp8v1kcli
    http://forum.unity3d.com/threads/networkanimator-multiple-animator-controller-layers-broken.402539/
    Oct 17th, 2016: Issue is marked as closed/postponed (will be fixed at a later date).

    3: [TBD] UNET SyncList Throws Not Initialized Errors When Set During Awake()
    http://forum.unity3d.com/threads/synclist-not-initialized-during-awake.356385/

    4: [TBD] UNET Setting SyncVar/SyncList Repeatedly to the Same Value Still Sets Dirty Bits and Chews Up Network Bandwidth
    I'd recommend a UNET check to see if value has changed before setting dirty bit. This prevents improper use of SyncVar's/SyncList where bandwidth is used up for some obscure reason.

    5: [762719] UNET Message Inheritance Broken

    https://issuetracker.unity3d.com/is...ebase-doesnt-call-overridden-serialize-method
    https://fogbugz.unity3d.com/default.asp?747334_sfs90f3bcm8nrcok
    http://forum.unity3d.com/threads/unet-message-inheritance-broken.369701/

    6: [TBD] UNET SyncStructs Do Not Automatically Set Dirty Bit When an Internal Field is Changed
    I'd recommend either SetDirtyBit when internal struct field is changed, or throw errors when changing internal fields to make SyncStructs foolproof. As it is they can be used incorrectly with no warnings.

    7: [TBD] UNET Commands Have Delay Even on Host
    When you issue a command on server there is a delay even though it's talking to itself and seems like it *should* be instant. For example, if you [Command] move inventory item to slot 17, then access the item in slot 17... the item doesn't exist yet... there's a delay before it happens. So this forces me to have 2 separate codes, one for host that does not use commands (and is therefore instant sequential code), and one for client, which is the whole thing UNET was trying to avoid.

    8: [822355] UNET [SyncVar] Hook Not Called on Client in Time Around Scene Change
    In the time around a scene change when a SyncVar is changed the hook will not always be called on the client... even though the value properly updates. Bug reported 2016_08_08.
    https://issuetracker.unity3d.com/is...-syncvar-value-is-changed-during-scene-change
    https://fogbugz.unity3d.com/default.asp?822355_sv7nmvbc0bv08rlh
    https://fogbugz.unity3d.com/default.asp?821633_5ps5qsis7vrrevrr
    http://forum.unity3d.com/threads/sy...client-immediately-after-scene-change.424844/

    9: [TBD] UNET SyncList Callbacks Have Insufficient Information
    For proper usage you need access to the OldVal and NewVal at the time of a Callback. SyncList callbacks only provide information on the newValue, not the oldValue. So when a value is changed/removed you do not know *what* was changed or removed.
    https://fogbugz.unity3d.com/default.asp?804379_hukgv5qh81vqncb0
    http://forum.unity3d.com/threads/synclist-behaviour-has-been-changed-in-5-3-2p4.387914/
    https://feedback.unity3d.com/suggestions/unet-synclist-callback-needs-access-to-oldvalue

    10: [TBD] ClientRPC's are Dropped if Sent Around SceneChange
    I sent a ClientRPC from the Host around the time of a new scene load the ClientRPC is never received by the clients (even the host client!).
    https://fogbugz.unity3d.com/default.asp?831893_63262uhermqgeju4

    11: [TBD] Ambiguous NetworkDestroy
    NetworkServer.Destroy() destroys an object on server and all clients. It calls a NetworkBehaviour.OnNetworkDestroy() on all clients. However, OnNetworkDestroy() is also called when destroying an object other ways (closing editor, exiting scene, etc.) and there is no easy way to distinguish if the object is being destroyed due to NetworkServer.Destroy()... or due to another reason.

    12: [TBD] SyncList Callback Failure
    For persistent DontDestroyOnLoad network objects with a SyncList the callbacks are not received on the client during the period around a scene transition. I believe this is due to the client's isReady flag being set to false and NetworkIdentiy.observer list momentarily being removed.
    https://fogbugz.unity3d.com/default.asp?833578_76432msnc8da1g6k

    13: [TBD] NetworkServer.connections Null
    After a client disconnects the NetworkServer.connections associated with that client will not be removed but the collection, but instead made null. This can cause errors unless you are constantly performing null checks.

    14: [TBD] SyncVars can Become Desynced Between Server and Client
    After a client connects all serialized data is sent only to the new client and dirty bits are cleared. This means that any SyncVar values are not sent to existing clients. Existing clients will have an incorrect SyncVar value indefinitely unless it is changed again on the server forcing all values to be sent again to all ready observers.
    https://forum.unity3d.com/threads/n...-onserialize-needs-robustness-changes.431999/

    15: [TBD] Networked GameObjects Sometimes are Not Destroyed when Network is Terminated
    Sometimes (both on Host and Client) networked GameObjects are disabled (not destroyed) when the network is terminated. Unsure of all the various ways this can occur but I submitted reduced sample code to replicate bug to QA.
    https://fogbugz.unity3d.com/default.asp?867411_621m3r66s84lt94f

    16: [898387] NetworkIdentity Causes Animator.SetFloat to Fail
    Calling NetworkIdentity.SetFloat(...) does not always work if the object has a NetworkIdentity component attached. The Animator.parameter value in GetFloat(...) and the value in the inspector also do not match.
    https://fogbugz.unity3d.com/default.asp?898387_m1dp0u9neo5qlsa4

    17: [932531] NetworkIdentity Causes GetComponentInParent<T> to Return Null
    In the build (not the editor) GetComponentInParent<T> will fail and return null when called externally before Awake(). Bug only occurs on UNET objects with NetworkIdentity... non-networked objects work fine. Bug #16 and #17 likely related?
    https://fogbugz.unity3d.com/default.asp?932531_okip5dh462jnf23q

    ***DESIGN ISSUES***
    101: Initialization of Player is Tricky to Do

    UNET serialization and Unity prefab/scene serialization are both incompatible with reading/writing to files. So essentially you end up with 3 forms of serialization... ugh!
    https://forum.unity3d.com/threads/unet-saving-networking-character-data.436763/

    102: Cannot AddComponent<NetworkBehaviour> at Runtime or by Script During Initialization
    It really makes it hard to use inheritance and manage scripts when you must drag & drop and manage EVERY prefab. Change 1 thing and you have to repair every prefab in the game manually...

    103: HLAPI Does Not Allow For Split Authority
    i.e. where NetworkAnimator is controlled by server, but NetworkTransform is controlled by client (this is a common strategy... server side authoritative player action control, but client side player motion control)

    104: SyncVar's & Client Control
    It would be nice if SyncVars could be controlled by a client. Instead you have to send message/Command to server and then have the server change the SyncVar, and then ignore the callback on the original client sender of the SyncVar. It's very convoluted.

    105: NetworkWriter and Bools
    When using the NetworkWriter/Reader bools are treated as bytes. Instead of writing a 1 or 0 it writes 1000000 or 00000000. This causes as much as 8x the bandwidth as necessary. I'd recommend the network writer/reader to allow writing single bits. If whole bytes are needed for the network package then round-up at the very end to the nearest whole byte. This would allow bools and syncVar dirty masks (see below) to be much more efficient.

    106: SyncVar's Dirty Mask Length = 32
    You cannot have more than 32 syncVars. And if you have less than 32 SyncVars then it sends unnecessary data. For example if I have an on/off switch with 1 SyncVar bool it will send 16 bits of data (8 bit compressed mask and 8 bit bool)! Bools should not be part of the DirtyBit mask system (since the dirtyBitMask itself uses as much bandwidth as the bool!). Additionally I think the dirtyBitMask should be variable length instead of Uint32. Summary:
    -DirtyBitMask should be variable length, not constant uint32
    -SyncVar Bools should not be part of dirtBitMask
    -Decouple dirtyBitMask from NetworkBehaviour.isDirty (changing a bool should still mark NetworkBehaviour as dirty)
    -Allow NetworkReader/Writer to send single bits (bits shouldn't read/write as 8bit bytes)

    107: NetworkBehaviour Do Not Have DirtyBit For the Script
    If you have an object with 20 NetworkBehaviour scripts attached and you change 1 SyncVar bool then all 19 other NetworkBehaviour scripts must write a 32bit zero to the NetworkWriter during OnSerialize. This means you will send 648 bits (20x32 + 8) of data just to send 1bit of bool data. Each NetworkBehaviour script should really have it's own dirtyBit (a dirtyBitMask for all NetworkBehaviour scripts) for network bandwith reasons.
    http://forum.unity3d.com/threads/un...idth-inefficiencies-suggested-changes.429187/

    108: Client-Control of NetworkBehaviour SyncVar Fields is an Absolute Nightmare!!!
    During OnDeserialize you must be careful to always read data, even if you are ignoring it. This is because OnSerialize always sends information to all clients... even if the client is the owner. So if you have a client-controlled script (i.e. NetworkTransform) you must send a serialized message from Client --> Server, then replicate this data to other clients by NetworkBehaviour.OnSerialize/Deserialize. The problem is that this also sends the data back to the original sender (the client authoritative owner). The owner must read this data (otherwise NetworkReader becomes out-of-sync) but ignore this data. Also, during scene changes all the serialized data is re-sent and this data also needs to be ignored otherwise a small backwards time step is taken where a client-owner can have it's data overridden by older server controlled data. Client-side control of synced data (like player position) is something many games will have but there is no clean UNET implementation.

    109: NetworkTransform Compressed Rotation Resolution Poor
    If compressed, the NetworkTransform compresses rotation to a short (16bits). The angles are basically rounded to whole degrees (i.e. 183.27deg becomes 183deg). With 16 bits the compressed angle could be 360/(2^16) or 0.005deg of resolution... but instead we get 1.000deg of resolution which makes things appear glitch even though enough bits are being transmitted to make it smooth. On a similar note if Bits (instead of Bytes) are used then a BitWriter/Reader is capable of something like this: BitWriter.WriteFloatCompressed(0f, 360f, 12) //corresponding to 0degMin, 360degMax, and 12bits of resolution. And float = BitReader.ReadFloatCompressed(0f, 360f, 12f).
     
    Last edited: Jul 18, 2017
  2. Chom1czek

    Chom1czek

    Joined:
    Sep 19, 2015
    Posts:
    66
    1. Sorry I kinda don't understand that bug :p



    6. SyncStructs Do Not Automatically Set Dirty Bit When an Internal Field is Changed


    You mean:
    Code (csharp):
    1.  
    2. public struct Magic
    3. {
    4.    public float power;
    5.    public bool realMagic;
    6. }
    7.  
    8. public class MagicSLS = new SyncStructList<Magic>{}
    9. public MagicSLS magicList = new MagicSLS();
    10.  
    11. magicList.Add(new Magic(69, true));
    12.  
    13. magicList[0].power = 70;
    14.  
    if you want this to happen then what is the difference between this (struct) and that (class)? Because I thought structs shouldn't be mutable and to make it sync you need to. But I agree that there should be some warning included since I am still newbie and it took me some time to realize how struct works :)
    Code (csharp):
    1.  
    2. magicList[0] = new Magic(70, true);
    3.  
    *OTHERS*

    Well I kinda like they way how [SyncVar] works. You change it on server and it gets synced to clients, it's safe. Why would you want to make it change when client change it? What's the point? How can you make it hack proof?
     
    Zullar likes this.
  3. Zullar

    Zullar

    Joined:
    May 21, 2013
    Posts:
    595
    I'll agree with you for online MMO's and FPS and such then being hackproof is important. However, for other games that are simple and non-competitive co-ops it's fine (IMO) for the game not to be hack proof. i.e. who is going to cheat at Mario Brothers... and if they do... so what? It's more important (IMO) that the game is functional. Not a big deal, just a nice-to-have.
     
    Wabunga and CarterG81 like this.
  4. Ashkan_gc

    Ashkan_gc

    Joined:
    Aug 12, 2009
    Posts:
    888
    Nice list. Please do consider submitting bugs for those which are not submitted because these threads will be lost. Specially the commands delay is concerning for me and it should not happen. did u look at uNet's source code to see why that happens?
     
  5. wobes

    wobes

    Joined:
    Mar 9, 2013
    Posts:
    628
    What about easly change [Command] on client , by disasemble Assembly-Csharp.dll trough NET. Reflector you can easly modify Commands in it. For example, CmdCheckCost(cost); just replace in code like, CmdCheckCost(0). And Server will accept it like cost = 0, not cost = value of real cost item.
     
  6. Zullar

    Zullar

    Joined:
    May 21, 2013
    Posts:
    595
    Updated and added Issue 8 and 9
     
  7. PhilSA

    PhilSA

    Joined:
    Jul 11, 2013
    Posts:
    1,035
    Awesome list. Very helpful

    Can anyone confirm/deny this bug ?

    Might be related to Bug #5 too. It pretty much seems like UNET doesn't like inheritance in general
     
  8. Zullar

    Zullar

    Joined:
    May 21, 2013
    Posts:
    595
    Added some info on network bandwidth inefficiencies (i.e. sending a SyncVar bool uses 40 bits instead of 1 bit).
     
  9. emrys90

    emrys90

    Joined:
    Oct 14, 2013
    Posts:
    489
    I hope those bandwidth inefficiencies get fixed.
     
  10. Zullar

    Zullar

    Joined:
    May 21, 2013
    Posts:
    595
    Added bug about ClientRPC's getting dropped and not being received on Clients intermittently.
     
  11. Zullar

    Zullar

    Joined:
    May 21, 2013
    Posts:
    595
    Added OnNetworkDestroy Ambiguity issue.
     
  12. shadiradio

    shadiradio

    Joined:
    Jun 22, 2013
    Posts:
    75
    I spent a very long time tracking down #7, especially since I saw the effects of it repeatedly recently at my booth at PAX West. Since using Unet is supposed to make your offline/online code almost the same, any bugs in Networking affect your offline local multiplayer game as well. This one was a same-frame timing issue with RPC calls not immediately executing on the local client / host. Basically, for every single cmd/rpc request I have, I now have to do this to make sure stuff is executed immediately on the host. As a bonus, this also solves the issue of RPC calls getting called out of order (on the local client).

    Code (CSharp):
    1. [Command]
    2. void CmdDoSomething()
    3. {
    4.    RpcDoSomething();
    5.    DoSomethingImmediately();
    6. }
    7.  
    8. [ClientRpc]
    9. void RpcDoSomething()
    10. {
    11.     // otherwise executed twice on the local client
    12.     if (!isHost)
    13.     {
    14.         DoSomethingImmediately();
    15.     }
    16. }
    17.  
    18. void DoSomethingImmediately()
    19. {
    20.     // do the stuff
    21. }
     
    Zullar likes this.
  13. Zullar

    Zullar

    Joined:
    May 21, 2013
    Posts:
    595
    That's a nice pattern, thanks.

    I plan on doing something similar but using messages (instead of Command RPC). The host will read message instantly, and then send to clients. Sort of like this.
    1: Make new network message on host
    2: Assign message data on host
    3: Apply message on host (it doesn't need to serialize/deserialize... it just applies the data)
    4: Serialize & send message to remote clients (not the client host)
    5: Receive & deserialize message on remote clients
    6: Apply message on remote client

    In my case ApplyMessage is in instant method.

    The reason I'm using message instead of Command/RPC is because of bug #10 where Commands/RPC's can be dropped and aren't reliable. Messages seem to be very robust though. As well as bug #1.
     
    Last edited: Sep 16, 2016
    shadiradio likes this.
  14. shadiradio

    shadiradio

    Joined:
    Jun 22, 2013
    Posts:
    75
    That's a good technique too. I've definitely also used some direct messages to get around RPC weirdness. There's also [TargetRpc] so you can send to all non-local clients using a loop, but I do miss the RPCMode.Others in the old networking system.
     
    Zullar likes this.
  15. Zullar

    Zullar

    Joined:
    May 21, 2013
    Posts:
    595
    Added SyncList callback bug.
     
  16. Zullar

    Zullar

    Joined:
    May 21, 2013
    Posts:
    595
    After looking into some of these bugs it seems many bugs are related to NetworkIdentiy.observers being removed momentarily during scene transition for persistent DontDestroyOnLoad networked objects. This causes.
    -RPC's to fail
    -SyncList callbacks to fail
    -SyncVar hooks to fail
    -The object to be "spawned" multiple times forcing you to ignore OnDeserialize information the 2nd+ time if doing custom serialization. Also consumes uneeded network bandwidth.
    -Client-Owned SyncVars to be overridden (where client uses Command to set SyncVar value, server sets SyncVar value, then client owner ignores value set callback). The client-owner's value can be overridden by server with OnSerialize initialState == true because the callback is never called.
     
  17. Zullar

    Zullar

    Joined:
    May 21, 2013
    Posts:
    595
    Unity says this is working as intended (for bugs #8, #10, #12, #14) and is closing the bug report.

    If anybody has had the same issues as me these please voice your opinions to raise awareness to hopefully get these bugs addressed.

    *Edit* These bugs are being closed/postponed. They hopefully will be addressed as part of a larger update in the future.
     
    Last edited: Oct 17, 2016
  18. Leoo

    Leoo

    Joined:
    May 13, 2013
    Posts:
    96
    Why isnt this STICKY already? hmmm...
     
  19. Zullar

    Zullar

    Joined:
    May 21, 2013
    Posts:
    595
    Updated issue 821633 regarding persistent DontDestroyOnLoad() objects where NetworkIdentiy.observers are dropped momentarily during scene change causing
    -OnSerialize() to be called every scene change
    -RPC's to fail to send during scene change
    -SyncVars/SyncLists to de-sync or hooks to fail

    Unity QA responded. Looks like it's on a future 2do list now.


    "Hey,

    Developers have resolved this case as postponed. This bug is unfixable without a major re-write of the internals of how Ready/NotReady/DirtyBits are handled. Your case was added to the "futureproofing' list and we will make sure that issue gets fixed in the future.

    Regards,
    Julius
    QA Team"
     
  20. Zullar

    Zullar

    Joined:
    May 21, 2013
    Posts:
    595
    Added bug where networked GameObjects sometimes are disabled (not destroyed) when the UNET connection ends. I've seen this happen 2 ways, and both on Host and Clients.
     
  21. Zullar

    Zullar

    Joined:
    May 21, 2013
    Posts:
    595
    Added 898387 where Animtor.SetFloat(...) fails to set the animator parameter float. It seems to only occur if I have a NetworkIdentity attached and (speculating) might be due to how UNET objects are disabled initially until "spawned".
     
    wobes likes this.
  22. Zullar

    Zullar

    Joined:
    May 21, 2013
    Posts:
    595
    Regarding bug #16 where Animator.setFloat fails. Also animator.isInitialized = false and animator.parameters.Length = 0 and animator.layerCount = 0. It's intermittent. I have 5prefabs in my scene and it only occurs on 1 of them, and only in the build (not in the editor).

    For some reason UNET is preventing the animator from initializing properly. If you remove NetworkIdentity the issue goes away.

    Animator.Rebind also does not fix the issue. animator.isInitialized = false after calling animator.Rebind.

    It's occurring in 5.6.1f1 but looks like it may be fixed with 2017.1
    See bugs 901268 and 899553
     
    Last edited: Jun 16, 2017
    wobes likes this.
  23. Zullar

    Zullar

    Joined:
    May 21, 2013
    Posts:
    595
    Added #17. UNET bugs out GetComponentInParent<T>() and it returns null. Very strange.
     
    TwoTen likes this.