private void GenerateStrandedKerbal(int bodyID, string kerbalName) { //Add kerbal to crew roster. DarkLog.Debug("Spawning missing kerbal, name: " + kerbalName); ProtoCrewMember pcm = HighLogic.CurrentGame.CrewRoster.GetNewKerbal(ProtoCrewMember.KerbalType.Unowned); pcm.name = kerbalName; pcm.rosterStatus = ProtoCrewMember.RosterStatus.Assigned; //Create protovessel uint newPartID = ShipConstruction.GetUniqueFlightID(HighLogic.CurrentGame.flightState); CelestialBody contractBody = FlightGlobals.Bodies[bodyID]; //Atmo: 10km above atmo, to half the planets radius out. //Non-atmo: 30km above ground, to half the planets radius out. double minAltitude = FinePrint.Utilities.CelestialUtilities.GetMinimumOrbitalAltitude(contractBody, 1.1f); double maxAltitude = minAltitude + contractBody.Radius * 0.5; Orbit strandedOrbit = Orbit.CreateRandomOrbitAround(FlightGlobals.Bodies[bodyID], minAltitude, maxAltitude); ConfigNode[] kerbalPartNode = new ConfigNode[1]; ProtoCrewMember[] partCrew = new ProtoCrewMember[1]; partCrew[0] = pcm; kerbalPartNode[0] = ProtoVessel.CreatePartNode("kerbalEVA", newPartID, partCrew); ConfigNode protoVesselNode = ProtoVessel.CreateVesselNode(kerbalName, VesselType.EVA, strandedOrbit, 0, kerbalPartNode); ConfigNode discoveryNode = ProtoVessel.CreateDiscoveryNode(DiscoveryLevels.Unowned, UntrackedObjectClass.A, double.PositiveInfinity, double.PositiveInfinity); ProtoVessel protoVessel = new ProtoVessel(protoVesselNode, HighLogic.CurrentGame); protoVessel.discoveryInfo = discoveryNode; //It's not supposed to be infinite, but you're crazy if you think I'm going to decipher the values field of the rescue node. HighLogic.CurrentGame.flightState.protoVessels.Add(protoVessel); }
/// <summary> /// Generates tracking station info appropriate for the chosen set. /// </summary> /// /// <param name="group">The set to which the asteroid belongs.</param> /// <param name="size">The asteroid's size class.</param> /// <returns>A ConfigNode storing the asteroid's DiscoveryInfo object.</returns> /// /// <exception cref="System.InvalidOperationException">Thrown if <c>group</c> cannot /// generate valid data. The program state will be unchanged in the event of an /// exception.</exception> /// <exception cref="System.NullReferenceException">Thrown if <c>group</c> is /// null.</exception> private static ConfigNode makeDiscoveryInfo(AsteroidSet group, UntrackedObjectClass size) { Tuple <double, double> lifetimes = group.drawTrackingTime(); ConfigNode trackingInfo = ProtoVessel.CreateDiscoveryNode( DiscoveryLevels.Presence, size, lifetimes.Item1, lifetimes.Item2); return(trackingInfo); }
protected override void OnAccepted() { // Actually spawn the kerbals in the game world! foreach (KerbalData kerbal in kerbals) { LoggingUtil.LogVerbose(this, "Spawning a Kerbal named " + kerbal.name); if (kerbal.altitude == null) { kerbal.altitude = LocationUtil.TerrainHeight(kerbal.latitude, kerbal.longitude, kerbal.body); } // Set additional info for landed kerbals if (kerbal.landed) { Vector3d pos = kerbal.body.GetWorldSurfacePosition(kerbal.latitude, kerbal.longitude, kerbal.altitude.Value); kerbal.orbit = new Orbit(0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, kerbal.body); kerbal.orbit.UpdateFromStateVectors(pos, kerbal.body.getRFrmVel(pos), kerbal.body, Planetarium.GetUniversalTime()); LoggingUtil.LogVerbose(typeof(SpawnKerbal), "kerbal generated, orbit = " + kerbal.orbit); } uint flightId = ShipConstruction.GetUniqueFlightID(HighLogic.CurrentGame.flightState); // Create crew member array ProtoCrewMember[] crewArray = new ProtoCrewMember[1]; crewArray[0] = kerbal.crewMember; // Create part nodes ConfigNode[] partNodes = new ConfigNode[1]; partNodes[0] = ProtoVessel.CreatePartNode("kerbalEVA", flightId, crewArray); // Create additional nodes ConfigNode[] additionalNodes = new ConfigNode[1]; DiscoveryLevels discoveryLevel = kerbal.owned ? DiscoveryLevels.Owned : DiscoveryLevels.Unowned; additionalNodes[0] = ProtoVessel.CreateDiscoveryNode(discoveryLevel, UntrackedObjectClass.A, contract.TimeDeadline, contract.TimeDeadline); // Create the config node representation of the ProtoVessel ConfigNode protoVesselNode = ProtoVessel.CreateVesselNode(kerbal.name, VesselType.EVA, kerbal.orbit, 0, partNodes, additionalNodes); // Additional seetings for a landed Kerbal if (kerbal.landed) { // Create the config node representation of the ProtoVessel protoVesselNode.SetValue("sit", Vessel.Situations.LANDED.ToString()); protoVesselNode.SetValue("landed", true.ToString()); protoVesselNode.SetValue("lat", kerbal.latitude.ToString()); protoVesselNode.SetValue("lon", kerbal.longitude.ToString()); protoVesselNode.SetValue("alt", kerbal.altitude.ToString()); } // Add vessel to the game HighLogic.CurrentGame.AddVessel(protoVesselNode); } }
private ConfigNode createAnomalyVessel(WBISpaceAnomaly anomaly) { // Generate vessel name string vesselName = DiscoverableObjectsUtil.GenerateAsteroidName(); string prefix = Localizer.Format("#autoLOC_6001923"); prefix = prefix.Replace(" <<1>>", ""); vesselName = vesselName.Replace(prefix, "UNK-"); vesselName = vesselName.Replace("- ", "-"); // Generate orbit Orbit orbit = generateOrbit(anomaly); // Create part nodes ConfigNode[] partNodes = new ConfigNode[] { ProtoVessel.CreatePartNode(anomaly.partName, 0) }; // Determine lifetime double minLifetime = anomaly.minLifetime; double maxLifetime = anomaly.maxLifetime; if (minLifetime < 0) { minLifetime = double.MaxValue; maxLifetime = double.MaxValue; } // Setup object class UntrackedObjectClass objectClass = UntrackedObjectClass.A; Enum.TryParse(anomaly.sizeClass, out objectClass); // Create discovery and additional nodes. ConfigNode discoveryNode = ProtoVessel.CreateDiscoveryNode(DiscoveryLevels.Presence, objectClass, minLifetime, maxLifetime); ConfigNode[] additionalNodes = new ConfigNode[] { new ConfigNode("ACTIONGROUPS"), discoveryNode }; // Create vessel node ConfigNode vesselNode = ProtoVessel.CreateVesselNode(vesselName, VesselType.SpaceObject, orbit, 0, partNodes, additionalNodes); // Add vessel node to the game. HighLogic.CurrentGame.AddVessel(vesselNode); // Get vessel ID if (vesselNode.HasValue("persistentId")) { anomaly.vesselId = vesselNode.GetValue("persistentId"); } return(vesselNode); }
/// <summary> /// Generates tracking station info appropriate for the chosen set. /// </summary> /// /// <param name="group">The set to which the asteroid belongs.</param> /// <returns>A ConfigNode storing the asteroid's DiscoveryInfo object.</returns> /// /// <exception cref="System.InvalidOperationException">Thrown if <c>group</c> cannot /// generate valid data. The program state will be unchanged in the event of an /// exception.</exception> /// <exception cref="System.NullReferenceException">Thrown if <c>group</c> is /// null.</exception> private static ConfigNode makeDiscoveryInfo(AsteroidSet group) { Pair <float, float> trackTimes = AsteroidManager.getOptions().getUntrackedTimes(); double lifetime = UnityEngine.Random.Range(trackTimes.first, trackTimes.second) * SECONDS_PER_EARTH_DAY; double maxLifetime = trackTimes.second * SECONDS_PER_EARTH_DAY; UntrackedObjectClass size = (UntrackedObjectClass)(int) (stockSizeCurve.Evaluate(UnityEngine.Random.Range(0.0f, 1.0f)) * Enum.GetNames(typeof(UntrackedObjectClass)).Length); ConfigNode trackingInfo = ProtoVessel.CreateDiscoveryNode( DiscoveryLevels.Presence, size, lifetime, maxLifetime); return(trackingInfo); }
private static void GenerateStrandedKerbal(int bodyId, string kerbalName) { //Add kerbal to crew roster. LunaLog.Log($"[LMP]: Spawning missing kerbal, Name: {kerbalName}"); var pcm = HighLogic.CurrentGame.CrewRoster.GetNewKerbal(ProtoCrewMember.KerbalType.Unowned); pcm.ChangeName(kerbalName); pcm.rosterStatus = ProtoCrewMember.RosterStatus.Assigned; //Create protovessel var newPartId = ShipConstruction.GetUniqueFlightID(HighLogic.CurrentGame.flightState); var contractBody = FlightGlobals.Bodies[bodyId]; //Atmo: 10km above atmo, to half the planets radius out. //Non-atmo: 30km above ground, to half the planets radius out. var minAltitude = CelestialUtilities.GetMinimumOrbitalDistance(contractBody, 1.1f); var maxAltitude = minAltitude + contractBody.Radius * 0.5; var strandedOrbit = Orbit.CreateRandomOrbitAround(FlightGlobals.Bodies[bodyId], minAltitude, maxAltitude); var kerbalPartNode = new[] { ProtoVessel.CreatePartNode("kerbalEVA", newPartId, pcm) }; var protoVesselNode = ProtoVessel.CreateVesselNode(kerbalName, VesselType.EVA, strandedOrbit, 0, kerbalPartNode); //It's not supposed to be infinite, but you're crazy if you think I'm going to decipher the values field of the rescue node. var discoveryNode = ProtoVessel.CreateDiscoveryNode(DiscoveryLevels.Unowned, UntrackedObjectClass.A, double.PositiveInfinity, double.PositiveInfinity); var protoVessel = new ProtoVessel(protoVesselNode, HighLogic.CurrentGame) { discoveryInfo = discoveryNode }; HighLogic.CurrentGame.flightState.protoVessels.Add(protoVessel); }
protected override void OnAccepted() { // Actually spawn the kerbals in the game world! foreach (KerbalData kerbal in kerbals) { uint flightId = ShipConstruction.GetUniqueFlightID(HighLogic.CurrentGame.flightState); // Create crew member array ProtoCrewMember[] crewArray = new ProtoCrewMember[1]; crewArray[0] = kerbal.crewMember; // Create part nodes ConfigNode[] partNodes = new ConfigNode[1]; partNodes[0] = ProtoVessel.CreatePartNode("kerbalEVA", flightId, crewArray); // Create additional nodes ConfigNode[] additionalNodes = new ConfigNode[1]; DiscoveryLevels discoveryLevel = kerbal.owned ? DiscoveryLevels.Owned : DiscoveryLevels.Unowned; additionalNodes[0] = ProtoVessel.CreateDiscoveryNode(discoveryLevel, UntrackedObjectClass.A, contract.TimeDeadline, contract.TimeDeadline); // Create the config node representation of the ProtoVessel ConfigNode protoVesselNode = ProtoVessel.CreateVesselNode(kerbal.name, VesselType.EVA, kerbal.orbit, 0, partNodes, additionalNodes); // Additional seetings for a landed Kerbal if (kerbal.landed) { // Create the config node representation of the ProtoVessel protoVesselNode.SetValue("sit", Vessel.Situations.LANDED.ToString()); protoVesselNode.SetValue("landed", true.ToString()); protoVesselNode.SetValue("lat", kerbal.latitude.ToString()); protoVesselNode.SetValue("lon", kerbal.longitude.ToString()); protoVesselNode.SetValue("alt", kerbal.altitude.ToString()); } // Add vessel to the game HighLogic.CurrentGame.AddVessel(protoVesselNode); } }
public void SpawnAsteroid(Asteroid asteroid, UInt32 seed) { // Create Default Orbit Orbit orbit = null; CelestialBody body = null; // Select Orbit Type Int32 type = Random.Range(0, 3); if (type == 0 && asteroid.Location.Around.Count != 0) { // Around Location.AroundLoader[] around = GetProbabilityList(asteroid.Location.Around, asteroid.Location.Around.Select(a => a.Probability.Value).ToList()).ToArray(); Location.AroundLoader loader = around[Random.Range(0, around.Length)]; body = UBI.GetBody(loader.Body); if (!body) { return; } if (loader.Reached && !ReachedBody(body)) { return; } orbit = new Orbit { referenceBody = body, eccentricity = loader.Eccentricity, semiMajorAxis = loader.SemiMajorAxis, inclination = loader.Inclination, LAN = loader.LongitudeOfAscendingNode, argumentOfPeriapsis = loader.ArgumentOfPeriapsis, meanAnomalyAtEpoch = loader.MeanAnomalyAtEpoch, epoch = loader.Epoch }; orbit.Init(); } else if (type == 1 && asteroid.Location.Nearby.Count != 0) { // Nearby Location.NearbyLoader[] nearby = GetProbabilityList(asteroid.Location.Nearby, asteroid.Location.Nearby.Select(a => a.Probability.Value).ToList()).ToArray(); Location.NearbyLoader loader = nearby[Random.Range(0, nearby.Length)]; body = UBI.GetBody(loader.Body); if (!body) { return; } if (loader.Reached && !ReachedBody(body)) { return; } orbit = new Orbit { eccentricity = body.orbit.eccentricity + loader.Eccentricity, semiMajorAxis = body.orbit.semiMajorAxis * loader.SemiMajorAxis, inclination = body.orbit.inclination + loader.Inclination, LAN = body.orbit.LAN * loader.LongitudeOfAscendingNode, argumentOfPeriapsis = body.orbit.argumentOfPeriapsis * loader.ArgumentOfPeriapsis, meanAnomalyAtEpoch = body.orbit.meanAnomalyAtEpoch * loader.MeanAnomalyAtEpoch, epoch = body.orbit.epoch, referenceBody = body.orbit.referenceBody }; orbit.Init(); } else if (type == 2 && asteroid.Location.Flyby.Count != 0) { // Flyby Location.FlybyLoader[] flyby = GetProbabilityList(asteroid.Location.Flyby, asteroid.Location.Flyby.Select(a => a.Probability.Value).ToList()).ToArray(); Location.FlybyLoader loader = flyby[Random.Range(0, flyby.Length)]; body = UBI.GetBody(loader.Body); if (!body) { return; } if (loader.Reached && !ReachedBody(body)) { return; } orbit = Orbit.CreateRandomOrbitFlyBy(body, Random.Range(loader.MinDuration, loader.MaxDuration)); } // Check if (orbit == null) { Debug.Log("[Kopernicus] No new objects this time. (Probability is " + asteroid.Probability.Value + "%)"); return; } // Name String asteroidName = DiscoverableObjectsUtil.GenerateAsteroidName(); // Lifetime Double lifetime = Random.Range(asteroid.MinUntrackedLifetime, asteroid.MaxUntrackedLifetime) * 24d * 60d * 60d; Double maxLifetime = asteroid.MaxUntrackedLifetime * 24d * 60d * 60d; // Size UntrackedObjectClass size = (UntrackedObjectClass)(Int32)(asteroid.Size.Evaluate(Random.Range(0f, 1f)) * Enum.GetNames(typeof(UntrackedObjectClass)).Length); // Spawn ConfigNode vessel = null; vessel = ProtoVessel.CreateVesselNode( asteroidName, VesselType.SpaceObject, orbit, 0, new[] { ProtoVessel.CreatePartNode( "PotatoRoid", seed ) }, new ConfigNode("ACTIONGROUPS"), ProtoVessel.CreateDiscoveryNode( DiscoveryLevels.Presence, size, lifetime, maxLifetime ) ); OverrideNode(ref vessel, asteroid.Vessel); ProtoVessel protoVessel = new ProtoVessel(vessel, HighLogic.CurrentGame); if (asteroid.UniqueName && FlightGlobals.Vessels.Count(v => v.vesselName == protoVessel.vesselName) != 0) { return; } Kopernicus.Events.OnRuntimeUtilitySpawnAsteroid.Fire(asteroid, protoVessel); protoVessel.Load(HighLogic.CurrentGame.flightState); GameEvents.onNewVesselCreated.Fire(protoVessel.vesselRef); GameEvents.onAsteroidSpawned.Fire(protoVessel.vesselRef); Debug.Log("[Kopernicus] New object found near " + body.name + ": " + protoVessel.vesselName + "!"); }
protected override void OnAccepted() { // Actually spawn the kerbals in the game world! foreach (KerbalData kd in kerbals) { LoggingUtil.LogVerbose(this, "Spawning a Kerbal named " + kd.kerbal.name); // Generate the ProtoCrewMember kd.kerbal.GenerateKerbal(); if (kd.altitude == null) { kd.altitude = LocationUtil.TerrainHeight(kd.latitude, kd.longitude, kd.body); } // Set additional info for landed kerbals if (kd.landed) { Vector3d pos = kd.body.GetWorldSurfacePosition(kd.latitude, kd.longitude, kd.altitude.Value); kd.orbit = new Orbit(0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, kd.body); kd.orbit.UpdateFromStateVectors(pos, kd.body.getRFrmVel(pos), kd.body, Planetarium.GetUniversalTime()); LoggingUtil.LogVerbose(typeof(SpawnKerbal), "kerbal generated, orbit = " + kd.orbit); } else { // Update the reference body in the orbit kd.orbit.referenceBody = kd.body; } uint flightId = ShipConstruction.GetUniqueFlightID(HighLogic.CurrentGame.flightState); // Create crew member array ProtoCrewMember[] crewArray = new ProtoCrewMember[1]; crewArray[0] = kd.kerbal.pcm; // Create part nodes ConfigNode[] partNodes = new ConfigNode[1]; partNodes[0] = ProtoVessel.CreatePartNode(kd.kerbal.gender == ProtoCrewMember.Gender.Male ? "kerbalEVA" : "kerbalEVAfemale", flightId, crewArray); // Create additional nodes ConfigNode[] additionalNodes = new ConfigNode[1]; DiscoveryLevels discoveryLevel = kd.owned ? DiscoveryLevels.Owned : DiscoveryLevels.Unowned; additionalNodes[0] = ProtoVessel.CreateDiscoveryNode(discoveryLevel, UntrackedObjectClass.A, contract.TimeDeadline, contract.TimeDeadline); // Create the config node representation of the ProtoVessel ConfigNode protoVesselNode = ProtoVessel.CreateVesselNode(kd.kerbal.name, VesselType.EVA, kd.orbit, 0, partNodes, additionalNodes); // Additional seetings for a landed Kerbal if (kd.landed) { bool splashed = kd.altitude.Value < 0.001 && kd.body.ocean; // Add a bit of height for landed kerbals if (!splashed) { kd.altitude += 0.2; } // Figure out the appropriate rotation Vector3d norm = kd.body.GetRelSurfaceNVector(kd.latitude, kd.longitude); Quaternion normal = Quaternion.LookRotation(new Vector3((float)norm.x, (float)norm.y, (float)norm.z)); Quaternion rotation = Quaternion.FromToRotation(Vector3.up, Vector3.forward); rotation = rotation * Quaternion.AngleAxis(kd.heading + 180, Vector3.up); // Create the config node representation of the ProtoVessel protoVesselNode.SetValue("sit", (splashed ? Vessel.Situations.SPLASHED : Vessel.Situations.LANDED).ToString()); protoVesselNode.SetValue("landed", (!splashed).ToString()); protoVesselNode.SetValue("splashed", splashed.ToString()); protoVesselNode.SetValue("lat", kd.latitude.ToString()); protoVesselNode.SetValue("lon", kd.longitude.ToString()); protoVesselNode.SetValue("alt", kd.altitude.ToString()); protoVesselNode.SetValue("rot", KSPUtil.WriteQuaternion(normal * rotation)); // Set the normal vector relative to the surface Vector3 nrm = (rotation * Vector3.forward); protoVesselNode.SetValue("nrm", nrm.x + "," + nrm.y + "," + nrm.z); } // Add vessel to the game HighLogic.CurrentGame.AddVessel(protoVesselNode); } }
protected bool CreateVessels() { if (vesselsCreated) { return(false); } String gameDataDir = KSPUtil.ApplicationRootPath; gameDataDir = gameDataDir.Replace("\\", "/"); if (!gameDataDir.EndsWith("/")) { gameDataDir += "/"; } gameDataDir += "GameData"; // Spawn the vessel in the game world foreach (VesselData vesselData in vessels) { LoggingUtil.LogVerbose(this, "Spawning a vessel named '" + vesselData.name + "'"); // Set additional info for landed vessels bool landed = false; if (!vesselData.orbiting) { landed = true; if (vesselData.altitude == null) { vesselData.altitude = LocationUtil.TerrainHeight(vesselData.latitude, vesselData.longitude, vesselData.body); } Vector3d pos = vesselData.body.GetWorldSurfacePosition(vesselData.latitude, vesselData.longitude, vesselData.altitude.Value); vesselData.orbit = new Orbit(0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, vesselData.body); vesselData.orbit.UpdateFromStateVectors(pos, vesselData.body.getRFrmVel(pos), vesselData.body, Planetarium.GetUniversalTime()); } else { vesselData.orbit.referenceBody = vesselData.body; } ConfigNode[] partNodes; UntrackedObjectClass sizeClass; ShipConstruct shipConstruct = null; if (!string.IsNullOrEmpty(vesselData.craftURL)) { // Save the current ShipConstruction ship, otherwise the player will see the spawned ship next time they enter the VAB! ConfigNode currentShip = ShipConstruction.ShipConfig; shipConstruct = ShipConstruction.LoadShip(gameDataDir + "/" + vesselData.craftURL); if (shipConstruct == null) { LoggingUtil.LogError(this, "ShipConstruct was null when tried to load '" + vesselData.craftURL + "' (usually this means the file could not be found)."); continue; } // Restore ShipConstruction ship ShipConstruction.ShipConfig = currentShip; // Set the name if (string.IsNullOrEmpty(vesselData.name)) { vesselData.name = shipConstruct.shipName; } // Set some parameters that need to be at the part level uint missionID = (uint)Guid.NewGuid().GetHashCode(); uint launchID = HighLogic.CurrentGame.launchID++; foreach (Part p in shipConstruct.parts) { p.flightID = ShipConstruction.GetUniqueFlightID(HighLogic.CurrentGame.flightState); p.missionID = missionID; p.launchID = launchID; p.flagURL = vesselData.flagURL ?? HighLogic.CurrentGame.flagURL; // Had some issues with this being set to -1 for some ships - can't figure out // why. End result is the vessel exploding, so let's just set it to a positive // value. p.temperature = 1.0; } foreach (CrewData cd in vesselData.crew) { bool success = false; // Find a seat for the crew Part part = shipConstruct.parts.Find(p => p.protoModuleCrew.Count < p.CrewCapacity); // Add the crew member if (part != null) { // Create the ProtoCrewMember ProtoCrewMember crewMember = HighLogic.CurrentGame.CrewRoster.GetNewKerbal(ProtoCrewMember.KerbalType.Unowned); if (cd.gender != null) { crewMember.gender = cd.gender.Value; } if (cd.name != null) { crewMember.name = cd.name; } // Add them to the part success = part.AddCrewmemberAt(crewMember, part.protoModuleCrew.Count); } if (!success) { LoggingUtil.LogWarning(this, "Unable to add crew to vessel named '" + vesselData.name + "'. Perhaps there's no room?"); break; } } // Create a dummy ProtoVessel, we will use this to dump the parts to a config node. // We can't use the config nodes from the .craft file, because they are in a // slightly different format than those required for a ProtoVessel (seriously // Squad?!?). ConfigNode empty = new ConfigNode(); ProtoVessel dummyProto = new ProtoVessel(empty, null); Vessel dummyVessel = new Vessel(); dummyVessel.parts = shipConstruct.parts; dummyProto.vesselRef = dummyVessel; // Create the ProtoPartSnapshot objects and then initialize them foreach (Part p in shipConstruct.parts) { dummyProto.protoPartSnapshots.Add(new ProtoPartSnapshot(p, dummyProto)); } foreach (ProtoPartSnapshot p in dummyProto.protoPartSnapshots) { p.storePartRefs(); } // Create the ship's parts partNodes = dummyProto.protoPartSnapshots.Select <ProtoPartSnapshot, ConfigNode>(GetNodeForPart).ToArray(); // Estimate an object class, numbers are based on the in game description of the // size classes. float size = shipConstruct.shipSize.magnitude / 2.0f; if (size < 4.0f) { sizeClass = UntrackedObjectClass.A; } else if (size < 7.0f) { sizeClass = UntrackedObjectClass.B; } else if (size < 12.0f) { sizeClass = UntrackedObjectClass.C; } else if (size < 18.0f) { sizeClass = UntrackedObjectClass.D; } else { sizeClass = UntrackedObjectClass.E; } } else { // Create crew member array ProtoCrewMember[] crewArray = new ProtoCrewMember[vesselData.crew.Count]; int i = 0; foreach (CrewData cd in vesselData.crew) { // Create the ProtoCrewMember ProtoCrewMember crewMember = HighLogic.CurrentGame.CrewRoster.GetNewKerbal(ProtoCrewMember.KerbalType.Unowned); if (cd.name != null) { crewMember.name = cd.name; } crewArray[i++] = crewMember; } // Create part nodes uint flightId = ShipConstruction.GetUniqueFlightID(HighLogic.CurrentGame.flightState); partNodes = new ConfigNode[1]; partNodes[0] = ProtoVessel.CreatePartNode(vesselData.craftPart.name, flightId, crewArray); // Default the size class sizeClass = UntrackedObjectClass.A; // Set the name if (string.IsNullOrEmpty(vesselData.name)) { vesselData.name = vesselData.craftPart.name; } } // Create additional nodes ConfigNode[] additionalNodes = new ConfigNode[1]; DiscoveryLevels discoveryLevel = vesselData.owned ? DiscoveryLevels.Owned : DiscoveryLevels.Unowned; additionalNodes[0] = ProtoVessel.CreateDiscoveryNode(discoveryLevel, sizeClass, contract.TimeDeadline, contract.TimeDeadline); // Create the config node representation of the ProtoVessel ConfigNode protoVesselNode = ProtoVessel.CreateVesselNode(vesselData.name, vesselData.vesselType, vesselData.orbit, 0, partNodes, additionalNodes); // Additional seetings for a landed vessel if (!vesselData.orbiting) { Vector3d norm = vesselData.body.GetRelSurfaceNVector(vesselData.latitude, vesselData.longitude); double terrainHeight = 0.0; if (vesselData.body.pqsController != null) { terrainHeight = vesselData.body.pqsController.GetSurfaceHeight(norm) - vesselData.body.pqsController.radius; } bool splashed = landed && terrainHeight < 0.001; // Create the config node representation of the ProtoVessel // Note - flying is experimental, and so far doesn't work protoVesselNode.SetValue("sit", (splashed ? Vessel.Situations.SPLASHED : landed ? Vessel.Situations.LANDED : Vessel.Situations.FLYING).ToString()); protoVesselNode.SetValue("landed", (landed && !splashed).ToString()); protoVesselNode.SetValue("splashed", splashed.ToString()); protoVesselNode.SetValue("lat", vesselData.latitude.ToString()); protoVesselNode.SetValue("lon", vesselData.longitude.ToString()); protoVesselNode.SetValue("alt", vesselData.altitude.ToString()); protoVesselNode.SetValue("landedAt", vesselData.body.name); // Figure out the additional height to subtract float lowest = float.MaxValue; if (shipConstruct != null) { foreach (Part p in shipConstruct.parts) { foreach (Collider collider in p.GetComponentsInChildren <Collider>()) { if (collider.gameObject.layer != 21 && collider.enabled) { lowest = Mathf.Min(lowest, collider.bounds.min.y); } } } } else { foreach (Collider collider in vesselData.craftPart.partPrefab.GetComponentsInChildren <Collider>()) { if (collider.gameObject.layer != 21 && collider.enabled) { lowest = Mathf.Min(lowest, collider.bounds.min.y); } } } if (lowest == float.MaxValue) { lowest = 0; } // Figure out the surface height and rotation Quaternion normal = Quaternion.LookRotation(new Vector3((float)norm.x, (float)norm.y, (float)norm.z)); Quaternion rotation = Quaternion.identity; float heading = vesselData.heading; if (shipConstruct == null) { rotation = rotation * Quaternion.FromToRotation(Vector3.up, Vector3.back); } else if (shipConstruct.shipFacility == EditorFacility.SPH) { rotation = rotation * Quaternion.FromToRotation(Vector3.forward, -Vector3.forward); heading += 180.0f; } else { rotation = rotation * Quaternion.FromToRotation(Vector3.up, Vector3.forward); } rotation = rotation * Quaternion.AngleAxis(heading, Vector3.back); rotation = rotation * Quaternion.AngleAxis(vesselData.roll, Vector3.down); rotation = rotation * Quaternion.AngleAxis(vesselData.pitch, Vector3.left); // Set the height and rotation if (landed || splashed) { float hgt = (shipConstruct != null ? shipConstruct.parts[0] : vesselData.craftPart.partPrefab).localRoot.attPos0.y - lowest; hgt += vesselData.height; protoVesselNode.SetValue("hgt", hgt.ToString()); } protoVesselNode.SetValue("rot", KSPUtil.WriteQuaternion(rotation * normal)); // Set the normal vector relative to the surface Vector3 nrm = (rotation * Vector3.forward); protoVesselNode.SetValue("nrm", nrm.x + "," + nrm.y + "," + nrm.z); protoVesselNode.SetValue("prst", false.ToString()); } // Add vessel to the game ProtoVessel protoVessel = HighLogic.CurrentGame.AddVessel(protoVesselNode); // Store the id for later use vesselData.id = protoVessel.vesselRef.id; // Associate it so that it can be used in contract parameters ContractVesselTracker.Instance.AssociateVessel(vesselData.name, protoVessel.vesselRef); } vesselsCreated = true; return(true); }
public void SpawnAsteroid(Asteroid asteroid, UInt32 seed) { // Create Default Orbit Orbit orbit = null; CelestialBody body = null; // Select Orbit Type Int32 type = Random.Range(0, 3); if (type == 0 && asteroid.Location.Around.Count != 0) { // Around Location.AroundLoader[] around = GetProbabilityList(asteroid.Location.Around, asteroid.Location.Around.Select(a => a.Probability.Value).ToList()).ToArray(); Location.AroundLoader loader = around[Random.Range(0, around.Length)]; body = UBI.GetBody(loader.Body); if (!body) { return; } if (loader.Reached && !ReachedBody(body)) { return; } orbit = new Orbit { referenceBody = body, eccentricity = loader.Eccentricity, semiMajorAxis = loader.SemiMajorAxis, inclination = loader.Inclination, LAN = loader.LongitudeOfAscendingNode, argumentOfPeriapsis = loader.ArgumentOfPeriapsis, meanAnomalyAtEpoch = loader.MeanAnomalyAtEpoch, epoch = loader.Epoch }; orbit.Init(); } else if (type == 1 && asteroid.Location.Nearby.Count != 0) { // Nearby Location.NearbyLoader[] nearby = GetProbabilityList(asteroid.Location.Nearby, asteroid.Location.Nearby.Select(a => a.Probability.Value).ToList()).ToArray(); Location.NearbyLoader loader = nearby[Random.Range(0, nearby.Length)]; body = UBI.GetBody(loader.Body); if (!body) { return; } if (loader.Reached && !ReachedBody(body)) { return; } orbit = new Orbit { eccentricity = body.orbit.eccentricity + loader.Eccentricity, semiMajorAxis = body.orbit.semiMajorAxis * loader.SemiMajorAxis, inclination = body.orbit.inclination + loader.Inclination, LAN = body.orbit.LAN * loader.LongitudeOfAscendingNode, argumentOfPeriapsis = body.orbit.argumentOfPeriapsis * loader.ArgumentOfPeriapsis, meanAnomalyAtEpoch = body.orbit.meanAnomalyAtEpoch * loader.MeanAnomalyAtEpoch, epoch = body.orbit.epoch, referenceBody = body.orbit.referenceBody }; orbit.Init(); } else if (type == 2 && asteroid.Location.Flyby.Count != 0) { // Flyby Location.FlybyLoader[] flyby = GetProbabilityList(asteroid.Location.Flyby, asteroid.Location.Flyby.Select(a => a.Probability.Value).ToList()).ToArray(); Location.FlybyLoader loader = flyby[Random.Range(0, flyby.Length)]; body = UBI.GetBody(loader.Body); if (!body) { return; } if (loader.Reached && !ReachedBody(body)) { return; } orbit = Orbit.CreateRandomOrbitFlyBy(body, Random.Range(loader.MinDuration, loader.MaxDuration)); } // Check if (orbit == null) { Debug.Log("[Kopernicus] No new objects this time. (Probability is " + asteroid.Probability.Value + "%)"); return; } // Name String asteroidName = DiscoverableObjectsUtil.GenerateAsteroidName(); // Lifetime Double lifetime = Random.Range(asteroid.MinUntrackedLifetime, asteroid.MaxUntrackedLifetime) * 24d * 60d * 60d; Double maxLifetime = asteroid.MaxUntrackedLifetime * 24d * 60d * 60d; // Size UntrackedObjectClass size = (UntrackedObjectClass)(Int32)(asteroid.Size.Evaluate(Random.Range(0f, 1f)) * Enum.GetNames(typeof(UntrackedObjectClass)).Length); // Spawn ConfigNode vessel = null; #if (KSP_VERSION_1_10_1 || KSP_VERSION_1_11_1) if (Random.Range(0, 100) > RuntimeUtility.KopernicusConfig.CometPercentage) { #endif vessel = ProtoVessel.CreateVesselNode( asteroidName, VesselType.SpaceObject, orbit, 0, new[] { ProtoVessel.CreatePartNode( "PotatoRoid", seed ) }, new ConfigNode("ACTIONGROUPS"), ProtoVessel.CreateDiscoveryNode( DiscoveryLevels.Presence, size, lifetime, maxLifetime ) ); OverrideNode(ref vessel, asteroid.Vessel); ProtoVessel protoVessel = new ProtoVessel(vessel, HighLogic.CurrentGame); if (asteroid.UniqueName && FlightGlobals.Vessels.Count(v => v.vesselName == protoVessel.vesselName) != 0) { return; } Kopernicus.Events.OnRuntimeUtilitySpawnAsteroid.Fire(asteroid, protoVessel); protoVessel.Load(HighLogic.CurrentGame.flightState); GameEvents.onNewVesselCreated.Fire(protoVessel.vesselRef); GameEvents.onAsteroidSpawned.Fire(protoVessel.vesselRef); Debug.Log("[Kopernicus] New object found near " + body.name + ": " + protoVessel.vesselName + "!"); #if (KSP_VERSION_1_10_1 || KSP_VERSION_1_11_1) } else { float fragmentDynamicPressureModifier = 0f; bool optimizedCollider = false; CometOrbitType cometType = CometManager.GenerateWeightedCometType(); Orbit cometOrbit = cometType.CalculateHomeOrbit(); UntrackedObjectClass randomObjClass = cometType.GetRandomObjClass(); CometDefinition cometDef = CometManager.GenerateDefinition(cometType, randomObjClass, (int)seed); ConfigNode configNode = cometDef.CreateVesselNode(optimizedCollider, fragmentDynamicPressureModifier, hasName: false); ConfigNode configNode2 = ProtoVessel.CreatePartNode("PotatoComet", seed); uint value = 0u; configNode2.TryGetValue("persistentId", ref value); configNode.AddValue("cometPartId", value); ConfigNode configNode3 = new ConfigNode("VESSELMODULES"); configNode3.AddNode(configNode); vessel = ProtoVessel.CreateVesselNode(DiscoverableObjectsUtil.GenerateCometName(), VesselType.SpaceObject, cometOrbit, 0, new ConfigNode[1] { configNode2 }, new ConfigNode("ACTIONGROUPS"), ProtoVessel.CreateDiscoveryNode(DiscoveryLevels.Presence, randomObjClass, lifetime, maxLifetime), configNode3); OverrideNode(ref vessel, asteroid.Vessel); ProtoVessel protoVessel = new ProtoVessel(vessel, HighLogic.CurrentGame); Kopernicus.Events.OnRuntimeUtilitySpawnAsteroid.Fire(asteroid, protoVessel); protoVessel.Load(HighLogic.CurrentGame.flightState); GameEvents.onNewVesselCreated.Fire(protoVessel.vesselRef); GameEvents.onAsteroidSpawned.Fire(protoVessel.vesselRef); Debug.Log("[Kopernicus] New object found near " + body.name + ": " + protoVessel.vesselName + "!"); } #endif }
// Spawn the actual asteroid public void SpawnAsteroid(Asteroid asteroid, uint seed) { // Create Default Orbit Orbit orbit = null; CelestialBody body = null; // Select Orbit Type int type = Random.Range(0, 3); if (type == 0 && asteroid.location.around.Count != 0) { // Around IEnumerable <Location.AroundLoader> arounds = GetProbabilityList(asteroid.location.around, asteroid.location.around.Select(a => a.probability.value)); Location.AroundLoader around = arounds.ElementAt(Random.Range(0, arounds.Count())); body = PSystemManager.Instance.localBodies.Find(b => b.name == around.body); if (!body) { return; } if (around.reached && !ReachedBody(body)) { return; } orbit = new Orbit(); orbit.referenceBody = body; orbit.eccentricity = around.eccentricity; orbit.semiMajorAxis = around.semiMajorAxis; orbit.inclination = around.inclination; orbit.LAN = around.longitudeOfAscendingNode; orbit.argumentOfPeriapsis = around.argumentOfPeriapsis; orbit.meanAnomalyAtEpoch = around.meanAnomalyAtEpoch; orbit.epoch = around.epoch; orbit.Init(); } else if (type == 1 && asteroid.location.nearby.Count != 0) { // Nearby IEnumerable <Location.NearbyLoader> nearbys = GetProbabilityList(asteroid.location.nearby, asteroid.location.nearby.Select(a => a.probability.value)); Location.NearbyLoader nearby = nearbys.ElementAt(Random.Range(0, nearbys.Count())); body = PSystemManager.Instance.localBodies.Find(b => b.name == nearby.body); if (!body) { return; } if (nearby.reached && !ReachedBody(body)) { return; } orbit = new Orbit(); orbit.eccentricity = body.orbit.eccentricity + nearby.eccentricity; orbit.semiMajorAxis = body.orbit.semiMajorAxis * nearby.semiMajorAxis; orbit.inclination = body.orbit.inclination + nearby.inclination; orbit.LAN = body.orbit.LAN * nearby.longitudeOfAscendingNode; orbit.argumentOfPeriapsis = body.orbit.argumentOfPeriapsis * nearby.argumentOfPeriapsis; orbit.meanAnomalyAtEpoch = body.orbit.meanAnomalyAtEpoch * nearby.meanAnomalyAtEpoch; orbit.epoch = body.orbit.epoch; orbit.referenceBody = body.orbit.referenceBody; orbit.Init(); } else if (type == 2 && asteroid.location.flyby.Count != 0) { // Flyby IEnumerable <Location.FlybyLoader> flybys = GetProbabilityList(asteroid.location.flyby, asteroid.location.flyby.Select(a => a.probability.value)); Location.FlybyLoader flyby = flybys.ElementAt(Random.Range(0, flybys.Count())); body = PSystemManager.Instance.localBodies.Find(b => b.name == flyby.body); if (!body) { return; } if (flyby.reached && !ReachedBody(body)) { return; } orbit = Orbit.CreateRandomOrbitFlyBy(body, Random.Range(flyby.minDuration, flyby.maxDuration)); } // Check if (orbit == null) { Debug.Log("[Kopernicus]: No new objects this time. (Probablility is " + asteroid.probability.value + "%)"); return; } // Name string name = DiscoverableObjectsUtil.GenerateAsteroidName(); // Lifetime double lifetime = Random.Range(asteroid.minUntrackedLifetime, asteroid.maxUntrackedLifetime) * 24d * 60d * 60d; double maxLifetime = asteroid.maxUntrackedLifetime * 24d * 60d * 60d; // Size UntrackedObjectClass size = (UntrackedObjectClass)((int)(asteroid.size.curve.Evaluate(Random.Range(0f, 1f)) * Enum.GetNames(typeof(UntrackedObjectClass)).Length)); // Spawn ConfigNode vessel = ProtoVessel.CreateVesselNode( name, VesselType.SpaceObject, orbit, 0, new[] { ProtoVessel.CreatePartNode( "PotatoRoid", seed, new ProtoCrewMember[0] ) }, new ConfigNode("ACTIONGROUPS"), ProtoVessel.CreateDiscoveryNode( DiscoveryLevels.Presence, size, lifetime, maxLifetime ) ); OverrideNode(ref vessel, asteroid.vessel); ProtoVessel protoVessel = new ProtoVessel(vessel, HighLogic.CurrentGame); if (asteroid.uniqueName && FlightGlobals.Vessels.Count(v => v.vesselName == protoVessel.vesselName) != 0) { return; } protoVessel.Load(HighLogic.CurrentGame.flightState); GameEvents.onNewVesselCreated.Fire(protoVessel.vesselRef); Debug.Log("[Kopernicus]: New object found near " + body.name + ": " + protoVessel.vesselName + "!"); }
private void GenerateStrandedKerbal(ConfigNode contractNode) { if (contractNode.GetValue("state") == "Active") { DarkLog.Debug("Generating stranded kerbal/compound contract"); int recoveryType = int.Parse(contractNode.GetValue("recoveryType")); int bodyID = int.Parse(contractNode.GetValue("targetBody")); int recoveryLocation = int.Parse(contractNode.GetValue("recoveryLocation")); int contractSeed = int.Parse(contractNode.GetValue("seed")); bool recoveringKerbal = recoveryType == 1 || recoveryType == 3; bool recoveringPart = recoveryType == 2 || recoveryType == 3; System.Random generator = new System.Random(contractSeed); // RECOVERY TYPES: // 0: None // 1: Kerbal // 2: Part // 3: Compound // Generate vessel part string partName = contractNode.GetValue("partName"); string[] contractValues = contractNode.GetValue("values").Split(','); double contractDeadline = double.Parse(contractValues[1]); uint newPartID = uint.Parse(contractNode.GetValue("partID")); CelestialBody contractBody = FlightGlobals.Bodies[bodyID]; List <string> vesselDescriptionList; if (recoveringKerbal) { vesselDescriptionList = new List <string> { "Shipwreck", "Wreckage", "Pod", "Capsule", "Derelict", "Heap", "Hulk", "Craft", "Debris", "Scrap" }; } else { vesselDescriptionList = new List <string> { "Prototype", "Device", "Part", "Module", "Unit", "Component" }; } string vesselDescription = vesselDescriptionList[generator.Next(0, vesselDescriptionList.Count)]; Orbit strandedOrbit; // Low orbit if (recoveryLocation != 1) { // High orbit if (recoveryLocation != 2) { strandedOrbit = new Orbit(0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, contractBody); } else { strandedOrbit = FinePrint.Utilities.OrbitUtilities.GenerateOrbit(contractSeed, contractBody, FinePrint.Utilities.OrbitType.RANDOM, FinePrint.ContractDefs.Recovery.HighOrbitDifficulty, FinePrint.ContractDefs.Recovery.HighOrbitDifficulty, 0.0); } } else { double minAltitude = FinePrint.Utilities.CelestialUtilities.GetMinimumOrbitalDistance(contractBody, 1f) - contractBody.Radius; strandedOrbit = Orbit.CreateRandomOrbitAround(contractBody, contractBody.Radius + minAltitude * 1.1000000238418579, contractBody.Radius + minAltitude * 1.25); strandedOrbit.meanAnomalyAtEpoch = generator.NextDouble() * 2.0 * Math.PI; } ConfigNode configNode = null; if (recoveringKerbal) { DarkLog.Debug("We want to recover a kerbal, so let's do it"); string kerbalName = contractNode.GetValue("kerbalName"); int kerbalGender = int.Parse(contractNode.GetValue("gender")); string vesselName = FinePrint.Utilities.StringUtilities.PossessiveString(FinePrint.Utilities.StringUtilities.ShortKerbalName(kerbalName)) + " " + vesselDescription; // Recovery Locations: // 0: None, // 1: Low Orbit, // 2: High Orbit, // 3: Surface ProtoCrewMember pcm = null; if (!HighLogic.CurrentGame.CrewRoster.Exists(kerbalName)) { DarkLog.Debug("Spawning missing kerbal, name: " + kerbalName); pcm = HighLogic.CurrentGame.CrewRoster.GetNewKerbal(ProtoCrewMember.KerbalType.Unowned); pcm.ChangeName(kerbalName); pcm.gender = (ProtoCrewMember.Gender)kerbalGender; pcm.rosterStatus = ProtoCrewMember.RosterStatus.Assigned; pcm.seat = null; pcm.seatIdx = -1; //Add kerbal to crew roster. } else { pcm = HighLogic.CurrentGame.CrewRoster[kerbalName]; } // Spawn lone kerbal if (partName == "kerbalEVA") { configNode = ProtoVessel.CreateVesselNode(kerbalName, VesselType.EVA, strandedOrbit, 0, new ConfigNode[] { CreateProcessedPartNode(partName, newPartID, new ProtoCrewMember[] { pcm }) }, new ConfigNode[] { ProtoVessel.CreateDiscoveryNode(DiscoveryLevels.Unowned, UntrackedObjectClass.A, contractDeadline * 2, contractDeadline * 2) }); configNode.AddValue("prst", true); ProtoVessel pv = HighLogic.CurrentGame.AddVessel(configNode); VesselWorker.fetch.LoadVessel(configNode, pv.vesselID, false); NetworkWorker.fetch.SendVesselProtoMessage(pv, false, false); } // Spawn kerbal in capsule/pod else { configNode = ProtoVessel.CreateVesselNode(vesselName, (recoveryLocation != 3) ? VesselType.Ship : VesselType.Lander, strandedOrbit, 0, new ConfigNode[] { CreateProcessedPartNode(partName, newPartID, new ProtoCrewMember[] { pcm }) }, new ConfigNode[] { new ConfigNode("ACTIONGROUPS"), ProtoVessel.CreateDiscoveryNode(DiscoveryLevels.Unowned, UntrackedObjectClass.A, contractDeadline * 2, contractDeadline * 2) }); configNode.AddValue("prst", true); ProtoVessel pv = HighLogic.CurrentGame.AddVessel(configNode); VesselWorker.fetch.LoadVessel(configNode, pv.vesselID, false); NetworkWorker.fetch.SendVesselProtoMessage(pv, false, false); } } } }
protected void CreateVessels() { if (vesselsCreated) { return; } String gameDataDir = KSPUtil.ApplicationRootPath; gameDataDir = gameDataDir.Replace("\\", "/"); if (!gameDataDir.EndsWith("/")) { gameDataDir += "/"; } gameDataDir += "GameData"; // Spawn the vessel in the game world foreach (VesselData vesselData in vessels) { LoggingUtil.LogVerbose(this, "Spawning a vessel named '" + vesselData.name + "'"); // Save the current ShipConstruction ship, otherwise the player will see the spawned ship next time they enter the VAB! ConfigNode currentShip = ShipConstruction.ShipConfig; ShipConstruct shipConstruct = ShipConstruction.LoadShip(gameDataDir + "/" + vesselData.craftURL); if (shipConstruct == null) { LoggingUtil.LogError(this, "ShipConstruct was null when tried to load '" + vesselData.craftURL + "' (usually this means the file could not be found)."); continue; } // Restore ShipConstruction ship ShipConstruction.ShipConfig = currentShip; // Set the name if (string.IsNullOrEmpty(vesselData.name)) { vesselData.name = shipConstruct.shipName; } // Set some parameters that need to be at the part level uint flightId = ShipConstruction.GetUniqueFlightID(HighLogic.CurrentGame.flightState); uint missionID = (uint)Guid.NewGuid().GetHashCode(); uint launchID = HighLogic.CurrentGame.launchID++; foreach (Part p in shipConstruct.parts) { p.flightID = flightId; p.missionID = missionID; p.launchID = launchID; p.flagURL = vesselData.flagURL ?? HighLogic.CurrentGame.flagURL; } // Assign crew to the vessel foreach (CrewData cd in vesselData.crew) { bool success = false; // Find a seat for the crew Part part = shipConstruct.parts.Find(p => p.protoModuleCrew.Count < p.CrewCapacity); // Add the crew member if (part != null) { // Create the ProtoCrewMember ProtoCrewMember crewMember = HighLogic.CurrentGame.CrewRoster.GetNewKerbal(ProtoCrewMember.KerbalType.Unowned); if (cd.name != null) { crewMember.name = cd.name; } // Add them to the part success = part.AddCrewmemberAt(crewMember, part.protoModuleCrew.Count); } if (!success) { LoggingUtil.LogWarning(this, "Unable to add crew to vessel named '" + vesselData.name + "'. Perhaps there's no room?"); break; } } // Set additional info for landed kerbals if (vesselData.landed) { if (vesselData.altitude == null) { vesselData.altitude = LocationUtil.TerrainHeight(vesselData.latitude, vesselData.longitude, vesselData.body); } Vector3d pos = vesselData.body.GetWorldSurfacePosition(vesselData.latitude, vesselData.longitude, vesselData.altitude.Value); vesselData.orbit = new Orbit(0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, vesselData.body); vesselData.orbit.UpdateFromStateVectors(pos, vesselData.body.getRFrmVel(pos), vesselData.body, Planetarium.GetUniversalTime()); LoggingUtil.LogDebug(this, "vesselData generated, orbit = " + vesselData.orbit); } // Create a dummy ProtoVessel, we will use this to dump the parts to a config node. // We can't use the config nodes from the .craft file, because they are in a // slightly different format than those required for a ProtoVessel (seriously // Squad?!?). ConfigNode empty = new ConfigNode(); ProtoVessel dummyProto = new ProtoVessel(empty, null); Vessel dummyVessel = new Vessel(); dummyVessel.parts = shipConstruct.parts; dummyProto.vesselRef = dummyVessel; // Create the ProtoPartSnapshot objects and then initialize them foreach (Part p in shipConstruct.parts) { dummyProto.protoPartSnapshots.Add(new ProtoPartSnapshot(p, dummyProto)); } foreach (ProtoPartSnapshot p in dummyProto.protoPartSnapshots) { p.storePartRefs(); } // Estimate an object class, numbers are based on the in game description of the // size classes. float size = shipConstruct.shipSize.magnitude / 2.0f; UntrackedObjectClass sizeClass; if (size < 4.0f) { sizeClass = UntrackedObjectClass.A; } else if (size < 7.0f) { sizeClass = UntrackedObjectClass.B; } else if (size < 12.0f) { sizeClass = UntrackedObjectClass.C; } else if (size < 18.0f) { sizeClass = UntrackedObjectClass.D; } else { sizeClass = UntrackedObjectClass.E; } // Create the ship's parts ConfigNode[] partNodes = dummyProto.protoPartSnapshots.Select <ProtoPartSnapshot, ConfigNode>(GetNodeForPart).ToArray(); // Create additional nodes ConfigNode[] additionalNodes = new ConfigNode[1]; DiscoveryLevels discoveryLevel = vesselData.owned ? DiscoveryLevels.Owned : DiscoveryLevels.Unowned; additionalNodes[0] = ProtoVessel.CreateDiscoveryNode(discoveryLevel, sizeClass, contract.TimeDeadline, contract.TimeDeadline); // Create the config node representation of the ProtoVessel ConfigNode protoVesselNode = ProtoVessel.CreateVesselNode(vesselData.name, vesselData.vesselType, vesselData.orbit, 0, partNodes, additionalNodes); // Additional seetings for a landed vessel if (vesselData.landed) { // Create the config node representation of the ProtoVessel protoVesselNode.SetValue("sit", Vessel.Situations.LANDED.ToString()); protoVesselNode.SetValue("landed", true.ToString()); protoVesselNode.SetValue("lat", vesselData.latitude.ToString()); protoVesselNode.SetValue("lon", vesselData.longitude.ToString()); protoVesselNode.SetValue("alt", vesselData.altitude.ToString()); protoVesselNode.SetValue("landedAt", vesselData.body.name); // Figure out the additional heigh to subtract float lowest = float.MaxValue; foreach (Part p in shipConstruct.parts) { foreach (Collider collider in p.GetComponentsInChildren <Collider>()) { if (collider.gameObject.layer != 21 && collider.enabled) { lowest = Mathf.Min(lowest, collider.bounds.min.y); } } } // Figure out the surface height and rotation Vector3d norm = vesselData.body.GetRelSurfaceNVector(vesselData.latitude, vesselData.longitude); Quaternion rotation = Quaternion.FromToRotation(Vector3.forward, Vector3.up) * Quaternion.LookRotation(new Vector3((float)norm.x, (float)norm.y, (float)norm.z)); protoVesselNode.SetValue("hgt", (shipConstruct.parts[0].localRoot.attPos0.y - lowest).ToString()); protoVesselNode.SetValue("rot", KSPUtil.WriteQuaternion(rotation)); } // Add vessel to the game ProtoVessel protoVessel = HighLogic.CurrentGame.AddVessel(protoVesselNode); // Store the id for later use vesselData.id = protoVessel.vesselRef.id; // Associate it so that it can be used in contract parameters ContractVesselTracker.Instance.AssociateVessel(vesselData.name, protoVessel.vesselRef); } vesselsCreated = true; }