Custom type Problem with serialization

Options
My problem:
The information that there in the API is very confusing and I can not understand how to create a custom class, in my opinion I am doing well, without any writing error in code, but when I am going to serialize more than 1 data I get an error that apparently I can't solve in any way
My code:

 void Awake()
    {
        PhotonPeer.RegisterType(typeof(WeaponDamageStruct), (byte)'S', WeaponDamageStruct.SerializaME, WeaponDamageStruct.DeserializaME);
    }

 public void ShootIng(WeaponDamageStruct WDS)
    {
        
        photonView.RPC("Damage", RpcTarget.All, WeaponDamageStruct.SerializaME(WDS));
    }
public static byte[]SerializaME(object wds)
    {
        var WDS = (WeaponDamageStruct)wds;
      
        byte[] Info = new byte[]
        {
             byte.Parse(Convert.ToString( WDS.Damage))
            ,byte.Parse(Convert.ToString( WDS.Jugador))
            ,byte.Parse(Convert.ToString( WDS.IdGun))
            ,byte.Parse( Convert.ToString( WDS.LookAt.x))
            ,byte.Parse( Convert.ToString( WDS.LookAt.y))
            ,byte.Parse( Convert.ToString( WDS.LookAt.z))
            ,byte.Parse( Convert.ToString( WDS.HitPoint.x))
            ,byte.Parse( Convert.ToString( WDS.HitPoint.y))
            ,byte.Parse( Convert.ToString( WDS.HitPoint.z))
            ,byte.Parse( Convert.ToString( WDS.Receptor))
            ,byte.Parse( Convert.ToString( WDS.HitSite))
            ,byte.Parse( Convert.ToString( WDS.MatType))
        };
        return Info;
      
    }


My Log:

FormatException: Input string was not in a correct format.
System.Number.StringToNumber (System.String str, System.Globalization.NumberStyles options, System.Number+NumberBuffer& number, System.Globalization.NumberFormatInfo info, System.Boolean parseDecimal) (at <7d97106330684add86d080ecf65bfe69>:0)
System.Number.ParseInt32 (System.String s, System.Globalization.NumberStyles style, System.Globalization.NumberFormatInfo info) (at <7d97106330684add86d080ecf65bfe69>:0)
System.Byte.Parse (System.String s, System.Globalization.NumberStyles style, System.Globalization.NumberFormatInfo info) (at <7d97106330684add86d080ecf65bfe69>:0)
System.Byte.Parse (System.String s) (at <7d97106330684add86d080ecf65bfe69>:0)

