Passing Custom Data Types to RPCs - BeardedManStudios/ForgeNetworkingRemastered GitHub Wiki

So, you want to send some custom data (enums or structs), with the RPC, and wondering how?
Well, before we go there, let's see an example of the classic use case, and why it doesn't work:

// This class is literally what you see, with just 1 RPC.
public class TestNetworkObject : TestNetworkObjectBehavior
{
    public enum Day { Monday, Tuesday, Thursday, Wednesday, Friday, Saturday, Sunday };
    
    protected override void NetworkStart()
    {
        base.NetworkStart();
    
        networkObject.SendRpc(RPC_SET_CURRENT_DAY, Receivers.All, Day.Monday);
    }

    public void SetCurrentDay(RpcArgs args)
    {
        Day currentDay = args.GetNext<Day>();
    }
    
}

So, in the above class what we do, is have an enum data-type, and just send it as an argument over the RPC.
However... The Unity Log will just throw an error in the above code!

So, you are wondering "well geez, how do I send custom data with RPC then?"

The answer is....

Serialization

In short, you have to convert the custom data-type into an array of bytes (byte[]) and send this byte[] as a parameter to SendRpc

And when the RPC function fires, the data it gets (in byte[] format), should be converted back to an object (and hence its original custom data-type)

Serialization means, converting an object to a byte array
De-Serialization means, converting a byte-array to its custom object data-type (that it used to have before serialization)

Sounds confusing? Seeing it in-code should help!
We will use 2 functions from a very useful repo
https://github.com/k77torpedo/ForgeAndUnity/blob/master/Examples/NodeManager%20Example/Assets/ForgeAndUnity/Forge/2_Classes/ExtensionMethodsForge.cs
From that link/repo, we will be copy-pasting a part of it, onto a new script, in order to make the serialization and de-serialization process, a piece of cake!

Please note that this tool is merely help to get you started. The binary formatter is not very efficient and you should look into other serializers, which packs the data way more efficient and doesn't take as much CPU usage per serialization

using System.IO;
using System.Runtime.Serialization.Formatters.Binary;
using BeardedManStudios.Forge.Networking.Unity;
using UnityEngine;

    /// <summary>
    /// Extension-methods for Forge Networking Remastered.
    /// </summary>
    public static class ExtensionMethodsForge 
    {
        // Functions

                // Converts an Object, to a byte[]
                public static byte[] ObjectToByteArray (this object obj) 
                {
                    if (obj == null)
                        return null;

                    BinaryFormatter bf = new BinaryFormatter();
                    MemoryStream ms = new MemoryStream();
                    bf.Serialize(ms, obj);

                    return ms.ToArray();
                }

                // Converts a byte[] to an Object<T>
                public static T ByteArrayToObject<T> (this byte[] arrBytes) 
                {
                    MemoryStream ms = new MemoryStream();
                    BinaryFormatter bf = new BinaryFormatter();
                    ms.Write(arrBytes, 0, arrBytes.Length);
                    ms.Seek(0, SeekOrigin.Begin);
                    T obj = (T)bf.Deserialize(ms);

                    return obj;
                }
    }

The above code, has 2 functions we will use.
In simple words, the one serializes data, and the other one de-serializes data.
Seeing they have public static, they can be used as extensions to the base classes, and hence, be used without having any class instance reference.

So, let's back to the original example, using the above 2 functions to succesfully send custom-data types!

// This class is literally what you see, with just 1 RPC.
public class TestNetworkObject : TestNetworkObjectBehavior
{
    public enum Day { Monday, Tuesday, Thursday, Wednesday, Friday, Saturday, Sunday };
    
    protected override void NetworkStart()
    {
        base.NetworkStart();
    
        //Note that we don't pass Day.Monday, but Day.Monday serialized into a byte[]
        networkObject.SendRpc(RPC_SET_CURRENT_DAY, Receivers.All, Day.Monday.ObjectToByteArray());
    }

    public void SetCurrentDay(RpcArgs args)
    {
        // This line below should be in pretty much every
        // RPC that takes custom-data types.
        byte[] receivedBytes = args.GetNext<byte[]>();

        // We convert receivedBytes to the original object of data-type <Day>
        Day currentDay = receivedBytes.ByteArrayToObject<Day>();
    }
    
}

Of course, for this all to work, and be able to send Custom Data-Types (any data-type that isn't default in the NCW), you must have set the NCW RPC parameter/argument data-type, as a byte-array!

Lastly, perhaps, you found this page, wanting to serialize a GameObject and pass it to an RPC.
However, this is very likely an indication of a bad design, and is to be avoided.

GameObject Serialization is a huge and complex topic, and it is heavily suggested, to never serialize&send a GameObject on the network.

⚠️ **GitHub.com Fallback** ⚠️