|
|
|
@ -8,6 +8,35 @@ using TNodeCore.Models; |
|
|
|
|
using UnityEngine; |
|
|
|
|
|
|
|
|
|
namespace TNodeCore.RuntimeCache{ |
|
|
|
|
public class PropAccessor<T1, T2>:IModelPropertyAccessor{ |
|
|
|
|
public readonly Func<T1, T2> Get; |
|
|
|
|
public readonly Action<T1, T2> Set; |
|
|
|
|
public PropAccessor(string propName){ |
|
|
|
|
Type t = typeof(T1); |
|
|
|
|
MethodInfo getter = t.GetMethod("get_" + propName); |
|
|
|
|
MethodInfo setter = t.GetMethod("set_" + propName); |
|
|
|
|
if(getter!=null) |
|
|
|
|
Get = (Func<T1, T2>)Delegate.CreateDelegate(typeof(Func<T1, T2>), null, getter); |
|
|
|
|
if(setter!=null) |
|
|
|
|
Set = (Action<T1, T2>)Delegate.CreateDelegate(typeof(Action<T1, T2>), null, setter); |
|
|
|
|
} |
|
|
|
|
public static PropAccessor<T1, T2> Create(string propName){ |
|
|
|
|
return new PropAccessor<T1, T2>(propName); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
public object GetValue(object model){ |
|
|
|
|
return Get((T1)model); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
public void SetValue(object model, object value){ |
|
|
|
|
Set((T1)model,(T2)value); |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
public class PropertyNotFoundException : Exception{ |
|
|
|
|
public PropertyNotFoundException(string path):base("Property not found :"+path){ |
|
|
|
|
|
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
public class RuntimeCache{ |
|
|
|
|
//Singleton instance for the runtime cache |
|
|
|
|
private static RuntimeCache _instance; |
|
|
|
@ -18,18 +47,16 @@ namespace TNodeCore.RuntimeCache{ |
|
|
|
|
public delegate object GetValueDelegate(IModel nodeData); |
|
|
|
|
public delegate void SetValueDelegate(IModel nodeData,object value); |
|
|
|
|
|
|
|
|
|
public delegate object GetPropertyValueDelegate(); |
|
|
|
|
public delegate void SetPropertyValueDelegate(object value); |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
public readonly Dictionary<Type, Dictionary<string,GetValueDelegate>> CachedDelegatesForGettingValue = |
|
|
|
|
new (); |
|
|
|
|
public readonly Dictionary<Type,Dictionary<string,SetValueDelegate>> CachedDelegatesForSettingValue = |
|
|
|
|
new (); |
|
|
|
|
public readonly Dictionary<Type,Dictionary<string,GetPropertyValueDelegate>> CachedDelegatesForGettingPropertyValue = |
|
|
|
|
new (); |
|
|
|
|
public readonly Dictionary<Type,Dictionary<string,SetPropertyValueDelegate>> CachedDelegatesForSettingPropertyValue = |
|
|
|
|
public readonly Dictionary<Type,Dictionary<string,IModelPropertyAccessor>> CachedPropertyAccessors = |
|
|
|
|
new (); |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
private readonly Dictionary<Type, Type> _graphBlackboardDictionary = new Dictionary<Type, Type>(); |
|
|
|
|
|
|
|
|
|
private static readonly string[] ExcludedAssemblies = new string[]{"Microsoft", "UnityEngine","UnityEditor","mscorlib","System"}; |
|
|
|
@ -46,23 +73,28 @@ namespace TNodeCore.RuntimeCache{ |
|
|
|
|
if (attribute is GraphUsageAttribute){ |
|
|
|
|
//if the type has GraphUsageAttribute, add it to the cache |
|
|
|
|
AddTypeToCache(type,attribute as GraphUsageAttribute); |
|
|
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
if (attribute is InternalModel){ |
|
|
|
|
AddTypeToCache(type,attribute as InternalModel); |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
private void AddTypeToCache(Type type,GraphUsageAttribute attribute){ |
|
|
|
|
private void AddTypeToCache(Type type,System.Attribute attribute){ |
|
|
|
|
//Check if the type is a blackboard data type |
|
|
|
|
if(typeof(BlackboardData).IsAssignableFrom(type)){ |
|
|
|
|
//if it is, add it to the cache |
|
|
|
|
AddBlackboardDataTypeToCache(type,attribute); |
|
|
|
|
RegisterRuntimeBlackboard(type); |
|
|
|
|
AddBlackboardDataTypeToCache(type,(GraphUsageAttribute)attribute); |
|
|
|
|
CacheRuntimeBlackboard(type); |
|
|
|
|
} |
|
|
|
|
//Check if the type is a node data type |
|
|
|
|
if(typeof(NodeData).IsAssignableFrom(type)){ |
|
|
|
|
//if it is, add it to the cache |
|
|
|
|
RegisterRuntimeNodeData(type); |
|
|
|
|
CacheRuntimeNodeData(type); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
} |
|
|
|
@ -87,7 +119,7 @@ namespace TNodeCore.RuntimeCache{ |
|
|
|
|
} |
|
|
|
|
return null; |
|
|
|
|
} |
|
|
|
|
public void RegisterRuntimeBlackboard(Type type){ |
|
|
|
|
public void CacheRuntimeBlackboard(Type type){ |
|
|
|
|
if (type == null) return; |
|
|
|
|
if(!CachedDelegatesForGettingValue.ContainsKey(type)){ |
|
|
|
|
CachedDelegatesForGettingValue.Add(type, new Dictionary<string, GetValueDelegate>()); |
|
|
|
@ -114,29 +146,24 @@ namespace TNodeCore.RuntimeCache{ |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
public void RegisterRuntimeNodeData(Type type){ |
|
|
|
|
public static IModelPropertyAccessor Create(string propName,Type targetType,Type valueType){ |
|
|
|
|
var makeGenericType = typeof (PropAccessor<,>).MakeGenericType(targetType,valueType); |
|
|
|
|
var constructor = makeGenericType.GetConstructor(new Type[]{typeof(string)}); |
|
|
|
|
var instance = constructor?.Invoke(new object[]{propName}); |
|
|
|
|
return (IModelPropertyAccessor) instance; |
|
|
|
|
} |
|
|
|
|
public void CacheRuntimeNodeData(Type type){ |
|
|
|
|
if (type == null) return; |
|
|
|
|
if(!CachedDelegatesForGettingValue.ContainsKey(type)){ |
|
|
|
|
CachedDelegatesForGettingValue.Add(type, new Dictionary<string, GetValueDelegate>()); |
|
|
|
|
CachedDelegatesForSettingValue.Add(type,new Dictionary<string, SetValueDelegate>()); |
|
|
|
|
|
|
|
|
|
CachedPropertyAccessors.Add(type,new Dictionary<string, IModelPropertyAccessor>()); |
|
|
|
|
|
|
|
|
|
var properties = type.GetProperties(); |
|
|
|
|
foreach(var property in properties){ |
|
|
|
|
//if the property only has a setter ,skip |
|
|
|
|
|
|
|
|
|
// if(property.GetSetMethod(false) != null){ |
|
|
|
|
// var setValueDelegate = SetValueDelegateForProperty(property); |
|
|
|
|
// CachedDelegatesForSettingPropertyValue[type].Add(property.Name,setValueDelegate); |
|
|
|
|
// } |
|
|
|
|
// if(property.GetMethod != null){ |
|
|
|
|
// var getValueDelegate = GetValueDelegateForProperty(property); |
|
|
|
|
// CachedDelegatesForGettingPropertyValue[type].Add(property.Name,getValueDelegate); |
|
|
|
|
// } |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
var propertyAccessor = Create(property.Name,type,property.PropertyType); |
|
|
|
|
CachedPropertyAccessors[type].Add(property.Name,propertyAccessor); |
|
|
|
|
} |
|
|
|
|
//register the fields |
|
|
|
|
var fields = type.GetFields(); |
|
|
|
@ -160,18 +187,9 @@ namespace TNodeCore.RuntimeCache{ |
|
|
|
|
|
|
|
|
|
return field.SetValue; |
|
|
|
|
} |
|
|
|
|
private GetPropertyValueDelegate GetValueDelegateForProperty(PropertyInfo property){ |
|
|
|
|
var getValueDelegate = (GetPropertyValueDelegate)Delegate.CreateDelegate(typeof(GetPropertyValueDelegate), property.GetGetMethod()); |
|
|
|
|
return getValueDelegate; |
|
|
|
|
} |
|
|
|
|
private SetPropertyValueDelegate SetValueDelegateForProperty(PropertyInfo property){ |
|
|
|
|
Debug.Log(property.GetSetMethod()); |
|
|
|
|
|
|
|
|
|
var setValueDelegate = (SetPropertyValueDelegate)Delegate.CreateDelegate(typeof(SetPropertyValueDelegate), property.GetSetMethod()); |
|
|
|
|
return setValueDelegate; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
public static class RuntimeExtension{ |
|
|
|
|
|
|
|
|
|
//todo latter on i will try some way caching reflection more efficiently |
|
|
|
@ -192,46 +210,5 @@ namespace TNodeCore.RuntimeCache{ |
|
|
|
|
var method = RuntimeCache.Instance.CachedDelegatesForSettingValue[type??data.GetType()][path]; |
|
|
|
|
method.Invoke(data,value); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
public static RuntimeCache.GetValueDelegate GetValueDelegate(this IModel blackboardData,string path){ |
|
|
|
|
var method = RuntimeCache.Instance.CachedDelegatesForGettingValue[blackboardData.GetType()][path]; |
|
|
|
|
return method; |
|
|
|
|
} |
|
|
|
|
/// <summary> |
|
|
|
|
/// it generate a delegate that can get the value fast,but it won't cache in runtime cache system,you should put it in somewhere you need |
|
|
|
|
/// </summary> |
|
|
|
|
/// <param name="data"></param> |
|
|
|
|
/// <param name="path"></param> |
|
|
|
|
/// <returns></returns> |
|
|
|
|
/// <exception cref="PropertyNotFoundException"></exception> |
|
|
|
|
public static RuntimeCache.GetPropertyValueDelegate CacheGetProperty(this IModel data,string path){ |
|
|
|
|
var type = data.GetType(); |
|
|
|
|
var property = type.GetProperty(path); |
|
|
|
|
if (property == null) throw new PropertyNotFoundException(path); |
|
|
|
|
var instance = Delegate.CreateDelegate(typeof(RuntimeCache.GetPropertyValueDelegate), data, |
|
|
|
|
property.GetGetMethod()); |
|
|
|
|
return instance as RuntimeCache.GetPropertyValueDelegate; |
|
|
|
|
} |
|
|
|
|
/// <summary> |
|
|
|
|
/// it generate a delegate that can get the value fast,but it won't cache in runtime cache system,you should put it in somewhere you need |
|
|
|
|
/// </summary> |
|
|
|
|
/// <param name="data"></param> |
|
|
|
|
/// <param name="path"></param> |
|
|
|
|
/// <returns></returns> |
|
|
|
|
/// <exception cref="PropertyNotFoundException"></exception> |
|
|
|
|
public static RuntimeCache.SetPropertyValueDelegate CacheSetProperty(this IModel data,string path){ |
|
|
|
|
var type = data.GetType(); |
|
|
|
|
var property = type.GetProperty(path); |
|
|
|
|
if (property == null) throw new PropertyNotFoundException(path); |
|
|
|
|
var instance = Delegate.CreateDelegate(typeof(RuntimeCache.SetPropertyValueDelegate), data, |
|
|
|
|
property.GetSetMethod()); |
|
|
|
|
return instance as RuntimeCache.SetPropertyValueDelegate; |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
public class PropertyNotFoundException : Exception{ |
|
|
|
|
public PropertyNotFoundException(string path):base("Property not found :"+path){ |
|
|
|
|
|
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
} |