using System; using System.Collections.Generic; using System.Linq; using System.Threading.Tasks; using Nullframes.Intrigues.Graph; using Nullframes.Threading; using UnityEngine; namespace Nullframes.Intrigues { public class Ruler : MonoBehaviour { public class RulerFactory { private Ruler Ruler { get; } public List NodeList { get; set; } public HashSet ActiveNodeList { get; set; } public List ErrorList { get; set; } public List ErrorNameList { get; set; } public List WarningList { get; set; } public List WarningNameList { get; set; } public bool IsAsync { get; set; } public readonly TaskCompletionSource _completionSource = new(); public NodeData GetNode(string nodeId) => NodeList.FirstOrDefault(n => n.ID == nodeId); public void ExecuteNode(NodeInfo nodeInfo) => ActiveNodeList.Add(nodeInfo); public void KillNode(NodeInfo nodeInfo) { ActiveNodeList.Remove(nodeInfo); if (ActiveNodeList.Count < 1) { _completionSource.SetResult(true); Dispatcher.Invoke(() => DestroyImmediate(Ruler)); } } public void SetConditionalState(RuleState state) => Ruler.Result = state; public void Kill() { ActiveNodeList.Clear(); Dispatcher.Invoke(() => DestroyImmediate(Ruler)); } public RulerFactory(Ruler ruler) { Ruler = ruler; } } public Actor Conspirator { get; private set; } public Actor Target { get; private set; } private RuleState Result { get; set; } private RulerFactory rulerFactory; private void Awake() { Init(); hideFlags = HideFlags.HideInInspector | HideFlags.HideInHierarchy; // NDebug.Log("Rule executed."); } private void Init() { rulerFactory = new RulerFactory(this); Result = RuleState.Failed; rulerFactory.NodeList = new List(); rulerFactory.ActiveNodeList = new HashSet(); rulerFactory.ErrorList = new List(); rulerFactory.ErrorNameList = new List(); rulerFactory.WarningList = new List(); rulerFactory.WarningNameList = new List(); } public static RuleResult StartGraph(string ruleNameOrId, Actor conspirator, Actor target) { if (conspirator == null) { return (new RuleResult(RuleState.Failed)); } var conditionGroup = (RuleGroupData)IM.IEDatabase.groupDataList.Find(g => g.Title == ruleNameOrId || g.ID == ruleNameOrId); if (conditionGroup == null) { return (new RuleResult(RuleState.Success)); } var conditional = SpawnRule(); foreach (var node in IM.IEDatabase.nodeDataList.Where(n => n.GroupId == conditionGroup.ID)) { conditional.rulerFactory.NodeList.Add(node); } conditional.Conspirator = conspirator; conditional.Target = target; conditional.GoStart(); if (conditional.rulerFactory.ErrorList.Count > 0) { conditional.Result = RuleState.Failed; } return (new RuleResult(conditional.Result, conditional.rulerFactory.ErrorNameList, conditional.rulerFactory.ErrorList, conditional.rulerFactory.WarningNameList, conditional.rulerFactory.WarningList)); } public static async Task StartGraphAsync(string ruleNameOrId, Actor conspirator, Actor target) { return await Task.Run(async () => { if (conspirator == null) { return (new RuleResult(RuleState.Failed)); } var conditionGroup = (RuleGroupData)IM.IEDatabase.groupDataList.Find(g => g.Title == ruleNameOrId || g.ID == ruleNameOrId); if (conditionGroup == null) { return (new RuleResult(RuleState.Success)); } var conditional = await SpawnRuleAsync(); conditional.rulerFactory.IsAsync = true; foreach (var node in IM.IEDatabase.nodeDataList.Where(n => n.GroupId == conditionGroup.ID)) { conditional.rulerFactory.NodeList.Add(node); } conditional.Conspirator = conspirator; conditional.Target = target; await conditional.GoStartAsync(); await conditional.rulerFactory._completionSource.Task; if (conditional.rulerFactory.ErrorList.Count > 0) { conditional.Result = RuleState.Failed; } return (new RuleResult(conditional.Result, conditional.rulerFactory.ErrorNameList, conditional.rulerFactory.ErrorList, conditional.rulerFactory.WarningNameList, conditional.rulerFactory.WarningList)); }); } private void GoStart() { var startNode = rulerFactory.NodeList.FirstOrDefault(n => n is StartRuleData); _ = startNode ?? throw new ArgumentException("Start node cannot be null."); startNode.Run(this, new NodeInfo { RulerFactory = rulerFactory }); } private async Task GoStartAsync() { await Task.Run(() => { var startNode = rulerFactory.NodeList.FirstOrDefault(n => n is StartRuleData); _ = startNode ?? throw new ArgumentException("Start node cannot be null."); startNode.Run(this, new NodeInfo { RulerFactory = rulerFactory }); }); } private static Task SpawnRuleAsync() { return Dispatcher.InvokeAsync(() => { var rulerObject = new GameObject("Ruler") { hideFlags = HideFlags.HideInHierarchy | HideFlags.HideInInspector }; return rulerObject.AddComponent(); }); } private static Ruler SpawnRule() { var rulerObject = new GameObject("Ruler") { hideFlags = HideFlags.HideInHierarchy | HideFlags.HideInInspector }; return rulerObject.AddComponent(); } } public struct RuleResult { public RuleState Result { get; } public List ErrorList { get; } public List WarningList { get; } public List ErrorNameList { get; } public List WarningNameList { get; } public RuleResult(RuleState result, IEnumerable errorNameList, IEnumerable errorList, IEnumerable warningNameList, IEnumerable warningList) { Result = result; ErrorNameList = new List(errorNameList); ErrorList = new List(errorList); WarningNameList = new List(warningNameList); WarningList = new List(warningList); } public RuleResult(RuleState result) { Result = result; ErrorNameList = new List(); ErrorList = new List(); WarningNameList = new List(); WarningList = new List(); } public static implicit operator bool(RuleResult d) => d.Result == RuleState.Success; } }