CSComponentCore.cs 7.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206
  1. using System;
  2. using System.Collections.Generic;
  3. using System.Reflection;
  4. using System.Linq;
  5. namespace AtomicEngine
  6. {
  7. internal class CSComponentInfo
  8. {
  9. public CSComponentInfo(Type type)
  10. {
  11. this.Type = type;
  12. // Fields
  13. var fields = type.GetFields(BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance)
  14. .Where(field => field.IsDefined(typeof(InspectorAttribute), true));
  15. InspectorFields = fields.ToArray<FieldInfo>();
  16. foreach (var field in InspectorFields)
  17. {
  18. fieldLookup[AtomicNET.StringToStringHash(field.Name)] = field;
  19. }
  20. // Methods
  21. Type[] parms = new Type[1] { typeof(float) };
  22. UpdateMethod = type.GetMethod("Update", BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic, Type.DefaultBinder, parms, null);
  23. }
  24. public void ApplyFieldValues(CSComponent component, IntPtr fieldValuePtr)
  25. {
  26. // FIXME: This will need to be optimized, specifically to use uint key hashes for value lookup
  27. fieldMap.CopyVariantMap(fieldValuePtr);
  28. foreach (var field in InspectorFields)
  29. {
  30. if (fieldMap.Contains(field.Name))
  31. {
  32. var fieldType = field.FieldType;
  33. if (fieldType.IsEnum)
  34. {
  35. field.SetValue(component, fieldMap.GetInt(field.Name));
  36. continue;
  37. }
  38. switch (Type.GetTypeCode(fieldType))
  39. {
  40. case TypeCode.Boolean:
  41. field.SetValue(component, fieldMap.GetBool(field.Name));
  42. break;
  43. case TypeCode.Int32:
  44. field.SetValue(component, fieldMap.GetInt(field.Name));
  45. break;
  46. case TypeCode.Single:
  47. field.SetValue(component, fieldMap.GetFloat(field.Name));
  48. break;
  49. case TypeCode.String:
  50. field.SetValue(component, fieldMap.GetString(field.Name));
  51. break;
  52. default:
  53. if (fieldType == typeof(Vector3))
  54. {
  55. field.SetValue(component, fieldMap.GetVector3(field.Name));
  56. }
  57. else if (fieldType == typeof(Quaternion))
  58. {
  59. field.SetValue(component, fieldMap.GetQuaternion(field.Name));
  60. }
  61. else if (fieldType.IsSubclassOf(typeof(Resource)))
  62. {
  63. field.SetValue(component, fieldMap.GetResourceFromRef(field.Name));
  64. }
  65. else if (fieldType.IsSubclassOf(typeof(RefCounted)))
  66. {
  67. field.SetValue(component, fieldMap.GetPtr(field.Name));
  68. }
  69. break;
  70. }
  71. }
  72. }
  73. }
  74. public void RegisterInstance(CSComponent component)
  75. {
  76. Instances.Add(component);
  77. }
  78. public List<CSComponent> Instances = new List<CSComponent>();
  79. public FieldInfo[] InspectorFields;
  80. public Type Type;
  81. public MethodInfo UpdateMethod = null;
  82. ScriptVariantMap fieldMap = new ScriptVariantMap();
  83. public Dictionary<uint, FieldInfo> fieldLookup = new Dictionary<uint, FieldInfo>();
  84. }
  85. internal class CSComponentCore : NETScriptObject
  86. {
  87. void HandleUpdate(uint eventType, ScriptVariantMap eventData)
  88. {
  89. Object[] args = new Object[1] { eventData.GetFloat("timestep") };
  90. foreach (var csinfo in csinfoLookup.Values)
  91. {
  92. var updateMethod = csinfo.UpdateMethod;
  93. if (updateMethod != null)
  94. {
  95. foreach (var instance in csinfo.Instances)
  96. {
  97. updateMethod.Invoke(instance, args);
  98. }
  99. }
  100. }
  101. }
  102. void HandleComponentLoad(uint eventType, ScriptVariantMap eventData)
  103. {
  104. var assemblyPath = eventData["AssemblyPath"];
  105. var className = eventData["ClassName"];
  106. IntPtr csnative = eventData.GetVoidPtr("NativeInstance");
  107. IntPtr fieldValues = IntPtr.Zero;
  108. if (eventData.Contains("FieldValues"))
  109. fieldValues = eventData.GetVoidPtr("FieldValues");
  110. Dictionary<string, CSComponentInfo> assemblyTypes = null;
  111. if (!componentCache.TryGetValue(assemblyPath, out assemblyTypes))
  112. {
  113. return;
  114. }
  115. CSComponentInfo csinfo;
  116. if (!assemblyTypes.TryGetValue(className, out csinfo))
  117. {
  118. return;
  119. }
  120. NativeCore.NativeContructorOverride = csnative;
  121. var component = (CSComponent)Activator.CreateInstance(csinfo.Type);
  122. NativeCore.VerifyNativeContructorOverrideConsumed();
  123. if (fieldValues != IntPtr.Zero)
  124. csinfo.ApplyFieldValues(component, fieldValues);
  125. csinfo.RegisterInstance(component);
  126. }
  127. void HandleComponentAssemblyReference(uint eventType, ScriptVariantMap eventData)
  128. {
  129. string assemblyPath = eventData["AssemblyPath"];
  130. Dictionary<string, CSComponentInfo> assemblyTypes = null;
  131. if (!componentCache.TryGetValue(assemblyPath, out assemblyTypes))
  132. {
  133. componentCache[assemblyPath] = assemblyTypes = new Dictionary<string, CSComponentInfo>();
  134. }
  135. Assembly assembly = Assembly.LoadFrom(assemblyPath);
  136. Type[] types = assembly.GetTypes();
  137. foreach (var type in types)
  138. {
  139. if (type.IsSubclassOf(typeof(CSComponent)))
  140. {
  141. var csinfo = new CSComponentInfo(type);
  142. csinfoLookup[csinfo.Type] = csinfo;
  143. assemblyTypes[type.Name] = csinfo;
  144. }
  145. }
  146. }
  147. internal static void Initialize()
  148. {
  149. instance = new CSComponentCore();
  150. instance.SubscribeToEvent("CSComponentAssemblyReference", instance.HandleComponentAssemblyReference);
  151. instance.SubscribeToEvent("CSComponentLoad", instance.HandleComponentLoad);
  152. instance.SubscribeToEvent("Update", instance.HandleUpdate);
  153. }
  154. Dictionary<string, Dictionary<string, CSComponentInfo>> componentCache = new Dictionary<string, Dictionary<string, CSComponentInfo>>();
  155. Dictionary<Type, CSComponentInfo> csinfoLookup = new Dictionary<Type, CSComponentInfo>();
  156. static CSComponentCore instance;
  157. }
  158. }