public void HandleMessage(IServerMessageBase msg) { if (!(msg.Data is ShareProgressBaseMsgData msgData)) { return; } if (msgData.ShareProgressMessageType != ShareProgressMessageType.ScienceUpdate) { return; } if (msgData is ShareProgressScienceMsgData data) { var science = data.Science; //create a copy of the science value so it will not change in the future. LunaLog.Log($"Queue ScienceUpdate with: {science}"); System.QueueAction(() => { ScienceUpdate(science); }); } }
/// <summary> /// Patches the methods defined in the XML with the transpiler /// </summary> private static void PatchFieldsAndMethods(Type partModule) { foreach (var partModuleMethod in partModule.GetMethods(BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.DeclaredOnly) .Where(m => m.Name == "OnUpdate" || m.Name == "OnFixedUpdate" || m.Name == "FixedUpdate" || m.Name == "Update" || m.Name == "LateUpdate" || m.GetCustomAttributes(typeof(KSPAction), false).Any() || m.GetCustomAttributes(typeof(KSPEvent), false).Any(a => ((KSPEvent)a).guiActive))) { if (_customizationModule.CustomizedFields.Any()) { try { LunaLog.Log($"Patching method {partModuleMethod.Name} for field changes in module {partModule.Name} of assembly {partModule.Assembly.GetName().Name}"); HarmonyPatcher.HarmonyInstance.Patch(partModuleMethod, null, null, BackupAndCallTranspilerMethod); } catch { LunaLog.LogError($"Could not patch method {partModuleMethod.Name} for field changes in module {partModule.Name} of assembly {partModule.Assembly.GetName().Name}"); HarmonyPatcher.HarmonyInstance.Patch(partModuleMethod, null, null, RestoreTranspilerMethod); } } } }
/// <summary> /// Main sending thread /// </summary> public static void SendMain() { try { while (!NetworkConnection.ResetRequested) { if (OutgoingMessages.Count > 0 && OutgoingMessages.TryDequeue(out var sendMessage)) { SendNetworkMessage(sendMessage); } else { Thread.Sleep(SettingsSystem.CurrentSettings.SendReceiveMsInterval); } } } catch (Exception e) { LunaLog.LogError($"[LMP]: Send thread error: {e}"); } }
public void HandleNewSubspace(ClientStructure client, WarpNewSubspaceMsgData message) { LunaLog.Debug($"{client.PlayerName} created a new subspace. Id {WarpContext.NextSubspaceId}"); //Create Subspace WarpContext.Subspaces.TryAdd(WarpContext.NextSubspaceId, message.ServerTimeDifference); VesselRelaySystem.CreateNewSubspace(WarpContext.NextSubspaceId); //Tell all Clients about the new Subspace var newMessageData = new WarpNewSubspaceMsgData { ServerTimeDifference = message.ServerTimeDifference, PlayerCreator = message.PlayerCreator, SubspaceKey = WarpContext.NextSubspaceId }; MessageQueuer.SendToAllClients <WarpSrvMsg>(newMessageData); WarpSystem.SaveSubspace(WarpContext.NextSubspaceId, message.ServerTimeDifference); //Save to disk WarpContext.NextSubspaceId++; }
public void HandleMessage(IServerMessageBase msg) { if (!(msg.Data is ShareProgressBaseMsgData msgData)) { return; } if (msgData.ShareProgressMessageType != ShareProgressMessageType.StrategyUpdate) { return; } if (msgData is ShareProgressStrategyMsgData data) { var strategy = new StrategyInfo(data.Strategy); //create a copy of the strategyInfo object so it will not change in the future. LunaLog.Log($"Queue StrategyUpdate with: {strategy.Name}"); System.QueueAction(() => { StrategyUpdate(strategy); }); } }
public void OnAsteroidSpawned(Vessel asteroid) { if (LockSystem.LockQuery.AsteroidLockBelongsToPlayer(SettingsSystem.CurrentSettings.PlayerName)) { if (System.GetAsteroidCount() <= SettingsSystem.ServerSettings.MaxNumberOfAsteroids) { System.ServerAsteroids.Add(asteroid.id.ToString()); VesselProtoSystem.Singleton.MessageSender.SendVesselMessage(asteroid, true); } else { LunaLog.Log($"[LMP]: Killing non-server asteroid {asteroid.id}"); TryKillAsteroid(asteroid); } } else { LunaLog.Log($"[LMP]: Killing non-server asteroid {asteroid.id}, we don't own the asteroid lock"); TryKillAsteroid(asteroid); } }
private static void SendNetworkMessage(ClientStructure client, IServerMessageBase message) { if (client.ConnectionStatus == ConnectionStatus.CONNECTED) { try { ServerContext.LidgrenServer.SendMessageToClient(client, message); } catch (Exception e) { ClientException.HandleDisconnectException("Send network message error: ", client, e); return; } } else { LunaLog.Normal($"Tried to send a message to client {client.PlayerName}, with connection status: {client.ConnectionStatus}"); } LmpPluginHandler.FireOnMessageSent(client, message); }
public void HandleMessage(IServerMessageBase msg) { if (!(msg.Data is ShareProgressBaseMsgData msgData)) { return; } if (msgData.ShareProgressMessageType != ShareProgressMessageType.ScienceSubjectUpdate) { return; } if (msgData is ShareProgressScienceSubjectMsgData data) { var subject = new ScienceSubjectInfo(data.ScienceSubject); //create a copy of the tech value so it will not change in the future. LunaLog.Log($"Queue Science subject: {subject.Id}"); System.QueueAction(() => { NewScienceSubject(subject); }); } }
/// <summary> /// Get the vessels that are in a past subspace and kill them /// </summary> private void KillPastSubspaceVessels() { if (SettingsSystem.ServerSettings.ShowVesselsInThePast) { return; } if (Enabled && SystemsContainer.Get <MainSystem>().GameRunning) { var vesselsToUnload = SystemsContainer.Get <VesselProtoSystem>().AllPlayerVessels .Where(v => v.Value.Loaded && VesselCommon.VesselIsControlledAndInPastSubspace(v.Key)) .Select(v => FlightGlobals.FindVessel(v.Key)) .ToArray(); if (vesselsToUnload.Any()) { LunaLog.Log($"[LMP]: Unloading {vesselsToUnload.Length} vessels that are in a past subspace"); UnloadVessels(vesselsToUnload); } } }
/// <summary> /// Check all part modules that inherit from PartModule. Then it gets all the fields of those classes that have the "ispersistent" as true. /// </summary> public static void ReadLoadedPartModules() { foreach (var assembly in AppDomain.CurrentDomain.GetAssemblies()) { var partModules = assembly.GetTypes().Where(myType => myType.IsClass && myType.IsSubclassOf(typeof(PartModule))); foreach (var partModule in partModules) { var persistentFields = partModule.GetFields(BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.DeclaredOnly) .Where(f => f.GetCustomAttributes(typeof(KSPField), true).Any(attr => ((KSPField)attr).isPersistant)).ToArray(); if (persistentFields.Any()) { ModuleFieldsDictionary.Add(partModule.Name, new FieldModuleDefinition(partModule, persistentFields)); } InheritanceTypeChain.Add(partModule.Name, GetInheritChain(partModule)); } } LunaLog.Log($"Loaded {ModuleFieldsDictionary.Keys.Count} modules and a total of {ModuleFieldsDictionary.Values.Count} fields"); }
/// <summary> /// Deletes a requested craft /// </summary> public static void DeleteCraft(ClientStructure client, CraftLibraryDeleteRequestMsgData data) { if (client.PlayerName != data.CraftToDelete.FolderName) { return; } Task.Run(() => { var file = Path.Combine(CraftFolder, data.CraftToDelete.FolderName, data.CraftToDelete.CraftType.ToString(), $"{data.CraftToDelete.CraftName}.craft"); if (FileHandler.FileExists(file)) { FileHandler.FileDelete(file); LunaLog.Debug($"Deleting craft {data.CraftToDelete.CraftName} as requested by {client.PlayerName}."); MessageQueuer.SendToAllClients <CraftLibrarySrvMsg>(data); } }); }
private static void TechnologyResearch(TechNodeInfo tech) { System.StartIgnoringEvents(); var node = AssetBase.RnDTechTree.GetTreeTechs().ToList().Find(n => n.techID == tech.Id); //Unlock the technology ResearchAndDevelopment.Instance.UnlockProtoTechNode(node); //Refresh RD nodes in case we are in the RD screen RDController.Instance?.partList?.Refresh(); RDController.Instance?.UpdatePanel(); //Refresh the tech tree ResearchAndDevelopment.RefreshTechTreeUI(); //Refresh the part list in case we are in the VAB/SPH EditorPartList.Instance?.Refresh(); System.StopIgnoringEvents(); LunaLog.Log($"TechnologyResearch received - technology researched: {tech.Id}"); }
public void HandleMessage(IServerMessageBase msg) { if (!(msg.Data is ShareProgressBaseMsgData msgData)) { return; } if (msgData.ShareProgressMessageType != ShareProgressMessageType.TechnologyUpdate) { return; } if (msgData is ShareProgressTechnologyMsgData data) { var tech = new TechNodeInfo(data.TechNode); //create a copy of the tech value so it will not change in the future. LunaLog.Log($"Queue TechnologyResearch with: {tech.Id}"); System.QueueAction(() => { TechnologyResearch(tech); }); } }
public void CheckCommonStockParts() { var missingPartsCount = 0; LunaLog.Log("[LMP]: Missing parts start"); var missingParts = PartLoader.LoadedPartsList.Where(p => !Common.GetStockParts().Contains(p.name)); foreach (var part in missingParts) { missingPartsCount++; LunaLog.Log($"[LMP]: Missing '{part.name}'"); } LunaLog.Log("[LMP]: Missing parts end"); ScreenMessages.PostScreenMessage( missingPartsCount > 0 ? $"{missingPartsCount} missing part(s) from Common.dll printed to debug log ({PartLoader.LoadedPartsList.Count} total)" : $"No missing parts out of from Common.dll ({PartLoader.LoadedPartsList.Count} total)", 5f, ScreenMessageStyle.UPPER_CENTER); }
public static async void DisplayNewVersionMsg() { while (ServerContext.ServerRunning) { if (LatestVersion > LmpVersioning.CurrentVersion) { LunaLog.Warning($"There is a new version of LMP! Please download it! Current: {LmpVersioning.CurrentVersion} Latest: {LatestVersion}"); if (LmpVersioning.IsCompatible(LatestVersion)) { LunaLog.Debug("Your version is compatible with the latest version so you will still be listed in the master servers."); } else { LunaLog.Warning("Your version is NOT compatible with the latest version. You won't be listed in the master servers!"); } } //Sleep for 30 seconds... await Task.Delay(30 * 1000); } }
private static void CheckMasterServerListed() { var ownAddress = LunaNetUtils.GetOwnExternalIpAddress(); if (ownAddress != null) { var ownEndpoint = new IPEndPoint(ownAddress, Port); if (!MasterServerRetriever.MasterServers.Contains(ownEndpoint)) { LunaLog.Error($"You're not listed in the master servers list ({RepoConstants.MasterServersListShortUrl}). Clients/Servers won't see you"); } else { LunaLog.Normal("You're correctly listed in the master servers list"); } } else { LunaLog.Error("Could not retrieve own external IP address, master server likely won't function properly"); } }
/// <summary> /// Sends the screenshots in a folder /// </summary> public static void SendScreenshotList(ClientStructure client, ScreenshotListRequestMsgData data) { var screenshots = new List <ScreenshotInfo>(); foreach (var file in FileHandler.GetFilesInPath(Path.Combine(ScreenshotPath, data.FolderName)).Where(f => thumbnail_handler(f))) { if (long.TryParse(Path.GetFileNameWithoutExtension(file).Replace("small_", string.Empty), out var dateTaken)) { if (data.AlreadyOwnedPhotoIds.Contains(dateTaken)) { continue; } var contents = FileHandler.ReadFile(file); LunaLog.Debug("IMG: " + LunaMath.UShortFromBytes(contents[18], contents[19]) + " X " + LunaMath.UShortFromBytes(contents[22], contents[23])); screenshots.Add(new ScreenshotInfo { Data = contents, DateTaken = dateTaken, NumBytes = contents.Length, Height = LunaMath.UShortFromBytes(contents[18], contents[19]), Width = LunaMath.UShortFromBytes(contents[22], contents[23]), FolderName = data.FolderName, }); } else { LunaLog.Error("Failed to parse data on screenshot: " + file); } } var msgData = ServerContext.ServerMessageFactory.CreateNewMessageData <ScreenshotListReplyMsgData>(); msgData.FolderName = data.FolderName; msgData.Screenshots = screenshots.ToArray(); msgData.NumScreenshots = screenshots.Count; LunaLog.Debug($"Sending {msgData.NumScreenshots} ({data.FolderName}) screenshots to: {client.PlayerName}"); MessageQueuer.SendToClient <ScreenshotSrvMsg>(client, msgData); }
public void HandleMessage(IServerMessageBase msg) { if (!(msg.Data is PlayerColorBaseMsgData msgData)) { return; } switch (msgData.PlayerColorMessageType) { case PlayerColorMessageType.Reply: { var data = (PlayerColorReplyMsgData)msgData; System.PlayerColors.Clear(); for (var i = 0; i < data.PlayerColorsCount; i++) { var playerName = data.PlayersColors[i].PlayerName; System.PlayerColors.Add(playerName, data.PlayersColors[i].Color); StatusWindow.Singleton.ColorEventHandled = false; //Refresh colors in status window } MainSystem.NetworkState = ClientState.ColorsSynced; } break; case PlayerColorMessageType.Set: { //Player joined or changed it's color so update his controlled vessel orbit colors var data = (PlayerColorSetMsgData)msgData; var playerName = data.PlayerColor.PlayerName; var playerColor = data.PlayerColor.Color; LunaLog.Log($"[LMP]: Color Message, Name: {playerName} , color: {playerColor}"); System.PlayerColors[playerName] = playerColor; UpdateVesselColors(playerName); StatusWindow.Singleton.ColorEventHandled = false; //Refresh colors in status window } break; } }
public void HandleMessage(IServerMessageBase msg) { if (!(msg.Data is VesselDockMsgData msgData)) { return; } LunaLog.Log("Docking message received!"); if (msgData.WeakVesselId == CurrentDockEvent.WeakVesselId && msgData.DominantVesselId == CurrentDockEvent.DominantVesselId && (LunaNetworkTime.UtcNow - CurrentDockEvent.DockingTime) < TimeSpan.FromSeconds(5)) { LunaLog.Log("Docking message received was detected so ignore it"); return; } var dominantProto = VesselSerializer.DeserializeVessel(msgData.FinalVesselData, msgData.NumBytes); VesselLoader.LoadVessel(dominantProto); WarpSystem.WarpIfSubspaceIsMoreAdvanced(msgData.SubspaceId); if (FlightGlobals.ActiveVessel && FlightGlobals.ActiveVessel.id == msgData.WeakVesselId) { LunaLog.Log($"Docking NOT detected. We DON'T OWN the dominant vessel. Switching to {msgData.DominantVesselId}"); if (dominantProto.vesselRef != null) { dominantProto.vesselRef.Load(); dominantProto.vesselRef.GoOffRails(); FlightGlobals.ForceSetActiveVessel(dominantProto.vesselRef); } } else if (FlightGlobals.ActiveVessel && FlightGlobals.ActiveVessel.id == msgData.DominantVesselId) { LunaLog.Log("Docking NOT detected. We OWN the dominant vessel"); } VesselRemoveSystem.Singleton.KillVessel(msgData.WeakVesselId, "Killing weak (active) vessel during a docking that was not detected"); CurrentDockEvent.Reset(); }
public void SendKerbalIfDifferent(ProtoCrewMember pcm) { if (pcm.type == ProtoCrewMember.KerbalType.Tourist) { //Don't send tourists LunaLog.Log($"[LMP]: Skipping sending of tourist: {pcm.name}"); return; } var kerbalNode = new ConfigNode(); pcm.Save(kerbalNode); var kerbalBytes = ConfigNodeSerializer.Serialize(kerbalNode); if (kerbalBytes == null || kerbalBytes.Length == 0) { LunaLog.Log("[LMP]: VesselWorker: Error sending kerbal - bytes are null or 0"); return; } var kerbalHash = Common.CalculateSha256Hash(kerbalBytes); var kerbalDifferent = false; if (!System.ServerKerbals.ContainsKey(pcm.name)) { //New kerbal LunaLog.Log("[LMP]: Found new kerbal, sending..."); kerbalDifferent = true; } else if (System.ServerKerbals[pcm.name] != kerbalHash) { LunaLog.Log($"[LMP]: Found changed kerbal ({pcm.name}), sending..."); kerbalDifferent = true; } if (kerbalDifferent) { System.ServerKerbals[pcm.name] = kerbalHash; SendKerbalProtoMessage(pcm.name, kerbalBytes); } }
private void UploadCraftFile(CraftType type, string name) { var uploadPath = ""; switch (System.UploadCraftType) { case CraftType.Vab: uploadPath = System.VabPath; break; case CraftType.Sph: uploadPath = System.SphPath; break; case CraftType.Subassembly: uploadPath = System.SubassemblyPath; break; } var filePath = CommonUtil.CombinePaths(uploadPath, $"{name}.craft"); if (File.Exists(filePath)) { var fileData = File.ReadAllBytes(filePath); var msgData = NetworkMain.CliMsgFactory.CreateNewMessageData <CraftLibraryUploadMsgData>(); msgData.PlayerName = SettingsSystem.CurrentSettings.PlayerName; msgData.UploadType = type; msgData.UploadName = name; msgData.CraftData = fileData; msgData.NumBytes = fileData.Length; System.MessageSender.SendMessage(msgData); AddCraftEntry(SettingsSystem.CurrentSettings.PlayerName, System.UploadCraftType, System.UploadCraftName); DisplayCraftUploadingMessage = true; } else { LunaLog.LogError($"[LMP]: Cannot upload file, {filePath} does not exist!"); } }
public static void SendLockAquireMessage(ClientStructure client, LockDefinition lockDefinition, bool force) { if (LockSystem.AcquireLock(lockDefinition, force, out var repeatedAcquire)) { var msgData = ServerContext.ServerMessageFactory.CreateNewMessageData <LockAcquireMsgData>(); msgData.Lock = lockDefinition; msgData.Force = force; MessageQueuer.SendToAllClients <LockSrvMsg>(msgData); //Just log it if we actually changed the value. Users might send repeated acquire locks as they take a bit of time to reach them... if (!repeatedAcquire) { LunaLog.Debug($"{lockDefinition.PlayerName} acquired lock {lockDefinition}"); } } else { SendStoredLockData(client, lockDefinition); LunaLog.Debug($"{lockDefinition.PlayerName} failed to acquire lock {lockDefinition}"); } }
/// <summary> /// Routine that checks our time against the server time and adjust it if needed. /// </summary> /// <returns></returns> private void SyncTime() { if (Enabled && Synced && !CurrentlyWarping && CanSyncTime() && !SystemsContainer.Get <WarpSystem>().WaitingSubspaceIdFromServer) { var targetTime = SystemsContainer.Get <WarpSystem>().GetCurrentSubspaceTime(); var currentError = TimeSpan.FromSeconds(GetCurrentError()).TotalMilliseconds; if (targetTime != 0 && Math.Abs(currentError) > MaxClockMsError) { if (Math.Abs(currentError) > MaxClockSkew) { LunaLog.LogWarning($"[LMP] Adjusted time from: {Planetarium.GetUniversalTime()} to: {targetTime} due to error:{currentError}"); //TODO: This causes the throttle to reset when called. This happens due to vessel unpacking resetting the throttle controls. //TODO: Try to get Squad to change their code. ClockHandler.StepClock(targetTime); } else { SkewClock(currentError); } } } }
public void BuildDllFileList() { DllList.Clear(); var checkList = Directory.GetFiles(CommonUtil.CombinePaths(Client.KspPath, "GameData"), "*", SearchOption.AllDirectories); foreach (var checkFile in checkList.Where(f => f.ToLower().EndsWith(".dll"))) { //We want the relative path to check against, example: LunaMultiPlayer/Plugins/LunaMultiPlayer.dll //Strip off everything from GameData //Replace windows backslashes with mac/linux forward slashes. //Make it lowercase so we don't worry about case sensitivity. var relativeFilePath = checkFile.ToLowerInvariant() .Substring(checkFile.ToLowerInvariant().IndexOf("gamedata", StringComparison.Ordinal) + 9) .Replace('\\', '/'); var fileHash = Common.CalculateSha256Hash(checkFile); DllList.Add(relativeFilePath, fileHash); LunaLog.Log($"[LMP]: Hashed file: {relativeFilePath}, hash: {fileHash}"); } }
/// <summary> /// Convert a byte array to a ConfigNode and then to a ScienceSubject. /// If anything goes wrong it will return null. /// </summary> private static ScienceSubject ConvertByteArrayToScienceSubject(byte[] data, int numBytes) { ConfigNode node; try { node = ConfigNodeSerializer.Deserialize(data, numBytes); } catch (Exception e) { LunaLog.LogError($"[LMP]: Error while deserializing science subject configNode: {e}"); return(null); } if (node == null) { LunaLog.LogError("[LMP]: Error, the science subject configNode was null."); return(null); } return(new ScienceSubject(node.GetNode("Science"))); }
/// <summary> /// Checks the protovessel for errors /// </summary> public static bool Validate(this ProtoVessel protoVessel) { if (protoVessel == null) { LunaLog.LogError("[LMP]: protoVessel is null!"); return(false); } if (protoVessel.vesselID == Guid.Empty) { LunaLog.LogError("[LMP]: protoVessel id is null!"); return(false); } if (protoVessel.situation == Vessel.Situations.FLYING) { if (protoVessel.orbitSnapShot == null) { LunaLog.LogWarning("[LMP]: Skipping flying vessel load - Protovessel does not have an orbit snapshot"); return(false); } if (FlightGlobals.Bodies == null || FlightGlobals.Bodies.Count < protoVessel.orbitSnapShot.ReferenceBodyIndex) { LunaLog.LogWarning($"[LMP]: Skipping flying vessel load - Could not find celestial body index {protoVessel.orbitSnapShot.ReferenceBodyIndex}"); return(false); } } //Fix the flags urls in the vessel. The flag have the value as: "Squad/Flags/default" foreach (var part in protoVessel.protoPartSnapshots.Where(p => !string.IsNullOrEmpty(p.flagURL))) { if (!FlagSystem.Singleton.FlagExists(part.flagURL)) { LunaLog.Log($"[LMP]: Flag '{part.flagURL}' doesn't exist, setting to default!"); part.flagURL = "Squad/Flags/default"; } } return(true); }
public void HandleMessage(IServerMessageBase msg) { if (!(msg.Data is ShareProgressBaseMsgData msgData)) { return; } if (msgData.ShareProgressMessageType != ShareProgressMessageType.AchievementsUpdate) { return; } if (msgData is ShareProgressAchievementsMsgData data) { var achievementInfos = CopyAchievements(data.Achievements); //create a deep copy of the achievements array so it will not change in the future. LunaLog.Log($"Queue AchievementsUpdate"); ShareCareerSystem.Singleton.QueueAction(() => { AchievementUpdate(achievementInfos); }); } }
/// <summary> /// Send a request to the master server to introduce us and do the nat punchtrough to the selected server /// </summary> public static void IntroduceToServer(long currentEntryId) { try { var token = RandomString(10); var ownEndpoint = new IPEndPoint(LunaNetUtils.GetMyAddress(), NetworkMain.Config.Port); var msgData = NetworkMain.CliMsgFactory.CreateNewMessageData <MsIntroductionMsgData>(); msgData.Id = currentEntryId; msgData.Token = token; msgData.InternalEndpoint = Common.StringFromEndpoint(ownEndpoint); var introduceMsg = NetworkMain.MstSrvMsgFactory.CreateNew <MainMstSrvMsg>(msgData); LunaLog.Log($"[LMP]: Sending NAT introduction to server. Token: {token}"); NetworkSender.QueueOutgoingMessage(introduceMsg); } catch (Exception e) { LunaLog.LogError($"[LMP]: Error connecting to server: {e}"); } }
/// <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, 1000); //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); }
public static void HandleFlagDataMessage(ClientStructure client, FlagDataMsgData message) { if (!ValidationRegex.IsMatch(message.Flag.FlagName)) { LunaLog.Warning($"Cannot save flag {message.Flag.FlagName} from {client.PlayerName} as it's flag name has invalid characters"); return; } var playerFlagPath = Path.Combine(FlagPath, client.PlayerName); if (!FileHandler.FolderExists(playerFlagPath)) { FileHandler.FolderCreate(playerFlagPath); } LunaLog.Debug($"Saving flag {message.Flag.FlagName} from {client.PlayerName}"); var newFileName = $"{message.Flag.FlagName.Replace('/', '$')}.png"; FileHandler.WriteToFile(Path.Combine(playerFlagPath, newFileName), message.Flag.FlagData, message.Flag.NumBytes); MessageQueuer.SendToAllClients <FlagSrvMsg>(message); }