CSComponentCore.cs 7.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213
  1. using System;
  2. using System.IO;
  3. using System.Collections.Generic;
  4. using System.Reflection;
  5. using System.Linq;
  6. namespace AtomicEngine
  7. {
  8. internal class CSComponentInfo
  9. {
  10. public CSComponentInfo(Type type)
  11. {
  12. #if ATOMIC_DESKTOP || ATOMIC_MOBILE
  13. this.Type = type;
  14. // Fields
  15. List<FieldInfo> fields = new List<FieldInfo>();
  16. fields.AddRange(type.GetFields(BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance)
  17. .Where(field => field.IsDefined(typeof(InspectorAttribute), true)));
  18. // Inspector fields may be private. BindingFlags.NonPublic does not report private fields in superclasses
  19. var baseType = type.BaseType;
  20. while (baseType != typeof(CSComponent))
  21. {
  22. fields.AddRange(baseType.GetFields(BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance)
  23. .Where(field => field.IsDefined(typeof(InspectorAttribute), true)));
  24. baseType = baseType.BaseType;
  25. }
  26. InspectorFields = fields.ToArray<FieldInfo>();
  27. foreach (var field in InspectorFields)
  28. {
  29. fieldLookup[AtomicNET.StringToStringHash(field.Name)] = field;
  30. }
  31. // Methods
  32. Type[] updateParms = new Type[1] { typeof(float) };
  33. UpdateMethod = type.GetMethod("Update", BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic, Type.DefaultBinder, updateParms, null);
  34. Type[] postUpdateParms = new Type[1] { typeof(float) };
  35. PostUpdateMethod = type.GetMethod("PostUpdate", BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic, Type.DefaultBinder, postUpdateParms, null);
  36. Type[] physicsPreStepParms = new Type[1] { typeof(float) };
  37. PhysicsPreStepMethod = type.GetMethod("PhysicsPreStep", BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic, Type.DefaultBinder, physicsPreStepParms, null);
  38. Type[] physicsPostStepParms = new Type[1] { typeof(float) };
  39. PhysicsPostStepMethod = type.GetMethod("PhysicsPostStep", BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic, Type.DefaultBinder, physicsPostStepParms, null);
  40. Type[] startParms = new Type[0] { };
  41. StartMethod = type.GetMethod("Start", BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic, Type.DefaultBinder, startParms, null);
  42. #endif
  43. }
  44. public void ApplyFieldValues(CSComponent component, IntPtr fieldValuePtr)
  45. {
  46. // FIXME: This will need to be optimized, specifically to use uint key hashes for value lookup
  47. #if ATOMIC_DESKTOP || ATOMIC_MOBILE
  48. fieldMap.CopyVariantMap(fieldValuePtr);
  49. foreach (var field in InspectorFields)
  50. {
  51. if (fieldMap.Contains(field.Name))
  52. {
  53. var fieldType = field.FieldType;
  54. if (fieldType.IsEnum)
  55. {
  56. field.SetValue(component, fieldMap.GetInt(field.Name));
  57. continue;
  58. }
  59. switch (Type.GetTypeCode(fieldType))
  60. {
  61. case TypeCode.Boolean:
  62. field.SetValue(component, fieldMap.GetBool(field.Name));
  63. break;
  64. case TypeCode.Int32:
  65. field.SetValue(component, fieldMap.GetInt(field.Name));
  66. break;
  67. case TypeCode.Single:
  68. field.SetValue(component, fieldMap.GetFloat(field.Name));
  69. break;
  70. case TypeCode.String:
  71. field.SetValue(component, fieldMap.GetString(field.Name));
  72. break;
  73. default:
  74. if (fieldType == typeof(Vector3))
  75. {
  76. field.SetValue(component, fieldMap.GetVector3(field.Name));
  77. }
  78. else if (fieldType == typeof(Quaternion))
  79. {
  80. field.SetValue(component, fieldMap.GetQuaternion(field.Name));
  81. }
  82. else if (fieldType.IsSubclassOf(typeof(Resource)))
  83. {
  84. field.SetValue(component, fieldMap.GetResourceFromRef(field.Name));
  85. }
  86. else if (fieldType.IsSubclassOf(typeof(RefCounted)))
  87. {
  88. field.SetValue(component, fieldMap.GetPtr(field.Name));
  89. }
  90. break;
  91. }
  92. }
  93. }
  94. #endif
  95. }
  96. public FieldInfo[] InspectorFields;
  97. public Type Type;
  98. // Start method called once
  99. public MethodInfo StartMethod = null;
  100. // Update called first
  101. public MethodInfo UpdateMethod = null;
  102. // Physics steps if any
  103. public MethodInfo PhysicsPreStepMethod = null;
  104. public MethodInfo PhysicsPostStepMethod = null;
  105. // Post Update
  106. public MethodInfo PostUpdateMethod = null;
  107. ScriptVariantMap fieldMap = new ScriptVariantMap();
  108. public Dictionary<uint, FieldInfo> fieldLookup = new Dictionary<uint, FieldInfo>();
  109. }
  110. public class CSComponentCore : NETScriptObject
  111. {
  112. [Obsolete("Method HandleComponentAssemblyReference is deprecated (loading component assemblies at runtime, will be changed to preload them)")]
  113. void HandleComponentAssemblyReference(uint eventType, ScriptVariantMap eventData)
  114. {
  115. string assemblyPath = eventData["AssemblyPath"];
  116. string assemblyName = Path.GetFileNameWithoutExtension(assemblyPath);
  117. Log.Info($"Component Assembly referenced {assemblyName} ");
  118. }
  119. void ParseComponents()
  120. {
  121. #if ATOMIC_DESKTOP || ATOMIC_MOBILE
  122. var assemblies = AppDomain.CurrentDomain.GetAssemblies().ToList();
  123. foreach (Assembly assembly in assemblies)
  124. {
  125. ParseAssembly(assembly);
  126. }
  127. #endif
  128. }
  129. void ParseAssembly(Assembly assembly)
  130. {
  131. #if ATOMIC_DESKTOP || ATOMIC_MOBILE
  132. if (parsedAssemblies.ContainsKey(assembly))
  133. {
  134. return;
  135. }
  136. parsedAssemblies[assembly] = true;
  137. Type[] types = assembly.GetTypes();
  138. foreach (var type in types)
  139. {
  140. if (type.IsSubclassOf(typeof(CSComponent)))
  141. {
  142. var csinfo = new CSComponentInfo(type);
  143. csinfoLookup[csinfo.Type] = csinfo;
  144. componentCache[type.Name] = csinfo;
  145. }
  146. }
  147. #endif
  148. }
  149. internal static void Initialize()
  150. {
  151. instance = new CSComponentCore();
  152. instance.ParseComponents();
  153. instance.SubscribeToEvent("CSComponentAssemblyReference", instance.HandleComponentAssemblyReference);
  154. }
  155. // type name -> CSComponentInfo lookup TODO: store with namespace to solve ambiguities
  156. internal static Dictionary<string, CSComponentInfo> componentCache = new Dictionary<string, CSComponentInfo>();
  157. [Obsolete("Member parsedAssemblies is temporarily required for runtime component assemblies loading")]
  158. Dictionary<Assembly, bool> parsedAssemblies = new Dictionary<Assembly, bool>();
  159. internal static Dictionary<Type, CSComponentInfo> csinfoLookup = new Dictionary<Type, CSComponentInfo>();
  160. static CSComponentCore instance;
  161. }
  162. }