Thanks for taking the time to post that. You helped me and I got it working.
In your system
The good: Can handle any number of parameters.
The bad: The method string name and the parameters are not typesafe (i.e. you could accidentally send a float to a method that requires an integer). Errors won’t be thrown until runtime.
I tried as best I could to use strongly typed and couldn’t figure it out completely. But managed to…
The good: The method name and parameters are typesafe.
The bad: is a little redundant during register (it’s not implicit) and you need a delegate for each number of parameters (but you only need to do this once). Methods must be registered manually (but you could make this automatic as you did).
In both cases the internal data is boxed/unboxed to and from object causing a little overhead (not a big deal assuming these methods aren’t called frequently).
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using System;
using System.Reflection;
public class CommandControllerGeneric
{
public delegate void DelegateComand0();
public delegate void DelegateComand1<T>(T tIn);
public delegate void DelegateComand2<T1, T2>(T1 t1In, T2 t2In);
public delegate void DelegateComand3<T1, T2, T3>(T1 t1In, T2 t2In, T3 t3In);
public delegate void DelegateComand4<T1, T2, T3, T4>(T1 t1In, T2 t2In, T3 t3In, T4 t4In);
public delegate void DelegateComand5<T1, T2, T3, T4, T5>(T1 t1In, T2 t2In, T3 t3In, T4 t4In, T5 t5In);
private BiDictionary<byte, Delegate> biDirectionaryCommandIndexToDelegate = new BiDictionary<byte, Delegate>();
private SteamGameObject steamGameObject;
public CommandControllerGeneric(SteamGameObject steamGameObjectIn)
{
steamGameObject = steamGameObjectIn;
}
public void InitializeRegisterCommand(DelegateComand0 delegateComandIn)
{
//Debug.Log("RegisterCommand0: " + delegateComandIn.Method.Name);
biDirectionaryCommandIndexToDelegate.Add((byte)(biDirectionaryCommandIndexToDelegate.Count+1), delegateComandIn);
}
public void InitializeRegisterCommand<T>(DelegateComand1<T> delegateComandIn)
{
//Debug.Log("RegisterCommand1: " + delegateComandIn.Method.Name + " " + typeof(T).Name);
biDirectionaryCommandIndexToDelegate.Add((byte)(biDirectionaryCommandIndexToDelegate.Count + 1), delegateComandIn);
}
public void InitializeRegisterCommand<T1, T2>(DelegateComand2<T1, T2> delegateComandIn)
{
//Debug.Log("RegisterCommand2: " + delegateComandIn.Method.Name + " " + typeof(T1).Name + " " + typeof(T2).Name);
biDirectionaryCommandIndexToDelegate.Add((byte)(biDirectionaryCommandIndexToDelegate.Count + 1), delegateComandIn);
}
public void Invoke(SendTo sendToIn, DelegateComand0 delegateCommandIn)
{
InvokeCommandInternal(sendToIn, delegateCommandIn, new object[] { });
}
public void Invoke<T>(SendTo sendToIn, DelegateComand1<T> delegateCommandIn, T tIn)
{
InvokeCommandInternal(sendToIn, delegateCommandIn, new object[] { tIn });
}
public void Invoke<T1, T2>(SendTo sendToIn, DelegateComand2<T1, T2> delegateCommandIn, T1 t1In, T2 t2In)
{
InvokeCommandInternal(sendToIn, delegateCommandIn, new object[] { t1In, t2In });
}
private void InvokeCommandInternal(SendTo sendToIn, Delegate delegateIn, object[] objectArgArrayIn)
{
try
{
byte commandIndexOut;
if (biDirectionaryCommandIndexToDelegate.TryGetAFromB(delegateIn, out commandIndexOut))
{
BatBitStreamWriter batBitStreamWriter = new BatBitStreamWriter();
for (int i = 0; i < objectArgArrayIn.Length; i++)
{
batBitStreamWriter.WriteCommandObject(objectArgArrayIn[i]);
}
bool[] bitArray = batBitStreamWriter.ToBitArray();
SteamMessageCommand steamMessageCommand = new SteamMessageCommand(steamGameObject, commandIndexOut, bitArray);
SendMessageInternal(steamMessageCommand, sendToIn);
}
else
{
BatDebug.Error(this, "46325hjntbg214y53t634", "Cannot Find Command");
}
}
catch(Exception exceptionIn)
{
BatDebug.Exception(this, "534uhtgr156564i75kjy", exceptionIn);
}
}
public void OnReceiveSteamMessageCommand(SteamMessageCommand steamMessageCommandIn) //Both Server AND Client can receive
{
try
{
Delegate delegateOut;
if (biDirectionaryCommandIndexToDelegate.TryGetBFromA(steamMessageCommandIn.actionIndex, out delegateOut))
{
ParameterInfo[] parameterInfoArray = delegateOut.Method.GetParameters();
object[] objectArray = new object[parameterInfoArray.Length];
BatBitStreamReader batBitStreamReader = new BatBitStreamReader(steamMessageCommandIn.bitArray);
for (int i = 0; i < parameterInfoArray.Length; i++)
{
objectArray[i] = batBitStreamReader.ReadCommandObject(parameterInfoArray[i].ParameterType);
}
delegateOut.DynamicInvoke(objectArray);
}
else
{
BatDebug.Error(this, "35786uijht156536ujikyunrb", "Cannot Find Command");
}
}
catch(Exception exceptionIn)
{
BatDebug.Exception(this, "473hjnbg31t2458u6i7uy551", exceptionIn);
}
}
public enum SendTo { ST0_HeroOwnerToServer, ST1_ServerToOwner, ST2_ServerToAll } //this is the input, and then based on whether you are the Server or Clientit choses a SendFromTo
private void SendMessageInternal(SteamMessageCommand steamMessageCommandIn, SendTo sendToIn)
{
if (sendToIn == SendTo.ST0_HeroOwnerToServer)
{
steamMessageCommandIn.SendToServer();
}
else if (sendToIn == SendTo.ST1_ServerToOwner)
{
steamMessageCommandIn.SendToClientOwner(steamGameObject.cSteamIdObjectOwner);
}
else if (sendToIn == SendTo.ST2_ServerToAll)
{
steamMessageCommandIn.SendFromServerToAllIncludingSelfFullyConnected();
}
else
{
BatDebug.Error(this, "3573753265262", "Invalid Enum");
}
}
}