My Compiled List of UNET Bugs/Issues

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.

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://fogbugz.unity3d.com/default.asp?794443_l24atkuvp8v1kcli

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()

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://fogbugz.unity3d.com/default.asp?747334_sfs90f3bcm8nrcok

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://fogbugz.unity3d.com/default.asp?822355_sv7nmvbc0bv08rlh
https://fogbugz.unity3d.com/default.asp?821633_5ps5qsis7vrrevrr

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

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.

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 to Return Null
In the build (not the editor) GetComponentInParent 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!

102: Cannot AddComponent 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.

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).

10 Likes

1. Sorry I kinda don’t understand that bug :stuck_out_tongue:
6. SyncStructs Do Not Automatically Set Dirty Bit When an Internal Field is Changed

You mean:

public struct Magic
{
   public float power;
   public bool realMagic;
}

public class MagicSLS = new SyncStructList<Magic>{}
public MagicSLS magicList = new MagicSLS();

magicList.Add(new Magic(69, true));

magicList[0].power = 70;

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 :slight_smile:

magicList[0] = new Magic(70, true);

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?

1 Like

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.

2 Likes

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?

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.

Updated and added Issue 8 and 9

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

Added some info on network bandwidth inefficiencies (i.e. sending a SyncVar bool uses 40 bits instead of 1 bit).

I hope those bandwidth inefficiencies get fixed.

Added bug about ClientRPC’s getting dropped and not being received on Clients intermittently.

Added OnNetworkDestroy Ambiguity issue.

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).

[Command]
void CmdDoSomething()
{
   RpcDoSomething();
   DoSomethingImmediately();
}

[ClientRpc]
void RpcDoSomething()
{
    // otherwise executed twice on the local client
    if (!isHost)
    {
        DoSomethingImmediately();
    }
}

void DoSomethingImmediately()
{
    // do the stuff
}
1 Like

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.

1 Like

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.

1 Like

Added SyncList callback bug.

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.

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.

Why isnt this STICKY already? hmmm…

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"

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.