public static void Reset() { payloadShipSelector = null; missionProfileSelector = null; orbitEditor = null; crewTransferSelector = null; flagSelector = null; scrollPos = Vector2.zero; shipName = ""; }
// Creates a new ship with the given parameters for this mission. The code however seems unnecessarily convoluted and // error-prone, but there are no better examples available on the internet. private void CreateShip() { try { // The ShipConstruct-object can only savely exist while not in flight, otherwise it will spam Null-Pointer Exceptions every tick: if (HighLogic.LoadedScene == GameScenes.FLIGHT) { throw new Exception("unable to run CreateShip while in flight"); } // Load the parts form the saved vessel: if (!File.Exists(shipTemplateFilename)) { throw new Exception("file '" + shipTemplateFilename + "' not found"); } var shipConstruct = ShipConstruction.LoadShip(shipTemplateFilename); // Maybe adjust the orbit: var vesselHeight = Math.Max(Math.Max(shipConstruct.shipSize.x, shipConstruct.shipSize.y), shipConstruct.shipSize.z); if (missionType == MissionType.DEPLOY) { // Make sure that there won't be any collisions, when the vessel is created at the given orbit: orbit = GUIOrbitEditor.ApplySafetyDistance(orbit, vesselHeight); } else if (missionType == MissionType.CONSTRUCT) { // Deploy the new ship next to the space-dock: var spaceDock = TargetVessel.GetVesselById((Guid)targetVesselId); orbit = GUIOrbitEditor.CreateFollowingOrbit(spaceDock.orbit, TargetVessel.GetVesselSize(spaceDock) + vesselHeight); orbit = GUIOrbitEditor.ApplySafetyDistance(orbit, vesselHeight); } else { throw new Exception("invalid mission-type '" + missionType + "'"); } var game = FlightDriver.FlightStateCache ?? HighLogic.CurrentGame; var profile = GetProfile(); var duration = profile.missionDuration; AssembleForLaunchUnlanded(shipConstruct, crewToDeliver ?? Enumerable.Empty <string>(), duration, orbit, flagURL, game); var newVessel = FlightGlobals.Vessels[FlightGlobals.Vessels.Count - 1]; newVessel.vesselName = shipName; Debug.Log("[KSTS] deployed new ship '" + shipName + "' as '" + newVessel.protoVessel.vesselRef.id + "'"); ScreenMessages.PostScreenMessage("Vessel '" + shipName + "' deployed"); // Popup message to notify the player // Notify other mods about the new vessel: GameEvents.onVesselCreate.Fire(newVessel); } catch (Exception e) { Debug.LogError("[KSTS] Mission.CreateShip(): " + e); } }
// Returns a config-node which contains all public attributes of this object to be saved: public ConfigNode CreateConfigNode(string name) { ConfigNode node = new ConfigNode(name); FieldInfo[] fields = this.GetType().GetFields(); foreach (FieldInfo field in fields) { if (!field.IsPublic) { continue; // Only public attributes should contain persistent values worth saving. } if (field.IsLiteral) { continue; // Don't save constants. } if (field.GetValue(this) == null) { continue; } // Save all elements of the list by creating multiple config-nodes with the same name: if (field.FieldType == typeof(List <string>)) { List <string> list = (List <string>)field.GetValue(this); if (list != null) { foreach (string element in list) { node.AddValue(field.Name.ToString(), element); } } } // Save dictionary-values in a sub-node: else if (field.FieldType == typeof(Dictionary <string, double>)) { ConfigNode dictNode = node.AddNode(field.Name.ToString()); foreach (KeyValuePair <string, double> item in (Dictionary <string, double>)field.GetValue(this)) { dictNode.AddValue(item.Key, item.Value.ToString()); } } // Use orbit helper-class to save compley orbit-object: else if (field.FieldType == typeof(Orbit)) { node.AddNode(GUIOrbitEditor.SaveOrbitToNode((Orbit)field.GetValue(this))); } // Default; save as string: else { node.AddValue(field.Name.ToString(), field.GetValue(this)); } } return(node); }
public static bool Display() { currentCost = 0; bool ready = DisplayInner(); bool launch = DisplayFooter(currentCost, ready); if (launch) { if (!GUIOrbitEditor.CheckOrbitClear(orbitEditor.GetOrbit())) { // The selected orbit is used by another vessel, abort: ScreenMessages.PostScreenMessage("Selected orbit already in use by another vessel, aborting mission!"); } else { // The orbit is clear, start the mission: MissionController.StartMission(Mission.CreateDeployment(shipName, payloadShipSelector.payload.template, orbitEditor.GetOrbit(), missionProfileSelector.selectedProfile, crewTransferSelector.crewToDeliver, flagSelector.flagURL)); KSTS.AddFunds(-currentCost); Reset(); return(true); } } return(false); }
public static Orbit CreateSimpleOrbit(CelestialBody body, double altitude, double inclination) { return(GUIOrbitEditor.CreateOrbit(inclination, 0, altitude + body.Radius, 0, 0, 0, 0, body)); }
// Creates a new object from the given config-node to fill all of the objects public attributes: public static object CreateFromConfigNode(ConfigNode node, object obj) { FieldInfo[] fields = obj.GetType().GetFields(); foreach (FieldInfo field in fields) { if (!field.IsPublic) { continue; // Only public attributes should contain persistent values worth saving. } if (field.IsLiteral) { continue; // Don't load constants. } if (!node.HasValue(field.Name.ToString()) && !node.HasNode(field.Name.ToString())) { continue; // Should only happen when the savegame is from a different version. } if (field.FieldType == typeof(double)) { field.SetValue(obj, double.Parse(node.GetValue(field.Name.ToString()))); } else if (field.FieldType == typeof(MissionType)) { field.SetValue(obj, Enum.Parse(typeof(MissionType), node.GetValue(field.Name.ToString()))); } else if (field.FieldType == typeof(MissionProfileType)) { field.SetValue(obj, Enum.Parse(typeof(MissionProfileType), node.GetValue(field.Name.ToString()))); } else if (field.FieldType == typeof(FlightRecordingStatus)) { field.SetValue(obj, Enum.Parse(typeof(FlightRecordingStatus), node.GetValue(field.Name.ToString()))); } else if (field.FieldType == typeof(int)) { field.SetValue(obj, int.Parse(node.GetValue(field.Name.ToString()))); } else if (field.FieldType == typeof(bool)) { field.SetValue(obj, bool.Parse(node.GetValue(field.Name.ToString()))); } else if (field.FieldType == typeof(Guid) || field.FieldType == typeof(Guid?)) { field.SetValue(obj, new Guid(node.GetValue(field.Name.ToString()))); } // Restore String-Lists by loading all nodes with the name of this field: else if (field.FieldType == typeof(List <string>)) { List <string> list = new List <string>(); foreach (string value in node.GetValues(field.Name.ToString())) { list.Add(value); } field.SetValue(obj, list); } // Restore the dictionary by loading all the values in the sub-node: else if (field.FieldType == typeof(Dictionary <string, double>)) { Dictionary <string, double> dict = new Dictionary <string, double>(); ConfigNode dictNode = node.GetNode(field.Name.ToString()); foreach (ConfigNode.Value item in dictNode.values) { dict.Add(item.name, double.Parse(item.value)); } field.SetValue(obj, dict); } // Load orbit via the helper-class: else if (field.FieldType == typeof(Orbit)) { field.SetValue(obj, GUIOrbitEditor.CreateOrbitFromNode(node.GetNode(field.Name.ToString()))); } // Fallback; try to store the value as string: else { field.SetValue(obj, node.GetValue(field.Name.ToString())); } } return(obj); }
public Orbit GetOrbit() { return(GUIOrbitEditor.CreateSimpleOrbit(this.body, this.altitudeSelector.Value, this.inclinationSelector.Value)); }
private static bool DisplayInner() { // Payload selection: if (payloadShipSelector == null) { payloadShipSelector = new GUIPayloadShipSelector(); } if (payloadShipSelector.payload == null) { payloadShipSelector.DisplayList(); return(false); } if (payloadShipSelector.DisplaySelected()) { missionProfileSelector = null; orbitEditor = null; crewTransferSelector = null; flagSelector = null; return(false); } currentCost += payloadShipSelector.payload.template.totalCost; // Mission-Profile selection: if (missionProfileSelector == null) { missionProfileSelector = new GUIMissionProfileSelector(); missionProfileSelector.filterMass = payloadShipSelector.payload.template.totalMass; missionProfileSelector.filterMissionType = MissionProfileType.DEPLOY; shipName = payloadShipSelector.payload.template.shipName; } if (missionProfileSelector.selectedProfile == null) { missionProfileSelector.DisplayList(); return(false); } if (missionProfileSelector.DisplaySelected()) { orbitEditor = null; crewTransferSelector = null; flagSelector = null; return(false); } currentCost += missionProfileSelector.selectedProfile.launchCost; // Mission-Parameters selection: if (orbitEditor == null) { orbitEditor = new GUIOrbitEditor(missionProfileSelector.selectedProfile); } if (crewTransferSelector == null) { crewTransferSelector = new GUICrewTransferSelector(payloadShipSelector.payload, missionProfileSelector.selectedProfile); } if (flagSelector == null) { flagSelector = new GUIFlagSelector(); } scrollPos = GUILayout.BeginScrollView(scrollPos, GUI.scrollStyle); GUILayout.Label("<size=14><b>Mission Parameters:</b></size>"); GUILayout.BeginHorizontal(); GUILayout.Label("Ship name:", new GUIStyle(GUI.labelStyle) { stretchWidth = true }); shipName = GUILayout.TextField(shipName, new GUIStyle(GUI.textFieldStyle) { alignment = TextAnchor.MiddleRight, stretchWidth = false, fixedWidth = 320 }); GUILayout.EndHorizontal(); orbitEditor.DisplayEditor(); // Display crew-selector, if the payload can hold kerbals: var selectionIsValid = true; if (payloadShipSelector.payload.GetCrewCapacity() > 0) { GUILayout.Label(""); GUILayout.Label("<size=14><b>Crew:</b></size>"); if (!crewTransferSelector.DisplayList()) { selectionIsValid = false; } } // Show Button for Flag-Selector: GUILayout.Label(""); flagSelector.ShowButton(); GUILayout.EndScrollView(); return(selectionIsValid); }
// Creates a new ship with the given parameters for this mission. The code however seems unnecessarily convoluted and // error-prone, but there are no better examples available on the internet. private void CreateShip() { // TODO: Apply the staging which was saved in the editor. // TODO: Settings from other mods like Part-Switchers must also be applied here, maybe copy the config-nodes... try { if (!File.Exists(shipTemplateFilename)) { throw new Exception("file '" + shipTemplateFilename + "' not found"); } if (missionType == MissionType.DEPLOY) { // Make sure that there won't be any collisions, when the vessel is created at the given orbit: orbit = GUIOrbitEditor.ApplySafetyDistance(orbit); } else if (missionType == MissionType.CONSTRUCT) { // Deploy the new ship next to the space-dock: Vessel spaceDock = TargetVessel.GetVesselById((Guid)targetVesselId); orbit = GUIOrbitEditor.CreateFollowingOrbit(spaceDock.orbit, 100); // TODO: Calculate the distance using the ships's size orbit = GUIOrbitEditor.ApplySafetyDistance(orbit); } else { throw new Exception("invalid mission-type '" + missionType.ToString() + "'"); } // The ShipConstruct-object can only savely exist while not in flight, otherwise it will spam Null-Pointer Exceptions every tick: if (HighLogic.LoadedScene == GameScenes.FLIGHT) { throw new Exception("unable to run CreateShip while in flight"); } // Load the parts form the saved vessel: ShipConstruct shipConstruct = ShipConstruction.LoadShip(shipTemplateFilename); ProtoVessel dummyProto = new ProtoVessel(new ConfigNode(), null); Vessel dummyVessel = new Vessel(); dummyProto.vesselRef = dummyVessel; // In theory it should be enough to simply copy the parts from the ShipConstruct to the ProtoVessel, but // this only seems to work when the saved vessel starts with the root-part and is designed top down from there. // It seems that the root part has to be the first part in the ProtoVessel's parts-list and all other parts have // to be listed in sequence radiating from the root part (eg 1=>2=>R<=3<=4 should be R,2,1,3,4). If the parts // are not in the correct order, their rotation seems to get messed up or they are attached to the wrong // attachmet-nodes, which is why we have to re-sort the parts with our own logic here. // This part of the code is experimental however and only based on my own theories and observations about KSP's vessels. Part rootPart = null; foreach (Part p in shipConstruct.parts) { if (p.parent == null) { rootPart = p; break; } } List <Part> pList = null; dummyVessel.parts = FindAndAddAttachedParts(rootPart, ref pList); // Find all parts which are directly attached to the root-part and add them in order. // Handle Subassemblies which are attached by surface attachment-nodes: bool handleSurfaceAttachments = true; while (dummyVessel.parts.Count < shipConstruct.parts.Count) { int processedParts = 0; foreach (Part p in shipConstruct.parts) { if (dummyVessel.parts.Contains(p)) { continue; } if (handleSurfaceAttachments) { // Check if the part is attached by a surface-node: if (p.srfAttachNode != null && dummyVessel.parts.Contains(p.srfAttachNode.attachedPart)) { // Add this surface attached part and all the sub-parts: dummyVessel.parts = FindAndAddAttachedParts(p, ref dummyVessel.parts); processedParts++; } } else { // Simply copy this part: dummyVessel.parts.Add(p); } } if (processedParts == 0) { // If there are still unprocessed parts, just throw them in the list during the next iteration, // this should not happen but we don't want to end up in an endless loop: handleSurfaceAttachments = false; } } // Initialize all parts: uint missionID = (uint)Guid.NewGuid().GetHashCode(); uint launchID = HighLogic.CurrentGame.launchID++; foreach (Part p in dummyVessel.parts) { p.flagURL = flagURL == null ? HighLogic.CurrentGame.flagURL : flagURL; p.missionID = missionID; p.launchID = launchID; p.temperature = 1.0; // If the KRnD-Mod is installed, make sure that all parts of this newly created ship are set to the lates version: foreach (PartModule module in p.Modules) { if (module.moduleName != "KRnDModule") { continue; } Debug.Log("[KSTS] found KRnD on '" + p.name.ToString() + "', setting to latest stats"); foreach (BaseField field in module.Fields) { if (field.name.ToString() == "upgradeToLatest") { field.SetValue(1, module); // Newer versions of KRnD use this flag to upgrade all attributes of the given part to the latest levels, when the vessel is activated. if (field.GetValue(module).ToString() != "1") { Debug.LogError("[KSTS] unable to modify '" + field.name.ToString() + "'"); } } } } dummyProto.protoPartSnapshots.Add(new ProtoPartSnapshot(p, dummyProto)); } // Store the parts in Config-Nodes: foreach (ProtoPartSnapshot p in dummyProto.protoPartSnapshots) { p.storePartRefs(); } List <ConfigNode> partNodesL = new List <ConfigNode>(); foreach (var snapShot in dummyProto.protoPartSnapshots) { ConfigNode node = new ConfigNode("PART"); snapShot.Save(node); partNodesL.Add(node); } ConfigNode[] partNodes = partNodesL.ToArray(); ConfigNode[] additionalNodes = new ConfigNode[0]; // This will actually create the ship and add it to the global list of flights: ConfigNode protoVesselNode = ProtoVessel.CreateVesselNode(shipName, VesselType.Ship, orbit, 0, partNodes, additionalNodes); ProtoVessel pv = HighLogic.CurrentGame.AddVessel(protoVesselNode); Debug.Log("[KSTS] deployed new ship '" + shipName.ToString() + "' as '" + pv.vesselRef.id.ToString() + "'"); ScreenMessages.PostScreenMessage("Vessel '" + shipName.ToString() + "' deployed"); // Popup message to notify the player Vessel newVessel = FlightGlobals.Vessels.Find(x => x.id == pv.vesselID); // Maybe add the initial crew to the vessel: if (crewToDeliver != null && crewToDeliver.Count > 0 && newVessel != null) { foreach (string kerbonautName in crewToDeliver) { TargetVessel.AddCrewMember(newVessel, kerbonautName); } } } catch (Exception e) { Debug.LogError("[KSTS] Mission.CreateShip(): " + e.ToString()); } }