using System; using System.Collections.Generic; using System.Linq; using System.Reflection; using System.Runtime.CompilerServices; namespace Encompass { internal class UberEngine : Engine { private readonly IEnumerable _componentTypes; private readonly IEnumerable _messageTypes; public Entity Entity { get; private set; } public UberEngine(IEnumerable componentTypes, IEnumerable messageTypes) { _componentTypes = componentTypes; _messageTypes = messageTypes; ReadTypes.UnionWith(componentTypes); WriteTypes.UnionWith(componentTypes); SendTypes.UnionWith(messageTypes); ReceiveTypes.UnionWith(messageTypes); } public void Write() { Entity = CreateEntity(); foreach (var type in _componentTypes) { var instanceParam = new object[] { Entity, Activator.CreateInstance(type) }; var setComponentMethod = typeof(Engine).GetMethod("SetComponent", BindingFlags.NonPublic | BindingFlags.Instance); var genericSetComponentMethod = setComponentMethod.MakeGenericMethod(type); genericSetComponentMethod.Invoke(this, instanceParam); } } // we can't reflect invoke on Span returns right now... tragic public override void Update(double dt) { foreach (var type in _componentTypes) { CallGenericMethod(type, "ReadComponent", null); //CallGenericMethod(type, "ReadComponents", null); CallGenericMethod(type, "ReadEntity", null); //CallGenericMethod(type, "ReadEntities", null); CallGenericMethod(type, "GetComponent", new object[] { Entity }); CallGenericMethod(type, "HasComponent", 1, new object[] { Entity }); CallGenericMethod(type, "SomeComponent", null); CallGenericMethod(type, "DestroyWith", null); CallGenericMethod(type, "DestroyAllWith", null); CallGenericMethod(type, "RemoveComponent", new object[] { Entity }); } foreach (var type in _messageTypes) { CallGenericMethod(type, "SendMessageIgnoringTimeDilation", new object[] { Activator.CreateInstance(type), 1 }); CallGenericMethod(type, "SendMessage", 1, new object[] { Activator.CreateInstance(type) }); CallGenericMethod(type, "SendMessage", 2, new object[] { Activator.CreateInstance(type), 1 }); CallGenericMethod(type, "ReadMessage", null); //CallGenericMethod(type, "ReadMessages", null); CallGenericMethod(type, "SomeMessage", null); if (typeof(IHasEntity).IsAssignableFrom(type)) { CallGenericMethod(type, "ReadMessagesWithEntity", new object[] { Entity }); CallGenericMethod(type, "ReadMessageWithEntity", new object[] { Entity }); CallGenericMethod(type, "SomeMessageWithEntity", new object[] { Entity }); } } } // trying to use PrepareMethod because we can't reflect invoke methods that return a span... private void CallGenericMethod(Type type, string methodName, object[] parameters) { var readComponentMethod = typeof(Engine).GetMethod(methodName, BindingFlags.NonPublic | BindingFlags.Instance); var genericReadComponentMethod = readComponentMethod.MakeGenericMethod(type); genericReadComponentMethod.Invoke(this, parameters); // RuntimeHelpers.PrepareMethod(genericReadComponentMethod.MethodHandle); } private void CallGenericMethod(Type type, string methodName, Type[] types, object[] parameters) { var readComponentMethod = typeof(Engine).GetMethod(methodName, BindingFlags.NonPublic | BindingFlags.Instance, null, types, null); var genericReadComponentMethod = readComponentMethod.MakeGenericMethod(type); genericReadComponentMethod.Invoke(this, parameters); // RuntimeHelpers.PrepareMethod(genericReadComponentMethod.MethodHandle); } private void CallGenericMethod(Type type, string methodName, int argumentNum, object[] parameters) { var method = typeof(Engine).GetRuntimeMethods().Where(m => m.Name == methodName && m.GetParameters().Length == argumentNum).First(); var genericMethod = method.MakeGenericMethod(type); genericMethod.Invoke(this, parameters); // RuntimeHelpers.PrepareMethod(genericMethod.MethodHandle); } } }