// Generates the system prefab from the configuration void IParserEventSubscriber.PostApply(ConfigNode node) { //Set of items seen while loading, to prevent duplicate loggers being created (throws IOExceptions) HashSet <String> seen = new HashSet <String>(); // Dictionary of bodies generated List <Body> bodies = new List <Body>(); Logger logger = new Logger(); // Load all of the bodies foreach (ConfigNode bodyNode in node.GetNodes(BODY_NODE_NAME)) { // Grab the name of the body String name = bodyNode.GetValue("name"); if (bodyNode.HasValue("identifier")) { name = bodyNode.GetValue("identifier"); } if (seen.Contains(name)) { Logger.Default.Log("[Kopernicus::PostApply] Skipped duplicate body " + name); continue; //next body, please } seen.Add(name); try { // Create a logfile for this body logger.SetFilename(name + ".Body"); logger.SetAsActive(); // Attempt to create the body Body currentBody = new Body(); Parser.SetState("Kopernicus:currentBody", () => currentBody); Parser.LoadObjectFromConfigurationNode(currentBody, bodyNode, "Kopernicus"); //logs to active logger bodies.Add(currentBody); Events.OnLoaderLoadBody.Fire(currentBody, bodyNode); Logger.Default.Log("[Kopernicus]: Configuration.Loader: Loaded Body: " + currentBody.Name); Parser.ClearState("Kopernicus:currentBody"); // Restore default logger Logger.Default.SetAsActive(); logger.Close(); //implicit flush } catch (Exception e) { logger.LogException(e); logger.Close(); //implicit flush Logger.Default.Log("[Kopernicus]: Configuration.Loader: Failed to load Body: " + name + ": " + e.Message); throw new Exception("Failed to load Body: " + name); } } seen.Clear(); // Load all of the asteroids foreach (ConfigNode asteroidNode in node.GetNodes(ASTEROID_NODE_NAME)) { if (seen.Contains(asteroidNode.GetValue("name"))) { Logger.Default.Log("[Kopernicus::PostApply] Skipped duplicate asteroid " + asteroidNode.GetValue("name")); continue; //next roid, please } seen.Add(asteroidNode.GetValue("name")); try { // Create a logfile for this asteroid logger.SetFilename(asteroidNode.GetValue("name") + ".Asteroid"); logger.SetAsActive(); // Attempt to create the Asteroid Asteroid asteroid = Parser.CreateObjectFromConfigNode <Asteroid>(asteroidNode, "Kopernicus"); //logs to active logger DiscoverableObjects.Asteroids.Add(asteroid); Events.OnLoaderLoadAsteroid.Fire(asteroid, asteroidNode); Logger.Default.Log("[Kopernicus]: Configuration.Loader: Loaded Asteroid: " + asteroid.Name); // Restore default logger Logger.Default.SetAsActive(); logger.Close(); //implicit flush } catch (Exception e) { Logger.Default.Log("[Kopernicus]: Configuration.Loader: Failed to load Asteroid: " + asteroidNode.GetValue("name") + ": " + e.Message); logger.LogException(e); logger.Close(); throw new Exception("Failed to load Asteroid: " + asteroidNode.GetValue("name")); } } seen.Clear(); logger.Close(); // Load all of the PQS Presets foreach (ConfigNode presetNode in node.GetNodes(PRESET_NODE_NAME)) { // Attempt to create the Preset try { PQSCache.PQSPreset preset = new PQSCache.PQSPreset(); preset.Load(presetNode); if (PQSCache.PresetList.presets.Any(p => p.name == preset.name)) { Logger.Default.Log("[Kopernicus]: Configuration.Loader: Failed to load Preset: " + preset.name); continue; } PQSCache.PresetList.presets.Add(preset); // Display name String displayName = preset.name; if (presetNode.HasValue("displayName")) { displayName = presetNode.GetValue("displayName"); } Templates.PresetDisplayNames.Add(displayName); Logger.Default.Log("[Kopernicus]: Configuration.Loader: Loaded Preset: " + preset.name); } catch { Logger.Default.Log("[Kopernicus]: Configuration.Loader: Failed to load Preset: " + presetNode.GetValue("name")); throw new Exception("Failed to load Asteroid: " + presetNode.GetValue("name")); } } // Register UBIs for all bodies CelestialBody[] localBodies = bodies.Select(b => b.GeneratedBody.celestialBody).ToArray(); foreach (Body body in bodies) { // Register the primary UBI if (!String.IsNullOrEmpty(body.Identifier)) { UBI.RegisterUBI(body.CelestialBody, body.Identifier, localBodies: localBodies); } // Register all implemented UBIs foreach (String ubi in body.Implements.SelectMany(u => u.Value).Distinct()) { if (!String.IsNullOrEmpty(ubi)) { UBI.RegisterUBI(body.CelestialBody, ubi, true, localBodies); } } } // Event Events.OnLoaderLoadedAllBodies.Fire(this, node); // Glue all the orbits together in the defined pattern foreach (Body body in bodies) { // If this body is in orbit around another body if (body.Orbit != null) { // Convert a UBI reference into a normal one String referenceBody = UBI.GetName(body.Orbit.ReferenceBody, localBodies); // Get the Body object for the reference body Body parent = bodies.Find(b => b.Name == referenceBody); if (parent == null) { throw new Exception("Reference body for \"" + (body.Identifier ?? body.Name) + "\" could not be found. Missing body name is \"" + body.Orbit.ReferenceBody + "\"."); } // Setup the orbit of the body parent.GeneratedBody.children.Add(body.GeneratedBody); body.GeneratedBody.orbitDriver.referenceBody = parent.GeneratedBody.celestialBody; body.GeneratedBody.orbitDriver.orbit.referenceBody = parent.GeneratedBody.celestialBody; } // Parent the generated body to the PSystem body.GeneratedBody.transform.parent = SystemPrefab.transform; // Delete ghost space centers if (!body.GeneratedBody.celestialBody.isHomeWorld && body.GeneratedBody.pqsVersion != null) { SpaceCenter[] centers = body.GeneratedBody.pqsVersion.GetComponentsInChildren <SpaceCenter>(true); if (centers != null) { foreach (SpaceCenter c in centers) { Object.Destroy(c); } } } // Event Events.OnLoaderFinalizeBody.Fire(body); } // Elect root body SystemPrefab.rootBody = bodies.First(p => p.Orbit == null).GeneratedBody; // Try to find a home world Body home = bodies.FirstOrDefault(p => p.GeneratedBody.celestialBody.isHomeWorld); if (home == null) { throw new Exception("Homeworld body could not be found."); } // Sort by distance from parent (discover how this effects local bodies) Utility.DoRecursive(SystemPrefab.rootBody, body => body.children, body => body.children = body.children .OrderBy(b => b.orbitDriver.orbit.semiMajorAxis * (1 + b.orbitDriver.orbit.eccentricity)).ToList()); // Fix doubled flightGlobals List <Int32> numbers = new List <Int32> { 0, 1 }; Int32 index = bodies.Sum(b => b.GeneratedBody.flightGlobalsIndex); Utility.DoRecursive(SystemPrefab.rootBody, body => body.children, body => { // ReSharper disable AccessToModifiedClosure if (numbers.Contains(body.flightGlobalsIndex)) { body.flightGlobalsIndex = index++; } if (body.celestialBody.isHomeWorld) { body.flightGlobalsIndex = 1; // Kerbin } if (body == SystemPrefab.rootBody) { body.flightGlobalsIndex = 0; // Sun } numbers.Add(body.flightGlobalsIndex); // ReSharper restore AccessToModifiedClosure }); // Event Events.OnLoaderPostApply.Fire(this, node); }
// Generates the system prefab from the configuration void IParserEventSubscriber.PostApply(ConfigNode node) { //Set of items seen while loading, to prevent duplicate loggers being created (throws IOExceptions) HashSet <String> seen = new HashSet <String>(); // Dictionary of bodies generated Dictionary <String, Body> bodies = new Dictionary <String, Body>(); Logger logger = new Logger(); // Load all of the bodies foreach (ConfigNode bodyNode in node.GetNodes(bodyNodeName)) { if (seen.Contains(bodyNode.GetValue("name"))) { Logger.Default.Log("[Kopernicus::PostApply] Skipped duplicate body " + bodyNode.GetValue("name")); continue; //next body, please } else { seen.Add(bodyNode.GetValue("name")); } try { // Create a logfile for this body logger.SetFilename(bodyNode.GetValue("name") + ".Body"); logger.SetAsActive(); // Attempt to create the body currentBody = new Body(); Parser.LoadObjectFromConfigurationNode(currentBody, bodyNode, "Kopernicus"); //logs to active logger bodies.Add(currentBody.name, currentBody); Events.OnLoaderLoadBody.Fire(currentBody, bodyNode); Logger.Default.Log("[Kopernicus]: Configuration.Loader: Loaded Body: " + currentBody.name); // Restore default logger Logger.Default.SetAsActive(); logger.Close(); //implicit flush } catch (Exception e) { logger.LogException(e); logger.Close(); //implicit flush Logger.Default.Log("[Kopernicus]: Configuration.Loader: Failed to load Body: " + bodyNode.GetValue("name") + ": " + e.Message); throw new Exception("Failed to load Body: " + bodyNode.GetValue("name")); } } seen.Clear(); // Event Events.OnLoaderLoadedAllBodies.Fire(this, node); // Load all of the asteroids foreach (ConfigNode asteroidNode in node.GetNodes(asteroidNodeName)) { if (seen.Contains(asteroidNode.GetValue("name"))) { Logger.Default.Log("[Kopernicus::PostApply] Skipped duplicate asteroid " + asteroidNode.GetValue("name")); continue; //next roid, please } else { seen.Add(asteroidNode.GetValue("name")); } try { // Create a logfile for this asteroid logger.SetFilename(asteroidNode.GetValue("name") + ".Asteroid"); logger.SetAsActive(); // Attempt to create the Asteroid Asteroid asteroid = Parser.CreateObjectFromConfigNode <Asteroid>(asteroidNode, "Kopernicus"); //logs to active logger DiscoverableObjects.asteroids.Add(asteroid); Events.OnLoaderLoadAsteroid.Fire(asteroid, asteroidNode); Logger.Default.Log("[Kopernicus]: Configuration.Loader: Loaded Asteroid: " + asteroid.name); // Restore default logger Logger.Default.SetAsActive(); logger.Close(); //implicit flush } catch (Exception e) { Logger.Default.Log("[Kopernicus]: Configuration.Loader: Failed to load Asteroid: " + asteroidNode.GetValue("name") + ": " + e.Message); logger.LogException(e); logger.Close(); throw new Exception("Failed to load Asteroid: " + asteroidNode.GetValue("name")); } } seen.Clear(); logger.Close(); logger = null; // Load all of the PQS Presets foreach (ConfigNode presetNode in node.GetNodes(presetNodeName)) { // Attempt to create the Preset try { PQSCache.PQSPreset preset = new PQSCache.PQSPreset(); preset.Load(presetNode); if (PQSCache.PresetList.presets.Any(p => p.name == preset.name)) { Logger.Default.Log("[Kopernicus]: Configuration.Loader: Failed to load Preset: " + preset.name); continue; } PQSCache.PresetList.presets.Add(preset); // Display name String displayName = preset.name; if (presetNode.HasValue("displayName")) { displayName = presetNode.GetValue("displayName"); } Templates.PresetDisplayNames.Add(displayName); Logger.Default.Log("[Kopernicus]: Configuration.Loader: Loaded Preset: " + preset.name); } catch { Logger.Default.Log("[Kopernicus]: Configuration.Loader: Failed to load Preset: " + presetNode.GetValue("name")); throw new Exception("Failed to load Asteroid: " + presetNode.GetValue("name")); } } // Register UBIs for all bodies CelestialBody[] localBodies = bodies.Values.Select(b => b.generatedBody.celestialBody).ToArray(); foreach (KeyValuePair <String, Body> body in bodies) { // Register the primary UBI if (!String.IsNullOrEmpty(body.Value.identifier)) { UBI.RegisterUBI(body.Value.celestialBody, body.Value.identifier, localBodies: localBodies); } // Register all implemented UBIs foreach (String ubi in body.Value.implements.SelectMany(u => u.Value).Distinct()) { if (!String.IsNullOrEmpty(ubi)) { UBI.RegisterUBI(body.Value.celestialBody, ubi, isAbstract: true, localBodies: localBodies); } } } // Glue all the orbits together in the defined pattern foreach (KeyValuePair <String, Body> body in bodies) { // If this body is in orbit around another body if (body.Value.orbit != null) { // Convert a UBI reference into a normal one String referenceBody = UBI.GetName(body.Value.orbit.referenceBody, localBodies: localBodies); // Get the Body object for the reference body if (!bodies.TryGetValue(referenceBody, out Body parent)) { throw new Exception("Reference body for \"" + body.Key + "\" could not be found. Missing body name is \"" + body.Value.orbit.referenceBody + "\"."); } // Setup the orbit of the body parent.generatedBody.children.Add(body.Value.generatedBody); body.Value.generatedBody.orbitDriver.referenceBody = parent.generatedBody.celestialBody; body.Value.generatedBody.orbitDriver.orbit.referenceBody = parent.generatedBody.celestialBody; } // Parent the generated body to the PSystem body.Value.generatedBody.transform.parent = systemPrefab.transform; // Delete ghost space centers if (!body.Value.generatedBody.celestialBody.isHomeWorld && body.Value.generatedBody.pqsVersion != null) { SpaceCenter[] centers = body.Value.generatedBody.pqsVersion.GetComponentsInChildren <SpaceCenter>(true); if (centers != null) { foreach (SpaceCenter c in centers) { UnityEngine.Object.Destroy(c); } } } // Event Events.OnLoaderFinalizeBody.Fire(body.Value); } // Elect root body systemPrefab.rootBody = bodies.First(p => p.Value.orbit == null).Value.generatedBody; // Try to find a home world Body home = bodies.Values.FirstOrDefault(p => p.generatedBody.celestialBody.isHomeWorld); if (home == null) { throw new Exception("Homeworld body could not be found."); } // Sort by distance from parent (discover how this effects local bodies) RecursivelySortBodies(systemPrefab.rootBody); // Fix doubled flightGlobals List <Int32> numbers = new List <Int32>() { 0, 1 }; Int32 index = bodies.Sum(b => b.Value.generatedBody.flightGlobalsIndex); PatchFGI(ref numbers, ref index, systemPrefab.rootBody); // We're done currentBody.generatedBody = null; // Event Events.OnLoaderPostApply.Fire(this, node); }