custom class object sent over RPC

The whole answer can be found below.

Please note: The Photon forum is closed permanently. After many dedicated years of service we have made the decision to retire our forum and switch to read-only: we've saved the best to last! And we offer you support through these channels:

Try Our
Documentation

Please check if you can find an answer in our extensive documentation on PUN.

Join Us
on Discord

Meet and talk to our staff and the entire Photon-Community via Discord.

Read More on
Stack Overflow

Find more information on Stack Overflow (for Circle members only).

Write Us
an E-Mail

Feel free to send your question directly to our developers.

custom class object sent over RPC

gnoblin
2011-10-09 18:11:22

Hello!

What are the possible approaches to sending an object of my custom class over RPC instead of sending lots of byte/short/string parameters?

Sending 13 parameters in RPC looks a bit sad :o.

[System.Serializable]
public class PlayerInfo
{
    public string name = "LittlePig";
    public int hp;
    public int health_original = 100;

    public float armor = 0;
    public bool dead = false;
    public int frags = 0;
    public int deaths = 0;

    public int actorID = -1;
    public int view_id = -1;
    public int level = -1;
    public int skill_level = -1;
    public TeamName team_name;

    public bool is_observer = false;
}

thanks, Slav

Comments

dreamora
2011-10-09 18:20:13

whats the problem with just sending it?

Beside naturally the fact that half the info needs to be sent once per map and others need to be constantly updated and thus would be handled through distinct rpcs (report death, report kill, ...)

gnoblin
2011-10-10 16:22:35

Oh, I didn't try to send it because I thought it is impossible. Thanks!

Tobias
2011-10-10 16:29:17

Photon doesn't support automatic serialization of your own classes but you can implement your own delegates to de/serialize your classes (to and from byte-array) and then register them. After that, you can use classes as parameters of RPCs or in event hashtables just like "int" is directly used. Photon Unity Networking uses this approach in CustomTypes.cs, so there is a blueprint for you.

dreamora is right though: Complex classes might contain parts that are sent once per game and values that are sent more often. It makes a lot of sense to separate those to save bandwidth and effort.

gnoblin
2011-10-10 17:08:17

Tobias, thanks for the pointer.

Dumb attempt of sending a custom type over rpc results in

SystemException: cannot serialize()

:)

Boris
2011-10-11 17:19:15

@gnoblin wrote:

What are the possible approaches to sending an object of my custom class over RPC instead of sending lots of byte/short/string parameters?

  1. Convert all class properties to a byte[] send just a single byte[] parameter
  2. Register a de/serializer for your custom type - server: Protocol.TryRegisterCustomType, client: PhotonPeer.RegisterType

For the byte[] conversion itself you can

  1. Use the .NET BinaryFormatter (not the most efficient in terms of size)
  2. Convert all properties manually to bytes (BitConverter, ASCII.GetBytes etc) and back
  3. Use the Photon serialization methods - server: Protocol.GpBinary's Serialize and TryParse methods, client: Protocol.Serialize and Deserialize.

tutibueno
2011-10-13 04:41:58

@Boris wrote:

@gnoblin wrote:

What are the possible approaches to sending an object of my custom class over RPC instead of sending lots of byte/short/string parameters?

  1. Convert all class properties to a byte[] send just a single byte[] parameter
  2. Register a de/serializer for your custom type - server: Protocol.TryRegisterCustomType, client: PhotonPeer.RegisterType

For the byte[] conversion itself you can

  1. Use the .NET BinaryFormatter (not the most efficient in terms of size)
  2. Convert all properties manually to bytes (BitConverter, ASCII.GetBytes etc) and back
  3. Use the Photon serialization methods - server: Protocol.GpBinary's Serialize and TryParse methods, client: Protocol.Serialize and Deserialize.

Is there any tutorial or example showing up how to do that? That would be extremely helpful! Thanks.

Tobias
2011-10-13 16:18:33

Photon Unity Networking uses custom type registration in CustomTypes.cs, so there is a blueprint for you.

escjosh
2012-02-06 20:36:39

A question about that second parameter: are those type codes only used for custom types, or do I need to share space with internal photon types? Is it safe to just pick something at random, and assume that if it works once it'll work forever?

More detail for future reference:

The only place I could find CustomTypes.cs was in Photon-Unity3D_v3-0-1-0_SDK.zip\demo-loadbalancing-unity\Assets\DemoCode\

CustomTypes.cs doesn't exist in any other project in the Photon-Unity3D distribution, nor in any of the server code.

It uses the following to register types:

    public static void Register()
    {
        PhotonPeer.RegisterType(typeof(Vector2), (byte)'W', SerializeVector2, DeserializeVector2);
        PhotonPeer.RegisterType(typeof(Vector3), (byte)'V', SerializeVector3, DeserializeVector3);
        PhotonPeer.RegisterType(typeof(Transform), (byte)'T', SerializeTransform, DeserializeTransform);
        PhotonPeer.RegisterType(typeof(Quaternion), (byte)'Q', SerializeQuaternion, DeserializeQuaternion);
    }

