Empty systems run once per phase

Previously they didn't run at all
since they don't match any entities.
wip/source-generators
copygirl 2 years ago
parent de2159299e
commit 9e55bffac8
  1. 45
      src/gaemstone/Utility/IL/IterActionGenerator.cs

@ -24,10 +24,12 @@ public unsafe class IterActionGenerator
private static readonly PropertyInfo _handleTargetProp = typeof(GCHandle).GetProperty(nameof(GCHandle.Target))!;
private static readonly ConditionalWeakTable<MethodInfo, IterActionGenerator> _cache = new();
private static readonly Dictionary<Type, Action<ILGeneratorWrapper, IArgument<Iterator>>> _globalUniqueParameters = new() {
[typeof(Universe)] = (IL, iter) => { IL.Load(iter, _iteratorUniverseProp); },
[typeof(TimeSpan)] = (IL, iter) => { IL.Load(iter, _iteratorDeltaTimeProp); },
};
private static readonly Dictionary<Type, Action<ILGeneratorWrapper, IArgument<Iterator>, ILocal<int>>> _uniqueParameters = new() {
[typeof(Iterator)] = (IL, iter, i) => { IL.Load(iter); },
[typeof(Universe)] = (IL, iter, i) => { IL.Load(iter, _iteratorUniverseProp); },
[typeof(TimeSpan)] = (IL, iter, i) => { IL.Load(iter, _iteratorDeltaTimeProp); },
[typeof(EntityRef)] = (IL, iter, i) => { IL.Load(iter); IL.Load(i); IL.Call(_iteratorEntityMethod); },
};
@ -61,7 +63,6 @@ public unsafe class IterActionGenerator
// if (!Parameters.Any(c => c.IsRequired && (c.Kind != ParamKind.Unique)))
// throw new ArgumentException($"At least one parameter in {method} is required");
var terms = new List<Term>();
var name = "<>Query_" + string.Join("_", Parameters.Select(p => p.UnderlyingType.Name));
var genMethod = new DynamicMethod(name, null, new[] { typeof(object), typeof(Iterator) });
var IL = new ILGeneratorWrapper(genMethod);
@ -69,12 +70,32 @@ public unsafe class IterActionGenerator
var instanceArg = IL.Argument<object?>(0);
var iteratorArg = IL.Argument<Iterator>(1);
// If parameters only contains global unique paremeters (such as
// Universe or TimeSpan), or is empty, just run the system, since
// without terms it won't match any entities anyway.
if (Parameters.All(p => p.Kind == ParamKind.GlobalUnique)) {
if (!Method.IsStatic) IL.Load(instanceArg);
foreach (var p in Parameters) {
IL.Comment($"Global unique parameter {p.ParameterType.GetFriendlyName()}");
_globalUniqueParameters[p.ParameterType](IL, iteratorArg);
}
IL.Call(Method);
IL.Return();
Terms = Array.Empty<Term>();
GeneratedAction = genMethod.CreateDelegate<Action<object?, Iterator>>();
ReadableString = IL.ToReadableString();
return;
}
var terms = new List<Term>();
var fieldLocals = new ILocal[Parameters.Length];
var tempLocals = new ILocal[Parameters.Length];
for (var i = 0; i < Parameters.Length; i++) {
var p = Parameters[i];
if (p.Kind == ParamKind.Unique) continue;
if (p.Kind <= ParamKind.Unique) continue;
// Add an entry to the terms to look for this type.
terms.Add(new(universe.LookupOrThrow(p.UnderlyingType)) {
@ -128,16 +149,18 @@ public unsafe class IterActionGenerator
// If there's any reference type parameters, we need to define a GCHandle local.
var hasReferenceType = Parameters
.Where(p => p.Kind != ParamKind.Unique)
.Where(p => p.Kind > ParamKind.Unique)
.Any(p => !p.UnderlyingType.IsValueType);
var handleLocal = hasReferenceType ? IL.Local<GCHandle>() : null;
using (IL.For(() => IL.Load(iteratorArg, _iteratorCountProp), out var currentLocal)) {
if (!Method.IsStatic)
IL.Load(instanceArg);
if (!Method.IsStatic) IL.Load(instanceArg);
for (var i = 0; i < Parameters.Length; i++) {
var p = Parameters[i];
if (p.Kind == ParamKind.Unique) {
if (p.Kind == ParamKind.GlobalUnique) {
IL.Comment($"Global unique parameter {p.ParameterType.GetFriendlyName()}");
_globalUniqueParameters[p.ParameterType](IL, iteratorArg);
} else if (p.Kind == ParamKind.Unique) {
IL.Comment($"Unique parameter {p.ParameterType.GetFriendlyName()}");
_uniqueParameters[p.ParameterType](IL, iteratorArg, currentLocal);
} else if (p.Kind is ParamKind.Has or ParamKind.Not) {
@ -242,6 +265,8 @@ public unsafe class IterActionGenerator
if (info.ParameterType.IsArray) throw new ArgumentException("Arrays are not supported\nParameter: " + info);
if (info.ParameterType.IsPointer) throw new ArgumentException("Pointers are not supported\nParameter: " + info);
if (_globalUniqueParameters.ContainsKey(info.ParameterType))
return new(info, index, ParamKind.GlobalUnique, info.ParameterType, info.ParameterType);
if (_uniqueParameters.ContainsKey(info.ParameterType))
return new(info, index, ParamKind.Unique, info.ParameterType, info.ParameterType);
@ -289,7 +314,9 @@ public unsafe class IterActionGenerator
public enum ParamKind
{
/// <summary> Parameter is not part of terms, handled uniquely, such as Universe and Entity. </summary>
/// <summary> Parameter is not part of terms, handled uniquely, such as Universe. </summary>
GlobalUnique,
/// <summary> Parameter is unique per matched entity, such as EntityRef. </summary>
Unique,
/// <summary> Passed by value. </summary>
Normal,

Loading…
Cancel
Save