private static void Add(Type type, List <ISystemAction>[] groupActions) { ISystemAction systemAction = GetSystemAction(type); LE_Log.Log.Info("ActionRegister", "ActionId: {0} ActionName: {1}", systemAction.Id, systemAction.Name); if ((Attribute.GetCustomAttribute(type, typeof(EntityActionAttribute)) is EntityActionAttribute actionAttribute)) { groupActions[EntityTypeManager.GetEntityTypeId(actionAttribute.Type)].Add(systemAction); }
/// <summary> /// Sends the given <see cref="ISystemAction"/> command. /// </summary> public void SendSystemCommand(ISystemAction systemCommand) { lock (locker) { // Pre-filter incompatible types. if (systemCommand is null) { throw new ArgumentNullException(nameof(systemCommand)); } if (!SystemCommands.Contains(systemCommand.GetType())) { return; } Log.Debug(this, nameof(SendSystemCommand) + ": " + systemCommand); ExecuteSystemCommand?.Invoke(systemCommand); } }
/// <summary> /// Handles the given <see cref="ISystemAction"/> event. /// </summary> public void HandleSystemEvent(ISystemAction systemEvent) { lock (locker) { // Pre-filter incompatible types. if (systemEvent is null) { throw new ArgumentNullException(nameof(systemEvent)); } if (!SystemEvents.Contains(systemEvent.GetType())) { return; } Log.Debug(this, nameof(HandleSystemEvent) + ": " + systemEvent); events.Enqueue(systemEvent); // This must now be called manually from the thread that should perform the operations. //CheckSystems(); } }
/// <summary> /// Checks the <see cref="inputs"/> and <see cref="events"/> queues. /// Determines if the <see cref="CurrentSystem"/> can be advanced. /// Determines if one of the <see cref="Systems"/> can be started. /// </summary> public void CheckSystems() { Log.Debug(this, nameof(CheckSystems) + " inputs: " + inputs.Count + " commands: " + events.Count + "\n" + this); bool transitioned = false; // If proactive transitions are possible, trigger them! if (!transitioned) { HashSet <Tuple <TransitionSystem, ProactiveTransition> > proactives = PossibleProactiveTransitions(); if (proactives.Count > 0) { Log.Debug(this, "Possible proactive transitions: " + string.Join(", ", proactives.Select(x => x.Item1.ModelAction.Name + ": " + x.Item2).ToArray())); Tuple <TransitionSystem, ProactiveTransition> selected = proactives.Random(); Log.Debug(this, "Selected proactive transition: " + selected.Item1.ModelAction.Name + ": " + selected.Item2); IAction generated = ExecuteProactiveTransition(selected); if (generated is ModelAction modelOutput) { SendModelOutput(modelOutput); } else if (generated is ISystemAction systemCommand) { SendSystemCommand(systemCommand); } transitioned = true; } } // If reactive transitions are possible, due to system events, trigger them! if (!transitioned) { if (events.Count > 0) { ISystemAction systemEvent = events.Dequeue(); Log.Debug(this, "Dequeueing system event: " + systemEvent); HashSet <Tuple <TransitionSystem, ReactiveTransition> > reactives = PossibleReactiveTransitions(systemEvent); if (reactives.Count > 0) { Log.Debug(this, "Possible reactive transitions: " + string.Join(", ", reactives.Select(x => x.Item1.ModelAction.Name + ": " + x.Item2).ToArray())); Tuple <TransitionSystem, ReactiveTransition> selected = reactives.Random(); Log.Debug(this, "Selected reactive transition: " + selected.Item1.ModelAction.Name + ": " + selected.Item2); ExecuteReactiveTransition(systemEvent, selected); transitioned = true; } else { // Since all system events are being looped through this, not being able to handle one is not an error per se. (TPE) Log.Warn(this, "No reactive transition possible for system event: " + systemEvent); } } } // If reactive transitions are possible, due to model inputs, trigger them! if (!transitioned) { if (inputs.Count > 0) { ModelAction modelInput = inputs.Dequeue(); Log.Debug(this, "Dequeueing model input: " + modelInput); HashSet <Tuple <TransitionSystem, ReactiveTransition> > reactives = PossibleReactiveTransitions(modelInput); if (reactives.Count > 0) { Log.Debug(this, "Possible reactive transitions: " + string.Join(", ", reactives.Select(x => x.Item1.ModelAction.Name + ": " + x.Item2).ToArray())); Tuple <TransitionSystem, ReactiveTransition> selected = reactives.Random(); Log.Debug(this, "Selected reactive transition: " + selected.Item1.ModelAction.Name + ": " + selected.Item2); ExecuteReactiveTransition(modelInput, selected); transitioned = true; } else { Log.Error(this, "No reactive transition possible for model input: " + modelInput); } } } // If a transition was taken, re-evaluate immediately! if (transitioned) { if (CurrentSystem.CurrentState == CurrentSystem.InitialState) { Log.Debug(this, "System has looped: " + CurrentSystem); CurrentSystem = null; } CheckSystems(); } // If no transition was taken (due to ignored input or event), we still need to check the next input or event. else if (inputs.Count > 0 || events.Count > 0) { CheckSystems(); } }