And then goes on to define those Serialize and Deserialize functions. It uses MemoryStream and BitConverter to serialize.

PhotonPeer.RegisterType is a helper function in ExitGames.Client.Photon.PhotonPeer in PhotonUnity3D.dll ( I didn't check the other client libraries):

// ExitGames.Client.Photon.PhotonPeer
public static bool RegisterType(Type customType, byte code, SerializeMethod serializeMethod, DeserializeMethod constructor)
{
	return Protocol.TryRegisterType(customType, code, serializeMethod, constructor);
}

You need to call Photon.SocketServer.Protocol.TryRegisterCustomType on the server side if you want to serialize custom types for server to server communication. Note that if you try to call this inside a *Peer subclass's method, you'll have to fully qualify the name since Protocol is a property on PeerBase and it's of type Photon.SocketServer.IRpcProtocol. The two classes collaborate but aren't related by inheritance. I haven't tried to actually do any of this yet.

The relationship between Protocol and IRpcProtocol isn't totally clear to me, but I don't think that's going to get in my way.

I'd hoped to use this for an enum, but I don't really want to serialize a byte into a byte[1] so I guess I'll just cast it.

Tobias
2012-02-07 10:11:37

We use one separate byte for the custom-type-code which you register. It is separated and won't collide with Photon codes.

Using a custom type for an enum sadly would add a lot of overhead, compared to the single byte that makes up the enum (in this case). For a custom type, we have to pass 4 additional bytes: 1 "this is a custom type" 1 "the custom type is" 2 "length of this custom type"

  • your serialized custom data.

If you use this enum in context of some more complex data types, you could include it in that type's serialization and cast it back to enum accordingly.

mindlube
2012-02-07 10:56:20

Protobuf-net is pretty nice if you want serialize stuff to byte[] http://code.google.com/p/protobuf-net/ There is a trick to getting it to work on iOS though (need to pre-compile your serializer classes to make it AOT friendly). But on other platforms it should just work out of the box. And it's very Unity C# friendly.

Nadegem
2012-02-24 09:59:00

@Boris wrote:

  1. Use the Photon serialization methods - server: Protocol.GpBinary's Serialize and TryParse methods, client: Protocol.Serialize and Deserialize.

Hello, Like escjosh, I don't really understand the relationship between Protocol and IRpcProtocol. I can't find a clean way to get the "current" IRpcProtocol. As I'm wishing to use Photon serialization methods, I need to know which Protocol.GpBinary is the one to use. For the moment I get a IRpcProtocol in the "CreatePeer" method of my application and then give it to my class containing my de/serialization methods. Is there a better way to get that information?
I didn't find any server side sample about this and i'm a little confused.

Thanks, Nadège

invulse
2012-02-24 18:24:08

I actually ran into something like this yesterday where I wanted to serialize a class and send it over an RPC without having to make 20 arguments to the RPC. It turns out that Photon's RPC method can accept object[] as a parameter and if this array of untyped objects has types that Photon will serialize such as Vector3, Vector2, int, float, etc... you can just send all the variables of the class as an object[] array, then basically deserialize this array once you recievce it in the RPC.

So for example:

void SendCustomClass ( SomeClass classObj ) {

object[] serializedClass = new object[3];

serializedClass[0] = classObj.var1;
serializedClass[1] = classObj.var2;
serializedClass[2] = classObj.var3;

photonView.RPC("ReceiveCustomClass",playerID, serializedClass);

}

[RPC]
void ReceiveCustomClass ( object[] serializedClass )
{

SomeClass deserializedClass = new SomeClass();
deserializedClass.var1 = (vartype)serializedClass[0];
deserializedClass.var2 =(vartype) serializedClass[1];
deserializedClass.var3 = (vartype)serializedClass[2];

}

In my case I just made a Serialize() and Deserialize() static methods of my class or struct which handle the serialization for me.

Kaiserludi
2012-02-24 18:46:25

Vector3 and Vector2 are not supported by Photon itself, but Photon does support custom types via a special custom type interface. PUN makes use of this interface, to add support for Vector3 and Vector2. You can have a look at the PUN-code, how it does that, to learn, how you can add support for other types, if needed.

BenStahl
2012-02-28 15:00:37

@Nadegem wrote:

Hello, Like escjosh, I don't really understand the relationship between Protocol and IRpcProtocol. I can't find a clean way to get the "current" IRpcProtocol. As I'm wishing to use Photon serialization methods, I need to know which Protocol.GpBinary is the one to use. For the moment I get a IRpcProtocol in the "CreatePeer" method of my application and then give it to my class containing my de/serialization methods. Is there a better way to get that information?
I didn't find any server side sample about this and i'm a little confused.

Thanks, Nadège

There is noe relationship between the Protocol class and the IRpcProtocol interface. The Protocol class just provides some helper methods and properties. The PeerBase class from which Peer implementations are inherited provides the public property Protocol which gives you access the the IRpcProtocol used by the peer.

ina
2017-03-04 18:00:37

it looks like this error also occurs if you enter in the app id for the wrong photon package, such as chat instead of realtime networking. the return code is -1, which makes it harder to debug

Back to top