Esempio n. 1
0
        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);
        }
Esempio n. 2
0
 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)));
     }
 }
Esempio n. 3
0
        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);
        }
Esempio n. 5
0
        /* 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);
                }
            }
        }
Esempio n. 8
0
        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);
            }
        }
Esempio n. 9
0
        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);
        }
Esempio n. 11
0
    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;
        }