public static void HandleKerbalsRequest(ClientStructure client) { var kerbalFiles = FileHandler.GetFilesInPath(KerbalsPath); var kerbalsData = kerbalFiles.Select(k => { var kerbalData = FileHandler.ReadFile(k); return(new KerbalInfo { KerbalData = kerbalData, NumBytes = kerbalData.Length, KerbalName = Path.GetFileNameWithoutExtension(k) }); }); LunaLog.Debug($"Sending {client.PlayerName} {kerbalFiles.Length} kerbals..."); var msgData = ServerContext.ServerMessageFactory.CreateNewMessageData <KerbalReplyMsgData>(); msgData.Kerbals = kerbalsData.ToArray(); msgData.KerbalsCount = msgData.Kerbals.Length; MessageQueuer.SendToClient <KerbalSrvMsg>(client, msgData); }
private static void HandleVesselCouple(ClientStructure client, VesselBaseMsgData message) { var msgData = (VesselCoupleMsgData)message; LunaLog.Debug($"Coupling message received! Dominant vessel: {msgData.VesselId}"); MessageQueuer.RelayMessage <VesselSrvMsg>(client, msgData); if (VesselContext.RemovedVessels.Contains(msgData.CoupledVesselId)) { return; } //Now remove the weak vessel but DO NOT add to the removed vessels as they might undock!!! LunaLog.Debug($"Removing weak coupled vessel {msgData.CoupledVesselId}"); VesselStoreSystem.RemoveVessel(msgData.CoupledVesselId); //Tell all clients to remove the weak vessel var removeMsgData = ServerContext.ServerMessageFactory.CreateNewMessageData <VesselRemoveMsgData>(); removeMsgData.VesselId = msgData.CoupledVesselId; MessageQueuer.SendToAllClients <VesselSrvMsg>(removeMsgData); }
private static void HandleVesselRemove(ClientStructure client, VesselBaseMsgData message) { var data = (VesselRemoveMsgData)message; if (LockSystem.LockQuery.ControlLockExists(data.VesselId) && !LockSystem.LockQuery.ControlLockBelongsToPlayer(data.VesselId, client.PlayerName)) { return; } if (VesselStoreSystem.VesselExists(data.VesselId)) { LunaLog.Debug($"Removing vessel {data.VesselId} from {client.PlayerName}"); VesselStoreSystem.RemoveVessel(data.VesselId); } if (data.AddToKillList) { VesselContext.RemovedVessels.Add(data.VesselId); } //Relay the message. MessageQueuer.RelayMessage <VesselSrvMsg>(client, data); }
public override void HandleCommand(string commandArgs) { CommandSystemHelperMethods.SplitCommand(commandArgs, out var func, out var playerName); switch (func) { default: LunaLog.Debug("Undefined function. Usage: /whitelist [add|del] playername or /whitelist show"); break; case "add": WhitelistAddCommand.Add(playerName); break; case "del": WhitelistRemoveCommand.Remove(playerName); break; case "show": WhitelistShowCommand.Retrieve(); break; } }
private static void HandleVesselProto(ClientStructure client, VesselBaseMsgData message) { var msgData = (VesselProtoMsgData)message; if (VesselContext.RemovedVessels.Contains(msgData.VesselId)) { return; } if (msgData.NumBytes == 0) { LunaLog.Warning($"Received a vessel with 0 bytes ({msgData.VesselId}) from {client.PlayerName}."); return; } if (!VesselStoreSystem.VesselExists(msgData.VesselId)) { LunaLog.Debug($"Saving vessel {msgData.VesselId} from {client.PlayerName}. Bytes: {msgData.NumBytes}"); } VesselDataUpdater.RawConfigNodeInsertOrUpdate(msgData.VesselId, Encoding.UTF8.GetString(msgData.Data, 0, msgData.NumBytes)); MessageQueuer.RelayMessage <VesselSrvMsg>(client, msgData); }
public void HandleNewSubspace(ClientStructure client, WarpNewSubspaceMsgData message) { if (message.PlayerCreator != client.PlayerName) { return; } 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 msgData = ServerContext.ServerMessageFactory.CreateNewMessageData <WarpNewSubspaceMsgData>(); msgData.ServerTimeDifference = message.ServerTimeDifference; msgData.PlayerCreator = message.PlayerCreator; msgData.SubspaceKey = WarpContext.NextSubspaceId; MessageQueuer.SendToAllClients <WarpSrvMsg>(msgData); WarpContext.NextSubspaceId++; }
public override void HandleMessage(ClientStructure client, IMessageData messageData) { var message = messageData as KerbalBaseMsgData; switch (message?.KerbalMessageType) { case KerbalMessageType.REQUEST: var kerbalFiles = FileHandler.GetFilesInPath(Path.Combine(ServerContext.UniverseDirectory, "Kerbals")); var kerbalsData = kerbalFiles.Select(k => new KeyValuePair <string, byte[]>(Path.GetFileNameWithoutExtension(k), FileHandler.ReadFile(k))); LunaLog.Debug($"Sending {client.PlayerName} {kerbalFiles.Length} kerbals..."); var newMessageData = new KerbalReplyMsgData { KerbalsData = kerbalsData.ToArray() }; MessageQueuer.SendToClient <KerbalSrvMsg>(client, newMessageData); break; case KerbalMessageType.PROTO: var data = (KerbalProtoMsgData)message; LunaLog.Debug($"Saving kerbal {data.KerbalName} from {client.PlayerName}"); var path = Path.Combine(ServerContext.UniverseDirectory, "Kerbals", data.KerbalName + ".txt"); FileHandler.WriteToFile(path, data.KerbalData); MessageQueuer.RelayMessage <KerbalSrvMsg>(client, data); break; default: throw new NotImplementedException("Kerbal type not implemented"); } }
public void HandleChangeSubspace(ClientStructure client, WarpChangeSubspaceMsgData message) { if (message.PlayerName != client.PlayerName) { return; } var oldSubspace = client.Subspace; var newSubspace = message.Subspace; if (oldSubspace != newSubspace) { if (newSubspace < 0) { LunaLog.Debug($"{client.PlayerName} is warping"); } else if (WarpContext.Subspaces[newSubspace].Creator != client.PlayerName) { LunaLog.Debug($"{client.PlayerName} synced with subspace '{message.Subspace}' created by {WarpContext.Subspaces[newSubspace].Creator}"); } var msgData = ServerContext.ServerMessageFactory.CreateNewMessageData <WarpChangeSubspaceMsgData>(); msgData.PlayerName = client.PlayerName; msgData.Subspace = message.Subspace; MessageQueuer.RelayMessage <WarpSrvMsg>(client, msgData); if (newSubspace != -1) { client.Subspace = newSubspace; //Try to remove his old subspace WarpSystem.RemoveSubspace(oldSubspace); } } }
public static bool RemoveSubspace(int subspaceToRemove) { //Do not remove the subspace if there are clients there if (ServerContext.Clients.Any(c => c.Value.Subspace == subspaceToRemove)) { return(false); } //If there's only 1 subspace do not remove it! if (WarpContext.Subspaces.Count == 1) { return(false); } //We are in the latest subspace and we NEVER remove it! if (subspaceToRemove == WarpContext.LatestSubspace.Id) { return(false); } LunaLog.Debug($"Removing abandoned subspace '{subspaceToRemove}'"); WarpContext.Subspaces.TryRemove(subspaceToRemove, out _); return(true); }
public static void HandleListFlagMessage(ClientStructure client, FlagListMsgData message) { //Send the list back var serverFlagFileNames = new List <string>(); var serverFlagOwners = new List <string>(); var serverFlagShaSums = new List <string>(); var serverFlags = FileHandler.GetFilesInPath(FlagPath, SearchOption.AllDirectories); foreach (var serverFlag in serverFlags) { var trimmedName = Path.GetFileName(serverFlag); var flagOwnerPath = Path.GetDirectoryName(serverFlag); var flagOwner = flagOwnerPath.Substring(Path.GetDirectoryName(flagOwnerPath).Length + 1); var isMatched = false; var shaDifferent = false; for (var i = 0; i < message.FlagFileNames.Length; i++) { if (message.FlagFileNames[i].ToLower() == trimmedName.ToLower()) { isMatched = true; shaDifferent = Common.CalculateSha256Hash(serverFlag) != message.FlagShaSums[i]; } } if (!isMatched || shaDifferent) { if (flagOwner == client.PlayerName) { LunaLog.Debug("Deleting flag " + trimmedName); FileHandler.FileDelete(serverFlag); MessageQueuer.RelayMessage <FlagSrvMsg>(client, new FlagDeleteMsgData { FlagName = trimmedName }); if (FileHandler.GetFilesInPath(flagOwnerPath).Length == 0) { FileHandler.FolderDelete(flagOwnerPath); } } else { LunaLog.Debug($"Sending flag {serverFlag} from {flagOwner} to {client.PlayerName}"); var newMessageData = new FlagDataMsgData { FlagName = trimmedName, OwnerPlayerName = flagOwner, FlagData = FileHandler.ReadFile(serverFlag) }; MessageQueuer.SendToClient <FlagSrvMsg>(client, newMessageData); } } //Don't tell the client we have a different copy of the flag so it is reuploaded if (FileHandler.FileExists(serverFlag)) { serverFlagFileNames.Add(trimmedName); serverFlagOwners.Add(flagOwner); serverFlagShaSums.Add(Common.CalculateSha256Hash(serverFlag)); } } var listMessageData = new FlagListMsgData { FlagFileNames = serverFlagFileNames.ToArray(), FlagOwners = serverFlagOwners.ToArray(), FlagShaSums = serverFlagShaSums.ToArray() }; MessageQueuer.SendToClient <FlagSrvMsg>(client, listMessageData); }
public static async void StartReceiveingMessages() { try { while (ServerContext.ServerRunning) { var msg = Server.ReadMessage(); if (msg != null) { var client = TryGetClient(msg); switch (msg.MessageType) { case NetIncomingMessageType.ConnectionApproval: if (ServerContext.UsePassword) { var password = msg.ReadString(); if (password != GeneralSettings.SettingsStore.Password) { msg.SenderConnection.Deny("Invalid password"); break; } } msg.SenderConnection.Approve(); break; case NetIncomingMessageType.Data: ClientMessageReceiver.ReceiveCallback(client, msg); break; case NetIncomingMessageType.WarningMessage: LunaLog.Warning(msg.ReadString()); break; case NetIncomingMessageType.DebugMessage: LunaLog.NetworkDebug(msg.ReadString()); break; case NetIncomingMessageType.ConnectionLatencyUpdated: case NetIncomingMessageType.VerboseDebugMessage: LunaLog.NetworkVerboseDebug(msg.ReadString()); break; case NetIncomingMessageType.Error: LunaLog.Error(msg.ReadString()); break; case NetIncomingMessageType.StatusChanged: switch ((NetConnectionStatus)msg.ReadByte()) { case NetConnectionStatus.Connected: var endpoint = msg.SenderConnection.RemoteEndPoint; LunaLog.Normal($"New client Connection from {endpoint.Address}:{endpoint.Port}"); ClientConnectionHandler.ConnectClient(msg.SenderConnection); break; case NetConnectionStatus.Disconnected: var reason = msg.ReadString(); if (client != null) { ClientConnectionHandler.DisconnectClient(client, reason); } break; } break; default: var details = msg.PeekString(); LunaLog.Debug($"Lidgren: {msg.MessageType.ToString().ToUpper()} -- {details}"); break; } } else { await Task.Delay(IntervalSettings.SettingsStore.SendReceiveThreadTickMs); } } } catch (Exception e) { LunaLog.Fatal($"ERROR in thread receive! Details: {e}"); } }
public void StartReceiveingMessages() { try { while (ServerContext.ServerRunning) { var msg = Server.ReadMessage(); if (msg != null) { var client = TryGetClient(msg); switch (msg.MessageType) { case NetIncomingMessageType.ConnectionApproval: msg.SenderConnection.Approve(); break; case NetIncomingMessageType.Data: ClientMessageReceiver.ReceiveCallback(client, msg); break; case NetIncomingMessageType.WarningMessage: LunaLog.Error($"Lidgren WARNING: {msg.ReadString()}"); break; case NetIncomingMessageType.DebugMessage: case NetIncomingMessageType.VerboseDebugMessage: LunaLog.Debug($"Lidgren DEBUG: {msg.MessageType}-- {msg.PeekString()}"); break; case NetIncomingMessageType.StatusChanged: switch ((NetConnectionStatus)msg.ReadByte()) { case NetConnectionStatus.Connected: var endpoint = msg.SenderConnection.RemoteEndPoint; LunaLog.Normal($"New client Connection from {endpoint.Address}:{endpoint.Port}"); ClientConnectionHandler.ConnectClient(msg.SenderConnection); break; case NetConnectionStatus.Disconnected: var reason = msg.ReadString(); if (client != null) { ClientConnectionHandler.DisconnectClient(client, reason); } break; } break; default: var details = msg.PeekString(); LunaLog.Debug($"Lidgren: {msg.MessageType.ToString().ToUpper()} -- {details}"); break; } } else { Thread.Sleep(GeneralSettings.SettingsStore.SendReceiveThreadTickMs); } } } catch (Exception e) { LunaLog.Fatal($"ERROR in thread receive! Details: {e}"); } }
public static void Main() { try { ServerContext.StartTime = DateTime.UtcNow.Ticks; //Start the server clock ServerContext.ServerClock.Start(); //Set the last player activity time to server start ServerContext.LastPlayerActivity = ServerContext.ServerClock.ElapsedMilliseconds; //Register the ctrl+c event Console.CancelKeyPress += CatchExit; ServerContext.ServerStarting = true; LunaLog.Debug("Loading settings..."); if (GeneralSettings.SettingsStore.GameDifficulty == GameDifficulty.Custom) { GameplaySettings.Reset(); GameplaySettings.Load(); } //Set day for log change ServerContext.Day = DateTime.Now.Day; //Load plugins LmpPluginHandler.LoadPlugins(); Console.Title = $"LMPServer v{VersionInfo.VersionNumber}"; while (ServerContext.ServerStarting || ServerContext.ServerRestarting) { if (ServerContext.ServerRestarting) { LunaLog.Debug("Reloading settings..."); GeneralSettings.Reset(); GeneralSettings.Load(); if (GeneralSettings.SettingsStore.GameDifficulty == GameDifficulty.Custom) { LunaLog.Debug("Reloading gameplay settings..."); GameplaySettings.Reset(); GameplaySettings.Load(); } } ServerContext.ServerRestarting = false; LunaLog.Normal($"Starting Luna Server v{VersionInfo.FullVersionNumber}"); if (GeneralSettings.SettingsStore.GameDifficulty == GameDifficulty.Custom) { //Generate the config file by accessing the object. LunaLog.Debug("Loading gameplay settings..."); GameplaySettings.Load(); } //Load universe LunaLog.Normal("Loading universe... "); Universe.CheckUniverse(); LunaLog.Normal($"Starting {GeneralSettings.SettingsStore.WarpMode} server on Port {GeneralSettings.SettingsStore.Port}... "); ServerContext.ServerRunning = true; var commandThread = Task.Run(() => new CommandHandler().ThreadMain()); var clientThread = Task.Run(() => new ClientMainThread().ThreadMain()); ServerContext.LidgrenServer.SetupLidgrenServer(); Task.Run(() => ServerContext.LidgrenServer.StartReceiveingMessages()); Task.Run(() => ServerContext.LidgrenServer.RegisterWithMasterServer()); var vesselRelayThread = Task.Run(() => VesselRelaySystem.RelayOldVesselMessages()); var vesselRelayFarThread = Task.Run(() => VesselUpdateRelaySystem.RelayToFarPlayers()); var vesselRelayMediumThread = Task.Run(() => VesselUpdateRelaySystem.RelayToMediumDistancePlayers()); var vesselRelayCloseThread = Task.Run(() => VesselUpdateRelaySystem.RelayToClosePlayers()); while (ServerContext.ServerStarting) { Thread.Sleep(500); } LunaLog.Normal("Ready!"); LmpPluginHandler.FireOnServerStart(); while (ServerContext.ServerRunning) { //Run the log expire function every 10 minutes if (ServerContext.ServerClock.ElapsedMilliseconds - _lastLogExpiredCheck > 600000) { _lastLogExpiredCheck = ServerContext.ServerClock.ElapsedMilliseconds; LogExpire.ExpireLogs(); } // Check if the day has changed, every minute if (ServerContext.ServerClock.ElapsedMilliseconds - _lastDayCheck > 60000) { _lastDayCheck = ServerContext.ServerClock.ElapsedMilliseconds; if (ServerContext.Day != DateTime.Now.Day) { LunaLog.LogFilename = Path.Combine(LunaLog.LogFolder, $"lmpserver {DateTime.Now:yyyy-MM-dd HH-mm-ss}.log"); LunaLog.WriteToLog($"Continued from logfile {DateTime.Now:yyyy-MM-dd HH-mm-ss}.log"); ServerContext.Day = DateTime.Now.Day; } } Thread.Sleep(500); } LmpPluginHandler.FireOnServerStop(); commandThread.Wait(); clientThread.Wait(); vesselRelayThread.Wait(); vesselRelayFarThread.Wait(); vesselRelayMediumThread.Wait(); vesselRelayCloseThread.Wait(); } LunaLog.Normal("Goodbye and thanks for all the fish!"); Environment.Exit(0); } catch (Exception e) { LunaLog.Fatal($"Error in main server thread, Exception: {e}"); throw; } }
public void HandleJoinMessage(ClientStructure client, ChatJoinMsgData message) { AddChannelToPlayer(message.From, message.Channel); LunaLog.Debug($"{message.From} joined channel: {message.Channel}"); MessageQueuer.RelayMessage <ChatSrvMsg>(client, message); }
public void HandleLeaveMessage(ClientStructure client, ChatLeaveMsgData message) { RemoveChannelFromPlayer(message.From, message.Channel); LunaLog.Debug($"{message.From} left channel: {message.Channel}"); MessageQueuer.RelayMessage <ChatSrvMsg>(client, message); }
public static void LoadPlugins() { var pluginDirectory = Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "Plugins"); if (!FileHandler.FolderExists(pluginDirectory)) { FileHandler.FolderCreate(pluginDirectory); } LunaLog.Debug("Loading plugins..."); //Load all the assemblies just in case they depend on each other during instantation var loadedAssemblies = new List <Assembly>(); var pluginFiles = FileHandler.GetFilesInPath(pluginDirectory, SearchOption.AllDirectories); foreach (var pluginFile in pluginFiles.Where(pluginFile => Path.GetExtension(pluginFile)?.ToLower() == ".dll")) { try { //UnsafeLoadFrom will not throw an exception if the dll is marked as unsafe, //such as downloaded from internet in Windows //See http://stackoverflow.com/a/15238782 var loadedAssembly = Assembly.UnsafeLoadFrom(pluginFile); loadedAssemblies.Add(loadedAssembly); LunaLog.Debug($"Loaded {pluginFile}"); } catch (NotSupportedException) { //This should only occur if using Assembly.LoadFrom() above instead of Assembly.UnsafeLoadFrom() LunaLog.Debug($"Can't load dll, perhaps it is blocked: {pluginFile}"); } catch { LunaLog.Debug($"Error loading {pluginFile}"); } } //Iterate through the assemblies looking for classes that have the ILmpPlugin interface foreach (var loadedAssembly in loadedAssemblies) { foreach (var loadedType in loadedAssembly.GetExportedTypes().Where(t => t.GetInterfaces().Any(i => i == typeof(ILmpPlugin)))) { LunaLog.Debug($"Loading plugin: {loadedType.FullName}"); try { var pluginInstance = ActivatePluginType(loadedType); if (pluginInstance != null) { LunaLog.Debug($"Loaded plugin: {loadedType.FullName}"); lock (ListLock) { LoadedPlugins.Add(pluginInstance); } } } catch (Exception ex) { LunaLog.Error($"Error loading plugin {loadedType.FullName}({loadedType.Assembly.FullName}) Exception: {ex}"); } } LunaLog.Debug("Done!"); } }
private static void HandleMessage(IMasterServerMessageBase message, NetIncomingMessage netMsg, NetPeer peer) { if (BannedIpsRetriever.IsBanned(netMsg.SenderEndPoint)) { LunaLog.Debug($"Ignoring BANNED ip: {netMsg.SenderEndPoint}"); return; } try { switch ((message?.Data as MsBaseMsgData)?.MasterServerMessageSubType) { case MasterServerMessageSubType.RegisterServer: RegisterServer(message, netMsg); break; case MasterServerMessageSubType.RequestServers: LunaLog.Normal($"LIST REQUEST from: {netMsg.SenderEndPoint}"); SendServerLists(netMsg, peer); break; case MasterServerMessageSubType.Introduction: var msgData = (MsIntroductionMsgData)message.Data; if (ServerDictionary.TryGetValue(msgData.Id, out var server)) { _ = Task.Run(() => { if (!server.InternalEndpoint6.Address.Equals(IPAddress.IPv6Loopback) && !server.InternalEndpoint6.Address.Equals(IPAddress.IPv6Loopback)) { // Both client and server are listening on IPv6, try an IPv6 firewall punchthrough // This also triggers a first punchthrough on IPv4 with the public addresses LunaLog.Normal( $"INTRODUCTION request from: {msgData.InternalEndpoint6} to server: {server.InternalEndpoint6}"); peer.Introduce(server.InternalEndpoint6, server.ExternalEndpoint, msgData.InternalEndpoint6, // client internal netMsg.SenderEndPoint, // client external msgData.Token); // request token // Give the first introduction attempt some time Thread.Sleep(50); } LunaLog.Normal( $"INTRODUCTION request from: {netMsg.SenderEndPoint} to server: {server.ExternalEndpoint}"); peer.Introduce(server.InternalEndpoint, server.ExternalEndpoint, msgData.InternalEndpoint, // client internal netMsg.SenderEndPoint, // client external msgData.Token); // request token }); } else { LunaLog.Warning($"Client {netMsg.SenderEndPoint} requested introduction to non listed host!"); } break; } } catch (Exception e) { LunaLog.Error($"Error handling message. Details: {e}"); } }