public static void Clear() { if (GlobalStatus == Status.Processing) { Dbg.Err($"Attempting to clear the environment while the world is in {GlobalStatus} state; should not be {Status.Processing} state"); // but we'll do it anyway } ComponentDecDict.Clear(); ComponentIndexDict.Clear(); Entities.Clear(); PhaseEndActions.Clear(); Singletons = null; ActiveSystem = null; ActiveEntity = null; GlobalStatus = Status.Uninitialized; }
public static void Process(ProcessDec process) { if (GlobalStatus != Status.Idle) { Dbg.Err($"Trying to run process while the world is in {GlobalStatus} state; should be {Status.Idle} state"); } GlobalStatus = Status.Processing; foreach (var system in process.order) { try { ActiveSystem = system; var executeMethod = system.type.GetMethod("Execute", System.Reflection.BindingFlags.Public | System.Reflection.BindingFlags.Static); var methodParameters = executeMethod.GetParameters(); var activeParameters = new object[methodParameters.Length]; for (int i = 0; i < methodParameters.Length; ++i) { if (methodParameters[i].ParameterType == typeof(Ghi.Entity)) { continue; } ComponentDec component = ComponentDecDict[methodParameters[i].ParameterType]; if (component != null && component.singleton) { if (system.permissions) { if (!system.accessibleSingletonsRO[component.index]) { var err = $"{system}: Attempted to use singleton {component} without any permission"; Dbg.Err(err); throw new PermissionException(err); } if (!system.accessibleSingletonsRW[component.index] && !methodParameters[i].Name.EndsWith("_ro")) { Dbg.Wrn($"{system}: Using read-only singleton {component} without \"_ro\" suffix"); } } activeParameters[i] = Singletons[component.index]; } } if (system.iterate.Count == 0) { // No-iteration pathway try { executeMethod.Invoke(null, activeParameters); } catch (Exception e) { Dbg.Ex(e); } } else { // Entity-iteration pathway // Doing this once per run is silly, it should be precalculated int[] requiredIndices = system.iterate.Keys.Select(comp => comp.index).OrderBy(x => x).ToArray(); foreach (var entity in List) { ActiveEntity = entity; bool valid = true; for (int k = 0; k < requiredIndices.Length; ++k) { if (entity.components[requiredIndices[k]] == null) { valid = false; break; } } if (!valid) { continue; } for (int i = 0; i < methodParameters.Length; ++i) { if (methodParameters[i].ParameterType == typeof(Entity)) { activeParameters[i] = entity; continue; } ComponentDec component = ComponentDecDict[methodParameters[i].ParameterType]; if (component != null && !component.singleton) { if (system.permissions) { var permission = system.iterate.TryGetValue(component); if (permission == SystemDec.Permissions.None) { Dbg.Err($"{system}: Attempted to use component {component} without any permission"); } if (permission == SystemDec.Permissions.ReadOnly && !methodParameters[i].Name.EndsWith("_ro")) { Dbg.Wrn($"{system}: Using read-only component {component} without \"_ro\" suffix"); } } activeParameters[i] = entity.components[component.index]; } } try { executeMethod.Invoke(null, activeParameters); } catch (Exception e) { Dbg.Ex(e); } } ActiveEntity = null; } } catch (Exception e) { Dbg.Ex(e); } } // clean up everything, even the things that should have already been cleaned up, just in case ActiveSystem = null; ActiveEntity = null; GlobalStatus = Status.Idle; foreach (var action in PhaseEndActions) { action(); } PhaseEndActions.Clear(); }