public void CreateVessel(comms.VesselList.VesselInfo vesselInfo) { try { this.Logger.LogDebug("creating vessel {0} {1}", vesselInfo.name, vesselInfo.id); var pv = new ProtoVessel(this.DummyVesselConfigNode, HighLogic.CurrentGame); pv.vesselID = vesselInfo.id; pv.vesselName = vesselInfo.name; pv.vesselType = (VesselType)vesselInfo.type; pv.altitude = vesselInfo.altitude; pv.landed = vesselInfo.landed; pv.landedAt = vesselInfo.landedAt; pv.latitude = vesselInfo.latitude; pv.longitude = vesselInfo.longitude; pv.situation = (Vessel.Situations)vesselInfo.situation; pv.splashed = vesselInfo.splashed; pv.orbitSnapShot = new OrbitSnapshot(vesselInfo.orbit.GetKspOrbit(FlightGlobals.Bodies)); pv.Load(HighLogic.CurrentGame.flightState); } catch (Exception e) { this.Logger.LogException(e); throw; } }
public IEnumerator <YieldInstruction> SpawnProtoVessel(ProtoVessel proto_vessel, Transform spawn_transform, Vector3 spawn_offset, Vector3 dV, Callback <ProtoVessel> on_proto_vessel_positioned = null, Callback <Vessel> on_vessel_loaded = null, Callback <Vessel> on_vessel_off_rails = null, Callback <Vessel> on_vessel_launched = null) { begin_launch(spawn_transform); position_proto_vessel(proto_vessel, spawn_transform, spawn_offset); on_proto_vessel_positioned?.Invoke(proto_vessel); proto_vessel.Load(HighLogic.CurrentGame.flightState); launched_vessel = proto_vessel.vesselRef; launched_vessel.orbitDriver.updateMode = OrbitDriver.UpdateMode.TRACK_Phys; launched_vessel.skipGroundPositioning = true; foreach (var i in launch_moving_vessel(spawn_transform, spawn_offset, Quaternion.identity, dV, on_vessel_loaded, on_vessel_off_rails, on_vessel_launched)) { yield return(i); } end_launch(); }
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); }
/// <summary> /// Loads the vessel proto into the current game /// </summary> private static bool LoadVesselIntoGame(ProtoVessel currentProto) { if (HighLogic.CurrentGame?.flightState == null) { return(false); } LunaLog.Log($"[LMP]: Loading {currentProto.vesselID}, Name: {currentProto.vesselName}, type: {currentProto.vesselType}"); currentProto.Load(HighLogic.CurrentGame.flightState); if (currentProto.vesselRef == null) { LunaLog.Log($"[LMP]: Protovessel {currentProto.vesselID} failed to create a vessel!"); return(false); } SystemsContainer.Get <PlayerColorSystem>().SetVesselOrbitColor(currentProto.vesselRef); if (HighLogic.LoadedScene == GameScenes.TRACKSTATION) { //When in trackstation rebuild the vessels left panel as otherwise the new vessel won't be listed var spaceTracking = Object.FindObjectOfType <SpaceTracking>(); if (spaceTracking != null) { BuildSpaceTrackingVesselList?.Invoke(spaceTracking, null); } } return(true); }
public static void UnhangarCraft(Vessel vVesselStored, StaticObject soHangar) { RemoveCorrectCraft(vVesselStored, soHangar); // Convert the stored protovessel to a new protovessel. // Use BackupVessel because that seems to work and protovessel does not. `\o/` ProtoVessel pVessel = vVesselStored.BackupVessel(); // Get rid of the original hidden vessel - even though it was unloaded KSP still 'sees' the original craft. // I do not care why. :| vVesselStored.state = Vessel.State.DEAD; foreach (Part p in vVesselStored.Parts) { if (p != null && p.gameObject != null) { p.gameObject.DestroyGameObject(); } } // Load the new protovessel we made. KSP won't reload (or rather render) a vessel that was unloaded - it will only load a protovessel. :$ pVessel.Load(FlightDriver.FlightStateCache.flightState); // I suspect this is actually a KSP bug since the same crap happens with newly spawned static objects. If you query the active state // of the invisible craft, it claims it is active. And no, forcing the renderers doesn't work either. // Convert protovessel to vessel Vessel vNewVessel = pVessel.vesselRef; // Unload then reload the vessel - this seems to be the way to properly re-initialise flightstate etc. // Don't do this and you get a craft with a stuck surface velocity reading. It looks like KSP transposes orbital // and surface velocity or some other stupid s**t. I don't care. // And yes, this time KSP does load an unloaded vessel with no need for protovessel b******t. I don't care why. vNewVessel.Unload(); vNewVessel.Load(); }
public void AllocVessel(NetworkViewID id, byte[] binaryCfg) { if (FlightGlobals.Vessels.Any(v => v.networkView != null && v.networkView.viewID == id)) return; var cfg = (ConfigNode)IOUtils.DeserializeFromBinary(binaryCfg); var protovessel = new ProtoVessel(cfg, HighLogic.CurrentGame.flightState); protovessel.orbitSnapShot.meanAnomalyAtEpoch += 1; protovessel.Load(HighLogic.CurrentGame.flightState); var vessel = protovessel.vesselRef; vessel.gameObject.AddNetworkView(id); vessel.gameObject.AddComponent<VesselNetworker>(); }
/// <summary> /// Loads the vessel proto into the current game /// </summary> private static bool LoadVesselIntoGame(ProtoVessel currentProto) { LunaLog.Log($"[LMP]: Loading {currentProto.vesselID}, Name: {currentProto.vesselName}, type: {currentProto.vesselType}"); currentProto.Load(HighLogic.CurrentGame.flightState); if (currentProto.vesselRef == null) { LunaLog.Log($"[LMP]: Protovessel {currentProto.vesselID} failed to create a vessel!"); return(false); } return(true); }
public void AllocVessel(NetworkViewID id, byte[] binaryCfg) { if (FlightGlobals.Vessels.Any(v => v.networkView != null && v.networkView.viewID == id)) { return; } var cfg = (ConfigNode)IOUtils.DeserializeFromBinary(binaryCfg); var protovessel = new ProtoVessel(cfg, HighLogic.CurrentGame.flightState); protovessel.orbitSnapShot.meanAnomalyAtEpoch += 1; protovessel.Load(HighLogic.CurrentGame.flightState); var vessel = protovessel.vesselRef; vessel.gameObject.AddNetworkView(id); vessel.gameObject.AddComponent <VesselNetworker>(); }
/// <summary> /// Loads the vessel proto into the current game /// </summary> private static bool LoadVesselIntoGame(ProtoVessel currentProto) { if (HighLogic.CurrentGame?.flightState == null) { return(false); } LunaLog.Log($"[LMP]: Loading {currentProto.vesselID}, Name: {currentProto.vesselName}, type: {currentProto.vesselType}"); currentProto.Load(HighLogic.CurrentGame.flightState); if (currentProto.vesselRef == null) { LunaLog.Log($"[LMP]: Protovessel {currentProto.vesselID} failed to create a vessel!"); return(false); } if (currentProto.vesselRef.isEVA) { var evaModule = currentProto.vesselRef.FindPartModuleImplementing <KerbalEVA>(); if (evaModule != null && evaModule.fsm != null && !evaModule.fsm.Started) { evaModule.fsm?.StartFSM("Idle (Grounded)"); } currentProto.vesselRef.GoOnRails(); } currentProto.vesselRef.orbitDriver?.updateFromParameters(); PlayerColorSystem.Singleton.SetVesselOrbitColor(currentProto.vesselRef); if (HighLogic.LoadedScene == GameScenes.TRACKSTATION) { //When in trackstation rebuild the vessels left panel as otherwise the new vessel won't be listed var spaceTracking = Object.FindObjectOfType <SpaceTracking>(); if (spaceTracking != null) { BuildSpaceTrackingVesselList?.Invoke(spaceTracking, null); } } if (HighLogic.LoadedScene == GameScenes.SPACECENTER) { KSCVesselMarkers.fetch?.RefreshMarkers(); } return(true); }
internal static Vessel RollOutVessel(StoredVessel storedVessel, Hangar hangar) { if (!hangar.storedVessels.Contains(storedVessel)) { Log.Error("no Stored Vessel found:" + storedVessel.vesselName); return(null); } hangar.storedVessels.Remove(storedVessel); ProtoVessel protoVessel = new ProtoVessel(storedVessel.vesselNode, HighLogic.CurrentGame); protoVessel.Load(HighLogic.CurrentGame.flightState); Vessel vessel = protoVessel.vesselRef; return(vessel); }
/// <summary> /// Loads the vessel proto into the current game /// </summary> private static bool LoadVesselIntoGame(ProtoVessel currentProto) { try { Debug.Log($"[LMP]: Loading {currentProto.vesselID}, Name: {currentProto.vesselName}, type: {currentProto.vesselType}"); currentProto.Load(HighLogic.CurrentGame.flightState); if (currentProto.vesselRef == null) { Debug.Log($"[LMP]: Protovessel {currentProto.vesselID} failed to create a vessel!"); return(false); } return(true); } catch (Exception e) { Debug.LogError($"[LMP]: Error in coroutine LoadVessel {e}"); return(false); } }
/// <summary> /// Rollout the Vessel and store it in the placeHolder variable, then open the Crew assignment dialog /// </summary> /// <param name="storedVessel"></param> /// <param name="hangar"></param> internal static void SelectVessel(Modules.Hangar.StoredVessel storedVessel, Modules.Hangar hangar) { if (selectedVessel != null) { foreach (ProtoCrewMember crew in selectedVessel.GetVesselCrew()) { // unseat all crew crew.rosterStatus = ProtoCrewMember.RosterStatus.Available; crew.seatIdx = -1; } } selectedVessel = null; if (!hangar.storedVessels.Contains(storedVessel)) { Log.Error("no stored vessel found:" + storedVessel.vesselName); return; } selectedHangar = hangar; selectedStoredVessel = storedVessel; ProtoVessel protoVessel = new ProtoVessel(storedVessel.vesselNode, HighLogic.CurrentGame); protoVessel.Load(HighLogic.CurrentGame.flightState); selectedVessel = protoVessel; if (selectedVessel == null) { Log.UserError("Could not receive vessel from storage."); return; } Reload(); }
private IEnumerator<WaitForFixedUpdate> loadProtovessel(Vessel oldVessel, Vector3 newWorldPos, Vector3 newOrbitVel, bool wasLoaded, bool wasActive, bool setTarget, ProtoVessel protovessel, Guid vessel_id, KMPVessel kvessel, KMPVesselUpdate update, double distance) { yield return new WaitForFixedUpdate(); Log.Debug("Loading protovessel: {0}", vessel_id.ToString() + ", name: " + protovessel.vesselName + ", type: " + protovessel.vesselType); if (oldVessel != null && !wasActive) { killVessel(oldVessel); } serverVessels_LoadDelay[vessel_id] = UnityEngine.Time.realtimeSinceStartup + 5f; serverVessels_PartCounts[vessel_id] = protovessel.protoPartSnapshots.Count; protovessel.Load(HighLogic.CurrentGame.flightState); Vessel created_vessel = protovessel.vesselRef; if (created_vessel != null) { try { OrbitPhysicsManager.HoldVesselUnpack(1); } catch (NullReferenceException e) { Log.Debug("Exception thrown in loadProtovessel(), catch 1, Exception: {0}", e.ToString()); } Log.Debug(created_vessel.id.ToString() + " initializing: ProtoParts=" + protovessel.protoPartSnapshots.Count + ",Parts=" + created_vessel.Parts.Count + ",Sit=" + created_vessel.situation.ToString() + ",type=" + created_vessel.vesselType + ",alt=" + protovessel.altitude); //vessels[vessel_id.ToString()].vessel.vesselRef = created_vessel; serverVessels_PartCounts[vessel_id] = created_vessel.Parts.Count; serverVessels_Parts[vessel_id] = new List<Part>(); serverVessels_Parts[vessel_id].AddRange(created_vessel.Parts); if (created_vessel.vesselType != VesselType.Flag && created_vessel.vesselType != VesselType.EVA) { foreach (Part part in created_vessel.Parts) { part.OnLoad(); part.OnJustAboutToBeDestroyed += checkRemoteVesselIntegrity; part.explosionPotential = 0; part.terrainCollider = new PQS_PartCollider(); part.terrainCollider.part = part; part.terrainCollider.useVelocityCollider = false; part.terrainCollider.useGravityCollider = false; part.breakingForce = float.MaxValue; part.breakingTorque = float.MaxValue; } if (update == null || (update != null && update.bodyName == FlightGlobals.ActiveVessel.mainBody.name)) { Log.Debug("update included"); if (update == null || (update.relTime == RelativeTime.PRESENT)) { if (newWorldPos != Vector3.zero) { Log.Debug("repositioning"); created_vessel.transform.position = newWorldPos; } if (newOrbitVel != Vector3.zero) { Log.Debug("updating velocity"); created_vessel.ChangeWorldVelocity((-1 * created_vessel.GetObtVelocity()) + (new Vector3(newOrbitVel.x, newOrbitVel.z, newOrbitVel.y))); //xzy? } StartCoroutine(restoreVesselState(created_vessel, newWorldPos, newOrbitVel)); //Update FlightCtrlState if (update != null) { if (created_vessel.ctrlState == null) created_vessel.ctrlState = new FlightCtrlState(); created_vessel.ctrlState.CopyFrom(update.flightCtrlState.getAsFlightCtrlState(0.75f)); } } else { StartCoroutine(setNewVesselNotInPresent(created_vessel)); } } } if (setTarget) StartCoroutine(setDockingTarget(created_vessel)); if (wasActive) StartCoroutine(setActiveVessel(created_vessel, oldVessel)); Log.Debug(created_vessel.id.ToString() + " initialized"); } else { Log.Debug("Failed to create vessel " + vessel_id); } }
public void SpawnAsteroid(Asteroid asteroid, UInt32 seed) { // Create Default Orbit Orbit orbit = null; CelestialBody body = null; // Select Orbit Type Int32 type = Random.Range(0, 3); if (type == 0 && asteroid.Location.Around.Count != 0) { // Around Location.AroundLoader[] around = GetProbabilityList(asteroid.Location.Around, asteroid.Location.Around.Select(a => a.Probability.Value).ToList()).ToArray(); Location.AroundLoader loader = around[Random.Range(0, around.Length)]; body = UBI.GetBody(loader.Body); if (!body) { return; } if (loader.Reached && !ReachedBody(body)) { return; } orbit = new Orbit { referenceBody = body, eccentricity = loader.Eccentricity, semiMajorAxis = loader.SemiMajorAxis, inclination = loader.Inclination, LAN = loader.LongitudeOfAscendingNode, argumentOfPeriapsis = loader.ArgumentOfPeriapsis, meanAnomalyAtEpoch = loader.MeanAnomalyAtEpoch, epoch = loader.Epoch }; orbit.Init(); } else if (type == 1 && asteroid.Location.Nearby.Count != 0) { // Nearby Location.NearbyLoader[] nearby = GetProbabilityList(asteroid.Location.Nearby, asteroid.Location.Nearby.Select(a => a.Probability.Value).ToList()).ToArray(); Location.NearbyLoader loader = nearby[Random.Range(0, nearby.Length)]; body = UBI.GetBody(loader.Body); if (!body) { return; } if (loader.Reached && !ReachedBody(body)) { return; } orbit = new Orbit { eccentricity = body.orbit.eccentricity + loader.Eccentricity, semiMajorAxis = body.orbit.semiMajorAxis * loader.SemiMajorAxis, inclination = body.orbit.inclination + loader.Inclination, LAN = body.orbit.LAN * loader.LongitudeOfAscendingNode, argumentOfPeriapsis = body.orbit.argumentOfPeriapsis * loader.ArgumentOfPeriapsis, meanAnomalyAtEpoch = body.orbit.meanAnomalyAtEpoch * loader.MeanAnomalyAtEpoch, epoch = body.orbit.epoch, referenceBody = body.orbit.referenceBody }; orbit.Init(); } else if (type == 2 && asteroid.Location.Flyby.Count != 0) { // Flyby Location.FlybyLoader[] flyby = GetProbabilityList(asteroid.Location.Flyby, asteroid.Location.Flyby.Select(a => a.Probability.Value).ToList()).ToArray(); Location.FlybyLoader loader = flyby[Random.Range(0, flyby.Length)]; body = UBI.GetBody(loader.Body); if (!body) { return; } if (loader.Reached && !ReachedBody(body)) { return; } orbit = Orbit.CreateRandomOrbitFlyBy(body, Random.Range(loader.MinDuration, loader.MaxDuration)); } // Check if (orbit == null) { Debug.Log("[Kopernicus] No new objects this time. (Probability is " + asteroid.Probability.Value + "%)"); return; } // Name String asteroidName = DiscoverableObjectsUtil.GenerateAsteroidName(); // Lifetime Double lifetime = Random.Range(asteroid.MinUntrackedLifetime, asteroid.MaxUntrackedLifetime) * 24d * 60d * 60d; Double maxLifetime = asteroid.MaxUntrackedLifetime * 24d * 60d * 60d; // Size UntrackedObjectClass size = (UntrackedObjectClass)(Int32)(asteroid.Size.Evaluate(Random.Range(0f, 1f)) * Enum.GetNames(typeof(UntrackedObjectClass)).Length); // Spawn ConfigNode vessel = null; vessel = ProtoVessel.CreateVesselNode( asteroidName, VesselType.SpaceObject, orbit, 0, new[] { ProtoVessel.CreatePartNode( "PotatoRoid", seed ) }, new ConfigNode("ACTIONGROUPS"), ProtoVessel.CreateDiscoveryNode( DiscoveryLevels.Presence, size, lifetime, maxLifetime ) ); OverrideNode(ref vessel, asteroid.Vessel); ProtoVessel protoVessel = new ProtoVessel(vessel, HighLogic.CurrentGame); if (asteroid.UniqueName && FlightGlobals.Vessels.Count(v => v.vesselName == protoVessel.vesselName) != 0) { return; } Kopernicus.Events.OnRuntimeUtilitySpawnAsteroid.Fire(asteroid, protoVessel); protoVessel.Load(HighLogic.CurrentGame.flightState); GameEvents.onNewVesselCreated.Fire(protoVessel.vesselRef); GameEvents.onAsteroidSpawned.Fire(protoVessel.vesselRef); Debug.Log("[Kopernicus] New object found near " + body.name + ": " + protoVessel.vesselName + "!"); }
protected 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; } // 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; } 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.ChangeName(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. ConfigNode empty = new ConfigNode(); ProtoVessel dummyProto = new ProtoVessel(empty, null); Vessel dummyVessel = new GameObject().AddComponent<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(); // Clean up GameObject.Destroy(dummyVessel.gameObject); } 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.ChangeName(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(vesselData.pitch, Vector3.right); rotation = rotation * Quaternion.AngleAxis(vesselData.roll, Vector3.down); rotation = rotation * Quaternion.AngleAxis(heading, Vector3.forward); // 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 = new ProtoVessel(protoVesselNode, HighLogic.CurrentGame); protoVessel.Load(HighLogic.CurrentGame.flightState); // 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; }
private bool loadVesselForRendezvous(ProtoVessel placeVessel, Vessel targetVessel) { targetVessel.BackupVessel(); placeVessel.orbitSnapShot = targetVessel.protoVessel.orbitSnapShot; placeVessel.orbitSnapShot.epoch = 0.0; tempID = RmmUtil.Rand.Next(1000000000).ToString(); //rename any vessels present with "AdministativeDockingName" foreach (Vessel ve in FlightGlobals.Vessels) { if (ve.vesselName == tempID) { Vessel NameVessel = null; NameVessel = ve; NameVessel.vesselName = "1"; } } placeVessel.vesselID = Guid.NewGuid(); placeVessel.vesselName = tempID; foreach (ProtoPartSnapshot p in placeVessel.protoPartSnapshots) { uint newFlightID = (UInt32)RmmUtil.Rand.Next(1000000000, 2147483647); // save flight ID of part which should dock if (p.flightID == _mission.flightIDDockPart) { missionFlightIDDockPart = newFlightID; } // update flight ID of each part and vessel reference transform id. if (placeVessel.refTransform == p.flightID) { p.flightID = newFlightID; placeVessel.refTransform = p.flightID; } else { p.flightID = newFlightID; } // clear out all crew if (p.protoModuleCrew != null && p.protoModuleCrew.Count() != 0) { List <ProtoCrewMember> cl = p.protoModuleCrew; List <ProtoCrewMember> clc = new List <ProtoCrewMember>(cl); foreach (ProtoCrewMember c in clc) { p.RemoveCrew(c); } } foreach (ProtoPartModuleSnapshot pm in p.modules) { if (pm.moduleName == "RMMModule") { pm.moduleValues.SetValue("trackingPrimary", false); pm.moduleValues.SetValue("trackingActive", false); } } } try { placeVessel.Load(HighLogic.CurrentGame.flightState); return(true); } catch { return(true); } }
public override void LaunchVessel() { if (FlightGlobals.ActiveVessel.situation != Vessel.Situations.ORBITING) { throw new Exception(_notInOrbitErrorText); } if (string.IsNullOrEmpty(_selectedCraftFilePath)) { throw new Exception(_noVesselSelectedErrorText); } if (LogisticsTools.AnyNearbyVessels(100d, FlightGlobals.ActiveVessel)) { throw new Exception(_nearbyVesselsErrorText); } PartUtilities.ConsumeResources(_cachedCostData); var vesselOrbit = FlightGlobals.ActiveVessel.orbit; var now = Planetarium.GetUniversalTime(); vesselOrbit.GetOrbitalStateVectorsAtUT( now, out Vector3d position, out Vector3d velocity); position.x += 50d; var orbit = new Orbit(vesselOrbit); orbit.UpdateFromStateVectors( position, velocity, vesselOrbit.referenceBody, now); var partNodes = _cachedProtoVessel.protoPartSnapshots .Select(s => { var node = new ConfigNode("PART"); s.Save(node); return(node); }) .ToArray(); var type = VesselType.Ship; _craftConfigNode.TryGetEnum("type", ref type, VesselType.Ship); var vesselConfigNode = ProtoVessel.CreateVesselNode( _cachedProtoVessel.GetDisplayName(), type, orbit, 0, partNodes); var spawnedProtoVessel = new ProtoVessel(vesselConfigNode, HighLogic.CurrentGame); spawnedProtoVessel.Load(HighLogic.CurrentGame.flightState); _window.CloseWindow(); var spawnedVessel = FlightGlobals.Vessels.Last(); spawnedVessel.protoVessel.stage = int.MaxValue; FlightGlobals.SetActiveVessel(spawnedVessel); }
private void CreateLode(LodeData lodeData) { lodeData.altitude = TerrainHeight(lodeData.latitude, lodeData.longitude, lodeData.body); Vector3d pos = lodeData.body.GetWorldSurfacePosition(lodeData.latitude, lodeData.longitude, lodeData.altitude.Value); lodeData.orbit = new Orbit(0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, lodeData.body); lodeData.orbit.UpdateFromStateVectors(pos, lodeData.body.getRFrmVel(pos), lodeData.body, Planetarium.GetUniversalTime()); ConfigNode[] partNodes; ShipConstruct shipConstruct = null; uint flightId = ShipConstruction.GetUniqueFlightID(HighLogic.CurrentGame.flightState); partNodes = new ConfigNode[1]; partNodes[0] = ProtoVessel.CreatePartNode(lodeData.craftPart.name, flightId); DiscoveryLevels discoveryLevel = DiscoveryLevels.Owned; ConfigNode protoVesselNode = ProtoVessel.CreateVesselNode(lodeData.name, lodeData.vesselType, lodeData.orbit, 0, partNodes); Vector3d norm = lodeData.body.GetRelSurfaceNVector(lodeData.latitude, lodeData.longitude); double terrainHeight = 0.0; if (lodeData.body.pqsController != null) { terrainHeight = lodeData.body.pqsController.GetSurfaceHeight(norm) - lodeData.body.pqsController.radius; } bool splashed = true && terrainHeight < 0.001; protoVesselNode.SetValue("sit", (splashed ? Vessel.Situations.SPLASHED : Vessel.Situations.LANDED).ToString()); protoVesselNode.SetValue("landed", (!splashed).ToString()); protoVesselNode.SetValue("splashed", splashed.ToString()); protoVesselNode.SetValue("lat", lodeData.latitude.ToString()); protoVesselNode.SetValue("lon", lodeData.longitude.ToString()); protoVesselNode.SetValue("alt", lodeData.altitude.ToString()); protoVesselNode.SetValue("landedAt", lodeData.body.name); float lowest = float.MaxValue; foreach (Collider collider in lodeData.craftPart.partPrefab.GetComponentsInChildren<Collider>()) { if (collider.gameObject.layer != 21 && collider.enabled) { lowest = Mathf.Min(lowest, collider.bounds.min.y); } } if (Mathf.Approximately(lowest,float.MaxValue)) { lowest = 0; } Quaternion normal = Quaternion.LookRotation(new Vector3((float)norm.x, (float)norm.y, (float)norm.z)); Quaternion rotation = Quaternion.identity; rotation = rotation * Quaternion.FromToRotation(Vector3.up, Vector3.back); float hgt = (shipConstruct != null ? shipConstruct.parts[0] : lodeData.craftPart.partPrefab).localRoot.attPos0.y - lowest; protoVesselNode.SetValue("hgt", hgt.ToString()); protoVesselNode.SetValue("rot", KSPUtil.WriteQuaternion(rotation * normal)); Vector3 nrm = (rotation * Vector3.forward); protoVesselNode.SetValue("nrm", nrm.x + "," + nrm.y + "," + nrm.z); protoVesselNode.SetValue("prst", false.ToString()); ProtoVessel protoVessel = new ProtoVessel(protoVesselNode, HighLogic.CurrentGame); protoVessel.Load(HighLogic.CurrentGame.flightState); }
public void SpawnAsteroid(Asteroid asteroid, UInt32 seed) { // Create Default Orbit Orbit orbit = null; CelestialBody body = null; // Select Orbit Type Int32 type = Random.Range(0, 3); if (type == 0 && asteroid.Location.Around.Count != 0) { // Around Location.AroundLoader[] around = GetProbabilityList(asteroid.Location.Around, asteroid.Location.Around.Select(a => a.Probability.Value).ToList()).ToArray(); Location.AroundLoader loader = around[Random.Range(0, around.Length)]; body = UBI.GetBody(loader.Body); if (!body) { return; } if (loader.Reached && !ReachedBody(body)) { return; } orbit = new Orbit { referenceBody = body, eccentricity = loader.Eccentricity, semiMajorAxis = loader.SemiMajorAxis, inclination = loader.Inclination, LAN = loader.LongitudeOfAscendingNode, argumentOfPeriapsis = loader.ArgumentOfPeriapsis, meanAnomalyAtEpoch = loader.MeanAnomalyAtEpoch, epoch = loader.Epoch }; orbit.Init(); } else if (type == 1 && asteroid.Location.Nearby.Count != 0) { // Nearby Location.NearbyLoader[] nearby = GetProbabilityList(asteroid.Location.Nearby, asteroid.Location.Nearby.Select(a => a.Probability.Value).ToList()).ToArray(); Location.NearbyLoader loader = nearby[Random.Range(0, nearby.Length)]; body = UBI.GetBody(loader.Body); if (!body) { return; } if (loader.Reached && !ReachedBody(body)) { return; } orbit = new Orbit { eccentricity = body.orbit.eccentricity + loader.Eccentricity, semiMajorAxis = body.orbit.semiMajorAxis * loader.SemiMajorAxis, inclination = body.orbit.inclination + loader.Inclination, LAN = body.orbit.LAN * loader.LongitudeOfAscendingNode, argumentOfPeriapsis = body.orbit.argumentOfPeriapsis * loader.ArgumentOfPeriapsis, meanAnomalyAtEpoch = body.orbit.meanAnomalyAtEpoch * loader.MeanAnomalyAtEpoch, epoch = body.orbit.epoch, referenceBody = body.orbit.referenceBody }; orbit.Init(); } else if (type == 2 && asteroid.Location.Flyby.Count != 0) { // Flyby Location.FlybyLoader[] flyby = GetProbabilityList(asteroid.Location.Flyby, asteroid.Location.Flyby.Select(a => a.Probability.Value).ToList()).ToArray(); Location.FlybyLoader loader = flyby[Random.Range(0, flyby.Length)]; body = UBI.GetBody(loader.Body); if (!body) { return; } if (loader.Reached && !ReachedBody(body)) { return; } orbit = Orbit.CreateRandomOrbitFlyBy(body, Random.Range(loader.MinDuration, loader.MaxDuration)); } // Check if (orbit == null) { Debug.Log("[Kopernicus] No new objects this time. (Probability is " + asteroid.Probability.Value + "%)"); return; } // Name String asteroidName = DiscoverableObjectsUtil.GenerateAsteroidName(); // Lifetime Double lifetime = Random.Range(asteroid.MinUntrackedLifetime, asteroid.MaxUntrackedLifetime) * 24d * 60d * 60d; Double maxLifetime = asteroid.MaxUntrackedLifetime * 24d * 60d * 60d; // Size UntrackedObjectClass size = (UntrackedObjectClass)(Int32)(asteroid.Size.Evaluate(Random.Range(0f, 1f)) * Enum.GetNames(typeof(UntrackedObjectClass)).Length); // Spawn ConfigNode vessel = null; #if (KSP_VERSION_1_10_1 || KSP_VERSION_1_11_1) if (Random.Range(0, 100) > RuntimeUtility.KopernicusConfig.CometPercentage) { #endif vessel = ProtoVessel.CreateVesselNode( asteroidName, VesselType.SpaceObject, orbit, 0, new[] { ProtoVessel.CreatePartNode( "PotatoRoid", seed ) }, new ConfigNode("ACTIONGROUPS"), ProtoVessel.CreateDiscoveryNode( DiscoveryLevels.Presence, size, lifetime, maxLifetime ) ); OverrideNode(ref vessel, asteroid.Vessel); ProtoVessel protoVessel = new ProtoVessel(vessel, HighLogic.CurrentGame); if (asteroid.UniqueName && FlightGlobals.Vessels.Count(v => v.vesselName == protoVessel.vesselName) != 0) { return; } Kopernicus.Events.OnRuntimeUtilitySpawnAsteroid.Fire(asteroid, protoVessel); protoVessel.Load(HighLogic.CurrentGame.flightState); GameEvents.onNewVesselCreated.Fire(protoVessel.vesselRef); GameEvents.onAsteroidSpawned.Fire(protoVessel.vesselRef); Debug.Log("[Kopernicus] New object found near " + body.name + ": " + protoVessel.vesselName + "!"); #if (KSP_VERSION_1_10_1 || KSP_VERSION_1_11_1) } else { float fragmentDynamicPressureModifier = 0f; bool optimizedCollider = false; CometOrbitType cometType = CometManager.GenerateWeightedCometType(); Orbit cometOrbit = cometType.CalculateHomeOrbit(); UntrackedObjectClass randomObjClass = cometType.GetRandomObjClass(); CometDefinition cometDef = CometManager.GenerateDefinition(cometType, randomObjClass, (int)seed); ConfigNode configNode = cometDef.CreateVesselNode(optimizedCollider, fragmentDynamicPressureModifier, hasName: false); ConfigNode configNode2 = ProtoVessel.CreatePartNode("PotatoComet", seed); uint value = 0u; configNode2.TryGetValue("persistentId", ref value); configNode.AddValue("cometPartId", value); ConfigNode configNode3 = new ConfigNode("VESSELMODULES"); configNode3.AddNode(configNode); vessel = ProtoVessel.CreateVesselNode(DiscoverableObjectsUtil.GenerateCometName(), VesselType.SpaceObject, cometOrbit, 0, new ConfigNode[1] { configNode2 }, new ConfigNode("ACTIONGROUPS"), ProtoVessel.CreateDiscoveryNode(DiscoveryLevels.Presence, randomObjClass, lifetime, maxLifetime), configNode3); OverrideNode(ref vessel, asteroid.Vessel); ProtoVessel protoVessel = new ProtoVessel(vessel, HighLogic.CurrentGame); Kopernicus.Events.OnRuntimeUtilitySpawnAsteroid.Fire(asteroid, protoVessel); protoVessel.Load(HighLogic.CurrentGame.flightState); GameEvents.onNewVesselCreated.Fire(protoVessel.vesselRef); GameEvents.onAsteroidSpawned.Fire(protoVessel.vesselRef); Debug.Log("[Kopernicus] New object found near " + body.name + ": " + protoVessel.vesselName + "!"); } #endif }
/// <summary> /// Loads the vessel proto into the current game /// </summary> private static bool LoadVesselIntoGame(ProtoVessel vesselProto) { if (HighLogic.CurrentGame?.flightState == null) { return(false); } var reloadingOwnVessel = FlightGlobals.ActiveVessel && vesselProto.vesselID == FlightGlobals.ActiveVessel.id && HighLogic.LoadedSceneIsFlight; //In case the vessel exists, silently remove them from unity and recreate it again var existingVessel = FlightGlobals.fetch.LmpFindVessel(vesselProto.vesselID); if (existingVessel != null) { if (reloadingOwnVessel) { foreach (var part in existingVessel.Parts) { if (part.protoModuleCrew.Any()) { //Serialize to avoid modifying the collection var crewMembers = part.protoModuleCrew.ToArray(); foreach (var crew in crewMembers) { part.RemoveCrew(crew); } } } } FlightGlobals.RemoveVessel(existingVessel); foreach (var part in existingVessel.parts) { Object.Destroy(part.gameObject); } Object.Destroy(existingVessel.gameObject); } vesselProto.Load(HighLogic.CurrentGame.flightState); if (vesselProto.vesselRef == null) { LunaLog.Log($"[LMP]: Protovessel {vesselProto.vesselID} failed to create a vessel!"); return(false); } vesselProto.vesselRef.protoVessel = vesselProto; if (vesselProto.vesselRef.isEVA) { var evaModule = vesselProto.vesselRef.FindPartModuleImplementing <KerbalEVA>(); if (evaModule != null && evaModule.fsm != null && !evaModule.fsm.Started) { evaModule.fsm?.StartFSM("Idle (Grounded)"); } vesselProto.vesselRef.GoOnRails(); } if (vesselProto.vesselRef.situation > Vessel.Situations.PRELAUNCH) { vesselProto.vesselRef.orbitDriver.updateFromParameters(); } if (double.IsNaN(vesselProto.vesselRef.orbitDriver.pos.x)) { LunaLog.Log($"[LMP]: Protovessel {vesselProto.vesselID} has an invalid orbit"); return(false); } PlayerColorSystem.Singleton.SetVesselOrbitColor(vesselProto.vesselRef); KscSceneSystem.Singleton.RefreshTrackingStationVessels(); if (KSCVesselMarkers.fetch) { KSCVesselMarkers.fetch.RefreshMarkers(); } if (reloadingOwnVessel) { vesselProto.vesselRef.Load(); vesselProto.vesselRef.RebuildCrewList(); //Do not do the setting of the active vessel manually, too many systems are dependant of the events triggered by KSP FlightGlobals.ForceSetActiveVessel(vesselProto.vesselRef); if (vesselProto.vesselRef.GetCrewCount() > 0) { foreach (var part in vesselProto.vesselRef.Parts) { if (part.protoModuleCrew.Any()) { //Serialize to avoid modifying the collection var crewMembers = part.protoModuleCrew.ToArray(); foreach (var crew in crewMembers) { part.RemoveCrew(crew); part.AddCrew(crew); } } } vesselProto.vesselRef.SpawnCrew(); if (KerbalPortraitGallery.Instance) { KerbalPortraitGallery.Instance.SetActivePortraitsForVessel(FlightGlobals.ActiveVessel); } } } return(true); }
public Vessel Spawn() { if (loaded) { if (protoVessel.vesselRef == null) { loaded = false; } else { Debugger.Log(name + " is already loaded."); return(protoVessel.vesselRef); } } if (WarpDrive.seedString != seed) { Debugger.LogError("Vessel " + name + " seed " + seed + " does not match Warp Drive seed " + WarpDrive.seedString + "!"); // Don't spawn us return(null); } if (id == Guid.Empty) { Debugger.LogWarning("Generating new GUID for " + name + "."); id = Guid.NewGuid(); protoVessel.vesselID = id; } // We have a valid seed, make sure we're unique Dictionary <Guid, Vessel> currentGuidLookup = null; if (seedGUIDLookup.ContainsKey(seed)) { currentGuidLookup = seedGUIDLookup [seed]; } else { currentGuidLookup = new Dictionary <Guid, Vessel> (); } if (currentGuidLookup.ContainsKey(id) && currentGuidLookup [id] != null) { loaded = true; Debugger.Log(name + " already exists in " + seed + "."); // Already spawned in this seed return(currentGuidLookup [id]); } // See if we're already in the loaded game // This shouldn't happen, but we want to make absolutely sure so we don't have duplicates foreach (Vessel vessel in FlightGlobals.Vessels) { if (vessel.id == id) { // Should not happen Debugger.LogWarning("Tried to spawn duplicate vessel! Name: " + vessel.name); currentGuidLookup.Add(id, vessel); seedGUIDLookup [seed] = currentGuidLookup; loaded = true; return(vessel); } } Debugger.Log("Spawning vessel " + name); protoVessel.Load(HighLogic.CurrentGame.flightState); GameEvents.onNewVesselCreated.Fire(protoVessel.vesselRef); currentGuidLookup [id] = protoVessel.vesselRef; seedGUIDLookup [seed] = currentGuidLookup; loaded = protoVessel.vesselRef != null; if (!loaded) { Debugger.LogError("Could not load " + protoVessel.vesselName + "!"); } return(protoVessel.vesselRef); }
//Also called from QuickSaveLoader public void LoadVessel(ConfigNode vesselNode) { if (vesselNode != null) { //Fix crew value numbers to Kerbal Names bool kerbalsDodged = DodgeVesselCrewValues(vesselNode); //Fix the "cannot control actiongroups bug" by dodging the last used time. DodgeVesselActionGroups(vesselNode); //Can be used for debugging incoming vessel config nodes. //vesselNode.Save(Path.Combine(KSPUtil.ApplicationRootPath, Path.Combine("DMP-RX", Planetarium.GetUniversalTime() + ".txt"))); ProtoVessel currentProto = new ProtoVessel(vesselNode, HighLogic.CurrentGame); if (kerbalsDodged && (NetworkWorker.fetch.state == ClientState.STARTING) && !LockSystem.fetch.LockExists("control-" + currentProto.vesselID) && !LockSystem.fetch.LockExists("update-" + currentProto.vesselID)) { DarkLog.Debug("Sending kerbal-dodged vessel " + currentProto.vesselID + ", name: " + currentProto.vesselName); NetworkWorker.fetch.SendVesselProtoMessage(currentProto, false, false); foreach (ProtoPartSnapshot pps in currentProto.protoPartSnapshots) { if (pps.protoModuleCrew != null) { foreach (ProtoCrewMember pcm in pps.protoModuleCrew) { if (pcm != null) { NetworkWorker.fetch.SendKerbalProtoMessage(pcm); } } } } } if (currentProto != null) { //Skip already loaded EVA's if ((currentProto.vesselType == VesselType.EVA) && (FlightGlobals.fetch.vessels.Find(v => v.id == currentProto.vesselID) != null)) { return; } //Register asteroids from other players if (currentProto.vesselType == VesselType.SpaceObject) { if (currentProto.protoPartSnapshots != null) { if (currentProto.protoPartSnapshots.Count == 1) { if (currentProto.protoPartSnapshots[0].partName == "PotatoRoid") { DarkLog.Debug("Registering remote server asteroid"); AsteroidWorker.fetch.RegisterServerAsteroid(currentProto.vesselID.ToString()); } } } } //Skip vessels that try to load in the safety bubble if (isProtoVesselInSafetyBubble(currentProto)) { DarkLog.Debug("Skipped loading protovessel " + currentProto.vesselID.ToString() + ", name: " + currentProto.vesselName + " because it is inside the safety bubble"); return; } //Skip flying vessel that are too far away bool usingHackyAtmoLoad = false; if (currentProto.situation == Vessel.Situations.FLYING) { DarkLog.Debug("Got a flying update for " + currentProto.vesselID + ", name: " + currentProto.vesselName); if (currentProto.orbitSnapShot == null) { DarkLog.Debug("Skipping flying vessel load - Protovessel does not have an orbit snapshot"); return; } CelestialBody updateBody = FlightGlobals.fetch.bodies[currentProto.orbitSnapShot.ReferenceBodyIndex]; if (updateBody == null) { DarkLog.Debug("Skipping flying vessel load - Could not find celestial body index " + currentProto.orbitSnapShot.ReferenceBodyIndex); return; } bool willGetKilledInAtmo = false; if (updateBody.atmosphere) { double atmoPressure = updateBody.staticPressureASL * Math.Pow(Math.E, ((-currentProto.altitude) / (updateBody.atmosphereScaleHeight * 1000))); //KSP magic cut off limit for killing vessels. Works out to be ~23km on kerbin. if (atmoPressure > 0.01f) { willGetKilledInAtmo = true; } } if (willGetKilledInAtmo) { if (HighLogic.LoadedScene == GameScenes.FLIGHT) { if ((FlightGlobals.fetch.vessels.Find(v => v.id == currentProto.vesselID) != null) && vesselPartCount.ContainsKey(currentProto.vesselID.ToString()) ? currentProto.protoPartSnapshots.Count == vesselPartCount[currentProto.vesselID.ToString()] : false) { DarkLog.Debug("Skipping flying vessel load - Vessel has the same part count"); return; } if (FlightGlobals.fetch.activeVessel == null) { DarkLog.Debug("Skipping flying vessel load - We do not have an active vessel"); return; } if (FlightGlobals.fetch.activeVessel.mainBody != updateBody) { DarkLog.Debug("Skipping flying vessel load - We are on a different celestial body"); return; } Vector3d ourPos = FlightGlobals.fetch.activeVessel.mainBody.GetWorldSurfacePosition(FlightGlobals.fetch.activeVessel.latitude, FlightGlobals.fetch.activeVessel.longitude, FlightGlobals.fetch.activeVessel.altitude); Vector3d protoPos = updateBody.GetWorldSurfacePosition(currentProto.latitude, currentProto.longitude, currentProto.altitude); double distance = Vector3d.Distance(ourPos, protoPos); //We'll load the vessel if possible if (distance > Vessel.loadDistance) { DarkLog.Debug("Skipping flying vessel load - We are not close enough, distance: " + distance); return; } else { DarkLog.Debug("Enabling FLYING vessel load!"); //If the vessel is landed it won't be killed by the atmosphere currentProto.landed = true; usingHackyAtmoLoad = true; } } else { DarkLog.Debug("Skipping flying vessel load - We cannot load vessels that will get killed in atmosphere while not in flight"); return; } } } RegisterServerVessel(currentProto.vesselID.ToString()); DarkLog.Debug("Loading " + currentProto.vesselID + ", name: " + currentProto.vesselName + ", type: " + currentProto.vesselType); foreach (ProtoPartSnapshot part in currentProto.protoPartSnapshots) { //This line doesn't actually do anything useful, but if you get this reference, you're officially the most geeky person darklight knows. part.temperature = ((part.temperature + 273.15f) * 0.8f) - 273.15f; //Fix up flag URLS. if (part.flagURL.Length != 0) { string flagFile = Path.Combine(Path.Combine(KSPUtil.ApplicationRootPath, "GameData"), part.flagURL + ".png"); if (!File.Exists(flagFile)) { DarkLog.Debug("Flag '" + part.flagURL + "' doesn't exist, setting to default!"); part.flagURL = "Squad/Flags/default"; } } } bool wasActive = false; bool wasTarget = false; if (HighLogic.LoadedScene == GameScenes.FLIGHT) { if (FlightGlobals.fetch.VesselTarget != null ? FlightGlobals.fetch.VesselTarget.GetVessel() != null : false) { wasTarget = FlightGlobals.fetch.VesselTarget.GetVessel().id == currentProto.vesselID; } if (wasTarget) { DarkLog.Debug("ProtoVessel update for target vessel!"); } wasActive = (FlightGlobals.fetch.activeVessel != null) ? (FlightGlobals.fetch.activeVessel.id == currentProto.vesselID) : false; } for (int vesselID = FlightGlobals.fetch.vessels.Count - 1; vesselID >= 0; vesselID--) { Vessel oldVessel = FlightGlobals.fetch.vessels[vesselID]; if (oldVessel.id.ToString() == currentProto.vesselID.ToString()) { //Don't replace the vessel if it's unpacked, not landed, close to the ground, and has the same amount of parts. double hft = oldVessel.GetHeightFromTerrain(); if (oldVessel.loaded && !oldVessel.packed && !oldVessel.Landed && (hft != -1) && (hft < 1000) && (currentProto.protoPartSnapshots.Count == oldVessel.parts.Count)) { DarkLog.Debug("Skipped loading protovessel " + currentProto.vesselID.ToString() + " because it is flying close to the ground and may get destroyed"); return; } //Don't kill the active vessel - Kill it after we switch. //Killing the active vessel causes all sorts of crazy problems. if (wasActive) { delayKillVessels.Add(oldVessel); } else { /* * Sorry guys - KSP's protovessel positioning is not as accurate as it could be. * * The loading vessel needs to come off rails in order for the error to be corrected, * but taking it off rails will allow the vessel to collide with others while it's in the incorrect spot for that fixed update. * * If the vessel is the selected target, close (unpacked), and has the same number of parts, we'll skip the protovessel load. */ if (wasTarget && !oldVessel.LandedOrSplashed && oldVessel.loaded && !oldVessel.packed && (oldVessel.parts.Count == currentProto.protoPartSnapshots.Count)) { DarkLog.Debug("Skipping loading protovessel " + currentProto.vesselID.ToString() + " because it is the selected target and may crash into us"); return; } KillVessel(oldVessel); } } } vesselPartCount[currentProto.vesselID.ToString()] = currentProto.protoPartSnapshots.Count; serverVesselsProtoUpdate[currentProto.vesselID.ToString()] = UnityEngine.Time.realtimeSinceStartup; lastLoadVessel[currentProto.vesselID.ToString()] = UnityEngine.Time.realtimeSinceStartup; currentProto.Load(HighLogic.CurrentGame.flightState); if (currentProto.vesselRef != null) { if (usingHackyAtmoLoad) { //Dodge unpack/pack distances currentProto.vesselRef.distanceUnpackThreshold = Vessel.loadDistance - 300; currentProto.vesselRef.distanceLandedUnpackThreshold = Vessel.loadDistance - 300; currentProto.vesselRef.distancePackThreshold = Vessel.loadDistance - 100; currentProto.vesselRef.distanceLandedPackThreshold = Vessel.loadDistance - 100; HackyFlyingVesselLoad hfvl = new HackyFlyingVesselLoad(); hfvl.flyingVessel = currentProto.vesselRef; hfvl.loadTime = UnityEngine.Time.realtimeSinceStartup; loadingFlyingVessels.Add(hfvl); } if (wasActive) { DarkLog.Debug("ProtoVessel update for active vessel!"); try { OrbitPhysicsManager.HoldVesselUnpack(5); FlightGlobals.fetch.activeVessel.GoOnRails(); //Put our vessel on rails so we don't collide with the new copy } catch { DarkLog.Debug("WARNING: Something very bad happened trying to replace the vessel, skipping update!"); return; } newActiveVessel = currentProto.vesselRef; } if (wasTarget) { DarkLog.Debug("Set docking target"); FlightGlobals.fetch.SetVesselTarget(currentProto.vesselRef); } DarkLog.Debug("Protovessel Loaded"); } else { DarkLog.Debug("Protovessel " + currentProto.vesselID + " failed to create a vessel!"); } } else { DarkLog.Debug("protoVessel is null!"); } } else { DarkLog.Debug("vesselNode is null!"); } }
/// <summary> /// Spawn ship construct /// https://github.com/KospY/KAS/blob/master/Plugin/KAS_Shared.cs /// </summary> /// <param name="_shipConstruct">Shipconstruct to spawn</param> /// <param name="_srcPart">Source part to spawn relative to</param> /// <param name="_spawnOffset">Offset spawn from Source part position</param> private void SpawnVessel(ShipConstruct _shipConstruct, Part _srcPart, Vector3 _spawnOffset) { //Store construct root Part _newConstructRootPart = _shipConstruct.parts[0]; //Center rootpart Vector3 offset = _newConstructRootPart.transform.localPosition; _newConstructRootPart.transform.Translate(-offset); //Get launch spawn point, relative to part Transform t = _srcPart.transform; GameObject launchPos = new GameObject(); launchPos.transform.parent = _srcPart.transform; launchPos.transform.position = t.position; launchPos.transform.position += t.TransformDirection(_spawnOffset); launchPos.transform.rotation = t.rotation; //Store our launch / spawn position Transform launchTransform = launchPos.transform; //Kill original object launchPos.DestroyGameObject(); //Set rootpart origin _shipConstruct.Parts[0].localRoot.transform.Translate(launchPos.transform.position, Space.World); //Position float angle; Vector3 axis; //Extract ToAngleAxis data from selected spawning location launchTransform.rotation.ToAngleAxis(out angle, out axis); //TRANSFORM Rotate localRootPart in relation to root _shipConstruct.Parts[0].localRoot.transform.RotateAround(launchTransform.position, axis, angle); //Create vessel object Vessel _newVessel = _newConstructRootPart.localRoot.gameObject.AddComponent <Vessel>(); //Attach vessel information _newVessel.id = Guid.NewGuid(); _newVessel.vesselName = _srcPart.vessel.vesselName + " - " + _shipConstruct.shipName; _newVessel.landedAt = _srcPart.vessel.vesselName; //Store backup ShipConstruction.CreateBackup(_shipConstruct); //Init from VAB _newVessel.Initialize(true); //Set Landed _newVessel.Landed = true; //_newVessel.situation = Vessel.Situations.PRELAUNCH; // _newVessel.GoOffRails(); //_newVessel.IgnoreGForces(240); //Set Orbit InitiateOrbit(launchTransform.position, _srcPart.vessel, _newVessel); //Set Mission info uint missionId = (uint)Guid.NewGuid().GetHashCode(); string flagUrl = _srcPart.flagURL; uint launchId = HighLogic.CurrentGame.launchID++; //Set part mission info for (int i = 0; i < _newVessel.parts.Count; i++) { Part part = _newVessel.parts[i]; part.flightID = ShipConstruction.GetUniqueFlightID(FlightDriver.FlightStateCache.flightState); part.flagURL = flagUrl; part.launchID = launchId; part.missionID = missionId; } //Generate staging KSP.UI.Screens.StageManager.BeginFlight(); _newConstructRootPart.vessel.ResumeStaging(); KSP.UI.Screens.StageManager.GenerateStagingSequence(_newConstructRootPart.localRoot); KSP.UI.Screens.StageManager.RecalculateVesselStaging(_newConstructRootPart.vessel); //Set position, again _newVessel.SetPosition(launchTransform.position); _newVessel.SetRotation(launchTransform.rotation); //Save Protovessel ProtoVessel _newProto = new ProtoVessel(_newVessel); //Kill and remove spawned vessel, had some serious problems with spawn position warping/glitching _newVessel.Die(); //Set the protovessels position to the relative one we found, maybe redundant _newProto.position = launchPos.transform.position; //If you check this value, you will see the height change from launch scene to resume scene, extra dafuq //float height = _newProto.height; if (FlightDriver.StartupBehaviour == FlightDriver.StartupBehaviours.RESUME_SAVED_FILE || FlightDriver.StartupBehaviour == FlightDriver.StartupBehaviours.RESUME_SAVED_CACHE) { //Odd behaviour with positioning during different flight scenes, workaround awaaaay Log.Info("Workaround of height"); _newProto.height = TrueAlt(launchTransform.position, _srcPart.vessel); } _newProto.altitude += 10; _newProto.height += 10; _newProto.situation = Vessel.Situations.FLYING; //Load Protovessel _newProto.Load(HighLogic.CurrentGame.flightState); // _newVessel.GoOnRails(); // Restore ShipConstruction ship, otherwise player sees loaded craft in VAB ShipConstruction.ShipConfig = _OldVabShip.GetConfigNode(); //Fix Control Lock FlightInputHandler.ResumeVesselCtrlState(FlightGlobals.ActiveVessel); //Fix active vessel staging FlightGlobals.ActiveVessel.ResumeStaging(); }
/// <summary> /// Loads the vessel proto into the current game /// </summary> private static bool LoadVesselIntoGame(ProtoVessel vesselProto, bool forceReload) { if (HighLogic.CurrentGame?.flightState == null) { return(false); } var reloadingOwnVessel = FlightGlobals.ActiveVessel && vesselProto.vesselID == FlightGlobals.ActiveVessel.id; //In case the vessel exists, silently remove them from unity and recreate it again var existingVessel = FlightGlobals.FindVessel(vesselProto.vesselID); if (existingVessel != null) { if (existingVessel.Parts.Count == vesselProto.protoPartSnapshots.Count && !forceReload) { return(true); } LunaLog.Log($"[LMP]: Reloading vessel {vesselProto.vesselID}"); if (reloadingOwnVessel) { existingVessel.RemoveAllCrew(); } FlightGlobals.RemoveVessel(existingVessel); foreach (var part in existingVessel.parts) { Object.Destroy(part.gameObject); } Object.Destroy(existingVessel.gameObject); } else { LunaLog.Log($"[LMP]: Loading vessel {vesselProto.vesselID}"); } vesselProto.Load(HighLogic.CurrentGame.flightState); if (vesselProto.vesselRef == null) { LunaLog.Log($"[LMP]: Protovessel {vesselProto.vesselID} failed to create a vessel!"); return(false); } VesselPositionSystem.Singleton.ForceUpdateVesselPosition(vesselProto.vesselRef.id); vesselProto.vesselRef.protoVessel = vesselProto; if (vesselProto.vesselRef.isEVA) { var evaModule = vesselProto.vesselRef.FindPartModuleImplementing <KerbalEVA>(); if (evaModule != null && evaModule.fsm != null && !evaModule.fsm.Started) { evaModule.fsm?.StartFSM("Idle (Grounded)"); } vesselProto.vesselRef.GoOnRails(); } if (vesselProto.vesselRef.situation > Vessel.Situations.PRELAUNCH) { vesselProto.vesselRef.orbitDriver.updateFromParameters(); } if (double.IsNaN(vesselProto.vesselRef.orbitDriver.pos.x)) { LunaLog.Log($"[LMP]: Protovessel {vesselProto.vesselID} has an invalid orbit"); return(false); } if (reloadingOwnVessel) { vesselProto.vesselRef.Load(); vesselProto.vesselRef.RebuildCrewList(); //Do not do the setting of the active vessel manually, too many systems are dependant of the events triggered by KSP FlightGlobals.ForceSetActiveVessel(vesselProto.vesselRef); vesselProto.vesselRef.SpawnCrew(); foreach (var crew in vesselProto.vesselRef.GetVesselCrew()) { if (crew.KerbalRef) { crew.KerbalRef.state = Kerbal.States.ALIVE; } } CoroutineUtil.StartDelayedRoutine("ReloadOwnVessel", () => { if (KerbalPortraitGallery.Instance.ActiveCrew.Count == 0) { FlightGlobals.ActiveVessel.SpawnCrew(); foreach (var kerbal in KerbalPortraitGallery.Instance.ActiveCrew) { kerbal.state = Kerbal.States.ALIVE; } KerbalPortraitGallery.Instance.StartRefresh(FlightGlobals.ActiveVessel); } }, 0.5f); } return(true); }
//Also called from QuickSaveLoader public void LoadVessel(ConfigNode vesselNode) { if (vesselNode != null) { //Fix the kerbals (Tracking station bug) checkProtoNodeCrew(ref vesselNode); //Can be used for debugging incoming vessel config nodes. //vesselNode.Save(Path.Combine(KSPUtil.ApplicationRootPath, Path.Combine("DMP-RX", Planetarium.GetUniversalTime() + ".txt"))); ProtoVessel currentProto = new ProtoVessel(vesselNode, HighLogic.CurrentGame); if (currentProto != null) { if (currentProto.vesselType == VesselType.SpaceObject) { if (currentProto.protoPartSnapshots != null) { if (currentProto.protoPartSnapshots.Count == 1) { if (currentProto.protoPartSnapshots[0].partName == "PotatoRoid") { DarkLog.Debug("Registering remote server asteroid"); AsteroidWorker.fetch.RegisterServerAsteroid(currentProto.vesselID.ToString()); } } } } if (isProtoVesselInSafetyBubble(currentProto)) { DarkLog.Debug("Removing protovessel " + currentProto.vesselID.ToString() + ", name: " + currentProto.vesselName + " from server - In safety bubble!"); NetworkWorker.fetch.SendVesselRemove(currentProto.vesselID.ToString(), false); return; } RegisterServerVessel(currentProto.vesselID.ToString()); DarkLog.Debug("Loading " + currentProto.vesselID + ", name: " + currentProto.vesselName + ", type: " + currentProto.vesselType); foreach (ProtoPartSnapshot part in currentProto.protoPartSnapshots) { //This line doesn't actually do anything useful, but if you get this reference, you're officially the most geeky person darklight knows. part.temperature = ((part.temperature + 273.15f) * 0.8f) - 273.15f; //Fix up flag URLS. if (part.flagURL.Length != 0) { string flagFile = Path.Combine(Path.Combine(KSPUtil.ApplicationRootPath, "GameData"), part.flagURL + ".png"); if (!File.Exists(flagFile)) { DarkLog.Debug("Flag '" + part.flagURL + "' doesn't exist, setting to default!"); part.flagURL = "Squad/Flags/default"; } } } bool wasActive = false; bool wasTarget = false; if (HighLogic.LoadedScene == GameScenes.FLIGHT) { if (FlightGlobals.fetch.VesselTarget != null ? FlightGlobals.fetch.VesselTarget.GetVessel() != null : false) { wasTarget = FlightGlobals.fetch.VesselTarget.GetVessel().id == currentProto.vesselID; } if (wasTarget) { DarkLog.Debug("ProtoVessel update for target vessel!"); } wasActive = (FlightGlobals.ActiveVessel != null) ? (FlightGlobals.ActiveVessel.id == currentProto.vesselID) : false; if (wasActive) { DarkLog.Debug("ProtoVessel update for active vessel!"); try { OrbitPhysicsManager.HoldVesselUnpack(5); } catch { //Don't care. } FlightGlobals.fetch.activeVessel.MakeInactive(); } } for (int vesselID = FlightGlobals.fetch.vessels.Count - 1; vesselID >= 0; vesselID--) { Vessel oldVessel = FlightGlobals.fetch.vessels[vesselID]; if (oldVessel.id.ToString() == currentProto.vesselID.ToString()) { KillVessel(oldVessel); } } serverVesselsProtoUpdate[currentProto.vesselID.ToString()] = UnityEngine.Time.realtimeSinceStartup; currentProto.Load(HighLogic.CurrentGame.flightState); if (currentProto.vesselRef != null) { UpdatePackDistance(currentProto.vesselRef.id.ToString()); if (wasActive) { DarkLog.Debug("Set active vessel"); switchActiveVesselOnNextUpdate = currentProto.vesselRef; } if (wasTarget) { DarkLog.Debug("Set docking target"); FlightGlobals.fetch.SetVesselTarget(currentProto.vesselRef); } DarkLog.Debug("Protovessel Loaded"); } else { DarkLog.Debug("Protovessel " + currentProto.vesselID + " failed to create a vessel!"); } } else { DarkLog.Debug("protoVessel is null!"); } } else { DarkLog.Debug("vesselNode is null!"); } }
// Spawn the actual asteroid public void SpawnAsteroid(Asteroid asteroid, uint seed) { // Create Default Orbit Orbit orbit = null; CelestialBody body = null; // Select Orbit Type int type = Random.Range(0, 3); if (type == 0 && asteroid.location.around.Count != 0) { // Around IEnumerable <Location.AroundLoader> arounds = GetProbabilityList(asteroid.location.around, asteroid.location.around.Select(a => a.probability.value)); Location.AroundLoader around = arounds.ElementAt(Random.Range(0, arounds.Count())); body = PSystemManager.Instance.localBodies.Find(b => b.name == around.body); if (!body) { return; } if (around.reached && !ReachedBody(body)) { return; } orbit = new Orbit(); orbit.referenceBody = body; orbit.eccentricity = around.eccentricity; orbit.semiMajorAxis = around.semiMajorAxis; orbit.inclination = around.inclination; orbit.LAN = around.longitudeOfAscendingNode; orbit.argumentOfPeriapsis = around.argumentOfPeriapsis; orbit.meanAnomalyAtEpoch = around.meanAnomalyAtEpoch; orbit.epoch = around.epoch; orbit.Init(); } else if (type == 1 && asteroid.location.nearby.Count != 0) { // Nearby IEnumerable <Location.NearbyLoader> nearbys = GetProbabilityList(asteroid.location.nearby, asteroid.location.nearby.Select(a => a.probability.value)); Location.NearbyLoader nearby = nearbys.ElementAt(Random.Range(0, nearbys.Count())); body = PSystemManager.Instance.localBodies.Find(b => b.name == nearby.body); if (!body) { return; } if (nearby.reached && !ReachedBody(body)) { return; } orbit = new Orbit(); orbit.eccentricity = body.orbit.eccentricity + nearby.eccentricity; orbit.semiMajorAxis = body.orbit.semiMajorAxis * nearby.semiMajorAxis; orbit.inclination = body.orbit.inclination + nearby.inclination; orbit.LAN = body.orbit.LAN * nearby.longitudeOfAscendingNode; orbit.argumentOfPeriapsis = body.orbit.argumentOfPeriapsis * nearby.argumentOfPeriapsis; orbit.meanAnomalyAtEpoch = body.orbit.meanAnomalyAtEpoch * nearby.meanAnomalyAtEpoch; orbit.epoch = body.orbit.epoch; orbit.referenceBody = body.orbit.referenceBody; orbit.Init(); } else if (type == 2 && asteroid.location.flyby.Count != 0) { // Flyby IEnumerable <Location.FlybyLoader> flybys = GetProbabilityList(asteroid.location.flyby, asteroid.location.flyby.Select(a => a.probability.value)); Location.FlybyLoader flyby = flybys.ElementAt(Random.Range(0, flybys.Count())); body = PSystemManager.Instance.localBodies.Find(b => b.name == flyby.body); if (!body) { return; } if (flyby.reached && !ReachedBody(body)) { return; } orbit = Orbit.CreateRandomOrbitFlyBy(body, Random.Range(flyby.minDuration, flyby.maxDuration)); } // Check if (orbit == null) { Debug.Log("[Kopernicus]: No new objects this time. (Probablility is " + asteroid.probability.value + "%)"); return; } // Name string name = DiscoverableObjectsUtil.GenerateAsteroidName(); // Lifetime double lifetime = Random.Range(asteroid.minUntrackedLifetime, asteroid.maxUntrackedLifetime) * 24d * 60d * 60d; double maxLifetime = asteroid.maxUntrackedLifetime * 24d * 60d * 60d; // Size UntrackedObjectClass size = (UntrackedObjectClass)((int)(asteroid.size.curve.Evaluate(Random.Range(0f, 1f)) * Enum.GetNames(typeof(UntrackedObjectClass)).Length)); // Spawn ConfigNode vessel = ProtoVessel.CreateVesselNode( name, VesselType.SpaceObject, orbit, 0, new[] { ProtoVessel.CreatePartNode( "PotatoRoid", seed, new ProtoCrewMember[0] ) }, new ConfigNode("ACTIONGROUPS"), ProtoVessel.CreateDiscoveryNode( DiscoveryLevels.Presence, size, lifetime, maxLifetime ) ); OverrideNode(ref vessel, asteroid.vessel); ProtoVessel protoVessel = new ProtoVessel(vessel, HighLogic.CurrentGame); if (asteroid.uniqueName && FlightGlobals.Vessels.Count(v => v.vesselName == protoVessel.vesselName) != 0) { return; } protoVessel.Load(HighLogic.CurrentGame.flightState); GameEvents.onNewVesselCreated.Fire(protoVessel.vesselRef); Debug.Log("[Kopernicus]: New object found near " + body.name + ": " + protoVessel.vesselName + "!"); }
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 '{0}'", 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 '{0}' (usually this means the file could not be found).", vesselData.craftURL); 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; p.UpdateOrgPosAndRot(shipConstruct.parts[0]); } // Estimate an object class, numbers are based on the code that generate objects. float size = shipConstruct.shipSize.magnitude / 2.0f; if (size < 4.05f) { sizeClass = UntrackedObjectClass.A; } else if (size < 6.75f) { sizeClass = UntrackedObjectClass.B; } else if (size < 11.25f) { sizeClass = UntrackedObjectClass.C; } else if (size < 18.25f) { sizeClass = UntrackedObjectClass.D; } else if (size < 31.25f || (Versioning.version_major <= 1 && Versioning.version_minor <= 10)) { sizeClass = UntrackedObjectClass.E; } // Only for KSP 1.10+ else if (size < 52.125f) { sizeClass = UntrackedObjectClass.F; } else if (size < 86.875f) { sizeClass = UntrackedObjectClass.G; } else if (size < 144.75f) { sizeClass = UntrackedObjectClass.H; } else { sizeClass = UntrackedObjectClass.I; } 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.ChangeName(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 '{0}'. Perhaps there's no room?", vesselData.name); 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. ConfigNode empty = new ConfigNode(); ProtoVessel dummyProto = new ProtoVessel(empty, null); Vessel dummyVessel = new GameObject().AddComponent <Vessel>(); dummyVessel.parts = shipConstruct.parts; dummyProto.vesselRef = dummyVessel; // Create the ProtoPartSnapshot objects and then initialize them foreach (Part p in shipConstruct.parts) { p.flightID = ShipConstruction.GetUniqueFlightID(HighLogic.CurrentGame.flightState); p.vessel = dummyVessel; 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(); // Clean up foreach (Part p in shipConstruct.parts) { GameObject.Destroy(p.gameObject); } GameObject.Destroy(dummyVessel.gameObject); } 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.ChangeName(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(vesselData.pitch, Vector3.right); rotation = rotation * Quaternion.AngleAxis(vesselData.roll, Vector3.down); rotation = rotation * Quaternion.AngleAxis(heading, Vector3.forward); // 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 = new ProtoVessel(protoVesselNode, HighLogic.CurrentGame); protoVessel.Load(HighLogic.CurrentGame.flightState); // 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); }
private void addRemoteVessel(ProtoVessel protovessel, Guid vessel_id, KMPVesselUpdate update = null, double distance = 501d) { if (isInFlight && vessel_id == FlightGlobals.ActiveVessel.id) { KMPClientMain.DebugLog("Attempted to update controlled vessel!"); return; } KMPClientMain.DebugLog("addRemoteVessel"); Vector3 newWorldPos = Vector3.zero, newOrbitVel = Vector3.zero; bool setTarget = false, wasLoaded = false; try { //Ensure this vessel isn't already loaded Vessel oldVessel = FlightGlobals.Vessels.Find (v => v.id == vessel_id); if (oldVessel != null) { KMPClientMain.DebugLog("killing extant vessel"); wasLoaded = oldVessel.loaded; if (protovessel.vesselType == VesselType.EVA && wasLoaded) { return; //Don't touch EVAs here } else { setTarget = FlightGlobals.fetch.VesselTarget != null && FlightGlobals.fetch.VesselTarget.GetVessel().id == vessel_id; if (oldVessel.loaded) { newWorldPos = oldVessel.transform.position; if (oldVessel.altitude > 10000d) newOrbitVel = oldVessel.GetObtVelocity(); } oldVessel.Die(); } } if (protovessel.vesselType != VesselType.EVA && serverVessels_Parts.ContainsKey(vessel_id)) { KMPClientMain.DebugLog("killing known precursor vessels"); foreach (Part part in serverVessels_Parts[vessel_id]) { try { if (!part.vessel.isEVA) part.vessel.Die(); } catch {} } } } catch {} try { if ((protovessel.vesselType != VesselType.Debris && protovessel.vesselType != VesselType.Unknown) && protovessel.situation == Vessel.Situations.SUB_ORBITAL && protovessel.altitude < 25d) { //Land flags, vessels and EVAs that are on sub-orbital trajectory KMPClientMain.DebugLog("Placing sub-orbital protovessel on surface"); protovessel.situation = Vessel.Situations.LANDED; protovessel.landed = true; if (protovessel.vesselType == VesselType.Flag) protovessel.height = -1; } //Don't bother with suborbital debris else if (protovessel.vesselType == VesselType.Debris && protovessel.situation == Vessel.Situations.SUB_ORBITAL) return; CelestialBody body = null; if (update != null) { body = FlightGlobals.Bodies.Find(b => b.name == update.bodyName); if (update.situation != Situation.LANDED && update.situation != Situation.SPLASHED) { if (body.atmosphere && body.maxAtmosphereAltitude > protovessel.altitude) { //In-atmo vessel--only load if within visible range if (distance > 500d) return; } } } if (isInSafetyBubble(protovessel.position, body, protovessel.altitude)) //refuse to load anything too close to the KSC { KMPClientMain.DebugLog("Tried to load vessel too close to KSC"); return; } IEnumerator<ProtoCrewMember> crewEnum = HighLogic.CurrentGame.CrewRoster.GetEnumerator(); int applicants = 0; while (crewEnum.MoveNext()) if (crewEnum.Current.rosterStatus == ProtoCrewMember.RosterStatus.AVAILABLE) applicants++; if (protovessel.GetVesselCrew().Count * 5 > applicants) { KMPClientMain.DebugLog("Adding crew applicants"); for (int i = 0; i < (protovessel.GetVesselCrew().Count * 5);) { ProtoCrewMember protoCrew = CrewGenerator.RandomCrewMemberPrototype(); if (!HighLogic.CurrentGame.CrewRoster.ExistsInRoster(protoCrew.name)) { HighLogic.CurrentGame.CrewRoster.AddCrewMember(protoCrew); i++; } } } if (vessels.ContainsKey(vessel_id.ToString()) && (!serverVessels_LoadDelay.ContainsKey(vessel_id) || (serverVessels_LoadDelay.ContainsKey(vessel_id) ? serverVessels_LoadDelay[vessel_id] < UnityEngine.Time.realtimeSinceStartup : false))) { protovessel.Load(HighLogic.CurrentGame.flightState); Vessel created_vessel = protovessel.vesselRef; if (created_vessel != null) { try { OrbitPhysicsManager.HoldVesselUnpack(1); } catch (NullReferenceException) { } if (!created_vessel.loaded) created_vessel.Load(); KMPClientMain.DebugLog(created_vessel.id.ToString() + " initializing: ProtoParts=" + protovessel.protoPartSnapshots.Count+ ",Parts=" + created_vessel.Parts.Count + ",Sit=" + created_vessel.situation.ToString() + ",type=" + created_vessel.vesselType + ",alt=" + protovessel.altitude); vessels[vessel_id.ToString()].vessel.vesselRef = created_vessel; serverVessels_PartCounts[vessel_id] = created_vessel.Parts.Count; serverVessels_Parts[vessel_id] = new List<Part>(); serverVessels_Parts[vessel_id].AddRange(created_vessel.Parts); bool distanceBlocksUnload = false; if (created_vessel.vesselType != VesselType.Flag && created_vessel.vesselType != VesselType.EVA) { foreach (Part part in created_vessel.Parts) { part.OnLoad(); part.OnJustAboutToBeDestroyed += checkRemoteVesselIntegrity; part.explosionPotential = 0; part.terrainCollider = new PQS_PartCollider(); part.terrainCollider.part = part; part.terrainCollider.useVelocityCollider = false; part.terrainCollider.useGravityCollider = false; part.breakingForce = float.MaxValue; part.breakingTorque = float.MaxValue; } if (update != null && update.bodyName == FlightGlobals.ActiveVessel.mainBody.name) { KMPClientMain.DebugLog("update included"); //Update rotation created_vessel.SetRotation(new Quaternion(update.rot[0],update.rot[1],update.rot[2],update.rot[3])); if (update.relTime == RelativeTime.PRESENT) { if (newWorldPos != Vector3.zero) { KMPClientMain.DebugLog("repositioning"); created_vessel.transform.position = newWorldPos; if (wasLoaded) distanceBlocksUnload = Vector3.Distance(created_vessel.transform.position,FlightGlobals.ActiveVessel.transform.position) < 2000f; } if (newOrbitVel != Vector3.zero) { KMPClientMain.DebugLog("updating velocity"); created_vessel.ChangeWorldVelocity((-1 * created_vessel.GetObtVelocity()) + newOrbitVel); } //Update FlightCtrlState if (created_vessel.ctrlState == null) created_vessel.ctrlState = new FlightCtrlState(); created_vessel.ctrlState.CopyFrom(update.flightCtrlState.getAsFlightCtrlState(0.75f)); } else { serverVessels_InPresent[update.id] = false; foreach (Part part in created_vessel.Parts) { part.setOpacity(0.3f); } } } } if (!syncing && !distanceBlocksUnload) //This explicit Unload helps correct the effects of "Can't remove Part (Script) because PartBuoyancy (Script) depends on it" errors and associated NREs seen during rendezvous mode switching, but for unknown reasons it causes problems if active during universe sync created_vessel.Unload(); if (setTarget) StartCoroutine(setDockingTarget(created_vessel)); KMPClientMain.DebugLog(created_vessel.id.ToString() + " initialized"); } } } catch (Exception e) { KMPClientMain.DebugLog("Error adding remote vessel: " + e.Message + " " + e.StackTrace); } }
private bool loadVesselForRendezvous(ProtoVessel placeVessel, Vessel targetVessel) { targetVessel.BackupVessel(); placeVessel.orbitSnapShot = targetVessel.protoVessel.orbitSnapShot; placeVessel.orbitSnapShot.epoch = 0.0; tempID = rand.Next(1000000000).ToString(); //rename any vessels present with "AdministativeDockingName" foreach (Vessel ve in FlightGlobals.Vessels) { if (ve.vesselName == tempID) { Vessel NameVessel = null; NameVessel = ve; NameVessel.vesselName = "1"; } } placeVessel.vesselID = Guid.NewGuid(); placeVessel.vesselName = tempID; foreach (ProtoPartSnapshot p in placeVessel.protoPartSnapshots) { if (placeVessel.refTransform == p.flightID) { p.flightID = (UInt32)rand.Next(1000000000, 2147483647); placeVessel.refTransform = p.flightID; } else { p.flightID = (UInt32)rand.Next(1000000000, 2147483647); } if (p.protoModuleCrew != null && p.protoModuleCrew.Count() != 0) { List<ProtoCrewMember> cl = p.protoModuleCrew; List<ProtoCrewMember> clc = new List<ProtoCrewMember>(cl); foreach (ProtoCrewMember c in clc) { p.RemoveCrew(c); //print("remove"); } } } try { placeVessel.Load(HighLogic.CurrentGame.flightState); return true; } catch { //abortArrival(); //return false; return true; } }