public class RPC { readonly IEnumerable _targets; // null for "everyone" IEnumerable _except = null; RPC(IEnumerable targets) => _targets = targets; public static RPC ToAll() => new(null); public static RPC To(IEnumerable peerIds) => new(peerIds); public static RPC To(params int[] peerIds) => To((IEnumerable)peerIds); public static RPC To(int peerId) => To([ peerId ]); public static RPC To(IEnumerable players) => To(players.Select(p => p.PeerId)); public static RPC To(params Player[] players) => To((IEnumerable)players); public static RPC To(Player player) => To(player.PeerId); public RPC Except(IEnumerable peerIds) { _except = peerIds; return this; } public RPC Except(params int[] peerIds) => Except((IEnumerable)peerIds); public RPC Except(int peerId) => Except([ peerId ]); public RPC Except(IEnumerable players) => Except(players.Select(p => p.PeerId)); public RPC Except(params Player[] players) => Except((IEnumerable)players); public RPC Except(Player player) => Except(player.PeerId); public void Send(Action action) => SendInternal(GetNode(action), action.Method.Name, []); public void Send<[MustBeVariant] T>(Action action, T arg) => SendInternal(GetNode(action), action.Method.Name, Variant.From(arg)); public void Send<[MustBeVariant] T0, [MustBeVariant] T1>(Action action, T0 arg0, T1 arg1) => SendInternal(GetNode(action), action.Method.Name, Variant.From(arg0), Variant.From(arg1)); public void Send<[MustBeVariant] T0, [MustBeVariant] T1, [MustBeVariant] T2>(Action action, T0 arg0, T1 arg1, T2 arg2) => SendInternal(GetNode(action), action.Method.Name, Variant.From(arg0), Variant.From(arg1), Variant.From(arg2)); public void Send<[MustBeVariant] T0, [MustBeVariant] T1, [MustBeVariant] T2, [MustBeVariant] T3>(Action action, T0 arg0, T1 arg1, T2 arg2, T3 arg3) => SendInternal(GetNode(action), action.Method.Name, Variant.From(arg0), Variant.From(arg1), Variant.From(arg2), Variant.From(arg3)); /// Returns the target of the instance method as a . static Node GetNode(Delegate action) => (action.Target as Node) ?? throw new ArgumentException( $"Target ({action.Target?.GetType().ToString() ?? "null"}) must be a Node", nameof(action)); void SendInternal(Node node, StringName method, params Variant[] args) { if ((_targets == null) && (_except == null)) node.Rpc(method, args); else { var targets = _targets ?? node.Multiplayer.GetPeers(); if (_except != null) targets = targets.Except(_except); foreach (var target in targets) node.RpcId(target, method, args); } } }