2017-01-20 2 views
1

Хорошо, до сих пор, у меня есть способ разоблачить некоторые методы, использующие это:C# RPC разоблачать методы API

AddCommand ("UpdateStar", ((args) => { 
    // do something 
})); 

Он добавляет команду в SortedDictionary<string, SimpleDelegate>. Вот мое SimpleDelegate определения:

public delegate void SimpleDelegate(JSONNode args); 

Это довольно прямо вперед, с Javascript Посылает список аргументов и в C# я получаю JSONNode который является JSONArray. Это работает, но это очень раздражает, чтобы сделать такие вещи, как:

string name = args[0].Value; 
int x = args[1].AsInt; 
... 

В конце концов, что я хотел бы сделать это вместо того, чтобы выставить фактические методы в C# вместо разоблачающие лямбды.

Другими словами, я хотел бы сделать что-то вроде этого:

[expose-to-rpc] 
public void AddSystem(string name, int x, int y) { 

} 

Это может найти имя метода, число аргументов и тип аргументов с помощью отражения. Я почти уверен, что что-то подобное возможно, но я потерялся здесь. Не знаете, как начать.

+1

Возможный дубликат [Как использовать отражение для вызова всех методов, которые имеют определенный пользовательский атрибут?] (Http://stackoverflow.com/questions/2831809/how-would-i-use-reflection-to- call-all-the-methods-that-has-an-custom-att-att) –

+0

@ KeithNicholas Я решил свой собственный ответ, но это немного сложнее, чем получить методы. Мы должны проанализировать параметры и тип возвращаемого значения, а затем вызывать фактический метод с преобразованными параметрами. –

+0

Да, это довольно прямолинейно, вам нужно что-то для начала в соответствии с вашим вопросом, все это уже было задано в SO, неоднократно :) –

ответ

0

А я получил его. Это было легче, чем я думал ...

Во-первых, требуется этот класс:

[AttributeUsage(AttributeTargets.Method)] 
public class ExposeAttribute: Attribute { 
} 

Затем нам нужно добавить этот другой класс:

public static class RPCApi 
{ 

    public static object nodeToType(JSONNode node, Type type) { 
     if (typeof(int) == type) { 
      return node.AsInt; 
     } 
     if (typeof(long) == type) { 
      return node.AsLong; 
     } 
     if (typeof(bool) == type) { 
      return node.AsBool; 
     } 
     if (typeof(string) == type) { 
      return node.Value; 
     } 
     if (typeof(float) == type) { 
      return node.AsFloat; 
     } 
     if (typeof(double) == type) { 
      return node.AsDouble; 
     } 
     if (typeof(JSONArray) == type) { 
      return node.AsArray; 
     } 
     if (typeof(JSONClass) == type) { 
      return node.AsObject; 
     } 

     return null; 
    } 

    public static void Resolve(MonoBehaviour behaviour) { 
     NetworkManager manager = behaviour.GetComponent<NetworkManager>(); 
     Type t = behaviour.GetType(); 
     MethodInfo[] methods = t.GetMethods(); 

     for (int i = 0; i < methods.Length; i++) { 
      MethodInfo meth = methods [i]; 
      ExposeAttribute[] atts = (ExposeAttribute[])meth.GetCustomAttributes (typeof(ExposeAttribute), true); 

      if (atts.Length == 0) { 
       continue; 
      } 

      ParameterInfo[] paramss = meth.GetParameters(); 
      manager.AddCommand (meth.Name, ((args) => { 
       object[] argss = new object[paramss.Length]; 
       for(int l=0; l<argss.Length; l++) { 
        argss[l] = nodeToType(
         args[l], 
         paramss[l].ParameterType 
        ); 
       } 
       meth.Invoke(behaviour, argss); 
      })); 
     } 
    } 
} 

Во-первых, мы получаем все методы объект передан в Resolve. Проверьте любой метод с атрибутом Expose.

Если он есть, найдите тип параметров и создайте новую команду, как я делал раньше ... Мысль перед вызовом фактического метода преобразует аргументы в тип, который ожидает метод. Поскольку мы получаем JSON, мы не можем получать сложные типы, поэтому мы можем легко конвертировать большинство параметров ... Это может быть лучшим способом.

Наконец, как использовать его:

public class NetworkManager : MonoBehaviour { 

    public void Start() { 
     RPCApi.Resolve (this); 
    } 

    ... 

    [Expose] 
    public void addStar(string system) { 
     Planet fun = JsonUtility.FromJson<Planet> (system); 
     GameObject prefabs = GameObject.Find ("PrefabContainer"); 
     PrefabContainer obj = prefabs.GetComponent<PrefabContainer>(); 
     GameObject newobj = Instantiate (obj.star, new Vector3 (fun.x, fun.y, 0), Quaternion.Euler (0, 0, 0)); 
     newobj.name = fun.id; 
     newobj.GetComponent<PlanetBehaviour>().planetConfig = fun; 
    } 

    [Expose] 
    public void UpdateStar (string uuid, float x, float y) { 
     GameObject system = GameObject.Find (uuid); 
     MoveToBehaviour move = system.GetComponent<MoveToBehaviour>(); 
     move.MoveTo(new Vector3(x, y, 0)); 
    } 
} 

Добавление возвращаемый тип не должен быть намного сложнее, либо.

Смежные вопросы