My Entity class doesn’t have anything too long in it. I see this bug about once a day, it occurs again sometimes after changing some code, then it disappears after changing code, then it appears again after changing other code.
I encountered it last October already, but then at some point the bug didn’t happen anymore, but it’s back now.
Since this bug pops up on the UNET forum every now and then, it would be awesome if someone can take a look at it and improve the error message to at least tell us where it happens, or fix the bug.
I suggest wrapping the automated serialization part in a try/catch block and then throwing a exception with the exact name of the variable that failed to deserialize. Perhaps even use one try/catch block for each variable if you have to. But currently the error message is useless and leave us like ‘well, let’s refactor the code a bit more until it works again and then randomly’.
I can send my project files to anyone from the Unity team, but can’t upload them publicly.
Update: I am able to track it down to one GameObject that causes it. I have several ‘entities’ in the Scene, for example Monsters, Players, Npcs etc. and one of them causes the error, even though it has no custom strings that are synchronized, only what is in the base Entity class - which works fine for all the other entities.
Here is the line from my Script that is mentioned in the error message above:
var pos = reader.ReadVector3();
So since it once happens in my custom serialization and once in UNET’s automated serialization, the error is very likely somewhere in the SpawnPayload function…
Edit: it also crashes the Unity Editor and build occasionally! Edit2: using the ‘All Cost Delivery’ channel fixes the ReadByte out of range bug. The first bug still persists.
Update: I removed the only SyncVar string from my Entity class. Now the first error doesn’t happen anymore because ReadString isn’t called anymore. It was replaced by the second error again though:
Okay so after 8 months I finally found out why it happens and reported a demo as bug #786248.
Errors in OnSerialize/OnDeserialize are not shown in the console because they happen in UNET somewhere. As result, UNET’s packet gets messed up and sent to the client (or skipped?) and the client then tries to parse a messed up (or skipped) packet. Hence random ReadByte out of range / ReadString too long errors.
I hope someone from the UNET team ( @JeremyUnity ?) looks at it (or confirms it for now), since this seems to be the worst UNET bug around, affected several people, happens randomly and is almost impossible to understand/work around from the error message.
If anyone is still having this issue, I think I found the cause of the error.
It’s probably because you are calling ReadMessage a second time. this is why the position is already at the range of the byte size in the error. You can overwrite the deserializer and put reader.SeekZero() at the start of your deserializer to make sure it always starts at zero. Hope this helps someout out because it took me 2 days to find out what was causing this.
TLDR: Make sure you’re running the same build on all clients/hosts. You may have changed what data is getting passed around!
I ran into this exact style of message because I was connecting two mismatched versions of my app.
I’d added a field to a struct that was being synchronized, but only updated one of my two test devices with a build containing the latest code changes to the struct. So, of course it can’t deserialize into a different data structure… oops!
I don’t know if those are related, but I’m getting similar error with Unity 2017.1b10 at 100% rate. I’m using double project setup, but I’ve triple checked - files are identical in both of them.
Does anyone knows why it could be happening with this struct? Initialize is called in OnServerStart();
using UnityEngine.Networking;
public class PlayerDataSyncList : SyncListStruct<PlayerData> {
public void Initialize() {
PlayerData nullPlayer = new PlayerData(NetworkInstanceId.Invalid);
Add(nullPlayer);
}
/// <summary>
/// Removes player with playerId from list
/// </summary>
public void RemoveById(NetworkInstanceId playerId) {
for (int i = 0; i < Count; i++) {
if (this[i].Id == playerId) {
RemoveAt(i);
}
}
}
}
[System.Serializable]
public struct PlayerData {
public NetworkInstanceId Id;
public string Username;
public string VisibleUsername;
public PlayerTeam PlayerTeam;
public int PeerId;
public PlayerData(NetworkInstanceId id,
int peerId = -1,
string username = null,
string visibleUsername = null,
PlayerTeam playerTeam = PlayerTeam.Undefined) {
Id = id;
Username = username;
VisibleUsername = visibleUsername;
PeerId = peerId;
PlayerTeam = playerTeam;
}
}
public static class PlayerDataExt {
public const string NonamePrefix = "Noname player";
}
[System.Serializable]
public enum PlayerTeam {
FFA,
TVT1,
TVT2,
Undefined
}
I don’t think it should be beyond that range in the first case, since I’m not sending too much data - strings are less than 10 chars long.
Edit: This only fails when there’s more than one PlayerData exists in the list. It works fine when there’s only one player in the list.