Unity doesn't seem to get updates to mirror-inherited code

Hello everyone,

I have a hard to describe problem but I will try.
I am using Unity 2020.3.17f1 and the Mirror Networking asset for multiplayer.
Everytime, after I have changed a minor thing in my custom NetworkRoomPlayer-class and build it to test as both host (in a virtual machine with a second Steam account) and client, I get System.IO.EndOfStreamExceptions when I’m in the room scene.

I can solve this problem by closing Unity and delete the Library/Artifacts-folder. The reopening my project in Unity (which takes a long time!) and rebuilding. Then everything is fine. No more exceptions.

Does this sound familiar to somebody? It can’t be the solution to do this procedure for every change I do…

Either Unity has a problem with not getting changes in files or the Mirror weaver does…

Greetings
Lone

Post the full stack trace please.
We can’t see your screen from here :slight_smile:

This is the warning that is thrown:

OnDeserialize was expected to read 45 instead of 32 bytes for object:NewRoomPlayer(Clone) component=Assets.GAME.ClassicMultiplayer.Scripts.LobbyAndRoom.NewTryNetworkRoomPlayerExt sceneId=0. Make sure that OnSerialize and OnDeserialize write/read the same amount of data in all cases.
UnityEngine.Debug:LogWarning (object)
Mirror.NetworkIdentity:OnDeserializeSafely (Mirror.NetworkBehaviour,Mirror.NetworkReader,bool) (at Assets/Mirror/Runtime/NetworkIdentity.cs:992)
Mirror.NetworkIdentity:OnDeserializeAllSafely (Mirror.NetworkReader,bool) (at Assets/Mirror/Runtime/NetworkIdentity.cs:1019)
Mirror.NetworkClient:OnEntityStateMessage (Mirror.EntityStateMessage) (at Assets/Mirror/Runtime/NetworkClient.cs:1251)
Mirror.NetworkClient/<>c__DisplayClass46_01<Mirror.EntityStateMessage>:<RegisterHandler>g__HandlerWrapped|0 (Mirror.NetworkConnection,Mirror.EntityStateMessage) (at Assets/Mirror/Runtime/NetworkClient.cs:452) Mirror.MessagePacking/<>c__DisplayClass6_02<Mirror.EntityStateMessage, Mirror.NetworkConnection>:b__0 (Mirror.NetworkConnection,Mirror.NetworkReader,int) (at Assets/Mirror/Runtime/MessagePacking.cs:118)
Mirror.NetworkClient:UnpackAndInvoke (Mirror.NetworkReader,int) (at Assets/Mirror/Runtime/NetworkClient.cs:274)
Mirror.NetworkClient:OnTransportData (System.ArraySegment`1,int) (at Assets/Mirror/Runtime/NetworkClient.cs:342)
Mirror.FizzySteam.NextClient/<>c__DisplayClass25_0:b__2 (byte[ ],int) (at Assets/FizzySteamworks-Heathen/NextClient.cs:41)
Mirror.FizzySteam.NextClient:ReceiveData () (at Assets/FizzySteamworks-Heathen/NextClient.cs:193)
Mirror.FizzySteam.FizzySteamworks:ClientEarlyUpdate () (at Assets/FizzySteamworks-Heathen/FizzySteamworks.cs:38)
Mirror.NetworkClient:NetworkEarlyUpdate () (at Assets/Mirror/Runtime/NetworkClient.cs:1343)
Mirror.NetworkLoop:NetworkEarlyUpdate () (at Assets/Mirror/Runtime/NetworkLoop.cs:186)

The error looks similar with the difference that there are also three options in the stacktrace why this would happen.
In the meantime I found out, that Unity’s AutoRefresh-option is causing that changes in the code are getting noticed but not updated in the build, so client in unity editor and host as standalone build differ. This is one of the mentioned options.

I’ve already spoken to Mr. Gadget in Mirror-Discord about this phaenomenon. I can’t repdroduce it within the Mirror examples.

I documented it here and also a workaround I am using until this somehow works again like it should by default.

Notice the error message. This only happens if OnSerialize & OnDeserialize don’t write/read the same amount of data. So check those.

I have already checked them, they are uncustomized. The Problem occurs only if I use a Build without explicitely deleted the Library/Artifacts-folder or uncheck AutoRefresh in Unity and click “Reimport” on my Scripts-folder before building.

The changes in the scripts are compiled but not updated before. The only working (around) way to not manually do this every time before build is currently using the two scripts that are invoked on pre- and postbuilding events I wrote you can find in that other post of mine here: Auto refresh isn't working properly anymore

I know this post is quite old and I’m sorry in advance to resurrect it.

But we had the exact same issue and after weeks of scratching heads we finally found the way to go.

Problem origin:
The issue is due to inheritance of a Mirror class while using one or more SyncVars.
In our case we needed to inherit from NetworkRoomPlayer and pass data as SyncVars in that class.

For an unknown reason, Mirror is unable to Serialize/Deserialize correctly the syncvars in the child class which inherits from NetworkRoomPlayer.

Solution:
The best workaround we found is to move the SyncVars to another NetworkBehaviour Component attached to the same GameObject as the NetworkRoomPlayer.
Then, after a GetComponent on Start, we can easily access data or via hooks on public UnityEvents of the other component holding the data.

1 Like

@Sphax84 Thank god I am not alone with this. \o/
@mischa2k Does this make sense to you?

@LoneSurvivor82 Are you using a class which inherits from something else than NetworkBehaviour while using syncvars?
Have you tried using a class which inherits directly from NetworkBehaviour instead?

If you found a bug, please post it on our issue tracker on github with steps to reproduce.
We want to get them all to 0 eventually :slight_smile:

1 Like

Sorry, I overlooked that you wrote to me.

My class directly inherits from NetworkRoomPlayer and has just these three SyncVars in it:

[SyncVar(hook = nameof(ColorIndexChanged))]
public int colorIndex;

[SyncVar]
public string playerName;

[SyncVar]
public CSteamID steamID; // this one is new, all the times before I only had used the int and the string in this class.

Not tried yet but I will and then give you an information about how it’s then.[/user]

1 Like

I don’t think you can put a Syncvar on a CSteamID or you would need to add a CustomReadWrite extension methods for Weaver. You could also serialize it into a string.

1 Like

As it seems, steamID doesn’t need to be a syncvar. It’s only used for the host to kick players but not needed to be available on the clients. I removed the attribute so it’s only a string and an int to synchronize.

And I moved both SyncVars to a new component on the gameobject which has the NetworkRoomPlayerExt, like you suggested. On a few tests with adding/renaming/removing test-syncvars this now seem to work like it should. \o/

I commented out the workaround-code I described here: Auto refresh isn't working properly anymore

1 Like