Comments

  • Rivax95
    Options
    It really seems that the data I send is too long, to one who does not agree with the error I receive, I have tried to send less information and still giving me the same error, but it does not give it with all the data, only with some.
  • JohnTube
    JohnTube ✭✭✭✭✭
    edited October 2019
    Options
    Hi @Rivax95,

    The code snippet and the stacktrace show that the problem is the serialization method, specifically in the byte.Parse(Convert.ToString( WDS.*)) calls.
    I don't think that it's the proper way to do it, you need to serialize each field or property to bytes differently, I don't think that converting it to a string then parsing that string to a single byte would do that. Most types require more than one byte!
    I think you should follow "Assets\Photon\PhotonUnityNetworking\Code\CustomTypes.cs" examples or find more examples on the internet.
    The idea is to convert the class to a byte array during serialization without losing type value and information then, during deserialization getting the custom object back from the byte array.

    Also, if you register custom types, you can directly send the registred custom type or an array of it w/o the need to explicitly serialize it since Photon learned how to do it on its own in the registration process:

    so instead of:
            photonView.RPC("Damage", RpcTarget.All, WeaponDamageStruct.SerializaME(WDS));
    
    do:
    photonView.RPC("Damage", RpcTarget.All, WDS);
  • Rivax95
    Options
    Could someone give me an example of how to do it? or some link where I can see a clear example?
    That would help me a lot
    Thank you !
  • Rivax95
    Rivax95
    edited December 2019
    Options

    Hi @JohnTube , i have a new problem :S


    When I deserialize the information it sends me a new error, this does not happen in the master client, check my code and there is nothing that tells me where the error can be

    this is log

    Deserialization failed for Event. System.Exception: Read failed. Custom type not found: 98

    at ExitGames.Client.Photon.Protocol18.ReadCustomType (ExitGames.Client.Photon.StreamBuffer stream, System.Byte gpType) [0x0009d] in C:\Dev\photon-sdk-dotnet\PhotonDotnet\Protocol18Read.cs:263

    at ExitGames.Client.Photon.Protocol18.Read (ExitGames.Client.Photon.StreamBuffer stream, System.Byte gpType) [0x0001c] in C:\Dev\photon-sdk-dotnet\PhotonDotnet\Protocol18Read.cs:21

    at ExitGames.Client.Photon.Protocol18.Read (ExitGames.Client.Photon.StreamBuffer stream) [0x00001] in C:\Dev\photon-sdk-dotnet\PhotonDotnet\Protocol18Read.cs:14

    at ExitGames.Client.Photon.Protocol18.ReadHashtable (ExitGames.Client.Photon.StreamBuffer stream) [0x00015] in C:\Dev\photon-sdk-dotnet\PhotonDotnet\Protocol18Read.cs:318

    at ExitGames.Client.Photon.Protocol18.Read (ExitGames.Client.Photon.StreamBuffer stream, System.Byte gpType) [0x00323] in C:\Dev\photon-sdk-dotnet\PhotonDotnet\Protocol18Read.cs:83

    at ExitGames.Client.Photon.Protocol18.ReadParameterTable (ExitGames.Client.Photon.StreamBuffer stream, System.Collections.Generic.Dictionary`2[TKey,TValue] target) [0x00023] in C:\Dev\photon-sdk-dotnet\PhotonDotnet\Protocol18Read.cs:301

    at ExitGames.Client.Photon.Protocol18.DeserializeEventData (ExitGames.Client.Photon.StreamBuffer din, ExitGames.Client.Photon.EventData target) [0x0002b] in C:\Dev\photon-sdk-dotnet\PhotonDotnet\Protocol18Read.cs:279

    at ExitGames.Client.Photon.PeerBase.DeserializeMessageAndCallback (ExitGames.Client.Photon.StreamBuffer stream) [0x0024b] in C:\Dev\photon-sdk-dotnet\PhotonDotnet\PeerBase.cs:642

    I have everything as it teaches in the custom types:

    public static object Deserialize(StreamBuffer inStream, short length)
      {
        WeaponDamageStruct WDS = new WeaponDamageStruct();
        int ID1;
        int ID2;
        lock (memWDS)
        {
          inStream.Read(memWDS, 0, 17 * 4); //falta esto
          int index = 0;
          Protocol.Deserialize(out WDS.Damage, memWDS, ref index);
          Protocol.Deserialize(out WDS.Direction.x, memWDS, ref index);
          Protocol.Deserialize(out WDS.Direction.y, memWDS, ref index);
          Protocol.Deserialize(out WDS.Direction.z, memWDS, ref index);
          Protocol.Deserialize(out WDS.Hit , memWDS, ref index);
          Protocol.Deserialize(out WDS.HitPoint.x, memWDS, ref index);
          Protocol.Deserialize(out WDS.HitPoint.y, memWDS, ref index);
          Protocol.Deserialize(out WDS.HitPoint.z, memWDS, ref index);
          Protocol.Deserialize(out WDS.IdGun, memWDS, ref index);
          Protocol.Deserialize(out WDS.Impact, memWDS, ref index);
      
          Protocol.Deserialize(out WDS.LookAt.x, memWDS, ref index);
          Protocol.Deserialize(out WDS.LookAt.y, memWDS, ref index);
          Protocol.Deserialize(out WDS.LookAt.z, memWDS, ref index);
          
          Protocol.Deserialize(out WDS.MatType, memWDS, ref index);
          Protocol.Deserialize(out WDS.HitSite, memWDS, ref index);
    
          Protocol.Deserialize(out ID1, memWDS, ref index);
          Protocol.Deserialize(out ID2, memWDS, ref index);
    
          if (PhotonNetwork.CurrentRoom != null)
          {
            WDS.Jugador= PhotonNetwork.CurrentRoom.GetPlayer(ID1);
             
          }
          if (WDS.Hit == 1)
          {
            if (PhotonNetwork.CurrentRoom != null)
            {
              WDS.Receptor = PhotonNetwork.CurrentRoom.GetPlayer(ID2);
    
            }
          }
        }
    
        return WDS;
      }
    


  • Rivax95
    Options

    up!

  • sthill
    Options

    I think it is quite simple.

    You have to be sure that WDS submembers are in the same range as a byte.

    A byte is a 8bit data taking value from 0 to 255.

    The only data you will be able to "data->string->byte" is globally an unsigned int between 0 and 255. However, a string can contains a float, negative numbers or numbers>255.

    The string are generally converted into a byte array for each string. To help deserialization, I like to use a header containing all strings length (and other information if needed).

    using System; // For Buffer copy
    using System.Text; // For string to byte array
    
    byte[] header = new byte[NUMBER_OF_PARAMETERS_TO_SERIALIAZE];
    int totalLength = 0;
    
    string damageString = Convert.ToString(WDS.Damage);
    byte[] damageByteArray = Encoding.UTF8.GetBytes(damageString);
    header[0] = damageString.Length;
    totalLength += damageString.Length;
    
    string jugadorString = Convert.ToString(WDS.Jugador);
    byte[] jugadorByteArray = Encoding.UTF8.GetBytes(jugadorString);
    header[1] = jugadorString.Length;
    totalLength += damageString.Length;
    
    // After whole conversion
    byte[] info = new byte[totalLength];
    Buffer.BlockCopy(header, 0, info, 0, header.Length);
    Buffer.BlockCopy(damageByteArray , 0, info, header.Length, damageByteArray.Length);
    Buffer.BlockCopy(jugadorByteArray , 0, info, header.Length + damageByteArray.Length, jugadorByteArray.Length);
    

    This is a "unrolled" code, it can be improved by creating method called multiple times during the process (for conversion and block copy).

  • Rivax95
    Options

    Hi @sthill, Thanks for you response.

    I think you have not understood me well, or I have not explained myself completely xD, The problem is that when I try to deserialize the error I posted in my last comment skips.


    It turns out that when the master client is alone in the room, there is no problem but when there more than one player starts with that fault.

    What I do not understand is, if I am correctly allocating the byte width necessary to transmit the message and I am using the serialization and deserialization protocols as indicated in the custom types documentation, why is the fault? I'm confused.

  • JohnTube
    JohnTube ✭✭✭✭✭
    edited December 2019
    Options

    Hi @Rivax95,


    Maybe you are not registering the type in all clients.

    or you are registering the type too late (after receiving a message with custom type).

    You need to register custom types as early as possible on all clients.

    Also check the return value of the register type method, if it's false then the custom type registration has failed and you need to fix it.

  • Rivax95
    Options
    JohnTube wrote: »
    Also check the return value of the register type method, if it's false then the custom type registration has failed and you need to fix it.
    how i check this value ?

    Thanks for you response !