/// <summary> /// Check vessels that must be loaded /// </summary> private void CheckVesselsToLoad() { try { if (ProtoSystemBasicReady && !VesselCommon.ActiveVesselIsInSafetyBubble()) { //Load vessels that don't exist, are in our subspace and out of safety bubble var vesselsToLoad = VesselsProtoStore.AllPlayerVessels .Where(v => !v.Value.VesselExist && v.Value.ShouldBeLoaded && !v.Value.IsInSafetyBubble); foreach (var vesselProto in vesselsToLoad) { if (VesselRemoveSystem.VesselWillBeKilled(vesselProto.Key)) { continue; } LunaLog.Log($"[LMP]: Loading vessel {vesselProto.Key}"); CurrentlyUpdatingVesselId = vesselProto.Key; if (VesselLoader.LoadVessel(vesselProto.Value.ProtoVessel)) { LunaLog.Log($"[LMP]: Vessel {vesselProto.Key} loaded"); } CurrentlyUpdatingVesselId = Guid.Empty; } } } catch (Exception e) { LunaLog.LogError($"[LMP]: Error in CheckVesselsToLoad {e}"); } }
/// <summary> /// Check vessels that must be loaded /// </summary> private void CheckVesselsToLoad() { try { if (ProtoSystemBasicReady) { //Load vessels that don't exist, are in our subspace and out of safety bubble var vesselsToLoad = VesselsProtoStore.AllPlayerVessels.Where(v => !v.Value.VesselExist && v.Value.ShouldBeLoaded); foreach (var vesselProto in vesselsToLoad) { if (VesselRemoveSystem.VesselWillBeKilled(vesselProto.Key)) { continue; } //If the vessel spawned later than the current time avoid loading it if (VesselsProtoStore.VesselsSpawnTime.TryGetValue(vesselProto.Key, out var spawnTime) && TimeSyncerSystem.UniversalTime < spawnTime) { continue; } //Only load vessels that are in safety bubble when not in flight if (vesselProto.Value.IsInSafetyBubble && HighLogic.LoadedScene == GameScenes.FLIGHT) { continue; } LunaLog.Log($"[LMP]: Loading vessel {vesselProto.Key}"); if (VesselLoader.LoadVessel(vesselProto.Value.ProtoVessel)) { LunaLog.Log($"[LMP]: Vessel {vesselProto.Key} loaded"); VesselLoadEvent.onLmpVesselLoaded.Fire(vesselProto.Value.Vessel); } } } } catch (Exception e) { LunaLog.LogError($"[LMP]: Error in CheckVesselsToLoad {e}"); } }
/// <summary> /// Check vessels that must be loaded /// </summary> private void CheckVesselsToLoad() { try { if (ProtoSystemBasicReady) { //Load vessels that don't exist, are in our subspace and out of safety bubble var vesselsToLoad = VesselsProtoStore.AllPlayerVessels.Where(v => !v.Value.VesselExist && v.Value.ShouldBeLoaded); foreach (var vesselProto in vesselsToLoad) { if (VesselRemoveSystem.VesselWillBeKilled(vesselProto.Key)) { continue; } //Only load vessels that are in safety bubble on the track station if (vesselProto.Value.IsInSafetyBubble && HighLogic.LoadedScene != GameScenes.TRACKSTATION) { continue; } if (VesselCommon.ActiveVesselIsInSafetyBubble() && VesselCommon.IsNearKsc(vesselProto.Value.ProtoVessel, 20000)) { continue; } LunaLog.Log($"[LMP]: Loading vessel {vesselProto.Key}"); CurrentlyUpdatingVesselId = vesselProto.Key; if (VesselLoader.LoadVessel(vesselProto.Value.ProtoVessel)) { LunaLog.Log($"[LMP]: Vessel {vesselProto.Key} loaded"); } CurrentlyUpdatingVesselId = Guid.Empty; } } } catch (Exception e) { LunaLog.LogError($"[LMP]: Error in CheckVesselsToLoad {e}"); } }
/// <summary> /// Check vessels that must be loaded /// </summary> private void CheckVesselsToLoad() { try { if (ProtoSystemBasicReady) { //Load vessels that don't exist, are in our subspace and out of safety bubble var vesselsToLoad = VesselsProtoStore.AllPlayerVessels.Where(v => !v.Value.VesselExist && v.Value.ShouldBeLoaded); foreach (var vesselProto in vesselsToLoad) { if (VesselRemoveSystem.VesselWillBeKilled(vesselProto.Key)) { continue; } //Only load vessels that are in safety bubble when not in flight if (vesselProto.Value.IsInSafetyBubble && HighLogic.LoadedScene == GameScenes.FLIGHT) { continue; } LunaLog.Log($"[LMP]: Loading vessel {vesselProto.Key}"); if (VesselLoader.LoadVessel(vesselProto.Value.ProtoVessel)) { LunaLog.Log($"[LMP]: Vessel {vesselProto.Key} loaded"); } } } } catch (Exception e) { LunaLog.LogError($"[LMP]: Error in CheckVesselsToLoad {e}"); } }
/// <summary> /// This method will take a vessel and update all it's parts and proto based on a protovessel we received /// Protovessel --------------> Vessel & ProtoVessel /// This way we avoid having to unload and reload a vessel with it's terrible performance /// </summary> public static void UpdateVesselPartsFromProtoVessel(Vessel vessel, ProtoVessel protoVessel, IEnumerable <uint> vesselPartsId = null) { if (vessel == null || protoVessel == null || vessel.state == Vessel.State.DEAD) { return; } if (vessel.id != protoVessel.vesselID) { LunaLog.LogError($"Tried to update a vessel id {vessel.id} with a protovessel of vessel id {protoVessel.vesselID}"); return; } var vesselProtoPartIds = vesselPartsId ?? protoVessel.protoPartSnapshots.Select(p => p.flightID); //If vessel is UNLOADED it won't have parts so we must take them from the proto... var vesselPartsIds = vessel.loaded ? vessel.parts.Select(p => p.flightID) : vessel.protoVessel.protoPartSnapshots.Select(p => p.flightID); var hasMissingparts = vesselProtoPartIds.Except(vesselPartsIds).Any(); if (hasMissingparts || !VesselCommon.IsSpectating && (vessel.isEVA && vessel.situation != protoVessel.situation || !vessel.Landed && protoVessel.landed || !vessel.Splashed && protoVessel.splashed || vessel.situation != protoVessel.situation && HighLogic.LoadedScene == GameScenes.TRACKSTATION)) { //Reload the whole vessel if vessel lands/splashes as otherwise map view puts the vessel next to the other player. //Also reload the whole vesse if it's a EVA and situation changed or in track station.... //Better to reload if has missing parts as creating them dinamically is a PIA VesselLoader.ReloadVessel(protoVessel); return; } var hasCrewChanges = false; //Never do vessel.protoVessel = protoVessel; not even if the vessel is not loaded as when it gets loaded the parts are created in the active vessel //and not on the target vessel //Run trough all the vessel parts and protoparts. //Vessel.parts will be empty if vessel is unloaded. var protoPartsToRemove = new List <ProtoPartSnapshot>(); for (var i = 0; i < vessel.protoVessel.protoPartSnapshots.Count; i++) { var protoPartToUpdate = vessel.protoVessel.protoPartSnapshots[i]; var partSnapshot = VesselCommon.FindProtoPartInProtovessel(protoVessel, protoPartToUpdate.flightID); if (partSnapshot == null) //Part does not exist in the protovessel definition so kill it { protoPartsToRemove.Add(protoPartToUpdate); continue; } AdjustCrewMembersInProtoPart(protoPartToUpdate, partSnapshot); protoPartToUpdate.state = partSnapshot.state; UpdatePartModulesInProtoPart(protoPartToUpdate, partSnapshot); UpdateProtoVesselResources(protoPartToUpdate, partSnapshot); var part = protoPartToUpdate.partRef; if (part != null) //Part can be null if the vessel is unloaded!! { //Remove or add crew members in given part and detect if there have been any change hasCrewChanges |= AdjustCrewMembersInPart(part, partSnapshot); //Set part "state" field... Important for fairings for example... StateField?.SetValue(part, partSnapshot.state); part.ResumeState = part.State; UpdatePartModules(partSnapshot, part); UpdateVesselResources(partSnapshot, part); UpdatePartFairings(partSnapshot, part); } } //Now kill both parts and protoparts that don't exist for (var i = 0; i < protoPartsToRemove.Count; i++) { //Part can be null if the vessel is unloaded. In this case, no need to kill it as it's already gone from the game. if (protoPartsToRemove[i].partRef != null) { if (protoPartsToRemove[i].partRef.FindModuleImplementing <ModuleDecouple>() != null) { protoPartsToRemove[i].partRef.decouple(); } else { protoPartsToRemove[i].partRef.Die(); } } vessel.protoVessel.protoPartSnapshots.Remove(protoPartsToRemove[i]); } if (hasCrewChanges) { //We must always refresh the crew in every part of the vessel, even if we don't spectate vessel.RebuildCrewList(); //IF we are spectating we must fix the portraits of the kerbals if (FlightGlobals.ActiveVessel?.id == vessel.id) { //If you don't call spawn crew and you do a crew transfer the transfered crew won't appear in the portraits... Client.Singleton.StartCoroutine(CallbackUtil.DelayedCallback(0.25f, () => { FlightGlobals.ActiveVessel?.SpawnCrew(); })); //If you don't call this the kerbal portraits appear in black... Client.Singleton.StartCoroutine(CallbackUtil.DelayedCallback(0.5f, () => { KerbalPortraitGallery.Instance?.SetActivePortraitsForVessel(FlightGlobals.ActiveVessel); })); } } }