private void CreateLode(LodeData lodeData) { lodeData.altitude = TerrainHeight(lodeData.latitude, lodeData.longitude, lodeData.body); Vector3d pos = lodeData.body.GetWorldSurfacePosition(lodeData.latitude, lodeData.longitude, lodeData.altitude.Value); lodeData.orbit = new Orbit(0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, lodeData.body); lodeData.orbit.UpdateFromStateVectors(pos, lodeData.body.getRFrmVel(pos), lodeData.body, Planetarium.GetUniversalTime()); ConfigNode[] partNodes; ShipConstruct shipConstruct = null; uint flightId = ShipConstruction.GetUniqueFlightID(HighLogic.CurrentGame.flightState); partNodes = new ConfigNode[1]; partNodes[0] = ProtoVessel.CreatePartNode(lodeData.craftPart.name, flightId); DiscoveryLevels discoveryLevel = DiscoveryLevels.Owned; ConfigNode protoVesselNode = ProtoVessel.CreateVesselNode(lodeData.name, lodeData.vesselType, lodeData.orbit, 0, partNodes); Vector3d norm = lodeData.body.GetRelSurfaceNVector(lodeData.latitude, lodeData.longitude); double terrainHeight = 0.0; if (lodeData.body.pqsController != null) { terrainHeight = lodeData.body.pqsController.GetSurfaceHeight(norm) - lodeData.body.pqsController.radius; } bool splashed = true && terrainHeight < 0.001; protoVesselNode.SetValue("sit", (splashed ? Vessel.Situations.SPLASHED : Vessel.Situations.LANDED).ToString()); protoVesselNode.SetValue("landed", (!splashed).ToString()); protoVesselNode.SetValue("splashed", splashed.ToString()); protoVesselNode.SetValue("lat", lodeData.latitude.ToString()); protoVesselNode.SetValue("lon", lodeData.longitude.ToString()); protoVesselNode.SetValue("alt", lodeData.altitude.ToString()); protoVesselNode.SetValue("landedAt", lodeData.body.name); float lowest = float.MaxValue; foreach (Collider collider in lodeData.craftPart.partPrefab.GetComponentsInChildren <Collider>()) { if (collider.gameObject.layer != 21 && collider.enabled) { lowest = Mathf.Min(lowest, collider.bounds.min.y); } } if (Mathf.Approximately(lowest, float.MaxValue)) { lowest = 0; } Quaternion normal = Quaternion.LookRotation(new Vector3((float)norm.x, (float)norm.y, (float)norm.z)); Quaternion rotation = Quaternion.identity; rotation = rotation * Quaternion.FromToRotation(Vector3.up, Vector3.back); float hgt = (shipConstruct != null ? shipConstruct.parts[0] : lodeData.craftPart.partPrefab).localRoot.attPos0.y - lowest; protoVesselNode.SetValue("hgt", hgt.ToString()); protoVesselNode.SetValue("rot", KSPUtil.WriteQuaternion(rotation * normal)); Vector3 nrm = (rotation * Vector3.forward); protoVesselNode.SetValue("nrm", nrm.x + "," + nrm.y + "," + nrm.z); protoVesselNode.SetValue("prst", false.ToString()); ProtoVessel protoVessel = new ProtoVessel(protoVesselNode, HighLogic.CurrentGame); protoVessel.Load(HighLogic.CurrentGame.flightState); }
public override void OnSave(ConfigNode node) { base.OnSave(node); foreach (KeyValuePair <int, SectionInfo> section in sections) { ConfigNode sectionNode = node.AddNode("SECTIONPOS"); sectionNode.AddValue("index", section.Key); sectionNode.AddValue("localPos", KSPUtil.WriteVector(KAS_Shared.GetLocalPosFrom(section.Value.transform, this.part.transform))); sectionNode.AddValue("localRot", KSPUtil.WriteQuaternion(KAS_Shared.GetLocalRotFrom(section.Value.transform, this.part.transform))); } }
public static void SaveSettings(ConfigNode node) { Quaternion pos; pos.x = winpos.x; pos.y = winpos.y; pos.z = winpos.width; pos.w = winpos.height; node.AddValue("rect", KSPUtil.WriteQuaternion(pos)); node.AddValue("visible", showGUI); }
public static void SaveSettings(ConfigNode node) { Quaternion pos; pos.x = windowpos.x; pos.y = windowpos.y; pos.z = windowpos.width; pos.w = windowpos.height; node.AddValue("rect", KSPUtil.WriteQuaternion(pos)); node.AddValue("visible", gui_enabled); node.AddValue("link_lfo_sliders", link_lfo_sliders); }
/* PRVESSEL STORAGE METHODS */ public void Save() { Debug.Log("[PR] Saving Data."); try { ConfigNode save = new ConfigNode(); save.AddValue("TIME", Planetarium.GetUniversalTime().ToString()); save.AddValue("DEFAULT_REFERENCE_MODE", ((int)defaultReferenceMode).ToString()); ConfigNode.CreateConfigFromObject(this, 0, save); //Save values per vessel foreach (PRVessel v in PRVessels) { ConfigNode cn_vessel = save.AddNode(v.vessel.id.ToString()); cn_vessel.AddValue("MOMENTUM", KSPUtil.WriteVector(v.momentum)); cn_vessel.AddValue("PLANETARIUM_RIGHT", KSPUtil.WriteVector(v.planetariumRight)); cn_vessel.AddValue("MJMODE", ((int)(v.mjMode)).ToString()); cn_vessel.AddValue("RTMODE", ((int)(v.rtMode)).ToString()); cn_vessel.AddValue("ROTATION_MODE_ACTIVE", v.rotationModeActive.ToString()); cn_vessel.AddValue("DYNAMIC_REFERENCE", v.dynamicReference.ToString()); cn_vessel.AddValue("ROTATION", KSPUtil.WriteQuaternion(v.rotation)); cn_vessel.AddValue("DIRECTION", KSPUtil.WriteVector(v.direction)); //Get Reference Type and save accordingly if (v.reference != null) { if (v.reference.GetType() == typeof(CelestialBody)) { cn_vessel.AddValue("REFERENCE", v.reference.GetName()); } else if (v.reference.GetType() == typeof(Vessel)) { cn_vessel.AddValue("REFERENCE", v.reference.GetVessel().id.ToString()); } } else { cn_vessel.AddValue("REFERENCE", "NONE"); } cn_vessel.AddValue("MOMENTUM_MODE_ACTIVE", v.momentumModeActive.ToString()); cn_vessel.AddValue("DESIRED_RPM", v.desiredRPM.ToString()); } save.Save(GetUnusedPath()); } catch (Exception e) { Debug.Log("[PR] Saving not sucessfull: " + e.Message); } }
public void Save(ConfigNode node) { if (!string.IsNullOrEmpty(md5sum)) { node.AddValue("CraftHullSum", md5sum); } node.AddValue("position", KSPUtil.WriteVector(position)); node.AddValue("rotation", KSPUtil.WriteQuaternion(rotation)); node.AddValue("hullError", hullError); if (bounds != null) { bounds.Save(node.AddNode("bounds")); node.AddValue("boundsOrigin", boundsOrigin); } }
private void SpawnVessel(WaldoAttackVesselData WaldoAttackVesselData, List <ProtoCrewMember> crewData = null) { // string gameDataDir = KSPUtil.ApplicationRootPath; Debug.Log("[Spawn OrX Waldo Attack] Spawning " + WaldoAttackVesselData.name); // Set additional info for landed vessels bool landed = false; if (!landed) { landed = true; if (WaldoAttackVesselData.altitude == null || WaldoAttackVesselData.altitude < 0) { WaldoAttackVesselData.altitude = 5;//LocationUtil.TerrainHeight(WaldoAttackVesselData.latitude, WaldoAttackVesselData.longitude, WaldoAttackVesselData.body); } Debug.Log("[Spawn OrX Waldo Attack] SpawnVessel Altitude: " + WaldoAttackVesselData.altitude); //Vector3d pos = WaldoAttackVesselData.body.GetWorldSurfacePosition(WaldoAttackVesselData.latitude, WaldoAttackVesselData.longitude, WaldoAttackVesselData.altitude.Value); Vector3d pos = WaldoAttackVesselData.body.GetRelSurfacePosition(WaldoAttackVesselData.latitude, WaldoAttackVesselData.longitude, WaldoAttackVesselData.altitude.Value); WaldoAttackVesselData.orbit = new Orbit(0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, WaldoAttackVesselData.body); WaldoAttackVesselData.orbit.UpdateFromStateVectors(pos, WaldoAttackVesselData.body.getRFrmVel(pos), WaldoAttackVesselData.body, Planetarium.GetUniversalTime()); } ConfigNode[] partNodes; ShipConstruct shipConstruct = null; bool hasClamp = false; float lcHeight = 0; ConfigNode craftNode; Quaternion craftRotation = Quaternion.identity; if (!string.IsNullOrEmpty(WaldoAttackVesselData.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(WaldoAttackVesselData.craftURL); if (shipConstruct == null) { Debug.Log("[Spawn OrX Waldo Attack] ShipConstruct was null when tried to load '" + WaldoAttackVesselData.craftURL + "' (usually this means the file could not be found)."); return;//continue; } craftNode = ConfigNode.Load(WaldoAttackVesselData.craftURL); lcHeight = ConfigNode.ParseVector3(craftNode.GetNode("PART").GetValue("pos")).y; craftRotation = ConfigNode.ParseQuaternion(craftNode.GetNode("PART").GetValue("rot")); // Restore ShipConstruction ship ShipConstruction.ShipConfig = currentShip; // Set the name if (string.IsNullOrEmpty(WaldoAttackVesselData.name)) { WaldoAttackVesselData.name = WaldoVesselName; ; } // 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 = 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; } // 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 List <ConfigNode> partNodesL = new List <ConfigNode>(); foreach (ProtoPartSnapshot snapShot in dummyProto.protoPartSnapshots) { ConfigNode node = new ConfigNode("PART"); snapShot.Save(node); partNodesL.Add(node); } partNodes = partNodesL.ToArray(); } else { // Create crew member array ProtoCrewMember[] crewArray = new ProtoCrewMember[WaldoAttackVesselData.crew.Count]; /* * int i = 0; * foreach (CrewData cd in WaldoAttackVesselData.crew) * { * /* * // Create the ProtoCrewMember * ProtoCrewMember crewMember = HighLogic.CurrentGame.CrewRoster.GetNewKerbal(ProtoCrewMember.KerbalType.Crew); * if (cd.name != null) * { * crewMember.KerbalRef.name = cd.name; * } * * crewArray[i++] = crewMember; * * } */ // Create part nodes uint flightId = ShipConstruction.GetUniqueFlightID(HighLogic.CurrentGame.flightState); partNodes = new ConfigNode[1]; partNodes[0] = ProtoVessel.CreatePartNode(WaldoAttackVesselData.craftPart.name, flightId, crewArray); // Default the size class //sizeClass = UntrackedObjectClass.A; // Set the name if (string.IsNullOrEmpty(WaldoAttackVesselData.name)) { WaldoAttackVesselData.name = WaldoAttackVesselData.craftPart.name; } } // Create additional nodes ConfigNode[] additionalNodes = new ConfigNode[0]; //DiscoveryLevels discoveryLevel = WaldoAttackVesselData.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(WaldoAttackVesselData.name, WaldoAttackVesselData.vesselType, WaldoAttackVesselData.orbit, 0, partNodes, additionalNodes); // Additional seetings for a landed vessel if (!WaldoAttackVesselData.orbiting) { Vector3d norm = WaldoAttackVesselData.body.GetRelSurfaceNVector(WaldoAttackVesselData.latitude, WaldoAttackVesselData.longitude); double terrainHeight = 0.0; if (WaldoAttackVesselData.body.pqsController != null) { terrainHeight = WaldoAttackVesselData.body.pqsController.GetSurfaceHeight(norm) - WaldoAttackVesselData.body.pqsController.radius; } bool splashed = false;// = landed && terrainHeight < 0.001; // Create the config node representation of the ProtoVessel // Note - flying is experimental, and so far doesn't worx 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", WaldoAttackVesselData.latitude.ToString()); protoVesselNode.SetValue("lon", WaldoAttackVesselData.longitude.ToString()); protoVesselNode.SetValue("alt", WaldoAttackVesselData.altitude.ToString()); protoVesselNode.SetValue("landedAt", WaldoAttackVesselData.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 WaldoAttackVesselData.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((Vector3)norm);// new Vector3((float)norm.x, (float)norm.y, (float)norm.z)); Quaternion rotation = Quaternion.identity; float heading = WaldoAttackVesselData.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 = Quaternion.FromToRotation(Vector3.up, -Vector3.up) * rotation; //rotation = craftRotation; WaldoAttackVesselData.heading = 0; WaldoAttackVesselData.pitch = 0; } rotation = rotation * Quaternion.AngleAxis(heading, Vector3.back); rotation = rotation * Quaternion.AngleAxis(WaldoAttackVesselData.roll, Vector3.down); rotation = rotation * Quaternion.AngleAxis(WaldoAttackVesselData.pitch, Vector3.left); // Set the height and rotation if (landed || splashed) { float hgt = (shipConstruct != null ? shipConstruct.parts[0] : WaldoAttackVesselData.craftPart.partPrefab).localRoot.attPos0.y - lowest; hgt += WaldoAttackVesselData.height; protoVesselNode.SetValue("hgt", hgt.ToString(), true); } protoVesselNode.SetValue("rot", KSPUtil.WriteQuaternion(normal * rotation), true); // Set the normal vector relative to the surface Vector3 nrm = (rotation * Vector3.forward); protoVesselNode.SetValue("nrm", nrm.x + "," + nrm.y + "," + nrm.z, true); protoVesselNode.SetValue("prst", false.ToString(), true); } // Add vessel to the game ProtoVessel protoVessel = HighLogic.CurrentGame.AddVessel(protoVesselNode); //protoVessel.vesselRef.transform.rotation = protoVessel.rotation; // Store the id for later use WaldoAttackVesselData.id = protoVessel.vesselRef.id; //protoVessel.vesselRef.currentStage = 0; hasClamp = false; StartCoroutine(PlaceSpawnedVessel(protoVessel.vesselRef, !hasClamp)); // Associate it so that it can be used in contract parameters //ContractVesselTracker.Instance.AssociateVessel(WaldoAttackVesselData.name, protoVessel.vesselRef); //destroy prefabs foreach (Part p in FindObjectsOfType <Part>()) { if (!p.vessel) { Destroy(p.gameObject); } } }
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 override void OnSave(ConfigNode node) { var rot = KSPUtil.WriteQuaternion(towerRot); node.AddValue("towerRot", rot); }
private void SpawnVessel(VesselData vesselData, List<ProtoCrewMember> crewData = null) { string gameDataDir = KSPUtil.ApplicationRootPath; Log.info("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 < 0) { vesselData.altitude = 35;//LocationUtil.TerrainHeight(vesselData.latitude, vesselData.longitude, vesselData.body); } //Vector3d pos = vesselData.body.GetWorldSurfacePosition(vesselData.latitude, vesselData.longitude, vesselData.altitude.Value); Vector3d pos = vesselData.body.GetRelSurfacePosition(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; bool hasClamp = false; float lcHeight = 0; ConfigNode craftNode; Quaternion craftRotation = Quaternion.identity; 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(vesselData.craftURL); if (shipConstruct == null) { Log.info("ShipConstruct was null when tried to load '{0}' (usually this means the file could not be found).", vesselData.craftURL); return;//continue; } craftNode = ConfigNode.Load(vesselData.craftURL); lcHeight = ConfigNode.ParseVector3(craftNode.GetNode("PART").GetValue("pos")).y; craftRotation = ConfigNode.ParseQuaternion(craftNode.GetNode("PART").GetValue("rot")); // 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; } //add minimal crew //bool success = false; Part part = shipConstruct.parts.Find(p => p.protoModuleCrew.Count < p.CrewCapacity); // Add the crew member if (part != null && VesselMoverToolbar.addCrewMembers) { if (VesselMoverToolbar.selectCrewMembers) { ProtoCrewMember crewMember = crewData.FirstOrDefault(); if (crewMember != null) part.AddCrewmemberAt(crewMember, part.protoModuleCrew.Count); VesselMoverToolbar.SelectedCrewMembers.Clear(); } else { // Create the ProtoCrewMember ProtoCrewMember crewMember = HighLogic.CurrentGame.CrewRoster.GetNewKerbal(); crewMember.gender = UnityEngine.Random.Range(0, 100) > 50 ? ProtoCrewMember.Gender.Female : ProtoCrewMember.Gender.Male; //crewMember.trait = "Pilot"; // Add them to the part part.AddCrewmemberAt(crewMember, part.protoModuleCrew.Count); } } // 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) { dummyVessel.loaded = false; p.vessel = dummyVessel; { #if KSP_18 ProtoPartSnapshot proto = new ProtoPartSnapshot(p, dummyProto, true)); // For KSP >= 1.8 #else ProtoPartSnapshot proto = new ProtoPartSnapshot(p, dummyProto); // For KSP 1.4.x #endif dummyProto.protoPartSnapshots.Add(proto); } } foreach (ProtoPartSnapshot p in dummyProto.protoPartSnapshots) { p.storePartRefs(); } // Create the ship's parts List<ConfigNode> partNodesL = new List<ConfigNode>(); foreach (ProtoPartSnapshot snapShot in dummyProto.protoPartSnapshots) { ConfigNode node = new ConfigNode("PART"); snapShot.Save(node); partNodesL.Add(node); } partNodes = partNodesL.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.Crew); if (cd.name != null) { crewMember.KerbalRef.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[0]; //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 = false;// = 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((Vector3)norm);// 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 = Quaternion.FromToRotation(Vector3.up, -Vector3.up) * rotation; //rotation = craftRotation; vesselData.heading = 0; vesselData.pitch = 0; } 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; foreach (Part p in shipConstruct.Parts) { LaunchClamp lc = p.FindModuleImplementing<LaunchClamp>(); if (lc) { hasClamp = true; break; } } if (!hasClamp) { hgt += 35; } else { hgt += lcHeight; } protoVesselNode.SetValue("hgt", hgt.ToString(), true); } protoVesselNode.SetValue("rot", KSPUtil.WriteQuaternion(normal * rotation), true); // Set the normal vector relative to the surface Vector3 nrm = (rotation * Vector3.forward); protoVesselNode.SetValue("nrm", nrm.x + "," + nrm.y + "," + nrm.z, true); protoVesselNode.SetValue("prst", false.ToString(), true); } // Add vessel to the game ProtoVessel protoVessel = HighLogic.CurrentGame.AddVessel(protoVesselNode); //protoVessel.vesselRef.transform.rotation = protoVessel.rotation; // Store the id for later use vesselData.id = protoVessel.vesselRef.id; //protoVessel.vesselRef.currentStage = 0; StartCoroutine(PlaceSpawnedVessel(protoVessel.vesselRef, !hasClamp)); // Associate it so that it can be used in contract parameters //ContractVesselTracker.Instance.AssociateVessel(vesselData.name, protoVessel.vesselRef); //destroy prefabs foreach (Part p in FindObjectsOfType<Part>()) { if (!p.vessel) { Destroy(p.gameObject); } } }
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; }