private static void SubscribeTokens <TAttr>(IComponentRpcProvider provider, byte compId, IEnumerable <KeyValuePair <byte?, TAttr> > tokens, Func <NetMessage, object> fncDel)
     where TAttr : Attribute, IRpcAttribute
 {
     foreach (var token in tokens)
     {
         if (token.Value == null)
         {
             continue;
         }
         provider.SubscribeToFunc(token.Key.HasValue ? token.Key.Value : compId, token.Value.RpcId, fncDel);
     }
 }
        /// <summary>
        /// Subscribe TAttr marked methods on obj to the provider
        /// </summary>
        /// <typeparam name="TInfo"></typeparam>
        /// <typeparam name="TAttr"></typeparam>
        /// <param name="provider"></param>
        /// <param name="obj"></param>
        /// <param name="serializer"></param>
        /// <param name="logger"></param>
        public static void SubscribeComponent <TAttr>(IComponentRpcProvider provider, object obj,
                                                      SerializationManager serializer, ILogger logger) where TAttr : Attribute, IRpcAttribute
        {
            if (obj == null)
            {
                return;
            }
            if (provider == obj)
            {
                return;
            }

            var objType = obj.GetType();

            //logger.Info("Subscribing " + obj);
            byte compId;

            if (!objType.GetNetId(out compId))
            {
                throw new Exception("Cannot subscribe type " + objType + " as it lacks the NetComponentAttribute");
            }

            ForEachRpc <TAttr>(objType, (method, parms, parmTypes, tokens) =>
            {
                var msgDel =
                    Delegate.CreateDelegate(typeof(Action <NetMessage>), obj, method, false) as Action <NetMessage>;
                if (msgDel != null)
                {
                    SubscribeTokens(provider, compId, tokens, msgDel);
                    return;
                }
                var fncDel =
                    Delegate.CreateDelegate(typeof(Func <NetMessage, object>), obj, method, false)
                    as Func <NetMessage, object>;
                if (fncDel != null)
                {
                    SubscribeTokens(provider, compId, tokens, fncDel);
                    return;
                }

                if (method.ReturnType == typeof(void))
                {
                    //the function isn't a deserializer function, so attempt to make our own from INetSerializable/default serializers
                    if (!CheckParameterSerialization <BadInfoType>(serializer, method, parms, logger))
                    {
                        return;
                    }

                    DynamicMethodDelegate pre;
                    RpcCallers.TryGetValue(method.MethodHandle, out pre);
                    //prevent the open delegate from needing a reference to this networkview?
                    var deser = new RpcDeserializer <BadInfoType>(method, obj, serializer, parmTypes, @delegate: pre);
                    msgDel    = deser.Message;
                    SubscribeTokens(provider, compId, tokens, msgDel);
                }
                else
                {
                    //method returns something, so it's a func processor
                    if (!CheckParameterSerialization <BadInfoType>(serializer, method, parms, logger))
                    {
                        return;
                    }
                    if (!serializer.CanSerialize(method.ReturnType))
                    {
                        logger.Error($"Tried to subscribe method {method} for rpc functions, but return type {method.ReturnType} cannot be serialized");
                        return;
                    }

                    DynamicMethodDelegate pre;
                    RpcCallers.TryGetValue(method.MethodHandle, out pre);

                    var deser = new RpcDeserializer <object>(method, obj, serializer, parmTypes, @delegate: pre);
                    fncDel    = deser.ReturnMessage;
                    SubscribeTokens(provider, compId, tokens, fncDel);
                }
            });
        }