private void OnVesselRecovered(ProtoVessel v) { // Don't check if we're not ready to complete if (!ReadyToComplete()) { return; } // Special handling for null vessel cases if (v.vesselRef == null) { VesselParameterGroup vpg = GetParameterGroupHost(); if (vpg == null) { SetState(ParameterState.Complete); } else { } } recovered[v.vesselRef] = true; CheckVessel(v.vesselRef); }
public void Save() { if ((HighLogic.LoadedScene == GameScenes.FLIGHT) && (FlightGlobals.fetch.activeVessel != null)) { if (FlightGlobals.fetch.activeVessel.loaded && !FlightGlobals.fetch.activeVessel.packed) { if (FlightGlobals.fetch.activeVessel.situation != Vessel.Situations.FLYING) { savedVessel = new ConfigNode(); ProtoVessel tempVessel = new ProtoVessel(FlightGlobals.fetch.activeVessel); tempVessel.Save(savedVessel); savedSubspace = new Subspace(); savedSubspace.planetTime = Planetarium.GetUniversalTime(); savedSubspace.serverClock = TimeSyncer.fetch.GetServerClock(); savedSubspace.subspaceSpeed = 1f; ScreenMessages.PostScreenMessage("Quicksaved!", 3f, ScreenMessageStyle.UPPER_CENTER); } else { ScreenMessages.PostScreenMessage("Cannot quicksave - Active vessel is in flight!", 3f, ScreenMessageStyle.UPPER_CENTER); } } else { ScreenMessages.PostScreenMessage("Cannot quicksave - Active vessel is not loaded!", 3f, ScreenMessageStyle.UPPER_CENTER); } } else { ScreenMessages.PostScreenMessage("Cannot quicksave - Not in flight!", 3f, ScreenMessageStyle.UPPER_CENTER); } }
private void RecoveryWatcher(float sci, ScienceSubject sub, ProtoVessel pv, bool reverse) { if (HighLogic.LoadedScene == GameScenes.SPACECENTER || HighLogic.LoadedScene == GameScenes.TRACKSTATION) { float DMScience = sci; DMUtils.DebugLog("Science Data Recovered For {0} Science", sci); DMScienceData DMData = DMScienceScenario.SciScenario.getDMScience(sub.title); if (DMData != null) { float oldSciVal = 0f; if (sub.scienceCap != 0) oldSciVal = Math.Max(0f, 1f - ((sub.science - sci) / sub.scienceCap)); DMScience = sub.subjectValue * DMData.BaseValue * DMData.SciVal * oldSciVal; DMScienceScenario.SciScenario.submitDMScience(DMData, DMScience); } if (DMScience != sci) { float extraScience = sci - DMScience; Debug.LogWarning(string.Format("[DMagic Orbital Science] [Asteroid Science Retrieval] Remove {0} Science From R&D Center After Asteroid Calculations", extraScience)); DMUtils.DebugLog("Remove {0} Science From R&D Center: From {1} To {2}", extraScience, ResearchAndDevelopment.Instance.Science, ResearchAndDevelopment.Instance.Science - extraScience); ResearchAndDevelopment.Instance.AddScience(-1f * extraScience, TransactionReasons.ScienceTransmission); } } }
//add some crew to a vessel public static void addCrew(ProtoVessel vsl, List<ProtoCrewMember> crew) { foreach(var p in vsl.protoPartSnapshots) { if(crew.Count == 0) break; addCrew(p, crew); } }
private void scienceReceived(float sci, ScienceSubject sub, ProtoVessel pv, bool reverse) { if (HighLogic.LoadedSceneIsFlight) { DMScienceData DMData = DMScienceScenario.SciScenario.getDMScience(sub.title); if (DMData != null) DMScienceScenario.SciScenario.submitDMScience(DMData, sci); } }
/// <summary> /// Gets the missionID of the ROOT part of the given vessel. /// </summary> /// <returns>The missionID</returns> /// <param name="pvessel">The ProtoVessel to get the missionID of.</param> public static uint GetVesselMissionID(ProtoVessel pvessel) { if(pvessel.protoPartSnapshots[pvessel.rootIndex] == null) { return 0; } else { return pvessel.protoPartSnapshots[pvessel.rootIndex].missionID; } }
public void vesselRecoveryProcessingEvent(ProtoVessel pvessel, MissionRecoveryDialog dialog, float recoveryFactor) { BeanCounter.LogFormatted_DebugOnly("---------- vesselRecoveryProcessingEvent ------------"); BeanCounter.LogFormatted_DebugOnly("recoveryFactor: {0:f3}", recoveryFactor); BeanCounter.LogFormatted_DebugOnly("Vessel root missionID: {0}", BCUtils.GetVesselMissionID(pvessel)); // Get a list of every missionID from the recovered parts List<uint> recovered_mission_ids = (from ppart in pvessel.protoPartSnapshots select ppart.missionID).ToList(); // Get a list of every unique part ID so we can match them up List<uint> recovered_part_ids = (from ppart in pvessel.protoPartSnapshots select ppart.flightID).ToList(); // Now lets get all of the launches that contain recovered parts List<BCLaunchData> recovered_launches = (from launch in OATBeanCounterData.data.launches where recovered_mission_ids.Contains(launch.missionID) select launch).ToList(); // And finally we get the full list of every recovered part so we can flag them all as recovered var recoveredparts = from launch in recovered_launches from part in launch.parts where recovered_part_ids.Contains(part.uid) select part; foreach(BCVesselPartData partdata in recoveredparts) { BeanCounter.LogFormatted_DebugOnly("Flagging part as recovered: {0} - {1}", partdata.partName, partdata.uid); partdata.status = BCVesselPartStatus.Recovered; } BCRecoveryData recovery = new BCRecoveryData(true); OATBeanCounterData.data.recoveries.Add(recovery); recovery.partIDs = recovered_part_ids; recovery.recoveryFactor = recoveryFactor; // Try to match this to the transaction BCTransactionData transaction = (from trans in OATBeanCounterData.data.transactions where trans.time == HighLogic.fetch.currentGame.UniversalTime && trans.reason == TransactionReasons.VesselRecovery select trans).SingleOrDefault(); if (transaction != null) { BeanCounter.LogFormatted_DebugOnly("Found matching transaction for this recovery: {0}", transaction.id); recovery.transactionID = transaction.id; transaction.dataID = recovery.id; } BeanCounter.LogFormatted_DebugOnly("--------- /vesselRecoveryProcessingEvent ------------"); }
public static float GetTotalVesselCost(ProtoVessel vessel) { float total = 0; foreach (ProtoPartSnapshot part in vessel.protoPartSnapshots) { float dry, wet; total += ShipConstruction.GetPartCosts(part, part.partInfo, out dry, out wet); } return total; }
public void RecordVesselRecovered(ProtoVessel vessel) { List<ProtoCrewMember> crew = vessel.GetVesselCrew(); foreach (ProtoCrewMember member in crew) { if (!member.IsTourist()) { Log.Info("kerbal " + member.name + " ended a mission "); hallOfFame.RecordMissionFinished(member); } } }
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>(); }
private void OnVesselRecovered(ProtoVessel vessel, bool quick) { foreach (ProtoCrewMember pcm in VesselUtil.GetVesselCrew(vessel.vesselRef)) { // Award the media star XP for each planet landed on foreach (string target in pcm.flightLog.Entries. Where(fle => fle.type == FlightLog.EntryType.Land.ToString()). Select(fle => fle.target).ToList()) { pcm.flightLog.AddEntry(MEDIA_STAR_XP, target); } } }
private void OnVesselRecovered(ProtoVessel v) { LoggingUtil.LogVerbose(this, "OnVesselRecovered: " + v); // EVA vessel if (v.vesselType == VesselType.EVA) { foreach (ProtoPartSnapshot p in v.protoPartSnapshots) { foreach (string name in p.protoCrewNames) { // Find this crew member in our data foreach (KerbalData kd in kerbals) { if (kd.name == name && kd.addToRoster) { // Add them to the roster kd.crewMember.type = ProtoCrewMember.KerbalType.Crew; } } } } } // Vessel with crew foreach (ProtoCrewMember crewMember in v.GetVesselCrew()) { foreach (KerbalData kd in kerbals) { if (kd.crewMember == crewMember && kd.addToRoster) { // Add them to the roster crewMember.type = ProtoCrewMember.KerbalType.Crew; } } } }
/* simple ISP dependant effi calculation. * NEEDS ballancing * removing fuel based on dV would make more sense, * and more thinkering to firgure it out * 1.60 milestone maybe? */ public static float FetchEfficiency(Vessel vessel) { float Efficiency = 0; if (vessel == FlightGlobals.ActiveVessel) { List <ModuleOrbitalDecay> modlist = vessel.FindPartModulesImplementing <ModuleOrbitalDecay>(); if (modlist.Count > 0) { Efficiency = modlist[0].stationKeepData.ISP; } } else { ProtoVessel proto = vessel.protoVessel; foreach (ProtoPartSnapshot protopart in proto.protoPartSnapshots) { foreach (ProtoPartModuleSnapshot protopartmodulesnapshot in protopart.modules) { if (protopartmodulesnapshot.moduleName == "ModuleOrbitalDecay") { ConfigNode node = protopartmodulesnapshot.moduleValues.GetNode("stationKeepData"); Efficiency = float.Parse(node.GetValue("ISP")); break; } } } } if (Settings.ReadRD()) { Efficiency *= 0.5f; // Balance here! } return(1 / Efficiency); }
private static void GenerateStrandedKerbal(int bodyId, string kerbalName) { //Add kerbal to crew roster. LunaLog.Log($"[LMP]: Spawning missing kerbal, Name: {kerbalName}"); var pcm = HighLogic.CurrentGame.CrewRoster.GetNewKerbal(ProtoCrewMember.KerbalType.Unowned); pcm.ChangeName(kerbalName); pcm.rosterStatus = ProtoCrewMember.RosterStatus.Assigned; //Create protovessel var newPartId = ShipConstruction.GetUniqueFlightID(HighLogic.CurrentGame.flightState); var contractBody = FlightGlobals.Bodies[bodyId]; //Atmo: 10km above atmo, to half the planets radius out. //Non-atmo: 30km above ground, to half the planets radius out. var minAltitude = CelestialUtilities.GetMinimumOrbitalDistance(contractBody, 1.1f); var maxAltitude = minAltitude + contractBody.Radius * 0.5; var strandedOrbit = Orbit.CreateRandomOrbitAround(FlightGlobals.Bodies[bodyId], minAltitude, maxAltitude); var kerbalPartNode = new[] { ProtoVessel.CreatePartNode("kerbalEVA", newPartId, pcm) }; var protoVesselNode = ProtoVessel.CreateVesselNode(kerbalName, VesselType.EVA, strandedOrbit, 0, kerbalPartNode); var discoveryNode = ProtoVessel.CreateDiscoveryNode(DiscoveryLevels.Unowned, UntrackedObjectClass.A, double.PositiveInfinity, double.PositiveInfinity); var protoVessel = new ProtoVessel(protoVesselNode, HighLogic.CurrentGame) { discoveryInfo = discoveryNode }; //It's not supposed to be infinite, but you're crazy if you think I'm going to decipher the values field of the rescue node. HighLogic.CurrentGame.flightState.protoVessels.Add(protoVessel); }
private void OnVesselRecovered(ProtoVessel recoveredVessel, bool quick) { if (HighLogic.CurrentGame.Parameters.CustomParams <XenoIndustryCoreGameParameters>().enabled) { Dictionary <string, int> recoveredResources = new Dictionary <string, int>(); CalculateLaunchCosts(ref recoveredResources, recoveredVessel); if (recoveredResources.Count > 0) { string message = "Following resources have been recovered: \n"; string bodyName = "Kerbin"; // Recovery is only possible on Kerbin for now foreach (KeyValuePair <string, int> kvPair in recoveredResources) { message += String.Format("\n {0} {1}", kvPair.Value, kvPair.Key); StartCoroutine(XenoIndustrySignpost.AddItemsToClusterio(bodyName, kvPair.Key, kvPair.Value)); } message += "\n"; if (!quick) { MultiOptionDialog dialog = new MultiOptionDialog("ClusterioResourceRecovery", message, "Recovery successful", UISkinManager.GetSkin("KSP window 7"), new DialogGUIBase[] { new DialogGUIButton("Continue", null) }); PopupDialog.SpawnPopupDialog(new Vector2(0.5f, 0.5f), new Vector2(0.5f, 0.5f), dialog, false, null); } } } }
/// <summary> /// Do some basic validations over the protovessel /// </summary> private static bool ProtoVesselValidationsPassed(ProtoVessel vesselProto) { if (vesselProto == null) { Debug.LogError("[LMP]: protoVessel is null!"); return(false); } if (vesselProto.situation == Vessel.Situations.FLYING) { if (vesselProto.orbitSnapShot == null) { Debug.Log("[LMP]: Skipping flying vessel load - Protovessel does not have an orbit snapshot"); return(false); } var updateBody = FlightGlobals.Bodies[vesselProto.orbitSnapShot.ReferenceBodyIndex]; if (updateBody == null) { Debug.Log("[LMP]: Skipping flying vessel load - Could not find celestial body index {currentProto.orbitSnapShot.ReferenceBodyIndex}"); return(false); } } return(true); }
/// <summary> /// This method prepares the protovessel class and send the message, it's intended to be run in another thread /// </summary> private void PrepareAndSendProtoVessel(ProtoVessel protoVessel) { //Never send empty vessel id's (it happens with flags...) if (protoVessel.vesselID == Guid.Empty) { return; } //VesselSerializedBytes is shared so lock it! lock (VesselArraySyncLock) { VesselSerializer.SerializeVesselToArray(protoVessel, VesselSerializedBytes, out var numBytes); if (numBytes > 0) { var msgData = NetworkMain.CliMsgFactory.CreateNewMessageData <VesselProtoMsgData>(); msgData.GameTime = TimeSyncSystem.UniversalTime; msgData.VesselId = protoVessel.vesselID; msgData.NumBytes = numBytes; if (msgData.Data.Length < numBytes) { Array.Resize(ref msgData.Data, numBytes); } Array.Copy(VesselSerializedBytes, 0, msgData.Data, 0, numBytes); SendMessage(msgData); } else { if (protoVessel.vesselType == VesselType.Debris) { LunaLog.Log($"Serialization of debris vessel: {protoVessel.vesselID} name: {protoVessel.vesselName} failed. Adding to kill list"); VesselRemoveSystem.Singleton.KillVessel(protoVessel.vesselID, true, "Serialization of debris failed"); } } } }
/// <summary> /// This event is called when the vessel is recovered /// </summary> public void OnVesselRecovered(ProtoVessel recoveredVessel, bool quick) { //quick == true when you press "space center" from the inflight menu if (!LockSystem.LockQuery.CanRecoverOrTerminateTheVessel(recoveredVessel.vesselID, SettingsSystem.CurrentSettings.PlayerName)) { LunaScreenMsg.PostScreenMessage(LocalizationContainer.ScreenText.CannotRecover, 5f, ScreenMessageStyle.UPPER_CENTER); return; } _recoveringTerminatingVesselId = recoveredVessel.vesselID; LunaLog.Log($"[LMP]: Removing vessel {recoveredVessel.vesselID}, Name: {recoveredVessel.vesselName} from the server: Recovered"); System.MessageSender.SendVesselRemove(recoveredVessel.vesselID); //Vessel is recovered so remove the locks. Do not remove the kerbal locks as that's done in the Kerbal system LockSystem.Singleton.ReleaseAllVesselLocks(null, recoveredVessel.vesselID, 1); //We consider this vessel removed but we let KSP do the remove of the vessel System.RemovedVessels.TryAdd(recoveredVessel.vesselID, DateTime.Now); RemoveEvent.onLmpRecoveredVessel.Fire(recoveredVessel); VesselCommon.RemoveVesselFromSystems(recoveredVessel.vesselID); }
public override bool protovesselHasDoneExperiement(ProtoVessel pv, AvailablePart experiment, CelestialBody targetBody, double contractAccepted) { NE_Helper.log("KEES-Experiement stategy"); foreach (ProtoPartSnapshot part in pv.protoPartSnapshots) { NE_Helper.log("KEES-Experiement stategy, Part: " + part.partName); if (part.partName == experiment.name) { if (experimentFound(part, experiment, targetBody, contractAccepted)) return true; } else if (part.partName == KEES_PC) { if (payloadCarrierFound(part, experiment, targetBody, contractAccepted)) return true; } else if (isKasContainerPart(part)) { if (payloadCarrierFound(part, experiment, targetBody, contractAccepted)) return true; } } return false; }
private void OnScienceReceived(float amount, ScienceSubject subject, ProtoVessel vessel, bool reverseEngineered) { // Check that the science is for home CelestialBody body = Science.GetCelestialBody(subject); if (body == null || !body.isHomeWorld) { return; } Biome biome = Science.GetBiome(subject); bool isKSC = biome != null && biome.IsKSC(); if (KSCScienceMultiplier > 0.0f && isKSC) { float delta = KSCScienceMultiplier * amount - amount; ResearchAndDevelopment.Instance.AddScience(delta, TransactionReasons.Strategies); CurrencyPopup.Instance.AddPopup(Currency.Science, delta, TransactionReasons.Strategies, Parent.Config.Title, true); } else if (nonKSCScienceMultiplier > 0.0f && !isKSC) { float delta = nonKSCScienceMultiplier * amount - amount; ResearchAndDevelopment.Instance.AddScience(delta, TransactionReasons.Strategies); CurrencyPopup.Instance.AddPopup(Currency.Science, delta, TransactionReasons.Strategies, Parent.Config.Title, true); } }
public void UpdateFairingsValuesInProtoVessel(ProtoVessel protoVessel, uint partFlightId) { if (protoVessel == null) { return; } var protoPart = VesselCommon.FindProtoPartInProtovessel(protoVessel, partFlightId); if (protoPart == null) { return; } var protoModule = VesselCommon.FindProtoPartModuleInProtoPart(protoPart, "ModuleProceduralFairing"); if (protoModule == null) { return; } protoModule.moduleValues.SetValue("fsm", "st_flight_deployed"); protoModule.moduleValues.RemoveNodesStartWith("XSECTION"); }
public void vesselRecoverEvent(ProtoVessel v, bool unknownAsOfNow) { if (!KCT_PresetManager.Instance.ActivePreset.generalSettings.Enabled) { return; } if (!KCT_GameStates.flightSimulated && !v.vesselRef.isEVA) { // if (KCT_GameStates.settings.Debug && HighLogic.LoadedScene != GameScenes.TRACKSTATION && (v.wasControllable || v.protoPartSnapshots.Find(p => p.modules.Find(m => m.moduleName.ToLower() == "modulecommand") != null) != null)) if (KCT_GameStates.recoveredVessel != null && v.vesselName == KCT_GameStates.recoveredVessel.shipName) { //KCT_GameStates.recoveredVessel = new KCT_BuildListVessel(v); KCT_Utilities.SpendFunds(KCT_GameStates.recoveredVessel.cost, TransactionReasons.VesselRollout); if (KCT_GameStates.recoveredVessel.type == KCT_BuildListVessel.ListType.VAB) { KCT_GameStates.ActiveKSC.VABWarehouse.Add(KCT_GameStates.recoveredVessel); } else { KCT_GameStates.ActiveKSC.SPHWarehouse.Add(KCT_GameStates.recoveredVessel); } KCT_GameStates.ActiveKSC.Recon_Rollout.Add(new KCT_Recon_Rollout(KCT_GameStates.recoveredVessel, KCT_Recon_Rollout.RolloutReconType.Recovery, KCT_GameStates.recoveredVessel.id.ToString())); KCT_GameStates.recoveredVessel = null; } else { KCTDebug.Log("Adding recovered parts to Part Inventory"); foreach (ProtoPartSnapshot p in v.protoPartSnapshots) { //string name = p.partInfo.name + KCT_Utilities.GetTweakScaleSize(p); KCT_Utilities.AddPartToInventory(p); } } } }
/*************************************************************************************************************************/ private List <ScienceData> recover_science(ProtoVessel proto_vessel) { List <ScienceData> science_data = new List <ScienceData>(); Log.PushStackInfo("FMRS_Core.recover_science", "enter recover_science(GUI Vessel_id, Game save) {0}", proto_vessel.vesselID); Log.dbg("Try recover science from: {0}", proto_vessel.vesselName); foreach (ProtoPartSnapshot part in proto_vessel.protoPartSnapshots) { foreach (ProtoPartModuleSnapshot module in part.modules) { foreach (ConfigNode science_node in module.moduleValues.GetNodes("ScienceData")) { science_data.Add(new ScienceData(science_node)); Log.dbg("ScienceData: {0 found", science_node.GetValue("subjectID")); } } } Log.PopStackInfo("leave recover_science(GUI Vessel_id, Game save)"); return(science_data); }
/*************************************************************************************************************************/ private float vessels_cost(ProtoVessel temp_vessel) { float partcost, float_dummy, vesselcost = 0; PartResourceDefinition resc_def; Log.PushStackInfo("FMRS_Core.vessels_cost", "enter float vessels_cost(ProtoVessel temp_vessel) {0}", temp_vessel.vesselID); Log.dbg("Calculate cost from: {0}", temp_vessel.vesselName); foreach (ProtoPartSnapshot part in temp_vessel.protoPartSnapshots) { ShipConstruction.GetPartCosts(part, part.partInfo, out partcost, out float_dummy); foreach (ProtoPartResourceSnapshot resc in part.resources) { resc_def = PartResourceLibrary.Instance.resourceDefinitions[resc.resourceName]; partcost += (float)resc.amount * resc_def.unitCost; } vesselcost += partcost; } Log.dbg("FMRS cost: {0}", vesselcost); Log.PopStackInfo("leave float vessels_cost(ProtoVessel temp_vessel)"); return(vesselcost); }
public static byte[] SerializeVessel(ProtoVessel protoVessel) { var vesselNode = new ConfigNode(); try { protoVessel.Save(vesselNode); } catch (Exception) { LunaLog.LogError("[LMP]: Error while saving vessel"); return(new byte[0]); } var vesselId = new Guid(vesselNode.GetValue("pid")); //Defend against NaN orbits if (VesselHasNaNPosition(vesselNode)) { LunaLog.Log($"[LMP]: Vessel {vesselId} has NaN position"); return(new byte[0]); } //Clean up the vessel so we send only the important data CleanUpVesselNode(vesselNode, vesselId); //TODO: Remove tourists from the vessel. This must be done in the CleanUpVesselNode method //foreach (var pps in protoVessel.protoPartSnapshots) //{ // foreach (var pcm in // pps.protoModuleCrew.Where(pcm => pcm.type == ProtoCrewMember.KerbalType.Tourist).ToArray()) // pps.protoModuleCrew.Remove(pcm); //} return(ConfigNodeSerializer.Serialize(vesselNode)); }
private void scienceRecieve(float sci, ScienceSubject sub, ProtoVessel pv, bool reverse) { if (this.Root.ContractState != Contract.State.Active) { return; } if (sub == null) { return; } if (sub.id.Contains(string.Format("{0}@Asteroid{1}{2}", scienceContainer.Exp.id, scienceLocation, ""))) { if (collected) { base.SetComplete(); } else { DMUtils.Logging("Data Not Collected From Correctly Sized Asteroid"); } } }
private static double GetUnloadedVesselMass(string name, ProtoVessel protoVessel) { double num = 0.0; for (int i = 0; i < protoVessel.protoPartSnapshots.Count; i++) { ProtoPartSnapshot protoPartSnapshot = protoVessel.protoPartSnapshots[i]; num += (double)protoPartSnapshot.mass; for (int j = 0; j < protoPartSnapshot.resources.Count; j++) { ProtoPartResourceSnapshot protoPartResourceSnapshot = protoPartSnapshot.resources[j]; if (protoPartResourceSnapshot != null) { if (protoPartResourceSnapshot.definition != null) { num += protoPartResourceSnapshot.amount * (double)protoPartResourceSnapshot.definition.density; } //else // Debug.Log("Vessel: " + name + ", resource: " + protoPartResourceSnapshot.resourceName + ", no definition"); } } } return(num); }
// remove science data, deleting the file when it is empty public void Delete_file(string subject_id, double amount, ProtoVessel pv) { // get data File file; if (files.TryGetValue(subject_id, out file)) { // decrease amount of data stored in the file file.size -= Math.Min(file.size, amount); file.ts = Planetarium.GetUniversalTime(); if (file.buff > double.Epsilon && pv != null) { Science.Credit(subject_id, file.buff, true, pv, true); file.buff = 0; } // remove file if empty if (file.size <= double.Epsilon) { files.Remove(subject_id); } } }
private void OnVesselWillDestroy(Vessel vessel) { bool pilotedByAnotherPlayer = lockSystem.LockExists("control-" + vessel.id) && !lockSystem.LockIsOurs("control-" + vessel.id); bool updatedByAnotherPlayer = lockSystem.LockExists("update-" + vessel.id) && !lockSystem.LockIsOurs("update-" + vessel.id); bool updatedInTheFuture = vesselWorker.VesselUpdatedInFuture(vessel.id); //Vessel was packed within the last 5 seconds if (lastPackTime.ContainsKey(vessel.id) && (Client.realtimeSinceStartup - lastPackTime[vessel.id]) < 5f) { lastPackTime.Remove(vessel.id); if (vessel.situation == Vessel.Situations.FLYING && (pilotedByAnotherPlayer || updatedByAnotherPlayer || updatedInTheFuture)) { DarkLog.Debug("Hacky load: Saving player vessel getting packed in atmosphere"); ProtoVessel pv = vessel.BackupVessel(); ConfigNode savedNode = new ConfigNode(); pv.Save(savedNode); vesselWorker.LoadVessel(savedNode, vessel.id, true); } } if (lastPackTime.ContainsKey(vessel.id)) { lastPackTime.Remove(vessel.id); } }
// recoveryFraction - percentage of funds added after recovery, based on distance from KSC public void onVesselRecoveryProcessing(ProtoVessel v, MissionRecoveryDialog dialog, float recoveryFraction) { KerbalGUIManager.print("[rusty] onVesselRecoveryProcessing: x = " + recoveryFraction); KerbalGUIManager.print("[rusty] onVesselRecoveryProcessing: AddFunds = " + -dialog.fundsEarned); // deduct recovered funds Funding.Instance.AddFunds(-dialog.fundsEarned, TransactionReasons.VesselRecovery); // calculate distance // longest possible ground distance on Kerbin [km] //const double HALF_CIRCLE = 2 * Mathf.PI * 600 / 2; // distance from KSC [m] double distance = SpaceCenter.Instance.GreatCircleDistance(SpaceCenter.Instance.cb.GetRelSurfaceNVector(v.latitude, v.longitude)); // KSC is supposedly 25 m^2 in size, so no more than 5 km can be considered free if (distance <= 5000.0) { distance = 0.0f; } KerbalGUIManager.print("[rusty] onVesselRecoveryProcessing: distance = " + distance + " m"); // calculate recovery price // price of 1 metric tone per 1km const double recoveryRate = 100.0; double recoveryPrice = (double)vesselMass * (distance / 1000.0) * recoveryRate; // reset funds dialog.fundsEarned = 0.0; // show recovery GUI GUIRecovery wndRecovery = new GUIRecovery(); wndRecovery.vesselMass = vesselMass; wndRecovery.vesselTitle = v.vesselName; wndRecovery.recoveryPrice = recoveryPrice; wndRecovery.recoveryDistance = Math.Ceiling(distance / 1000.0); wndRecovery.show(); }
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 void OnVesselTerminated(ProtoVessel data) { KMPClientMain.DebugLog("Vessel termination: " + data.vesselID + " " + serverVessels_RemoteID.ContainsKey(data.vesselID) + " " + (HighLogic.LoadedScene == GameScenes.TRACKSTATION) + " " + (data.vesselType == VesselType.Debris || (serverVessels_IsMine.ContainsKey(data.vesselID) ? serverVessels_IsMine[data.vesselID] : true))); if (serverVessels_RemoteID.ContainsKey(data.vesselID) //"activeTermination" only if this is remote vessel && HighLogic.LoadedScene == GameScenes.TRACKSTATION //and at TrackStation && (data.vesselType == VesselType.Debris || (serverVessels_IsMine.ContainsKey(data.vesselID) ? serverVessels_IsMine[data.vesselID] : true))) //and is debris or owned vessel { activeTermination = true; } }
private void applyVesselUpdate(KMPVesselUpdate vessel_update, KMPVessel vessel) { serverVessels_RemoteID[vessel_update.id] = vessel_update.kmpID; //Find the CelestialBody that matches the one in the update CelestialBody update_body = null; if (vessel.mainBody != null && vessel.mainBody.bodyName == vessel_update.bodyName) update_body = vessel.mainBody; //Vessel already has the correct body else { //Find the celestial body in the list of bodies foreach (CelestialBody body in FlightGlobals.Bodies) { if (body.bodyName == vessel_update.bodyName) { update_body = body; break; } } } Vector3 oldPosition = vessel.worldPosition; if (update_body != null) { //Convert float arrays to Vector3s Vector3 pos = new Vector3(vessel_update.pos[0], vessel_update.pos[1], vessel_update.pos[2]); Vector3 dir = new Vector3(vessel_update.dir[0], vessel_update.dir[1], vessel_update.dir[2]); Vector3 vel = new Vector3(vessel_update.vel[0], vessel_update.vel[1], vessel_update.vel[2]); vessel.info = vessel_update; vessel.setOrbitalData(update_body, pos, vel, dir); } KMPClientMain.DebugLog("vessel state: " + vessel_update.state.ToString() + ", tick=" + vessel_update.tick + ", realTick=" + Planetarium.GetUniversalTime()); if (vessel_update.state == State.ACTIVE && !vessel_update.isSyncOnlyUpdate && vessel_update.relTime != RelativeTime.FUTURE && !vessel_update.isDockUpdate) { //Update the player status info VesselStatusInfo status = new VesselStatusInfo(); if (vessel_update.relTime == RelativeTime.PRESENT) status.info = vessel_update; status.ownerName = vessel_update.player; status.vesselName = vessel_update.name; if (vessel.orbitValid) status.orbit = vessel.orbitRenderer.driver.orbit; status.lastUpdateTime = UnityEngine.Time.realtimeSinceStartup; status.color = KMPVessel.generateActiveColor(status.ownerName); if (playerStatus.ContainsKey(status.ownerName)) playerStatus[status.ownerName] = status; else playerStatus.Add(status.ownerName, status); } if (!vessel_update.id.Equals(Guid.Empty) && !docking) { //Update vessel privacy locks if (!isInFlight || vessel_update.id != FlightGlobals.ActiveVessel.id) { serverVessels_InUse[vessel_update.id] = vessel_update.state == State.ACTIVE; serverVessels_IsPrivate[vessel_update.id] = vessel_update.isPrivate; serverVessels_IsMine[vessel_update.id] = vessel_update.isMine; KMPClientMain.DebugLog("status flags updated: " + (vessel_update.state == State.ACTIVE) + " " + vessel_update.isPrivate + " " + vessel_update.isMine); if (vessel_update.situation == Situation.DESTROYED) { KMPClientMain.DebugLog("killing vessel"); Vessel extant_vessel = FlightGlobals.Vessels.Find(v => v.id == vessel_update.id); if (extant_vessel != null && !extant_vessel.isEVA) try { extant_vessel.Die(); } catch {} return; } } //Store protovessel if included if (vessel_update.getProtoVesselNode() != null && (!isInFlight || vessel_update.id != FlightGlobals.ActiveVessel.id)) serverVessels_ProtoVessels[vessel_update.id] = vessel_update.getProtoVesselNode(); } if (isInFlightOrTracking) { if (vessel_update.id != FlightGlobals.ActiveVessel.id) { KMPClientMain.DebugLog("retrieving vessel: " + vessel_update.id.ToString()); if (!vessel_update.id.Equals(Guid.Empty)) { Vessel extant_vessel = vessel.vesselRef; if (extant_vessel == null) extant_vessel = FlightGlobals.Vessels.Find(v => v.id == vessel_update.id); if (isInFlight) { if (extant_vessel != null && vessel_update.state == State.ACTIVE && !vessel_update.isSyncOnlyUpdate) { extant_vessel.name = vessel_update.name + " <" + vessel_update.player + ">"; extant_vessel.vesselName = vessel_update.name + " <" + vessel_update.player + ">"; } else if (extant_vessel != null) { extant_vessel.name = vessel_update.name; extant_vessel.vesselName = vessel_update.name; } } if (!serverVessels_LoadDelay.ContainsKey(vessel_update.id) || (serverVessels_LoadDelay.ContainsKey(vessel_update.id) ? (serverVessels_LoadDelay[vessel_update.id] < UnityEngine.Time.realtimeSinceStartup) : false)) { float incomingDistance = 2500f; if (!syncing && vessel.worldPosition != Vector3.zero && vessel_update.relTime == RelativeTime.PRESENT) incomingDistance = Vector3.Distance(vessel.worldPosition,FlightGlobals.ship_position); if (vessel_update.relTime != RelativeTime.PRESENT) incomingDistance = 3000f; //Never treat vessels from another time as close by if (vessel_update.state == State.ACTIVE || vessel_update.isDockUpdate || (incomingDistance > vessel_update.distance && (serverVessels_LastUpdateDistanceTime.ContainsKey(vessel_update.id) ? (serverVessels_LastUpdateDistanceTime[vessel_update.id].Key > vessel_update.distance || serverVessels_LastUpdateDistanceTime[vessel_update.id].Value < Planetarium.GetUniversalTime()): true))) { serverVessels_LastUpdateDistanceTime[vessel_update.id] = new KeyValuePair<double, double>(vessel_update.distance,Planetarium.GetUniversalTime() + 0.75f); if (extant_vessel != null) { KMPClientMain.DebugLog("vessel found: " + extant_vessel.id); if (extant_vessel.vesselType != VesselType.Flag) //Special treatment for flags { vessel.vesselRef = extant_vessel; float ourDistance = 3000f; if (!extant_vessel.loaded) { if (KMPVessel.situationIsOrbital(vessel_update.situation)) ourDistance = Vector3.Distance(extant_vessel.orbit.getPositionAtUT(Planetarium.GetUniversalTime()), FlightGlobals.ship_position); else ourDistance = Vector3.Distance(oldPosition, FlightGlobals.ship_position); } else ourDistance = Vector3.Distance(extant_vessel.GetWorldPos3D(), FlightGlobals.ship_position); bool countMismatch = false; ProtoVessel protovessel = null; if (serverVessels_ProtoVessels.ContainsKey(vessel_update.id)) { protovessel = new ProtoVessel(serverVessels_ProtoVessels[vessel_update.id], HighLogic.CurrentGame); } if (serverVessels_PartCounts.ContainsKey(vessel_update.id)) { //countMismatch = serverVessels_PartCounts[vessel_update.id] > 0 && extant_vessel.loaded && !extant_vessel.packed && serverVessels_PartCounts[vessel_update.id] != protovessel.protoPartSnapshots.Count; countMismatch = serverVessels_PartCounts[vessel_update.id] > 0 && serverVessels_PartCounts[vessel_update.id] != protovessel.protoPartSnapshots.Count; } if ((vessel_update.getProtoVesselNode() != null && (!KMPVessel.situationIsOrbital(vessel_update.situation) || ourDistance > 2500f || extant_vessel.altitude < 10000d)) || countMismatch) { KMPClientMain.DebugLog("updating from protovessel"); serverVessels_PartCounts[vessel_update.id] = 0; if (protovessel != null) { if (vessel.orbitValid && KMPVessel.situationIsOrbital(vessel_update.situation) && protovessel.altitude > 10000f && protovessel.vesselType != VesselType.Flag && protovessel.vesselType != VesselType.EVA) { protovessel = syncOrbit(vessel, vessel_update.tick, protovessel, vessel_update.w_pos[0]); } addRemoteVessel(protovessel, vessel_update.id, vessel_update, incomingDistance); if (vessel_update.situation == Situation.FLYING) serverVessels_LoadDelay[vessel.id] = UnityEngine.Time.realtimeSinceStartup + 5f; } else { KMPClientMain.DebugLog("Protovessel missing!"); } } else { KMPClientMain.DebugLog("no protovessel"); if (vessel.orbitValid && !extant_vessel.isActiveVessel) { KMPClientMain.DebugLog("updating from flight data, distance: " + ourDistance); //Update orbit to our game's time if necessary //bool throttled = serverVessels_ObtSyncDelay.ContainsKey(vessel_update.id) && serverVessels_ObtSyncDelay[vessel_update.id] > UnityEngine.Time.realtimeSinceStartup; bool throttled = false; if (KMPVessel.situationIsOrbital(vessel_update.situation) && extant_vessel.altitude > 10000f) { double tick = Planetarium.GetUniversalTime(); //Update orbit whenever out of sync or other vessel in past/future, or not in docking range if (!throttled && (vessel_update.relTime == RelativeTime.PRESENT && ourDistance > (INACTIVE_VESSEL_RANGE+500f)) || (vessel_update.relTime != RelativeTime.PRESENT && Math.Abs(tick-vessel_update.tick) > 1.5d)) { syncExtantVesselOrbit(vessel,vessel_update.tick,extant_vessel,vessel_update.w_pos[0]); serverVessels_ObtSyncDelay[vessel_update.id] = UnityEngine.Time.realtimeSinceStartup + 1f; } } if (FlightGlobals.ActiveVessel.mainBody == update_body && vessel_update.relTime == RelativeTime.PRESENT) { KMPClientMain.DebugLog("full update"); if (serverVessels_InPresent.ContainsKey(vessel_update.id) ? !serverVessels_InPresent[vessel_update.id] : true) { serverVessels_InPresent[vessel_update.id] = true; foreach (Part part in extant_vessel.Parts) { part.setOpacity(1f); } } //Update rotation if (extant_vessel.loaded) { extant_vessel.transform.up = vessel.worldDirection; Quaternion rot = new Quaternion(vessel_update.rot[0],vessel_update.rot[1],vessel_update.rot[2],vessel_update.rot[3]); extant_vessel.SetRotation(rot); extant_vessel.angularMomentum = Vector3.zero; extant_vessel.VesselSAS.LockHeading(rot); extant_vessel.VesselSAS.currentRotation = rot; extant_vessel.VesselSAS.SetDampingMode(false); } if (!KMPVessel.situationIsOrbital(vessel_update.situation) || extant_vessel.altitude < 10000f || ourDistance > 2500f) { KMPClientMain.DebugLog ("velocity update"); //Update velocity if (extant_vessel.loaded) { if (update_body.GetAltitude(vessel.worldPosition)<10000d) { //Set velocity by surface velocity Vector3d new_srf_vel = new Vector3d(vessel_update.s_vel[0],vessel_update.s_vel[1],vessel_update.s_vel[2]); if (new_srf_vel.sqrMagnitude>1d) extant_vessel.ChangeWorldVelocity((-1 * extant_vessel.srf_velocity) + new_srf_vel); else extant_vessel.ChangeWorldVelocity(-0.99f * extant_vessel.srf_velocity); } else { //Set velocity by orbit velocity Vector3d new_obt_vel = new Vector3d(vessel_update.o_vel[0],vessel_update.o_vel[1],vessel_update.o_vel[2]); if (new_obt_vel.sqrMagnitude>1d) extant_vessel.ChangeWorldVelocity((-1 * extant_vessel.obt_velocity) + new_obt_vel); else extant_vessel.ChangeWorldVelocity(-0.99f * extant_vessel.obt_velocity); } } //Update position if (extant_vessel.altitude < 10000f || !extant_vessel.loaded) { if (extant_vessel.loaded && (vessel_update.situation == Situation.LANDED || vessel_update.situation == Situation.SPLASHED)) { //Update surface position KMPClientMain.DebugLog("surface position update"); Vector3d newPos = update_body.GetWorldSurfacePosition(vessel_update.w_pos[1],vessel_update.w_pos[2],extant_vessel.altitude+0.001d); if ((newPos - extant_vessel.GetWorldPos3D()).sqrMagnitude > 1d) extant_vessel.SetPosition(newPos); else if (Vector3.Distance(vessel.worldPosition, extant_vessel.GetWorldPos3D()) > 25f) { serverVessels_PartCounts[vessel_update.id] = 0; addRemoteVessel(protovessel,vessel_update.id,vessel_update); } } else if (!throttled && Vector3.Distance(vessel.worldPosition, extant_vessel.GetWorldPos3D()) > 1d && (extant_vessel.altitude < 10000f || ourDistance > 3000f) && update_body.GetAltitude(vessel.worldPosition) > 1d) { //Update 3D position KMPClientMain.DebugLog("position update"); extant_vessel.SetPosition(vessel.worldPosition); } else if (!extant_vessel.loaded && ourDistance > 1000 && update_body.GetAltitude(vessel.worldPosition) > 1d) { //Stretch packing thresholds to prevent excessive load/unloads during rendezvous initiation extant_vessel.distancePackThreshold += 250f; extant_vessel.distanceUnpackThreshold += 100f; } else { //Reset packing thresholds extant_vessel.distancePackThreshold = 7500f; extant_vessel.distanceUnpackThreshold = 1000f; } } //Update FlightCtrlState extant_vessel.ctrlState.CopyFrom(vessel_update.flightCtrlState.getAsFlightCtrlState(0.75f)); } else { //Orbital rendezvous KMPClientMain.DebugLog("orbital rendezvous"); //Update FlightCtrlState extant_vessel.ctrlState.CopyFrom(vessel_update.flightCtrlState.getAsFlightCtrlState(0.6f)); } } else if (FlightGlobals.ActiveVessel.mainBody == vessel.mainBody) { KMPClientMain.DebugLog("update from past/future"); if (!serverVessels_InPresent.ContainsKey(vessel_update.id) || serverVessels_InPresent.ContainsKey(vessel_update.id) ? serverVessels_InPresent[vessel_update.id]: false) { serverVessels_InPresent[vessel_update.id] = false; foreach (Part part in extant_vessel.Parts) { part.setOpacity(0.3f); } } //Update rotation only extant_vessel.transform.up = vessel.worldDirection; extant_vessel.SetRotation(new Quaternion(vessel_update.rot[0],vessel_update.rot[1],vessel_update.rot[2],vessel_update.rot[3])); } } } KMPClientMain.DebugLog("updated"); } else { //Update flag if needed if (vessel_update.getProtoVesselNode() != null) { ProtoVessel protovessel = new ProtoVessel(serverVessels_ProtoVessels[vessel_update.id], HighLogic.CurrentGame); addRemoteVessel(protovessel,vessel_update.id,vessel_update); } } } else { try { if (serverVessels_ProtoVessels.ContainsKey(vessel_update.id)) { KMPClientMain.DebugLog("Adding new vessel: " + vessel_update.id); ProtoVessel protovessel = new ProtoVessel(serverVessels_ProtoVessels[vessel_update.id], HighLogic.CurrentGame); if (vessel.orbitValid && KMPVessel.situationIsOrbital(vessel_update.situation) && protovessel.vesselType != VesselType.Flag && protovessel.vesselType != VesselType.EVA) { protovessel = syncOrbit(vessel, vessel_update.tick, protovessel, vessel_update.w_pos[0]); } serverVessels_PartCounts[vessel_update.id] = 0; addRemoteVessel(protovessel, vessel_update.id, vessel_update, incomingDistance); HighLogic.CurrentGame.CrewRoster.ValidateAssignments(HighLogic.CurrentGame); } else { KMPClientMain.DebugLog("New vessel, but no matching protovessel available"); } } catch (Exception e) { KMPClientMain.DebugLog("Vessel add error: " + e.Message + "\n" + e.StackTrace); } } } else { KMPClientMain.DebugLog("Vessel update ignored: we are closer to target vessel or have recently updated from someone who was closer"); } } else { KMPClientMain.DebugLog("Vessel update ignored: target vessel on load delay list"); } } } else { //This is our vessel! if (vessel_update.getProtoVesselNode() != null && docking) { KMPClientMain.DebugLog("Received updated protovessel for active vessel"); serverVessels_ProtoVessels[vessel_update.id] = vessel_update.getProtoVesselNode(); } if (vessel_update.isDockUpdate && vessel_update.relTime == RelativeTime.PRESENT) { //Someone docked with us and has control docking = true; syncing = true; ScreenMessages.PostScreenMessage("Other player has control of newly docked vessel",2.5f,ScreenMessageStyle.UPPER_LEFT); KMPClientMain.DebugLog("Received docking update"); serverVessels_PartCounts[FlightGlobals.ActiveVessel.id] = 0; //Return to tracking station Invoke("dockedKickToTrackingStation",0.25f); return; } //Try to negotiate our relative position with whatever sent this update if (FlightGlobals.ActiveVessel.altitude > 10000d && vessel_update.relativeTo != Guid.Empty && Math.Abs(Planetarium.GetUniversalTime() - vessel_update.tick) < 2d) { Vessel updateFrom = FlightGlobals.Vessels.Find (v => v.id == vessel_update.relativeTo); if (updateFrom != null && !updateFrom.loaded) { KMPClientMain.DebugLog("Rendezvous update from unloaded vessel"); if (vessel_update.distance < INACTIVE_VESSEL_RANGE) { //We're not in normal secondary vessel range but other vessel is, send negotiating reply KMPVesselUpdate update = getVesselUpdate(updateFrom); update.distance = INACTIVE_VESSEL_RANGE; update.state = State.INACTIVE; //Rendezvous relative position data update.relativeTo = FlightGlobals.ActiveVessel.id; Vector3d w_pos = updateFrom.findWorldCenterOfMass() - activeVesselPosition; Vector3d o_vel = updateFrom.GetObtVelocity() - FlightGlobals.ActiveVessel.GetObtVelocity(); for (int i = 0; i < 3; i++) { update.w_pos[i] = w_pos[i]; update.o_vel[i] = o_vel[i]; } byte[] update_bytes = KSP.IO.IOUtils.SerializeToBinary(update); enqueuePluginInteropMessage(KMPCommon.PluginInteropMessageID.SECONDARY_PLUGIN_UPDATE, update_bytes); //updateFrom.distancePackThreshold += INACTIVE_VESSEL_RANGE/2; } } else if (updateFrom != null && updateFrom.loaded) { KMPClientMain.DebugLog("rendezvous positioning: " + updateFrom.id); Vector3d updateFromPos = updateFrom.findWorldCenterOfMass(); Vector3d relPos = activeVesselPosition-updateFromPos; Vector3d updateRelPos = new Vector3d(vessel_update.w_pos[0],vessel_update.w_pos[1],vessel_update.w_pos[2]); if (!dockingRelVel.ContainsKey(updateFrom.id)) dockingRelVel[updateFrom.id] = updateFrom.GetObtVelocity(); Vector3d relVel = FlightGlobals.ActiveVessel.GetObtVelocity()-dockingRelVel[updateFrom.id]; Vector3d updateRelVel = new Vector3d(vessel_update.o_vel[0],vessel_update.o_vel[1],vessel_update.o_vel[2]); Vector3d diffPos = updateRelPos - relPos; Vector3d diffVel = updateRelVel - relVel; diffPos *= 0.45d; diffVel *= 0.45d; Vector3d newPos = updateFromPos-diffPos; bool applyUpdate = true; double curTick = Planetarium.GetUniversalTime(); if (serverVessels_RendezvousSmoothPos.ContainsKey(updateFrom.id) ? (relPos.sqrMagnitude > (serverVessels_RendezvousSmoothPos[updateFrom.id].Key * 25) && serverVessels_RendezvousSmoothPos[updateFrom.id].Value > (curTick-5d)): false) applyUpdate = false; if (serverVessels_RendezvousSmoothVel.ContainsKey(updateFrom.id) ? (relVel.sqrMagnitude > (serverVessels_RendezvousSmoothVel[updateFrom.id].Key * 25) && serverVessels_RendezvousSmoothVel[updateFrom.id].Value > (curTick-5d)): false) applyUpdate = false; double expectedDist = Vector3d.Distance(newPos, activeVesselPosition); if (applyUpdate) { serverVessels_RendezvousSmoothPos[updateFrom.id] = new KeyValuePair<double, double>(diffPos.sqrMagnitude,curTick); serverVessels_RendezvousSmoothVel[updateFrom.id] = new KeyValuePair<double, double>(diffVel.sqrMagnitude,curTick); try { OrbitPhysicsManager.HoldVesselUnpack(1); } catch (NullReferenceException) { } if (diffPos.sqrMagnitude < 1000000d && diffPos.sqrMagnitude > 0.5d) { KMPClientMain.DebugLog("Docking Krakensbane shift"); foreach (Vessel otherVessel in FlightGlobals.Vessels.Where(v => v.packed == false && v.id != FlightGlobals.ActiveVessel.id && v.id == updateFrom.id)) otherVessel.GoOnRails(); getKrakensbane().setOffset(diffPos); } else if (diffPos.sqrMagnitude >= 1000000d) { KMPClientMain.DebugLog("Clamped docking Krakensbane shift"); diffPos.Normalize(); diffPos *= 1000d; foreach (Vessel otherVessel in FlightGlobals.Vessels.Where(v => v.packed == false && v.id != FlightGlobals.ActiveVessel.id)) otherVessel.GoOnRails(); getKrakensbane().setOffset(diffPos); } activeVesselPosition += diffPos; if (diffVel.sqrMagnitude > 0.0025d && diffVel.sqrMagnitude < 2500d) { KMPClientMain.DebugLog("Docking velocity update"); if (updateFrom.packed) updateFrom.GoOffRails(); updateFrom.ChangeWorldVelocity(-diffVel); } else if (diffVel.sqrMagnitude >= 2500d) { KMPClientMain.DebugLog("Damping large velocity differential"); diffVel = diffVel.normalized; diffVel *= 50d; if (updateFrom.packed) updateFrom.GoOffRails(); updateFrom.ChangeWorldVelocity(-diffVel); } dockingRelVel[updateFrom.id] -= diffVel; KMPClientMain.DebugLog("had dist:" + relPos.magnitude + " got dist:" + updateRelPos.magnitude); KMPClientMain.DebugLog("expected dist:" + expectedDist + " diffPos mag: " + diffPos.sqrMagnitude); KMPClientMain.DebugLog("had relVel:" + relVel.magnitude + " got relVel:" + updateRelVel.magnitude + " diffVel mag:" + diffVel.sqrMagnitude); } } else KMPClientMain.DebugLog("Ignored docking position update: unexpected large pos/vel shift"); } else KMPClientMain.DebugLog("Ignored docking position update: " + (FlightGlobals.ActiveVessel.altitude > 10000d) + " " + (vessel_update.relativeTo != Guid.Empty) + " " + (Math.Abs(Planetarium.GetUniversalTime() - vessel_update.tick) < 1d)); } } }
//Called from main public void LoadVesselsIntoGame() { DarkLog.Debug("Loading vessels into game"); foreach (KeyValuePair<string, Queue<VesselProtoUpdate>> vesselQueue in vesselProtoQueue) { while (vesselQueue.Value.Count > 0) { ConfigNode currentNode = vesselQueue.Value.Dequeue().vesselNode; if (currentNode != null) { DodgeVesselActionGroups(currentNode); DodgeVesselCrewValues(currentNode); ProtoVessel pv = new ProtoVessel(currentNode, HighLogic.CurrentGame); if (pv != null) { RegisterServerVessel(pv.vesselID.ToString()); HighLogic.CurrentGame.flightState.protoVessels.Add(pv); } } } } DarkLog.Debug("Vessels loaded into game"); }
private void SendVesselUpdateIfNeeded(Vessel checkVessel) { //Check vessel parts if (ModWorker.fetch.modControl != ModControlMode.DISABLED) { if (!vesselPartsOk.ContainsKey(checkVessel.id.ToString())) { CheckVesselParts(checkVessel); } if (!vesselPartsOk[checkVessel.id.ToString()]) { //Vessel with bad parts return; } } if (checkVessel.state == Vessel.State.DEAD) { //Don't send dead vessels return; } if (checkVessel.vesselType == VesselType.Flag && checkVessel.id == Guid.Empty && checkVessel.vesselName != "Flag") { DarkLog.Debug("Fixing flag GUID for " + checkVessel.vesselName); checkVessel.id = Guid.NewGuid(); } //Only send updates for craft we have update locks for. Request the lock if it's not taken. if (!LockSystem.fetch.LockExists("update-" + checkVessel.id.ToString())) { LockSystem.fetch.ThrottledAcquireLock("update-" + checkVessel.id.ToString()); //Wait until we have the update lock return; } //Take the update lock off another player if we have the control lock and it's our vessel if (checkVessel.id.ToString() == FlightGlobals.fetch.activeVessel.id.ToString()) { if (LockSystem.fetch.LockExists("update-" + checkVessel.id.ToString()) && !LockSystem.fetch.LockIsOurs("update-" + checkVessel.id.ToString()) && LockSystem.fetch.LockIsOurs("control-" + checkVessel.id.ToString())) { LockSystem.fetch.ThrottledAcquireLock("update-" + checkVessel.id.ToString()); //Wait until we have the update lock return; } } //Send updates for unpacked vessels that aren't being flown by other players bool notRecentlySentProtoUpdate = serverVesselsProtoUpdate.ContainsKey(checkVessel.id.ToString()) ? ((UnityEngine.Time.realtimeSinceStartup - serverVesselsProtoUpdate[checkVessel.id.ToString()]) > VESSEL_PROTOVESSEL_UPDATE_INTERVAL) : true; bool notRecentlySentPositionUpdate = serverVesselsPositionUpdate.ContainsKey(checkVessel.id.ToString()) ? ((UnityEngine.Time.realtimeSinceStartup - serverVesselsPositionUpdate[checkVessel.id.ToString()]) > (1f / (float)DynamicTickWorker.fetch.sendTickRate)) : true; //Check that is hasn't been recently sent if (notRecentlySentProtoUpdate) { ProtoVessel checkProto = new ProtoVessel(checkVessel); //TODO: Fix sending of flying vessels. if (checkProto != null) { if (checkProto.vesselID != Guid.Empty) { //Also check for kerbal state changes foreach (ProtoPartSnapshot part in checkProto.protoPartSnapshots) { foreach (ProtoCrewMember pcm in part.protoModuleCrew) { if (!serverKerbals.ContainsKey(pcm.name)) { //New kerbal DarkLog.Debug("Found new kerbal, sending..."); serverKerbals[pcm.name] = new ProtoCrewMember(pcm); NetworkWorker.fetch.SendKerbalProtoMessage(pcm); } else { bool kerbalDifferent = false; kerbalDifferent = (pcm.name != serverKerbals[pcm.name].name) || kerbalDifferent; kerbalDifferent = (pcm.courage != serverKerbals[pcm.name].courage) || kerbalDifferent; kerbalDifferent = (pcm.isBadass != serverKerbals[pcm.name].isBadass) || kerbalDifferent; kerbalDifferent = (pcm.seatIdx != serverKerbals[pcm.name].seatIdx) || kerbalDifferent; kerbalDifferent = (pcm.stupidity != serverKerbals[pcm.name].stupidity) || kerbalDifferent; kerbalDifferent = (pcm.UTaR != serverKerbals[pcm.name].UTaR) || kerbalDifferent; if (kerbalDifferent) { DarkLog.Debug("Found changed kerbal, sending..."); NetworkWorker.fetch.SendKerbalProtoMessage(pcm); serverKerbals[pcm.name].name = pcm.name; serverKerbals[pcm.name].courage = pcm.courage; serverKerbals[pcm.name].isBadass = pcm.isBadass; serverKerbals[pcm.name].rosterStatus = pcm.rosterStatus; serverKerbals[pcm.name].seatIdx = pcm.seatIdx; serverKerbals[pcm.name].stupidity = pcm.stupidity; serverKerbals[pcm.name].UTaR = pcm.UTaR; } } } } RegisterServerVessel(checkProto.vesselID.ToString()); //Mark the update as sent serverVesselsProtoUpdate[checkVessel.id.ToString()] = UnityEngine.Time.realtimeSinceStartup; //Also delay the position send serverVesselsPositionUpdate[checkVessel.id.ToString()] = UnityEngine.Time.realtimeSinceStartup; latestUpdateSent[checkVessel.id.ToString()] = UnityEngine.Time.realtimeSinceStartup; bool isFlyingUpdate = (checkProto.situation == Vessel.Situations.FLYING); NetworkWorker.fetch.SendVesselProtoMessage(checkProto, false, isFlyingUpdate); } else { DarkLog.Debug(checkVessel.vesselName + " does not have a guid!"); } } } else if (notRecentlySentPositionUpdate && checkVessel.vesselType != VesselType.Flag) { //Send a position update - Except for flags. They aren't exactly known for their mobility. serverVesselsPositionUpdate[checkVessel.id.ToString()] = UnityEngine.Time.realtimeSinceStartup; latestUpdateSent[checkVessel.id.ToString()] = UnityEngine.Time.realtimeSinceStartup; VesselUpdate update = GetVesselUpdate(checkVessel); if (update != null) { NetworkWorker.fetch.SendVesselUpdate(update); } } }
private void HandleDocking() { if (sentDockingDestroyUpdate) { //One of them will be null, the other one will be the docked craft. string dockedID = fromDockedVesselID != null ? fromDockedVesselID : toDockedVesselID; //Find the docked craft Vessel dockedVessel = FlightGlobals.fetch.vessels.FindLast(v => v.id.ToString() == dockedID); if (dockedVessel != null ? !dockedVessel.packed : false) { ProtoVessel sendProto = new ProtoVessel(dockedVessel); if (sendProto != null) { DarkLog.Debug("Sending docked protovessel " + dockedID); //Mark the vessel as sent serverVesselsProtoUpdate[dockedID] = UnityEngine.Time.realtimeSinceStartup; serverVesselsPositionUpdate[dockedID] = UnityEngine.Time.realtimeSinceStartup; RegisterServerVessel(dockedID); vesselPartCount[dockedID] = dockedVessel.parts.Count; vesselNames[dockedID] = dockedVessel.vesselName; vesselTypes[dockedID] = dockedVessel.vesselType; vesselSituations[dockedID] = dockedVessel.situation; //Update status if it's us. if (dockedVessel == FlightGlobals.fetch.activeVessel) { //Release old control locks if (lastVesselID != FlightGlobals.fetch.activeVessel.id.ToString()) { LockSystem.fetch.ReleasePlayerLocksWithPrefix(Settings.fetch.playerName, "control-"); lastVesselID = FlightGlobals.fetch.activeVessel.id.ToString(); } //Force the control lock off any other player LockSystem.fetch.AcquireLock("control-" + dockedID, true); PlayerStatusWorker.fetch.myPlayerStatus.vesselText = FlightGlobals.fetch.activeVessel.vesselName; } fromDockedVesselID = null; toDockedVesselID = null; sentDockingDestroyUpdate = false; bool isFlyingUpdate = (sendProto.situation == Vessel.Situations.FLYING); NetworkWorker.fetch.SendVesselProtoMessage(sendProto, true, isFlyingUpdate); if (dockingMessage != null) { dockingMessage.duration = 0f; } dockingMessage = ScreenMessages.PostScreenMessage("Docked!", 3f, ScreenMessageStyle.UPPER_CENTER); DarkLog.Debug("Docking event over!"); } else { DarkLog.Debug("Error sending protovessel!"); PrintDockingInProgress(); } } else { PrintDockingInProgress(); } } else { PrintDockingInProgress(); } }
public bool ProtoVesselIsAsteroid(ProtoVessel protoVessel) { return((protoVessel.protoPartSnapshots == null || protoVessel.protoPartSnapshots.Count == 0) && protoVessel.vesselName.StartsWith("Ast.") || protoVessel.protoPartSnapshots != null && protoVessel.protoPartSnapshots.Count == 1 && protoVessel.protoPartSnapshots[0].partName == "PotatoRoid"); }
void onVesselRecoveryProcessing(ProtoVessel vessel, MissionRecoveryDialog d, float f) { Debug.Log (String.Format ("[KS Exp] {0}: {1} {2} {3}", "onVesselRecoveryProcessing", vessel, d, f)); }
private void VesselRecoveryProcessing(ProtoVessel v, MissionRecoveryDialog mrDialog, float data) { Debug.Log("[VR] - Vessel recovery processing"); List <string> retirementChanges = new List <string>(); List <string> inactivity = new List <string>(); double UT = Planetarium.GetUniversalTime(); // normally we would use v.missionTime, but that doesn't seem to update // when you're not actually controlling the vessel double elapsedTime = UT - v.launchTime; // When flight duration was too short, mission training should not be set as expired. // This can happen when an on-the-pad failure occurs and the vessel is recovered. // We could perhaps override this if they're not actually in flight // (if the user didn't recover right from the pad I think this is a fair assumption) if (elapsedTime < settings.minFlightDurationSecondsForTrainingExpire) { Debug.Log("[VR] - mission time too short for crew to be inactive (elapsed time was " + elapsedTime + ", settings set for " + settings.minFlightDurationSecondsForTrainingExpire + ")"); return; } foreach (ProtoCrewMember pcm in v.GetVesselCrew()) { Debug.Log("[VR] - Found ProtoCrewMember: " + pcm.displayName); bool hasSpace = false; bool hasOrbit = false; bool hasEVA = false; bool hasEVAOther = false; bool hasOther = false; bool hasOrbitOther = false; bool hasLandOther = false; int curFlight = pcm.careerLog.Last().flight; foreach (FlightLog.Entry e in pcm.careerLog.Entries) { if (e.type == "TRAINING_mission") { SetExpiration(pcm.name, e, Planetarium.GetUniversalTime()); } if (e.flight != curFlight) { continue; } bool isOther = false; if (!string.IsNullOrEmpty(e.target) && e.target != Planetarium.fetch.Home.name) { isOther = hasOther = true; } if (!string.IsNullOrEmpty(e.type)) { switch (e.type) { case "Suborbit": hasSpace = true; break; case "Orbit": if (isOther) { hasOrbitOther = true; } else { hasOrbit = true; } break; case "ExitVessel": if (isOther) { hasEVAOther = true; } else { hasEVA = true; } break; case "Land": if (isOther) { hasLandOther = true; } break; default: break; } } } double multiplier = 1d; double constant = 0.5d; if (hasSpace) { multiplier += settings.recSpace.x; constant += settings.recSpace.y; } if (hasOrbit) { multiplier += settings.recOrbit.x; constant += settings.recOrbit.y; } if (hasOther) { multiplier += settings.recOtherBody.x; constant += settings.recOtherBody.y; } if (hasOrbit && hasEVA) // EVA should only count while in orbit, not when walking on Earth { multiplier += settings.recEVA.x; constant += settings.recEVA.y; } if (hasEVAOther) { multiplier += settings.recEVAOther.x; constant += settings.recEVAOther.y; } if (hasOrbitOther) { multiplier += settings.recOrbitOther.x; constant += settings.recOrbitOther.y; } if (hasLandOther) { multiplier += settings.recLandOther.x; constant += settings.recLandOther.y; } double retTime; if (kerbalRetireTimes.TryGetValue(pcm.name, out retTime)) { double offset = constant * 86400d * settings.retireOffsetBaseMult / (1 + Math.Pow(Math.Max(curFlight + settings.retireOffsetFlightNumOffset, 0d), settings.retireOffsetFlightNumPow) * UtilMath.Lerp(settings.retireOffsetStupidMin, settings.retireOffsetStupidMax, pcm.stupidity)); if (offset > 0d) { retTime += offset; kerbalRetireTimes[pcm.name] = retTime; retirementChanges.Add("\n" + pcm.name + ", no earlier than " + KSPUtil.PrintDate(retTime, false)); } } multiplier /= (ScenarioUpgradeableFacilities.GetFacilityLevel(SpaceCenterFacility.AstronautComplex) + 1d); double inactiveTime = elapsedTime * multiplier + constant * 86400d; pcm.SetInactive(inactiveTime, false); inactivity.Add("\n" + pcm.name + ", until " + KSPUtil.PrintDate(inactiveTime + UT, true, false)); } if (inactivity.Count > 0) { Debug.Log("[VR] - showing on leave message"); string msgStr = "The following crew members will be on leave:"; foreach (string s in inactivity) { msgStr += s; } if (retirementEnabled && retirementChanges.Count > 0) { msgStr += "\n\nThe following retirement changes have occurred:"; foreach (string s in retirementChanges) { msgStr += s; } } PopupDialog.SpawnPopupDialog(new Vector2(0.5f, 0.5f), new Vector2(0.5f, 0.5f), "CrewUpdateNotification", "Crew Updates", msgStr, "OK", true, HighLogic.UISkin); } }
public float SubmitScienceData(float dataAmount, ScienceSubject subject, float xmitScalar = 1f, ProtoVessel source = null, bool reverseEngineered = false);
/// <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); }
/// <summary> /// Checks if vessel is an asteroid /// </summary> private static bool ProtoVesselIsAsteroid(ProtoVessel possibleAsteroid) { return(possibleAsteroid.vesselType == VesselType.SpaceObject && possibleAsteroid.protoPartSnapshots?.Count == 1 && possibleAsteroid.protoPartSnapshots[0].partName == "PotatoRoid"); }
static bool vesselIsOK(ProtoVessel pv) { return(pv.vesselType != VesselType.Debris && pv.vesselType != VesselType.Flag && pv.vesselType != VesselType.SpaceObject && pv.vesselType != VesselType.Unknown); }
private void OnVesselRecovered(ProtoVessel v) { // Don't check if we're not ready to complete if (!ReadyToComplete()) { return; } // EVA vessel if (v.vesselType == VesselType.EVA) { if (v.protoPartSnapshots != null) { foreach (ProtoPartSnapshot p in v.protoPartSnapshots) { foreach (ProtoCrewMember pcm in p.protoModuleCrew) { recovered[pcm.name] = true; } } } } else { foreach (ProtoCrewMember crew in v.GetVesselCrew()) { if (recovered.ContainsKey(crew.name)) { recovered[crew.name] = true; } } } TestConditions(); }
/// <summary> /// Request Resource processing on a ProtoVessel. /// If the ProtoVessel is not known or resources not cached for the ProtoVessel will automatically add them to the Cached data. /// </summary> /// <param name="vessel">ProtoVessel reference</param> /// <param name="resourceName">Name of the Resource we want to process</param> /// <param name="amount">The amount of the resource we want to process</param> /// <param name="amountReceived">returns the amount processed for the request in this variable</param> /// <param name="pushing">default of false (which means take resource). If true will push (put resource)</param> public static void RequestResource(ProtoVessel vessel, string resourceName, double amount, out double amountReceived, bool pushing = false) { amountReceived = 0d; if (UnloadedResources.InterestedVessels == null) { UnloadedResources.InterestedVessels = new DictionaryValueList <ProtoVessel, InterestedVessel>(); } //If there are no cachedResources for the vessel create one. if (!UnloadedResources.InterestedVessels.Contains(vessel)) { CacheResources.CreatecachedVesselResources(vessel); } //Double check, not really necessary. Now find the resource amounts if in the vessel. if (UnloadedResources.InterestedVessels.Contains(vessel)) { List <CacheResources.CacheResource> vslresources = UnloadedResources.InterestedVessels[vessel].CachedResources; for (int i = 0; i < vslresources.Count; i++) { CacheResources.CacheResource cacheResource = vslresources[i]; if (cacheResource.resourceName == resourceName) { if (!pushing) //We are taking resource { if (cacheResource.amount > 0 || cacheResource.timeWarpOverflow.totalAmount > 0) { if (cacheResource.timeWarpOverflow.totalAmount > 0 && TimeWarp.fetch != null && TimeWarp.CurrentRateIndex > CacheResources.timeWarpStep) //If we have timewarp Overflow check that first. { double amountTaken = 0; cacheResource.timeWarpOverflow.Take(amount, out amountTaken); amountReceived += amountTaken; amount -= amountTaken; if (amount <= 0) //Did we get all we need already? If so return. { return; } } //TimewarpOverflow didn't have enough or didn't have what we need. so now the partResrouceSnapshot Dictionary <string, ProtoPartResourceSnapshot> .Enumerator ppRSenumerator = cacheResource.protoPartResourceSnapshot.GetDictEnumerator(); while (ppRSenumerator.MoveNext()) { ProtoPartResourceSnapshot partResourceSnapshot = ppRSenumerator.Current.Value; if (partResourceSnapshot.amount > 0) { if (partResourceSnapshot.amount <= amount) //Not enough but take what it has { amountReceived += partResourceSnapshot.amount; amount -= partResourceSnapshot.amount; cacheResource.amount -= partResourceSnapshot.amount; partResourceSnapshot.amount = 0; } else //this part has more than we need. { amountReceived += amount; cacheResource.amount -= amount; partResourceSnapshot.amount -= amount; amount = 0; } } if (amount <= 0) //Did we get all we wanted? if so return. { ppRSenumerator.Dispose(); return; } } ppRSenumerator.Dispose(); } } else //We are putting a resource { //Get how much space there is in this part. double spaceAvailable = cacheResource.maxAmount - cacheResource.amount; if (spaceAvailable > 0) //If we have space put some in. { Dictionary <string, ProtoPartResourceSnapshot> .Enumerator ppRSenumerator = cacheResource.protoPartResourceSnapshot.GetDictEnumerator(); while (ppRSenumerator.MoveNext()) { ProtoPartResourceSnapshot partResourceSnapshot = ppRSenumerator.Current.Value; double partspaceAvailable = partResourceSnapshot.maxAmount - partResourceSnapshot.amount; if (partspaceAvailable > 0) { if (amount > partspaceAvailable) //If we can't fit it all in this part. Put what we can. { partResourceSnapshot.amount = partResourceSnapshot.maxAmount; cacheResource.amount += partspaceAvailable; amount -= partspaceAvailable; amountReceived += partspaceAvailable; } else //If we can fit it all in this part, put it in. { partResourceSnapshot.amount += amount; cacheResource.amount += amount; amountReceived += amount; amount = 0; } if (amount <= 0) //Did we get all we wanted? if so return. { return; } } } } //If we get here we had more than can fit in the parts... But if TimeWarp is too high, we put it in the overflow. if (TimeWarp.fetch != null && amount > 0) { if (TimeWarp.CurrentRateIndex > CacheResources.timeWarpStep) //But only if timewarp rate is high enough. { cacheResource.timeWarpOverflow.Add(amount); amountReceived += amount; amount = 0; return; } } } } } //End For loop all vessel resources. } }
protected void OnScienceReceived(float science, ScienceSubject subject, ProtoVessel protoVessel, bool reverseEngineered) { if (protoVessel == null || reverseEngineered) { LoggingUtil.LogVerbose(this, "OnScienceReceived: returning, protoVessel = " + (protoVessel == null ? "null" :protoVessel.vesselName) + ", reverseEng = " + reverseEngineered); return; } LoggingUtil.LogVerbose(this, "OnScienceReceived: " + subject.id + ", " + protoVessel.vesselID); // Check the given subject is okay foreach (string exp in experiment) { if (CheckSubject(exp, subject)) { if (HighLogic.LoadedScene == GameScenes.FLIGHT) { if ((RecoveryMethod(exp) & ScienceRecoveryMethod.Transmit) != 0) { recoveryDone[exp] = true; } } else { if ((RecoveryMethod(exp) & ScienceRecoveryMethod.Recover) != 0) { recoveryDone[exp] = true; } } } } UpdateDelegates(); CheckVessel(protoVessel.vesselRef); }
private void CheckVesselParts(Vessel checkVessel) { List<string> allowedParts = ModWorker.fetch.GetAllowedPartsList(); List<string> bannedParts = new List<string>(); ProtoVessel checkProto = checkVessel.protoVessel; if (!checkVessel.packed) { checkProto = new ProtoVessel(checkVessel); } foreach (ProtoPartSnapshot part in checkProto.protoPartSnapshots) { if (!allowedParts.Contains(part.partName)) { if (!bannedParts.Contains(part.partName)) { bannedParts.Add(part.partName); } } } if (checkVessel.id.ToString() == FlightGlobals.fetch.activeVessel.id.ToString()) { bannedPartsString = ""; foreach (string bannedPart in bannedParts) { bannedPartsString += bannedPart + "\n"; } } DarkLog.Debug("Checked vessel " + checkVessel.id.ToString() + " for banned parts, is ok: " + (bannedParts.Count == 0)); vesselPartsOk[checkVessel.id.ToString()] = (bannedParts.Count == 0); }
private IEnumerable<string> GetVesselSubjects(ProtoVessel v) { foreach (ProtoPartSnapshot pps in v.protoPartSnapshots) { foreach (ProtoPartModuleSnapshot ppms in pps.modules) { ConfigNode mod = ppms.moduleValues; foreach (ConfigNode scienceData in mod.GetNodes("ScienceData")) { string subjectID = ConfigNodeUtil.ParseValue<string>(scienceData, "subjectID"); if (!string.IsNullOrEmpty(subjectID)) { yield return subjectID; } } } } }
//Adapted from KMP. private bool isProtoVesselInSafetyBubble(ProtoVessel protovessel) { CelestialBody kerbinBody = FlightGlobals.Bodies.Find(b => b.name == "Kerbin"); if (kerbinBody == null) { //We don't know where the safety bubble is if kerbin doesn't exist, let's just disable it. return false; } if (protovessel == null) { DarkLog.Debug("isProtoVesselInSafetyBubble: protovessel is null!"); return true; } if (protovessel.orbitSnapShot == null) { DarkLog.Debug("isProtoVesselInSafetyBubble: protovessel has no orbit snapshot!"); return true; } //If not kerbin, we aren't in the safety bubble. if (protovessel.orbitSnapShot.ReferenceBodyIndex != FlightGlobals.Bodies.IndexOf(kerbinBody)) { return false; } Vector3d protoVesselPosition = kerbinBody.GetWorldSurfacePosition(protovessel.latitude, protovessel.longitude, protovessel.altitude); return isInSafetyBubble(protoVesselPosition, kerbinBody); }
private void OnVesselRecovered(ProtoVessel vessel, bool quick) { cachedVessel = vessel.vesselRef; cacheTime = Time.fixedTime; }
//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!"); } }
private void VesselRecoveryProcessing(ProtoVessel v, MissionRecoveryDialog mrDialog, float data) { Debug.Log("[RP-0] - Vessel recovery processing"); var retirementChanges = new List <string>(); var inactivity = new List <string>(); double UT = KSPUtils.GetUT(); // normally we would use v.missionTime, but that doesn't seem to update // when you're not actually controlling the vessel double elapsedTime = UT - v.launchTime; Debug.Log($"[RP-0] mission elapsedTime: {KSPUtil.PrintDateDeltaCompact(elapsedTime, true, true)}"); // When flight duration was too short, mission training should not be set as expired. // This can happen when an on-the-pad failure occurs and the vessel is recovered. // We could perhaps override this if they're not actually in flight // (if the user didn't recover right from the pad I think this is a fair assumption) if (elapsedTime < Settings.minFlightDurationSecondsForTrainingExpire) { Debug.Log($"[RP-0] - mission time too short for crew to be inactive (elapsed time was {elapsedTime}, settings set for {Settings.minFlightDurationSecondsForTrainingExpire})"); return; } var validStatuses = new List <string> { FlightLog.EntryType.Flight.ToString(), Situation_FlightHigh, FlightLog.EntryType.Suborbit.ToString(), FlightLog.EntryType.Orbit.ToString(), FlightLog.EntryType.ExitVessel.ToString(), FlightLog.EntryType.Land.ToString(), FlightLog.EntryType.Flyby.ToString() }; foreach (ProtoCrewMember pcm in v.GetVesselCrew()) { Debug.Log("[RP-0] - Found ProtoCrewMember: " + pcm.displayName); var allFlightsDict = new Dictionary <string, int>(); int curFlight = pcm.careerLog.Last().flight; double inactivityMult = 0; double retirementMult = 0; foreach (FlightLog.Entry e in pcm.careerLog.Entries) { if (e.type == "Nationality") { continue; } if (e.type == TrainingType_Mission) { SetExpiration(pcm.name, e, KSPUtils.GetUT()); } if (validStatuses.Contains(e.type)) { int situationCount; var key = $"{e.target}-{e.type}"; if (allFlightsDict.ContainsKey(key)) { situationCount = allFlightsDict[key]; allFlightsDict[key] = ++situationCount; } else { situationCount = 1; allFlightsDict.Add(key, situationCount); } if (e.flight != curFlight) { continue; } if (TryGetBestSituationMatch(e.target, e.type, "Retire", out double situationMult)) { double countMult = 1 + Math.Pow(situationCount - 1, Settings.retireOffsetFlightNumPow); retirementMult += situationMult / countMult; } if (TryGetBestSituationMatch(e.target, e.type, "Inactive", out double inactivMult)) { inactivityMult += inactivMult; } } } Debug.Log("[RP-0] retirementMult: " + retirementMult); Debug.Log("[RP-0] inactivityMult: " + inactivityMult); double acMult = ScenarioUpgradeableFacilities.GetFacilityLevel(SpaceCenterFacility.AstronautComplex) + 1; Debug.Log("[RP-0] AC multiplier: " + acMult); if (KerbalRetireTimes.TryGetValue(pcm.name, out double retTime)) { double stupidityPenalty = UtilMath.Lerp(Settings.retireOffsetStupidMin, Settings.retireOffsetStupidMax, pcm.stupidity); Debug.Log($"[RP-0] stupidityPenalty for {pcm.stupidity}: {stupidityPenalty}"); double retireOffset = retirementMult * 86400 * Settings.retireOffsetBaseMult / stupidityPenalty; if (retireOffset > 0) { KerbalRetireIncreases.TryGetValue(pcm.name, out double retIncreaseTotal); retIncreaseTotal += retireOffset; if (retIncreaseTotal > Settings.retireIncreaseCap) { // Cap the total retirement increase at a specific number of years retireOffset -= retIncreaseTotal - Settings.retireIncreaseCap; retIncreaseTotal = Settings.retireIncreaseCap; } KerbalRetireIncreases[pcm.name] = retIncreaseTotal; string sRetireOffset = KSPUtil.PrintDateDelta(retireOffset, false, false); Debug.Log("[RP-0] retire date increased by: " + sRetireOffset); retTime += retireOffset; KerbalRetireTimes[pcm.name] = retTime; retirementChanges.Add($"\n{pcm.name}, +{sRetireOffset}, no earlier than {KSPUtil.PrintDate(retTime, false)}"); } } inactivityMult = Math.Max(1, inactivityMult); double elapsedTimeDays = elapsedTime / 86400; double inactiveTimeDays = Math.Pow(Math.Max(Settings.inactivityMinFlightDurationDays, elapsedTimeDays), Settings.inactivityFlightDurationExponent) * Math.Min(Settings.inactivityMaxSituationMult, inactivityMult) / acMult; double inactiveTime = inactiveTimeDays * 86400; Debug.Log("[RP-0] inactive for: " + KSPUtil.PrintDateDeltaCompact(inactiveTime, true, false)); pcm.SetInactive(inactiveTime, false); inactivity.Add($"\n{pcm.name}, until {KSPUtil.PrintDate(inactiveTime + UT, true, false)}"); } if (inactivity.Count > 0) { StringBuilder sb = new StringBuilder(); sb.Append("The following crew members will be on leave:"); foreach (string s in inactivity) { sb.Append(s); } if (RetirementEnabled && retirementChanges.Count > 0) { sb.Append("\n\nThe following retirement changes have occurred:"); foreach (string s in retirementChanges) { sb.Append(s); } } PopupDialog.SpawnPopupDialog(new Vector2(0.5f, 0.5f), new Vector2(0.5f, 0.5f), "CrewUpdateNotification", "Crew Updates", sb.ToString(), "OK", true, HighLogic.UISkin); } }
public void OnVesselTerminated(ProtoVessel terminatedVessel) { string terminatedVesselID = terminatedVessel.vesselID.ToString(); //Check the vessel hasn't been changed in the future if (LockSystem.fetch.LockExists("control-" + terminatedVesselID) && !LockSystem.fetch.LockIsOurs("control-" + terminatedVesselID)) { ScreenMessages.PostScreenMessage("Cannot terminate vessel, the vessel is in use.", 5f, ScreenMessageStyle.UPPER_CENTER); return; } if (VesselUpdatedInFuture(terminatedVesselID)) { ScreenMessages.PostScreenMessage("Cannot terminate vessel, the vessel been changed in the future.", 5f, ScreenMessageStyle.UPPER_CENTER); return; } if (!serverVessels.Contains(terminatedVesselID)) { DarkLog.Debug("Cannot terminate a non-server vessel!"); return; } DarkLog.Debug("Removing vessel " + terminatedVesselID + ", name: " + terminatedVessel.vesselName + " from the server: Terminated"); unassignKerbals(terminatedVesselID); serverVessels.Remove(terminatedVesselID); NetworkWorker.fetch.SendVesselRemove(terminatedVesselID, false); }
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); } } }
private void checkRemoteVesselIntegrity() { try { if (!isInFlight || syncing || warping || docking) return; foreach (Vessel vessel in FlightGlobals.Vessels.FindAll(v => v.loaded && v.id != FlightGlobals.ActiveVessel.id && serverVessels_PartCounts.ContainsKey(v.id) && serverVessels_ProtoVessels.ContainsKey(v.id))) { if (serverVessels_PartCounts[vessel.id] > 0 && serverVessels_PartCounts[vessel.id] > vessel.Parts.Count) { KMPClientMain.DebugLog("checkRemoteVesselIntegrity killing vessel: " + vessel.id); serverVessels_PartCounts[vessel.id] = 0; foreach (Part part in serverVessels_Parts[vessel.id]) { try { if (!part.vessel.isEVA) part.vessel.Die(); } catch {} } ProtoVessel protovessel = new ProtoVessel(serverVessels_ProtoVessels[vessel.id], HighLogic.CurrentGame); addRemoteVessel(protovessel,vessel.id); serverVessels_LoadDelay[vessel.id] = UnityEngine.Time.realtimeSinceStartup + 10f; } } } catch (Exception ex) { KMPClientMain.DebugLog("cRVI err: " + ex.Message + " " + ex.StackTrace); } }
public void vesselRecoverEvent(ProtoVessel v, bool unknownAsOfNow) { const string logBlockName = nameof(KCTEvents) + "." + nameof(vesselRecoverEvent); using (EntryExitLogger.EntryExitLog(logBlockName, EntryExitLoggerOptions.All)) { if (!KCT_PresetManager.Instance.ActivePreset.generalSettings.Enabled) { return; } if (!v.vesselRef.isEVA) { // if (KCT_GameStates.settings.Debug && HighLogic.LoadedScene != GameScenes.TRACKSTATION && (v.wasControllable || v.protoPartSnapshots.Find(p => p.modules.Find(m => m.moduleName.ToLower() == "modulecommand") != null) != null)) if (GameStates.recoveredVessel != null && v.vesselName == GameStates.recoveredVessel.shipName) { //KCT_GameStates.recoveredVessel = new KCT_BuildListVessel(v); //rebuy the ship if ScrapYard isn't overriding funds if (!ScrapYardWrapper.OverrideFunds) { KCT_Utilities.SpendFunds(GameStates.recoveredVessel.cost, TransactionReasons.VesselRollout); //pay for the ship again } //pull all of the parts out of the inventory //This is a bit funky since we grab the part id from our part, grab the inventory part out, then try to reapply that ontop of our part if (ScrapYardWrapper.Available) { foreach (ConfigNode partNode in GameStates.recoveredVessel.ExtractedPartNodes) { string id = ScrapYardWrapper.GetPartID(partNode); ConfigNode inventoryVersion = ScrapYardWrapper.FindInventoryPart(id); if (inventoryVersion != null) { //apply it to our copy of the part ConfigNode ourTracker = partNode.GetNodes("MODULE").FirstOrDefault(n => string.Equals(n.GetValue("name"), "ModuleSYPartTracker", StringComparison.Ordinal)); if (ourTracker != null) { ourTracker.SetValue("TimesRecovered", inventoryVersion.GetValue("_timesRecovered")); ourTracker.SetValue("Inventoried", inventoryVersion.GetValue("_inventoried")); } } } //process the vessel in ScrapYard ScrapYardWrapper.ProcessVessel(GameStates.recoveredVessel.ExtractedPartNodes); //reset the BP GameStates.recoveredVessel.buildPoints = KCT_Utilities.GetBuildTime(GameStates.recoveredVessel.ExtractedPartNodes); } if (GameStates.recoveredVessel.type == BuildListVessel.ListType.VAB) { GameStates.ActiveKSC.VABWarehouse.Add(GameStates.recoveredVessel); } else { GameStates.ActiveKSC.SPHWarehouse.Add(GameStates.recoveredVessel); } GameStates.ActiveKSC.Recon_Rollout.Add(new Recon_Rollout(GameStates.recoveredVessel, Recon_Rollout.RolloutReconType.Recovery, GameStates.recoveredVessel.id.ToString())); GameStates.recoveredVessel = null; } } } }
private ProtoVessel syncOrbit(KMPVessel kvessel, double fromTick, ProtoVessel protovessel, double LAN) { KMPClientMain.DebugLog("updating OrbitSnapshot"); double tick = Planetarium.GetUniversalTime(); //Update orbit Planetarium.SetUniversalTime(fromTick); Vector3 orbit_pos = kvessel.translationFromBody; Vector3 orbit_vel = kvessel.worldVelocity; //Swap the y and z values of the orbital position/velocities float temp = orbit_pos.y; orbit_pos.y = orbit_pos.z; orbit_pos.z = temp; temp = orbit_vel.y; orbit_vel.y = orbit_vel.z; orbit_vel.z = temp; OrbitDriver orbitDriver = new OrbitDriver(); orbitDriver.orbit.UpdateFromStateVectors(orbit_pos, orbit_vel, kvessel.mainBody, fromTick); Orbit newOrbit = orbitDriver.orbit; newOrbit.LAN = LAN; Vessel victim = FlightGlobals.ActiveVessel; OrbitDriver oldDriver = victim.orbitDriver; victim.orbitDriver = orbitDriver; victim.patchedConicSolver.obtDriver = orbitDriver; victim.orbitDriver.UpdateOrbit(); victim.patchedConicSolver.Update(); newOrbit = victim.patchedConicSolver.orbit; if (newOrbit.referenceBody == null) newOrbit.referenceBody = FlightGlobals.Bodies.Find(b => b.name == "Sun"); if (newOrbit.EndUT > 0) { double lastEndUT = newOrbit.EndUT; while (newOrbit.EndUT > 0 && newOrbit.EndUT < tick && newOrbit.EndUT > lastEndUT && newOrbit.nextPatch != null) { KMPClientMain.DebugLog("orbit EndUT < target: " + newOrbit.EndUT + " vs " + tick); lastEndUT = newOrbit.EndUT; newOrbit = newOrbit.nextPatch; if (newOrbit.referenceBody == null) newOrbit.referenceBody = FlightGlobals.Bodies.Find(b => b.name == "Sun"); KMPClientMain.DebugLog("updated to next patch"); } } victim.patchedConicSolver.obtDriver = oldDriver; victim.orbitDriver = oldDriver; Planetarium.SetUniversalTime(tick); protovessel.orbitSnapShot = new OrbitSnapshot(newOrbit); KMPClientMain.DebugLog("OrbitSnapshot updated"); return protovessel; }
public static ProtoPartResourceSnapshot GetMatchingResourceSnapShot(string keyField, ProtoPartResourceSnapshot protoresSnap, ProtoVessel protoVessel) { ProtoPartResourceSnapshot returnSnapshot = null; string resourceKey = ""; uint craftID = CacheResource.RetrieveKey(keyField, out resourceKey); for (int pvPartI = 0; pvPartI < protoVessel.protoPartSnapshots.Count; pvPartI++) { if (protoVessel.protoPartSnapshots[pvPartI].craftID == craftID) { bool found = false; for (int ppSnapI = 0; ppSnapI < protoVessel.protoPartSnapshots[pvPartI].resources.Count; ppSnapI++) { if (protoVessel.protoPartSnapshots[pvPartI].resources[ppSnapI].resourceName == resourceKey) { //Compare the loaded values to the protoVessel snapshot. //If loaded is more then DO WE? update the protoVessel. Let's just report it for now. if (protoVessel.protoPartSnapshots[pvPartI].resources[ppSnapI].amount != protoresSnap.amount) { RSTUtils.Utilities.Log("ProtoVessel resource amounts differ"); } if (protoVessel.protoPartSnapshots[pvPartI].resources[ppSnapI].maxAmount != protoresSnap.maxAmount) { RSTUtils.Utilities.Log("ProtoVessel resource max amounts differ"); } returnSnapshot = protoVessel.protoPartSnapshots[pvPartI].resources[ppSnapI]; break; } } if (found) { break; } } } return(returnSnapshot); }
public DeferredCreditValues(string subject_id, double size, ProtoVessel pv) { this.subject_id = subject_id; this.size = size; this.pv = pv; }
protected void onVesselRecovered(ProtoVessel vessel, bool notSureWhatFor) { Utilities.Log("DeepFreezeEvents onVesselRecovered " + vessel.vesselID); List <string> frznKerbalkeys = new List <string>(DFgameSettings.KnownFrozenKerbals.Keys); foreach (string key in frznKerbalkeys) { KerbalInfo kerbalinfo = DFgameSettings.KnownFrozenKerbals[key]; if (kerbalinfo.vesselID == vessel.vesselID) { if (kerbalinfo.type == ProtoCrewMember.KerbalType.Unowned) //Frozen crew { if (Instance.DFsettings.AutoRecoverFznKerbals) { Utilities.Log_Debug("AutoRecover is ON"); Utilities.Log("Calling ThawFrozen Crew to thaw FrozenCrew " + key); ThawFrozenCrew(key, vessel.vesselID); } else { Utilities.Log("DeepFreeze AutoRecovery of frozen kerbals is set to off. Must be thawed manually."); Utilities.Log("DeepFreezeEvents frozenkerbal remains frozen =" + key); ProtoCrewMember realkerbal = HighLogic.CurrentGame.CrewRoster.Unowned.FirstOrDefault(b => b.name == key); if (realkerbal != null) { realkerbal.type = ProtoCrewMember.KerbalType.Unowned; realkerbal.rosterStatus = ProtoCrewMember.RosterStatus.Dead; Utilities.Log_Debug("Kerbal " + realkerbal.name + " " + realkerbal.type + " " + realkerbal.rosterStatus); ScreenMessages.PostScreenMessage(key + " was stored frozen at KSC", 5.0f, ScreenMessageStyle.UPPER_LEFT); } } } else // Tourist/Comatose crew { Utilities.Log_Debug("Comatose crew - reset to crew " + key); ProtoCrewMember crew = HighLogic.CurrentGame.CrewRoster.Tourist.FirstOrDefault(c => c.name == key); if (crew != null) { crew.type = ProtoCrewMember.KerbalType.Crew; crew.rosterStatus = ProtoCrewMember.RosterStatus.Assigned; Utilities.Log_Debug("Kerbal " + crew.name + " " + crew.type + " " + crew.rosterStatus); crew.ArchiveFlightLog(); crew.rosterStatus = ProtoCrewMember.RosterStatus.Available; DFgameSettings.KnownFrozenKerbals.Remove(crew.name); } } } } var alarmsToDelete = new List <string>(); alarmsToDelete.AddRange(Instance.DFgameSettings.knownKACAlarms.Where(e => e.Value.VesselID == vessel.vesselID).Select(e => e.Key).ToList()); alarmsToDelete.ForEach(id => Instance.DFgameSettings.knownKACAlarms.Remove(id)); var partsToDelete = new List <uint>(); partsToDelete.AddRange(Instance.DFgameSettings.knownFreezerParts.Where(e => e.Value.vesselID == vessel.vesselID).Select(e => e.Key).ToList()); partsToDelete.ForEach(id => Instance.DFgameSettings.knownFreezerParts.Remove(id)); if (DFgameSettings.knownVessels.ContainsKey(vessel.vesselID)) { DFgameSettings.knownVessels.Remove(vessel.vesselID); } }