private ShipConstruct shipConstruct = null; // Only needed to get more info about the template-ship, like its crew-capacity. public int GetCrewCapacity() { int crewCapacity = 0; if (HighLogic.LoadedScene == GameScenes.FLIGHT) { throw new Exception("ShipConstruction.LoadShip cannot be run while in flight"); // This would create a new, non-functioning vessel near the current vessel } try { if (this.shipConstruct == null) { shipConstruct = ShipConstruction.LoadShip(template.filename); } foreach (Part part in shipConstruct.parts) { crewCapacity += part.CrewCapacity; } } catch (Exception e) { Debug.LogError("[KSTS] CachedShipTemplate::GetCrewCapacity(): " + e.ToString()); } return(crewCapacity); }
public void SpawnVessel() { //var allowedSituations = Vessel.Situations.LANDED | Vessel.Situations.PRELAUNCH | Vessel.Situations.SPLASHED; //if (allowedSituations != (allowedSituations & FlightGlobals.ActiveVessel.situation)) //{ // throw new Exception(_notLandedErrorText); //} if (string.IsNullOrEmpty(_selectedCraftFilePath)) { throw new Exception(_noVesselSelectedErrorText); } PartUtilities.ConsumeResources(_cachedCostData); // Backup the ship config from the VAB/SPH, load the selected .craft file // and restore the cached config from the VAB/SPH var constructBak = ShipConstruction.ShipConfig; var construct = ShipConstruction.LoadShip(_selectedCraftFilePath); ShipConstruction.ShipConfig = constructBak; ShipConstruction.PutShipToGround(construct, transform); ShipConstruction.AssembleForLaunch( construct, vessel.landedAt, vessel.displaylandedAt, construct.missionFlag, HighLogic.CurrentGame, new VesselCrewManifest()); _window.CloseWindow(); }
public double GetDryMass() { double dryMass = 0; if (HighLogic.LoadedScene == GameScenes.FLIGHT) { throw new Exception("ShipConstruction.LoadShip cannot be run while in flight"); // This would create a new, non-functioning vessel near the current vessel } try { if (this.shipConstruct == null) { shipConstruct = ShipConstruction.LoadShip(template.filename); } foreach (Part part in shipConstruct.parts) { dryMass += part.mass - part.resourceMass; } } catch (Exception e) { Debug.LogError("[KSTS] CachedShipTemplate::GetDryMass(): " + e.ToString()); } return(dryMass); }
// 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); } }
/// <summary> /// //////////////////// /// </summary> protected void BuildContent() { // getModList (); m_directoriesWithImages = new GUIContent[m_directories.Length]; for (int i = 0; i < m_directoriesWithImages.Length; ++i) { m_directoriesWithImages [i] = new GUIContent(m_directories [i], DirectoryImage); } m_nonMatchingDirectoriesWithImages = new GUIContent[m_nonMatchingDirectories.Length]; for (int i = 0; i < m_nonMatchingDirectoriesWithImages.Length; ++i) { m_nonMatchingDirectoriesWithImages [i] = new GUIContent(m_nonMatchingDirectories [i], DirectoryImage); } m_filesWithImages = new GUIContent[m_files.Length]; //ShipConstruct ship; // = new ShipConstruct (); for (int i = 0; i < m_filesWithImages.Length; ++i) { #if false //if (i == 0) if (m_files [i].Contains(".craft")) { string f = m_newDirectory + "/" + m_files [i]; Log.Info("f: " + f); if (System.IO.File.Exists(f)) { //var configFile = ConfigNode.Load (f); ShipConstruct ship = ShipConstruction.LoadShip(f); ThumbnailHelper.CaptureThumbnail(ship, 256, "tmp", m_files [i] + i.ToString()); //ShipConstruction.CaptureThumbnail (ship, "tmp", m_files [i] + "-2-" + i.ToString ()); foreach (var p in ship.Parts) { UnityEngine.Object.Destroy(p.gameObject); } //configFile = null; //ship = null; } } #endif m_filesWithImages [i] = new GUIContent(m_files [i], FileImage); } m_nonMatchingFilesWithImages = new GUIContent[m_nonMatchingFiles.Length]; for (int i = 0; i < m_nonMatchingFilesWithImages.Length; ++i) { m_nonMatchingFilesWithImages [i] = new GUIContent(m_nonMatchingFiles [i], FileImage); } }
private void BuildAndLaunchCraft() { // build craft ShipConstruct nship = ShipConstruction.LoadShip(uis.craftfile); Vector3 offset = nship.Parts[0].transform.localPosition; nship.Parts[0].transform.Translate(-offset); string landedAt = "External Launchpad"; string flag = uis.flagname; Game state = FlightDriver.FlightStateCache; VesselCrewManifest crew = new VesselCrewManifest(); ShipConstruction.CreateBackup(nship); ShipConstruction.PutShipToGround(nship, GetLanchTransform()); ShipConstruction.AssembleForLaunch(nship, landedAt, flag, state, crew); Vessel vsl = FlightGlobals.Vessels[FlightGlobals.Vessels.Count - 1]; FlightGlobals.ForceSetActiveVessel(vsl); vsl.Landed = false; if (kethane_present && !DebugPad) { UseResources(vsl); } if (vessel.situation == Vessel.Situations.ORBITING) { HackStruts(vsl); uis.vesselInfo = new DockedVesselInfo(); uis.vesselInfo.name = vsl.vesselName; uis.vesselInfo.vesselType = vsl.vesselType; uis.vesselInfo.rootPartUId = vsl.rootPart.flightID; vsl.rootPart.Couple(part); FlightGlobals.ForceSetActiveVessel(vessel); } else { uis.timer = 3.0f; uis.launchee = vsl; } Staging.beginFlight(); }
private void BuildCraft() { // build craft ShipConstruct nship = ShipConstruction.LoadShip(uifs.craftfile); Transform launchtransform = GetLaunchTransform(); Vector3 offset = nship.Parts[0].transform.localPosition; nship.Parts[0].transform.Translate(-offset); Game state = FlightDriver.FlightStateCache; VesselCrewManifest crew = new VesselCrewManifest(); ShipConstruction.CreateBackup(nship); ShipConstruction.PutShipToGround(nship, launchtransform); ShipConstruction.AssembleForLaunch(nship, uifs.LaunchSiteName, uifs.flagname, state, crew); Vessel vsl = FlightGlobals.Vessels[FlightGlobals.Vessels.Count - 1]; FlightGlobals.ForceSetActiveVessel(vsl); vsl.Landed = false; HackStruts(vsl); uifs.vesselInfo = new DockedVesselInfo(); uifs.vesselInfo.name = vsl.vesselName; uifs.vesselInfo.vesselType = vsl.vesselType; uifs.vesselInfo.rootPartUId = vsl.rootPart.uid; uifs.vesselFlightID = vsl.rootPart.flightID; FlightDriver.flightStarted = true; FlightDriver.newShipFlagURL = uifs.flagname; FlightDriver.newShipManifest = crew; vsl.state = Vessel.State.ACTIVE; vsl.situation = Vessel.Situations.ORBITING; Staging.beginFlight(); vsl.ResumeStaging(); Staging.GenerateStagingSequence(vsl.rootPart); Staging.RecalculateVesselStaging(vsl); FlightGlobals.ForceSetActiveVessel(vessel); vsl.rootPart.Couple(part); vessel.ResumeStaging(); Staging.GenerateStagingSequence(vessel.rootPart); Staging.RecalculateVesselStaging(vessel); Events[("DecoupleVessel")].active = true; }
/// <summary> /// Attempt vessel load /// </summary> /// <param name="_craftFile"></param> /// <returns></returns> private ShipConstruct LoadVessel(string _craftFile) { //Get path to vessel string BasePath = Environment.CurrentDirectory + PluginPath; string path = BasePath + _craftFile; Log.Info("LoadVessel, full path: " + path); //Save old ship for later, else player will see it in the VAB _OldVabShip = new HideConfigNode(ShipConstruction.ShipConfig); //Load craft file ShipConstruct _shipConstruct = ShipConstruction.LoadShip(path); //Check load if (_shipConstruct == null) { // Restore ShipConstruction ship, otherwise player sees loaded craft in VAB ShipConstruction.ShipConfig = _OldVabShip.GetConfigNode(); Log.Info("vessel not loaded"); return(null); //Fail } return(_shipConstruct); }
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; }
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); }
void SpawnVessel(VesselData vesselData) { string gameDataDir = KSPUtil.ApplicationRootPath; vesselData.orbit = vessel.GetOrbit(); vesselData.orbit.vel = vessel.orbit.vel; vesselData.orbit.meanAnomalyAtEpoch = vesselData.orbit.meanAnomalyAtEpoch + Math.Atan(UnityEngine.Random.Range(200, 300) / vesselData.orbit.semiMajorAxis); ConfigNode[] partNodes; ShipConstruct shipConstruct = null; float lcHeight = 0; ConfigNode craftNode; ConfigNode currentShip = ShipConstruction.ShipConfig; shipConstruct = ShipConstruction.LoadShip(vesselData.craftURL); float dryCost = 0; float cost = 0; shipConstruct.GetShipCosts(out dryCost, out cost); cost = cost + dryCost; if (cost > Funding.Instance.Funds) { foreach (var p in FindObjectsOfType <Part>()) { if (!p.vessel) { Destroy(p.gameObject); } } ScreenMessages.PostScreenMessage("not enought funds", 5.0f, ScreenMessageStyle.UPPER_CENTER); return; } craftNode = ConfigNode.Load(vesselData.craftURL); lcHeight = ConfigNode.ParseVector3(craftNode.GetNode("PART").GetValue("pos")).y; ShipConstruction.ShipConfig = currentShip; vesselData.name = shipConstruct.shipName; uint missionID = (uint)Guid.NewGuid().GetHashCode(); uint launchID = HighLogic.CurrentGame.launchID++; foreach (Part p in shipConstruct.parts) { p.missionID = missionID; p.launchID = launchID; p.flightID = ShipConstruction.GetUniqueFlightID(HighLogic.CurrentGame.flightState); p.temperature = 1.0; } ConfigNode empty = new ConfigNode(); ProtoVessel dummyProto = new ProtoVessel(empty, null); Vessel dummyVessel = new Vessel(); dummyVessel.parts = shipConstruct.parts; dummyProto.vesselRef = dummyVessel; foreach (Part p in shipConstruct.parts) { dummyProto.protoPartSnapshots.Add(new ProtoPartSnapshot(p, dummyProto)); } 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); } partNodes = partNodesL.ToArray(); ConfigNode[] additionalNodes = new ConfigNode[0]; ConfigNode protoVesselNode = ProtoVessel.CreateVesselNode(vesselData.name, VesselType.Ship, vesselData.orbit, 0, partNodes, additionalNodes); ProtoVessel protoVessel = HighLogic.CurrentGame.AddVessel(protoVesselNode); vesselData.id = protoVessel.vesselRef.id; protoVessel.vesselRef.Load(); Funding.Instance.AddFunds(-cost, TransactionReasons.Vessels); ScreenMessages.PostScreenMessage("vessel buy !", 5.0f, ScreenMessageStyle.UPPER_CENTER); foreach (var p in FindObjectsOfType <Part>()) { if (!p.vessel) { Destroy(p.gameObject); } } }
void SpawnVessel(string craftURL, CelestialBody orbitmainBodyName, double altitude, string stationName) { foreach (Vessel vessel in FlightGlobals.Vessels) { if (vessel.vesselName == stationName) { vessel.Die(); break; } } VesselData vesselData = new VesselData(); vesselData.craftURL = craftURL; vesselData.orbiting = true; vesselData.flagURL = HighLogic.CurrentGame.flagURL; vesselData.owned = true; string gameDataDir = KSPUtil.ApplicationRootPath; ConfigNode[] partNodes; ShipConstruct shipConstruct = null; float lcHeight = 0; ConfigNode craftNode; ConfigNode currentShip = ShipConstruction.ShipConfig; shipConstruct = ShipConstruction.LoadShip(vesselData.craftURL); craftNode = ConfigNode.Load(vesselData.craftURL); lcHeight = ConfigNode.ParseVector3(craftNode.GetNode("PART").GetValue("pos")).y; ShipConstruction.ShipConfig = currentShip; ConfigNode empty = new ConfigNode(); ProtoVessel dummyProto = new ProtoVessel(empty, null); Vessel dummyVessel = new Vessel(); dummyVessel.parts = shipConstruct.parts; dummyProto.vesselRef = dummyVessel; uint missionID = (uint)Guid.NewGuid().GetHashCode(); uint launchID = HighLogic.CurrentGame.launchID++; foreach (Part p in shipConstruct.parts) { p.missionID = missionID; p.launchID = launchID; p.flightID = ShipConstruction.GetUniqueFlightID(HighLogic.CurrentGame.flightState); p.temperature = 1.0; dummyProto.protoPartSnapshots.Add(new ProtoPartSnapshot(p, dummyProto)); } 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); } partNodes = partNodesL.ToArray(); ConfigNode[] additionalNodes = new ConfigNode[0]; ConfigNode protoVesselNode = ProtoVessel.CreateVesselNode(stationName, VesselType.Station, new Orbit(0, 0, altitude + orbitmainBodyName.Radius, 0, 0, 0, 0, orbitmainBodyName), 0, partNodes, additionalNodes); ProtoVessel protoVessel = HighLogic.CurrentGame.AddVessel(protoVesselNode); vesselData.id = protoVessel.vesselRef.id; foreach (var p in FindObjectsOfType <Part>()) { if (!p.vessel) { Destroy(p.gameObject); } } }
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); } } }
static void SpawnVessel(VesselData vesselData) { string gameDataDir = KSPUtil.ApplicationRootPath; if (vesselData.vesselType == VesselType.Ship) { vesselData.name = "abandoned ship " + UnityEngine.Random.Range(1000, 10000); } else { vesselData.name = "abandoned science station " + UnityEngine.Random.Range(1000, 10000); } vesselData.orbit = FlightGlobals.ActiveVessel.GetOrbit(); vesselData.orbit.inclination = UnityEngine.Random.Range(0, 360); vesselData.orbit.eccentricity = UnityEngine.Random.Range(0, 0.3f); vesselData.orbit.semiMajorAxis = UnityEngine.Random.Range(Convert.ToSingle(FlightGlobals.ActiveVessel.mainBody.Radius + FlightGlobals.ActiveVessel.mainBody.atmosphereDepth + 50000), Convert.ToSingle(FlightGlobals.ActiveVessel.mainBody.sphereOfInfluence)); vesselData.orbit.LAN = UnityEngine.Random.Range(0, 360); vesselData.orbit.argumentOfPeriapsis = UnityEngine.Random.Range(0, 360); vesselData.orbit.meanAnomalyAtEpoch = 0; ConfigNode[] partNodes; ShipConstruct shipConstruct = null; float lcHeight = 0; ConfigNode craftNode; ConfigNode currentShip = ShipConstruction.ShipConfig; shipConstruct = ShipConstruction.LoadShip(vesselData.craftURL); craftNode = ConfigNode.Load(vesselData.craftURL); lcHeight = ConfigNode.ParseVector3(craftNode.GetNode("PART").GetValue("pos")).y; ShipConstruction.ShipConfig = currentShip; ConfigNode empty = new ConfigNode(); ProtoVessel dummyProto = new ProtoVessel(empty, null); Vessel dummyVessel = new Vessel(); dummyVessel.parts = shipConstruct.parts; dummyProto.vesselRef = dummyVessel; uint missionID = (uint)Guid.NewGuid().GetHashCode(); uint launchID = HighLogic.CurrentGame.launchID++; foreach (Part p in shipConstruct.parts) { p.missionID = missionID; p.launchID = launchID; p.flightID = ShipConstruction.GetUniqueFlightID(HighLogic.CurrentGame.flightState); p.temperature = 1.0; dummyProto.protoPartSnapshots.Add(new ProtoPartSnapshot(p, dummyProto)); } 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); } partNodes = partNodesL.ToArray(); ConfigNode[] additionalNodes = new ConfigNode[0]; ConfigNode protoVesselNode = ProtoVessel.CreateVesselNode(vesselData.name, vesselData.vesselType, vesselData.orbit, 0, partNodes, additionalNodes); ProtoVessel protoVessel = HighLogic.CurrentGame.AddVessel(protoVesselNode); vesselData.id = protoVessel.vesselRef.id; foreach (var p in FindObjectsOfType <Part>()) { if (!p.vessel) { Destroy(p.gameObject); } } if (vesselData.vesselType == VesselType.Ship) { setResourcesAmount(protoVessel.vesselRef); } if (vesselData.vesselType == VesselType.Station) { setScience(protoVessel.vesselRef); } }
static void ReadAllCraftFiles(string editorFacility, string shipDirectory) { foreach (var craftFile in Directory.GetFiles(shipDirectory, "*.craft")) { try { string validFileName = Path.GetFileNameWithoutExtension(craftFile); if (validFileName == "Auto-Saved Ship") { continue; // Skip these, they would lead to duplicates, we only use finished crafts. } var cachedTemplate = new CachedShipTemplate(); switch (editorFacility) { case "VAB": cachedTemplate.templateOrigin = TemplateOrigin.VAB; break; case "SPH": cachedTemplate.templateOrigin = TemplateOrigin.SPH; break; case "Subassemblies": cachedTemplate.templateOrigin = TemplateOrigin.SubAssembly; break; } cachedTemplate.template = ShipConstruction.LoadTemplate(craftFile); if (cachedTemplate.template == null) { continue; } if (cachedTemplate.template.shipPartsExperimental || !cachedTemplate.template.shipPartsUnlocked) { continue; // We won't bother with ships we can't use anyways. } // Try to load the thumbnail for this craft: var thumbFile = KSPUtil.ApplicationRootPath + "thumbs/" + HighLogic.SaveFolder + "_" + editorFacility + "_" + validFileName + ".png"; Texture2D thumbnail; // // Make the thumbnail file if it doesn't exist. // Needed for the subassemblies, will also replace any missing thumbnail files for regular craft // if (!HighLogic.LoadedSceneIsFlight) { if (!File.Exists(thumbFile)) { Log.Info("Missing Thumbfile: " + thumbFile); ShipConstruct ship = ShipConstruction.LoadShip(craftFile); ThumbnailHelper.CaptureThumbnail(ship, 256, "thumbs/", HighLogic.SaveFolder + "_" + editorFacility + "_" + validFileName); } } bool placeholder = false; if (File.Exists(thumbFile)) { thumbnail = new Texture2D(256, 256, TextureFormat.RGBA32, false); thumbnail.LoadImage(File.ReadAllBytes(thumbFile)); } else { thumbnail = placeholderImage; placeholder = true; } // The thumbnails are rather large, so we have to resize them first: cachedTemplate.thumbnail = GUI.ResizeTexture(thumbnail, 64, 64); if (!placeholder) { Destroy(thumbnail); } GUI.shipTemplates.Add(cachedTemplate); } catch (Exception e) { Debug.LogError("UpdateShipTemplateCache() processing '" + craftFile + "': " + e.ToString()); } } }
// 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()); } }
protected ProtoVessel CreateProtoVessel() { ProtoVessel protoVessel = null; ShipConstruct construct = null; Vessel vessel = null; try { // Backup the ship config from the VAB/SPH, load the selected .craft file // and restore the cached config from the VAB/SPH var constructBak = ShipConstruction.ShipConfig; construct = ShipConstruction.LoadShip(_selectedCraftFilePath); ShipConstruction.ShipConfig = constructBak; // Calculate vessel cost and mass and generate a thumbnail construct.GetShipCosts(out _cachedFundsCost, out _); construct.GetShipMass(out _cachedDryMass, out _); _cachedThumbnail = _thumbnailService.GetThumbnail(construct); // Create an emtpy Vessel and copy the parts from the loaded .craft file vessel = new GameObject().AddComponent <Vessel>(); vessel.parts = construct.parts; // Create an empty ProtoVessel that we'll ultimately use to create the template // for the vessel to be spawned in-game later protoVessel = new ProtoVessel(new ConfigNode(), null) { vesselName = construct.shipName, vesselRef = vessel }; // Setup necessary Vessel and Part parameters for the template (also check for launch clamps) var launchId = HighLogic.CurrentGame.launchID++; var missionId = (uint)Guid.NewGuid().GetHashCode(); var rootPart = construct.parts.First(); _hasLaunchClamp = false; foreach (var part in construct.parts) { _hasLaunchClamp |= part.HasModuleImplementing <LaunchClamp>(); part.flagURL = construct.missionFlag ?? HighLogic.CurrentGame.flagURL; part.flightID = ShipConstruction.GetUniqueFlightID(HighLogic.CurrentGame.flightState); part.launchID = launchId; part.missionID = missionId; part.temperature = Math.Abs(part.temperature); part.UpdateOrgPosAndRot(rootPart); part.vessel = vessel; var partSnapshot = new ProtoPartSnapshot(part, protoVessel); foreach (var resource in partSnapshot.resources) { if (resource.resourceName != "ElectricCharge") { resource.amount = 0d; } } protoVessel.protoPartSnapshots.Add(partSnapshot); } foreach (var snapshot in protoVessel.protoPartSnapshots) { snapshot.storePartRefs(); } // Cache the ProtoVessel to use as the template for spawning the vessel later _cachedProtoVessel = protoVessel; } catch (Exception ex) { Debug.LogException(ex); } finally { // ShipConstruction.LoadShip seems to load in all the part meshes for the vessel // (presumably for use in the VAB/SPH), so we need to destroy them if (construct != null && construct.parts != null && construct.parts.Count > 0) { foreach (var part in construct.parts) { Destroy(part.gameObject); } } // Destroy the temporary Vessel we created as well if (vessel != null) { Destroy(vessel.gameObject); } } return(protoVessel); }
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); } } }
public static Vessel SpawnVessel(string name, string craftURL, string flagURL, VesselType vesselType, CelestialBody body, Orbit orbit, List <ProtoCrewMember> crewList) { string gameDataDir = KSPUtil.ApplicationRootPath; ConfigNode[] partNodes; ShipConstruct shipConstruct = null; float lcHeight = 0; ConfigNode craftNode; ConfigNode currentShip = ShipConstruction.ShipConfig; shipConstruct = ShipConstruction.LoadShip(craftURL); craftNode = ConfigNode.Load(craftURL); lcHeight = ConfigNode.ParseVector3(craftNode.GetNode("PART").GetValue("pos")).y; ShipConstruction.ShipConfig = currentShip; foreach (ProtoCrewMember crew in crewList) { Part part = shipConstruct.parts.Find(p => p.protoModuleCrew.Count < p.CrewCapacity); if (part != null) { part.AddCrewmemberAt(crew, part.protoModuleCrew.Count); } } ConfigNode empty = new ConfigNode(); ProtoVessel dummyProto = new ProtoVessel(empty, null); Vessel dummyVessel = new Vessel(); dummyVessel.parts = shipConstruct.parts; dummyProto.vesselRef = dummyVessel; uint missionID = (uint)Guid.NewGuid().GetHashCode(); uint launchID = HighLogic.CurrentGame.launchID++; foreach (Part p in shipConstruct.parts) { p.missionID = missionID; p.launchID = launchID; p.flightID = ShipConstruction.GetUniqueFlightID(HighLogic.CurrentGame.flightState); p.temperature = 1.0; dummyProto.protoPartSnapshots.Add(new ProtoPartSnapshot(p, dummyProto)); } 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); } partNodes = partNodesL.ToArray(); ConfigNode[] additionalNodes = new ConfigNode[0]; ConfigNode protoVesselNode = ProtoVessel.CreateVesselNode(name, VesselType.Ship, orbit, 0, partNodes, additionalNodes); ProtoVessel protoVessel = HighLogic.CurrentGame.AddVessel(protoVesselNode); foreach (var p in UnityEngine.Object.FindObjectsOfType <Part>()) { if (!p.vessel) { UnityEngine.Object.Destroy(p.gameObject); } } return(protoVessel.vesselRef); }