public void HandleMessage(IServerMessageBase msg) { if (!(msg.Data is VesselFairingMsgData msgData) || !System.FairingSystemReady) { return; } //Vessel might exist in the store but not in game (if the vessel is in safety bubble for example) VesselsProtoStore.UpdateVesselProtoPartFairing(msgData); var vessel = FlightGlobals.FindVessel(msgData.VesselId); if (vessel == null) { return; } var part = VesselCommon.FindProtoPartInProtovessel(vessel.protoVessel, msgData.PartFlightId); if (part != null) { var module = VesselCommon.FindProtoPartModuleInProtoPart(part, "ModuleProceduralFairing"); module?.moduleValues.SetValue("fsm", "st_flight_deployed"); module?.moduleValues.RemoveNodesStartWith("XSECTION"); (module?.moduleRef as ModuleProceduralFairing)?.DeployFairing(); } }
private void UpdateVesselFields(Vessel vessel) { if (vessel.protoVessel == null) { return; } for (var i = 0; i < ResourcesCount; i++) { var partSnapshot = VesselCommon.FindProtoPartInProtovessel(vessel.protoVessel, Resources[i].PartFlightId); var resourceSnapshot = VesselCommon.FindResourceInProtoPart(partSnapshot, Resources[i].ResourceName); if (resourceSnapshot != null) { resourceSnapshot.amount = Resources[i].Amount; resourceSnapshot.flowState = Resources[i].FlowState; //Using "resourceSnapshot.resourceRef" sometimes returns null so we also try to get the resource from the part... if (resourceSnapshot.resourceRef == null) { if (partSnapshot.partRef != null) { var foundResource = partSnapshot.partRef.FindResource(resourceSnapshot.resourceName); foundResource.amount = Resources[i].Amount; foundResource.flowState = Resources[i].FlowState; } } else { resourceSnapshot.resourceRef.amount = Resources[i].Amount; resourceSnapshot.resourceRef.flowState = Resources[i].FlowState; } } } }
public static void UpdateVesselProtoResources(VesselResourceMsgData msgData) { if (AllPlayerVessels.TryGetValue(msgData.VesselId, out var vesselProtoUpd)) { if (vesselProtoUpd.ProtoVessel == null) { return; } for (var i = 0; i < msgData.ResourcesCount; i++) { var resource = msgData.Resources[i]; if (resource == null) { continue; } var partSnapshot = VesselCommon.FindProtoPartInProtovessel(vesselProtoUpd.ProtoVessel, resource.PartFlightId); var resourceSnapshot = VesselCommon.FindResourceInProtoPart(partSnapshot, resource.ResourceName); if (resourceSnapshot != null) { resourceSnapshot.amount = resource.Amount; resourceSnapshot.flowState = resource.FlowState; } } } }
public void ProcessPartMethodCallSync() { var vessel = FlightGlobals.fetch.LmpFindVessel(VesselId); if (vessel == null || !vessel.loaded) { return; } if (!VesselCommon.DoVesselChecks(VesselId)) { return; } var part = VesselCommon.FindProtoPartInProtovessel(vessel.protoVessel, PartFlightId); if (part != null) { var module = VesselCommon.FindProtoPartModuleInProtoPart(part, ModuleName); if (module != null) { if (module.moduleRef != null) { module.moduleRef.GetType().GetMethod(MethodName, AccessTools.all)?.Invoke(module.moduleRef, null); PartModuleEvent.onPartModuleMethodProcessed.Fire(module, MethodName); } } } }
private static void UpdateProtoVesselResources(ProtoVessel protoVessel, VesselResourceMsgData msgData) { if (protoVessel == null) { return; } for (var i = 0; i < msgData.ResourcesCount; i++) { var resource = msgData.Resources[i]; var partSnapshot = VesselCommon.FindProtoPartInProtovessel(protoVessel, resource.PartFlightId); var resourceSnapshot = VesselCommon.FindResourceInProtoPart(partSnapshot, resource.ResourceName); if (resourceSnapshot != null) { resourceSnapshot.amount = resource.Amount; resourceSnapshot.flowState = resource.FlowState; if (resourceSnapshot.resourceRef == null) { continue; } resourceSnapshot.resourceRef.amount = resource.Amount; resourceSnapshot.resourceRef.flowState = resource.FlowState; } } }
public void ProcessPartMethodSync() { var vessel = FlightGlobals.fetch.LmpFindVessel(VesselId); if (vessel == null) { return; } if (!VesselCommon.DoVesselChecks(VesselId)) { return; } var part = VesselCommon.FindProtoPartInProtovessel(vessel.protoVessel, PartFlightId); if (part != null) { var module = VesselCommon.FindProtoPartModuleInProtoPart(part, ModuleName); if (module != null) { switch (FieldType) { case PartSyncFieldType.Boolean: module.moduleValues.SetValue(FieldName, BoolValue); if (module.moduleRef != null) { module.moduleRef.Fields[FieldName].SetValue(BoolValue, module.moduleRef); } PartModuleEvent.onPartModuleBoolFieldProcessed.Fire(module, FieldName, BoolValue); break; case PartSyncFieldType.Integer: module.moduleValues.SetValue(FieldName, IntValue); if (module.moduleRef != null) { module.moduleRef.Fields[FieldName].SetValue(IntValue, module.moduleRef); } PartModuleEvent.onPartModuleIntFieldProcessed.Fire(module, FieldName, IntValue); break; case PartSyncFieldType.Float: module.moduleValues.SetValue(FieldName, FloatValue); if (module.moduleRef != null) { module.moduleRef.Fields[FieldName].SetValue(FloatValue, module.moduleRef); } PartModuleEvent.onPartModuleFloatFieldProcessed.Fire(module, FieldName, FloatValue); break; default: throw new ArgumentOutOfRangeException(); } } } }
private static ProtoPartModuleSnapshot GetKerbalEvaProtoModule(ProtoVessel protoVessel) { if (protoVessel == null) { return(null); } var partSnapshot = VesselCommon.FindProtoPartInProtovessel(protoVessel, "kerbalEVA"); if (partSnapshot == null) { return(null); } return(VesselCommon.FindProtoPartModuleInProtoPart(partSnapshot, "KerbalEVA")); }
private static void UpdateProtoVesselResources(ProtoVessel protoVessel, VesselResourceMsgData msgData) { if (protoVessel != null) { for (var i = 0; i < msgData.ResourcesCount; i++) { var resource = msgData.Resources[i]; var partSnapshot = VesselCommon.FindProtoPartInProtovessel(protoVessel, resource.PartFlightId); var resourceSnapshot = VesselCommon.FindResourceInProtoPart(partSnapshot, resource.ResourceName); if (resourceSnapshot != null) { resourceSnapshot.amount = resource.Amount; } } } }
public static void UpdateVesselProtoPartModules(VesselPartSyncMsgData msgData) { if (AllPlayerVessels.TryGetValue(msgData.VesselId, out var vesselProtoUpd)) { if (vesselProtoUpd.ProtoVessel == null) { return; } var partSnapshot = VesselCommon.FindProtoPartInProtovessel(vesselProtoUpd.ProtoVessel, msgData.PartFlightId); if (partSnapshot != null) { var module = VesselCommon.FindProtoPartModuleInProtoPart(partSnapshot, msgData.ModuleName); module?.moduleValues.SetValue(msgData.FieldName, msgData.Value); } } }
public static void UpdateVesselProtoPartFairing(VesselFairingMsgData msgData) { if (AllPlayerVessels.TryGetValue(msgData.VesselId, out var vesselProtoUpd)) { if (vesselProtoUpd.ProtoVessel == null) { return; } var part = VesselCommon.FindProtoPartInProtovessel(vesselProtoUpd.ProtoVessel, msgData.PartFlightId); if (part != null) { var module = VesselCommon.FindProtoPartModuleInProtoPart(part, "ModuleProceduralFairing"); module?.moduleValues.SetValue("fsm", "st_flight_deployed"); module?.moduleValues.RemoveNodesStartWith("XSECTION"); } } }
public string GetFairingStateFromStore(Guid vesselId, uint partFlightId) { if (VesselsProtoStore.AllPlayerVessels.TryGetValue(vesselId, out var vesselProtoUpd)) { var protoVessel = vesselProtoUpd.ProtoVessel; var protoPart = VesselCommon.FindProtoPartInProtovessel(protoVessel, partFlightId); if (protoPart == null) { return(null); } var protoModule = VesselCommon.FindProtoPartModuleInProtoPart(protoPart, "ModuleProceduralFairing"); return(protoModule?.moduleValues.GetValue("fsm")); } return(null); }
private static void UpdateVesselValues(ProtoVessel protoVessel, VesselPartSyncMsgData msgData) { if (protoVessel == null) { return; } var part = VesselCommon.FindProtoPartInProtovessel(protoVessel, msgData.PartFlightId); if (part != null) { var module = VesselCommon.FindProtoPartModuleInProtoPart(part, msgData.ModuleName); if (module != null) { module.moduleValues.SetValue(msgData.FieldName, msgData.Value); UpdateVesselModuleIfNeeded(protoVessel.vesselID, part.flightID, msgData, module, part); } } }
public void HandleMessage(IServerMessageBase msg) { if (!(msg.Data is VesselFairingMsgData msgData) || !System.FairingSystemReady) { return; } //We received a msg for our own controlled/updated vessel so ignore it if (!VesselCommon.DoVesselChecks(msgData.VesselId)) { return; } //Vessel might exist in the store but not in game (if the vessel is in safety bubble for example) VesselsProtoStore.UpdateVesselProtoPartFairing(msgData); var vessel = FlightGlobals.FindVessel(msgData.VesselId); if (vessel == null) { return; } var part = VesselCommon.FindProtoPartInProtovessel(vessel.protoVessel, msgData.PartFlightId); if (part != null) { var module = VesselCommon.FindProtoPartModuleInProtoPart(part, "ModuleProceduralFairing"); module?.moduleValues.SetValue("fsm", "st_flight_deployed"); module?.moduleValues.RemoveNodesStartWith("XSECTION"); try { (module?.moduleRef as ModuleProceduralFairing)?.DeployFairing(); } catch (Exception) { //TODO reload the module } } }
public void ProcessFairing() { if (!VesselCommon.DoVesselChecks(VesselId)) { return; } //Finding using persistentId failed, try searching it with the flightId... var vessel = FlightGlobals.fetch.LmpFindVessel(VesselId); if (vessel == null) { return; } var protoPart = VesselCommon.FindProtoPartInProtovessel(vessel.protoVessel, PartFlightId); if (protoPart != null) { ProcessFairingChange(protoPart); } }
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 ProcessPartMethodSync() { var vessel = FlightGlobals.fetch.LmpFindVessel(VesselId); if (vessel == null) { return; } if (!VesselCommon.DoVesselChecks(VesselId)) { return; } var part = VesselCommon.FindProtoPartInProtovessel(vessel.protoVessel, PartFlightId); if (part != null) { var module = VesselCommon.FindProtoPartModuleInProtoPart(part, ModuleName); if (module != null) { switch (FieldType) { case PartSyncFieldType.Boolean: module.moduleValues.SetValue(FieldName, BoolValue); PartModuleEvent.onPartModuleBoolFieldProcessed.Fire(module, FieldName, BoolValue); break; case PartSyncFieldType.Integer: module.moduleValues.SetValue(FieldName, IntValue); PartModuleEvent.onPartModuleIntFieldProcessed.Fire(module, FieldName, IntValue); break; case PartSyncFieldType.Float: module.moduleValues.SetValue(FieldName, FloatValue); PartModuleEvent.onPartModuleFloatFieldProcessed.Fire(module, FieldName, FloatValue); break; case PartSyncFieldType.Double: module.moduleValues.SetValue(FieldName, DoubleValue); PartModuleEvent.onPartModuleDoubleFieldProcessed.Fire(module, FieldName, DoubleValue); break; case PartSyncFieldType.Vector3: module.moduleValues.SetValue(FieldName, VectorValue); PartModuleEvent.onPartModuleVectorFieldProcessed.Fire(module, FieldName, VectorValue); break; case PartSyncFieldType.Quaternion: module.moduleValues.SetValue(FieldName, QuaternionValue); PartModuleEvent.onPartModuleQuaternionFieldProcessed.Fire(module, FieldName, QuaternionValue); break; case PartSyncFieldType.String: module.moduleValues.SetValue(FieldName, StrValue); PartModuleEvent.onPartModuleStringFieldProcessed.Fire(module, FieldName, StrValue); break; case PartSyncFieldType.Enum: module.moduleValues.SetValue(FieldName, StrValue); PartModuleEvent.onPartModuleEnumFieldProcessed.Fire(module, FieldName, IntValue, StrValue); break; case PartSyncFieldType.Object: module.moduleValues.SetValue(FieldName, StrValue); PartModuleEvent.onPartModuleObjectFieldProcessed.Fire(module, FieldName, StrValue); //We do not set the value of objects in the module as we cannot be sure if they can be transformed from a string back to the object break; default: throw new ArgumentOutOfRangeException(); } } } }
/// <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); })); } } }