Serialization\Deserialization problem

I have posted a similar question to this one, but I had to do some changes to the code so I ended up creating a new question. (Serialize an array of custom objects - Unity Answers)

I have a Team class that (now) has an LauncherPlayer array that stores info about the players. Serialization\deserialziation methods for this class I know they are working fine because I already tested them.

The problem is that in my Team class I’am serializing that array, with no problems (I guess, at least I get no errors), but upon deserialization I get an object of type string instead of LauncherPlayer type.

public class Team 
{
    private int teamID;
    private LauncherPlayer[] players;
    private int playersJoined = 0;
}

public static byte[] serializeTeam(object o)
{
	Team team = (Team)o;
	var playerBytes = ExitGames.Client.Photon.Protocol.Serialize(team.players);
	//Lenght = playerBytes.Lenght + (4 * 3) (4 bytes in size, 3 ints)
	byte[] bytes = new byte[playerBytes.Length + 12];
	int index = 0;
	ExitGames.Client.Photon.Protocol.Serialize(team.teamID, bytes, ref index);
	//We need to store the lenght for deserialization
	ExitGames.Client.Photon.Protocol.Serialize(playerBytes.Length, bytes, ref index);
	System.Array.Copy(playerBytes, 0, bytes, index, playerBytes.Length);
	index += playerBytes.Length;
	ExitGames.Client.Photon.Protocol.Serialize(team.playersJoined, bytes, ref index);
	return bytes;
}

public static object deserializeTeam(byte[] bytes)
{
	Team team = new Team();
	int index = 0;
	int playerBytesLength;
	ExitGames.Client.Photon.Protocol.Deserialize(out team.teamID, bytes, ref index);
	ExitGames.Client.Photon.Protocol.Deserialize(out playerBytesLength, bytes, ref index);
	var playerBytes = new byte[playerBytesLength];
	System.Array.Copy(bytes, index, playerBytes, 0, playerBytesLength);
    index += playerBytes.Length;
    Debug.Log(ExitGames.Client.Photon.Protocol.Deserialize(playerBytes).GetType());
    Debug.Log((string)ExitGames.Client.Photon.Protocol.Deserialize(playerBytes)+",");
    //team.players = (LauncherPlayer[]) ExitGames.Client.Photon.Protocol.Deserialize(playerBytes);
	ExitGames.Client.Photon.Protocol.Deserialize(out team.playersJoined, bytes, ref index);
	return team;
}

public class LauncherPlayer {

private string playerName;
    private int teamID = -1;
    private int pos = -1;
    private bool ready = false;
}

public static byte[] serializePlayer(object o)
{
    LauncherPlayer player = (LauncherPlayer)o;
    var nameBytes = ExitGames.Client.Photon.Protocol.Serialize(player.playerName);
    //Lenght playerBytes.Lenght + (4 * 3) (4 bytes in size, 3 ints) + (1 byte from bool)
    byte[] bytes = new byte[nameBytes.Length + 13];
    int index = 0;
    //We need to store the lenght for deserialization
    ExitGames.Client.Photon.Protocol.Serialize(nameBytes.Length, bytes, ref index);
    System.Array.Copy(nameBytes, 0, bytes, index, nameBytes.Length);
    index += nameBytes.Length;
    ExitGames.Client.Photon.Protocol.Serialize(player.teamID, bytes, ref index);
    ExitGames.Client.Photon.Protocol.Serialize(player.pos, bytes, ref index);
    bytes[index] = player.ready ? (byte) 1 : (byte) 0;
    return bytes;
}

public static object deserializePlayer(byte[] bytes)
{
    LauncherPlayer player = new LauncherPlayer();
    int index = 0;
    int nameBytesLenght;
    ExitGames.Client.Photon.Protocol.Deserialize(out nameBytesLenght, bytes, ref index);
    var nameBytes = new byte[nameBytesLenght];
    System.Array.Copy(bytes, index, nameBytes, 0, nameBytesLenght);
    player.playerName = (string)ExitGames.Client.Photon.Protocol.Deserialize(nameBytes);
    index += nameBytes.Length;
    ExitGames.Client.Photon.Protocol.Deserialize(out player.teamID, bytes, ref index);
    ExitGames.Client.Photon.Protocol.Deserialize(out player.pos, bytes, ref index);
    byte b = bytes [index];
    player.ready = b == (byte)1 ? true : false;
    return player;
}

Console output:

System.String
,

The only difference I see, is changed type of players field, so this looks like a source of problem.

Photon knows how to serialize string (and string[]) types, but it doesn’t know how to serialize LauncherPlayer type. You need to register it, and provide serialize/deserialize methods for this type, the same way you did for Team class.

EDIT

I checked the code of Serialize(object) method, and in my opinion it contains error. To serialize it uses a readonly MemoryStream, which is reused for each call. If at some point this stream has for example length of 10, then serializing an object which should result in 3-elements array, will still return 10-element array.

Anyway - I created a method, which can be used instead of Serialize(object), and in my tests it works:

public static byte[] SerializeObject(object obj)
{
	var serializeMethod = typeof(ExitGames.Client.Photon.Protocol).GetMethod("Serialize",
		System.Reflection.BindingFlags.Static | System.Reflection.BindingFlags.NonPublic, null,
		new System.Type[] { typeof(System.IO.MemoryStream), typeof(object), typeof(bool) }, null);
	using (var ms = new System.IO.MemoryStream())
	{
		serializeMethod.Invoke(null, new object[] { ms, obj, true });
		return ms.ToArray();
	}
}

Please note that this uses reflection, so it is not blazing fast, and additionally might stop working in the next version of PUN.

I suggest posting this issue in ExitGame’s forums, and asking for some guidance. Maybe their Serialize method was meant to be used in a different way?

For serializing you can choose c# Binary formatter or else third party plugin from asset store. I would also recommend you to check out our plugin Runtime Serialization for Unity which can serialize custom c# objects as well as Unity objects like GameObjects, Transform, MonoBehaviours etc. For complete list of supported types, please check this 2.