using NewHorizons.External.Configs; using NewHorizons.Utility; using System; using System.Collections; using System.Collections.Generic; using System.Linq; using Logger = NewHorizons.Utility.Logger; namespace NewHorizons.Handlers { public class PlanetGraphHandler : IEnumerable { public class PlanetNode { public NewHorizonsBody body; public PlanetNode parent; public IEnumerable children; } public class FocalPointNode : PlanetNode { public PlanetNode primary; public PlanetNode secondary; } private PlanetNode _rootNode; public PlanetGraphHandler(IEnumerable iBodies) { var bodies = iBodies.ToArray(); var centers = bodies.Where(b => b.Config.Base.centerOfSolarSystem).ToArray(); if (centers.Length == 1) { _rootNode = ConstructGraph(centers[0], bodies); } else { if (centers.Length == 0 && Main.Instance.CurrentStarSystem == "SolarSystem") { var SunConfig = new PlanetConfig(); SunConfig.name = "Sun"; _rootNode = ConstructGraph(new NewHorizonsBody(SunConfig, Main.Instance), bodies); } else { Logger.LogError("There must be one and only one centerOfSolarSystem!"); } } } public PlanetGraphHandler() { } public static List ConstructStockGraph(NewHorizonsBody[] bodies) { var astroObjects = bodies.Select(x => AstroObjectLocator.GetAstroObject(x.Config.name)).ToArray(); var children = astroObjects.Select(x => AstroObjectLocator.GetChildren(x)).ToArray(); var nodeDict = new Dictionary(); //Logger.Log($"AstroObjects [{String.Join(", ", astroObjects.ToList())}]"); var childBodyDict = new Dictionary>(); // Mmmm O(N^2) moment but this is limited to stock bodies for (int i = 0; i < bodies.Length; i++) { var ao = astroObjects[i]; var childBodies = new List(); for (int j = 0; j < bodies.Length; j++) { if (i == j) continue; // If the list of children for current object (i) containes the ao for body at index j if (children[i] != null && astroObjects[j]?.gameObject != null && children[i].Contains(astroObjects[j].gameObject)) { childBodies.Add(bodies[j]); } // If uh the primary body straight up matches the name else if (bodies[j].Config.Orbit.PrimaryBody == bodies[i].Config.name) { childBodies.Add(bodies[j]); } // If finding the astro object of the primary body matches the astro object but not null bc if its a new planet it'll always be null else if (AstroObjectLocator.GetAstroObject(bodies[j].Config.Orbit.PrimaryBody) == astroObjects[i] && astroObjects[i] != null) { childBodies.Add(bodies[j]); } } childBodyDict.Add(bodies[i], childBodies); //Logger.Log($"Children of [{ao}] : [{String.Join(", ", childBodyDict[bodies[i]].Select(x => x.Config.Name).ToList())}]"); nodeDict.Add(bodies[i], new PlanetNode { body = bodies[i] }); } // Set their children/parents foreach (var body in bodies) { nodeDict[body].children = childBodyDict[body].Select(x => nodeDict[x]); foreach (var child in nodeDict[body].children) { child.parent = nodeDict[body]; } } // Verifying it worked foreach (var node in nodeDict.Values.ToList()) { var childrenString = String.Join(", ", node.children.Select(x => x?.body?.Config?.name).ToList()); Logger.Log($"NODE: [{node?.body?.Config?.name}], [{node?.parent?.body?.Config?.name}], [{childrenString}]"); } // Return all tree roots (no parents) return nodeDict.Values.Where(x => x.parent == null).Select(x => new PlanetGraphHandler() { _rootNode = x }).ToList(); } private static bool DetermineIfChildOfFocal(NewHorizonsBody body, FocalPointNode node) { var name = body.Config.name.ToLower(); var primary = (body.Config.Orbit?.PrimaryBody ?? "").ToLower(); var primaryName = node.primary.body.Config.name.ToLower(); var secondaryName = node.secondary.body.Config.name.ToLower(); return name != primaryName && name != secondaryName && (primary == node.body.Config.name.ToLower() || primary == primaryName || primary == secondaryName); } private static PlanetNode ConstructGraph(NewHorizonsBody body, NewHorizonsBody[] bodies) { if (body.Config.FocalPoint == null) { return new PlanetNode { body = body, children = bodies .Where(b => string.Equals(b.Config.Orbit.PrimaryBody, body.Config.name, StringComparison.CurrentCultureIgnoreCase)) .Select(b => ConstructGraph(b, bodies)) }; } else { var newNode = new FocalPointNode { body = body }; foreach (var child in bodies) { if (string.Equals(child.Config.name, body.Config.FocalPoint.primary, StringComparison.CurrentCultureIgnoreCase)) { newNode.primary = new PlanetNode { body = child, children = new List() }; } else if (string.Equals(child.Config.name, body.Config.FocalPoint.secondary, StringComparison.CurrentCultureIgnoreCase)) { newNode.secondary = new PlanetNode { body = child, children = new List() }; } } newNode.children = bodies .Where(b => DetermineIfChildOfFocal(b, newNode)) .Select(b => ConstructGraph(b, bodies)); return newNode; } } public IEnumerator GetEnumerator() { yield return _rootNode; var queue = new Queue(_rootNode.children); while (queue.Count != 0) { var node = queue.Dequeue(); yield return node; foreach (var child in node.children) { queue.Enqueue(child); } } } IEnumerator IEnumerable.GetEnumerator() { return GetEnumerator(); } } }