Is there a way to invoke SendCommand in a type safe manner?
Instead of calling requester.SendCommand<Type>(name, MessageTarget, arguments)
to be able to call the arguments so that they are respective of the target method.
Passing along strings and arbitrary arguments is error prone.
example: the global counter:
public class NumberRequester : MonoBehaviour
{
[Command]
public void GotNumber(int number)
{
Debug.Log($"Got number: {number}");
}
}
public class Counter : MonoBehaviour
{
public int counter;
public void NextNumber(CoherenceSync requester)
{
requester.SendCommand<NumberRequester>(
nameof(NumberRequester.GotNumber),
MessageTarget.AuthorityOnly,
counter
);
}
}
If we change GotNumber’s call signature to
public void ReceivedNumber(int number, int previous)
Then the code above would break; and it would be tricky to find where the wrong / missing variables are until the function is called
(coherence) CoherenceSync: Unable to send command '<name>' to 'Number Requester': command was not found. Check the command's name and parameters, or Bake again
(coherence) CoherenceSync: Unable to send command 'NumberRequester.GotNumber' to 'Number Requester': command NumberRequester.GotNumber(<arguments>) was not found. Check the command's name and parameters, or Bake again
I made a small script that extracts all [Command] attributes into helpers:
requester.For<NumberRequester>().GotNumber(counter);
Which is pretty much 3 extension methods + a struct to associate the method invocations to
public struct NumberRequester_RPCHelper
{
public Coherence.Toolkit.CoherenceSync sync;
public NumberRequester_RPCHelper(Coherence.Toolkit.CoherenceSync sync)
{
this.sync = sync;
}
}
public static CoherenceSyncExtensions
{
// by having T data = default the user can use it as sync.For(variable) or sync.For<VariableType>
public static NumberRequester_RPCHelper For<T>(this Coherence.Toolkit.CoherenceSync sync, T data = default) where T:NumberRequester => new NumberRequester_RPCHelper(sync);
// allow rounting target
public static void GotNumber(this NumberRequester_RPCHelper helper, Coherence.MessageTarget target, System.Int32 number)
{
helper.sync.SendCommand<NumberRequester>("GotNumber", target, number);
}
// without routing target
public static void GotNumber(this NumberRequester_RPCHelper helper, System.Int32 number)
{
// by default the [Command] has defaultRouting = MessageTarget.All . If the default routing is changed - it would be changed here as well
helper.sync.SendCommand<NumberRequester>("GotNumber", MessageTarget.All, number);
}
}
Thoughts?
Would it be possible to integrate something like this in the future versions? Thanks!