Entitas  0.35.0
Entitas is a super fast Entity Component System (ECS) Framework specifically made for C# and Unity
TypeReflectionProvider.cs
1 using System;
2 using System.Collections.Generic;
3 using System.Linq;
5 
6 namespace Entitas.CodeGenerator {
7 
9 
10  public ComponentInfo[] componentInfos { get { return _componentInfos; } }
11  public string[] poolNames { get { return _poolNames; } }
12  public string[] blueprintNames { get { return _blueprintNames; } }
13 
14  readonly ComponentInfo[] _componentInfos;
15  readonly string[] _poolNames;
16  readonly string[] _blueprintNames;
17 
18  public TypeReflectionProvider(Type[] types, string[] poolNames, string[] blueprintNames) {
19  var pools = new HashSet<string>(poolNames);
20  if(poolNames.Length == 0) {
21  pools.Add(CodeGenerator.DEFAULT_POOL_NAME);
22  }
23  _componentInfos = GetComponentInfos(types);
24  _poolNames = pools
25  .Select(poolName => poolName.UppercaseFirst())
26  .OrderBy(poolName => poolName)
27  .ToArray();
28  _blueprintNames = blueprintNames;
29  }
30 
31  public static ComponentInfo[] GetComponentInfos(params Type[] types) {
32  var infosFromComponents = types
33  .Where(type => !type.IsInterface)
34  .Where(type => !type.IsAbstract)
35  .Where(type => type.GetInterfaces().Any(i => i.FullName == "Entitas.IComponent"))
36  .Select(type => CreateComponentInfo(type));
37 
38  var infosForNonComponents = types
39  .Where(type => !type.IsGenericType)
40  .Where(type => !type.GetInterfaces().Any(i => i.FullName == "Entitas.IComponent"))
41  .Where(type => GetPools(type, false).Length > 0)
42  .SelectMany(type => CreateComponentInfosForClass(type));
43 
44  var generatedComponentsLookup = infosForNonComponents.ToLookup(info => info.fullTypeName);
45 
46  return infosFromComponents
47  .Where(info => !generatedComponentsLookup.Contains(info.fullTypeName))
48  .Concat(infosForNonComponents)
49  .ToArray();
50  }
51 
52  public static ComponentInfo CreateComponentInfo(Type type) {
53  return new ComponentInfo(
54  type.ToCompilableString(),
55  GetPublicMemberInfo(type),
56  GetPools(type, true),
57  GetIsSingleEntity(type),
58  GetSingleComponentPrefix(type),
59  false,
60  GetGenerateMethods(type),
61  GetGenerateIndex(type),
62  GetHideInBlueprintInspector(type)
63  );
64  }
65 
66  public static ComponentInfo[] CreateComponentInfosForClass(Type type) {
67  return GetComponentNames(type)
68  .Select(componentName => new ComponentInfo(
69  componentName,
70  new List<PublicMemberInfo> {
71  new PublicMemberInfo(type, "value")
72  },
73  GetPools(type, false),
74  GetIsSingleEntity(type),
75  GetSingleComponentPrefix(type),
76  true,
77  GetGenerateMethods(type),
78  GetGenerateIndex(type),
79  GetHideInBlueprintInspector(type)
80  )).ToArray();
81  }
82 
83  public static List<PublicMemberInfo> GetPublicMemberInfo(Type type) {
84  return type.GetPublicMemberInfos();
85  }
86 
87  public static string[] GetPools(Type type, bool defaultIfEmpty) {
88  var pools = Attribute.GetCustomAttributes(type)
89  .Where(attr => isTypeOrHasBaseType(attr.GetType(), "Entitas.CodeGenerator.PoolAttribute"))
90  .Select(attr => attr.GetType().GetField("poolName").GetValue(attr) as string)
91  .OrderBy(poolName => poolName)
92  .ToArray();
93 
94  if(pools.Length == 0 && defaultIfEmpty) {
95  return new [] { CodeGenerator.DEFAULT_POOL_NAME };
96  }
97 
98  var defaultPoolIndex = Array.IndexOf(pools, CodeGenerator.DEFAULT_POOL_NAME);
99  if(defaultPoolIndex != -1) {
100  pools[defaultPoolIndex] = pools[0];
101  pools[0] = CodeGenerator.DEFAULT_POOL_NAME;
102  }
103 
104  return pools;
105  }
106 
107  public static bool GetIsSingleEntity(Type type) {
108  return Attribute.GetCustomAttributes(type)
109  .Any(attr => attr.GetType().FullName == "Entitas.CodeGenerator.SingleEntityAttribute");
110  }
111 
112  public static string GetSingleComponentPrefix(Type type) {
113  var attr = Attribute.GetCustomAttributes(type)
114  .SingleOrDefault(a => isTypeOrHasBaseType(a.GetType(), "Entitas.CodeGenerator.CustomPrefixAttribute"));
115 
116  return attr == null ? "is" : (string)attr.GetType().GetField("prefix").GetValue(attr);
117  }
118 
119  public static string[] GetComponentNames(Type type) {
120  var attr = Attribute.GetCustomAttributes(type)
121  .SingleOrDefault(a => isTypeOrHasBaseType(a.GetType(), "Entitas.CodeGenerator.CustomComponentNameAttribute"));
122 
123  if(attr == null) {
124  var nameSplit = type.ToCompilableString().Split('.');
125  var componentName = nameSplit[nameSplit.Length - 1].AddComponentSuffix();
126  return new [] { componentName };
127  }
128 
129  return (string[])attr.GetType().GetField("componentNames").GetValue(attr);
130  }
131 
132  public static bool GetGenerateMethods(Type type) {
133  return Attribute.GetCustomAttributes(type)
134  .All(attr => attr.GetType().FullName != "Entitas.CodeGenerator.DontGenerateAttribute");
135  }
136 
137  public static bool GetGenerateIndex(Type type) {
138  var attr = Attribute.GetCustomAttributes(type)
139  .SingleOrDefault(a => isTypeOrHasBaseType(a.GetType(), "Entitas.CodeGenerator.DontGenerateAttribute"));
140 
141  return attr == null || (bool)attr.GetType().GetField("generateIndex").GetValue(attr);
142  }
143 
144  public static bool GetHideInBlueprintInspector(Type type) {
145  var attr = Attribute.GetCustomAttributes(type)
146  .SingleOrDefault(a => isTypeOrHasBaseType(a.GetType(), "Entitas.Serialization.Blueprints.HideInBlueprintInspectorAttribute"));
147 
148  return attr != null;
149  }
150 
151  static bool hasBaseType(Type type, string fullTypeName) {
152  if(type.FullName == fullTypeName) {
153  return false;
154  }
155 
156  return isTypeOrHasBaseType(type, fullTypeName);
157  }
158 
159  static bool isTypeOrHasBaseType(Type type, string fullTypeName) {
160  var t = type;
161  while (t != null) {
162  if(t.FullName == fullTypeName) {
163  return true;
164  }
165  t = t.BaseType;
166  }
167 
168  return false;
169  }
170  }
171 }