public static void ThreadMain() { try { //Register commands CommandHandler.RegisterCommand("help", CommandHandler.DisplayHelp, "Displays this help"); CommandHandler.RegisterCommand("say", CommandHandler.Say, "Broadcasts a message to clients"); CommandHandler.RegisterCommand("dekessler", Dekessler.RunDekessler, "Clears out debris from the server"); CommandHandler.RegisterCommand("nukeksc", NukeKSC.RunNukeKSC, "Clears ALL vessels from KSC and the Runway"); CommandHandler.RegisterCommand("listclients", ListClients, "Lists connected clients"); CommandHandler.RegisterCommand("countclients", CountClients, "Counts connected clients"); //Main loop while (Server.serverRunning) { string input = ""; try { input = Console.ReadLine(); if (input == null) { DarkLog.Debug("Terminal may be not attached or broken, Exiting out of command handler"); return; } } catch { if (Server.serverRunning) { DarkLog.Debug("Ignored mono Console.ReadLine() bug"); } Thread.Sleep(500); } DarkLog.Normal("Command input: " + input); if (input.StartsWith("/")) { string commandPart = input.Substring(1); string argumentPart = ""; if (commandPart.Contains(" ")) { if (commandPart.Length > commandPart.IndexOf(' ') + 1) { argumentPart = commandPart.Substring(commandPart.IndexOf(' ') + 1); } commandPart = commandPart.Substring(0, commandPart.IndexOf(' ')); } if (commandPart.Length > 0) { if (commands.ContainsKey(commandPart)) { try { commands[commandPart].func(argumentPart); } catch (Exception e) { DarkLog.Error("Error handling command " + commandPart + ", Exception " + e); } } else { DarkLog.Normal("Unknown command: " + commandPart); } } } else { if (input != "") { commands["say"].func(input); } } } } catch (Exception e) { if (Server.serverRunning) { DarkLog.Fatal("Error in command handler thread, Exception: " + e); throw; } } }
public static void Main() { #if !DEBUG try { #endif //Start the server clock serverClock = new Stopwatch(); serverClock.Start(); Settings.Reset(); //Set the last player activity time to server start lastPlayerActivity = serverClock.ElapsedMilliseconds; //Periodic garbage collection long lastGarbageCollect = 0; //Periodic screenshot check long lastScreenshotExpiredCheck = 0; //Periodic log check long lastLogExpiredCheck = 0; //Periodic day check long lastDayCheck = 0; //Set universe directory and modfile path universeDirectory = Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "Universe"); modFile = Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "DMPModControl.txt"); if (!Directory.Exists(configDirectory)) { Directory.CreateDirectory(configDirectory); } string oldSettingsFile = Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "DMPServerSettings.txt"); string newSettingsFile = Path.Combine(Server.configDirectory, "Settings.txt"); string oldGameplayFile = Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "DMPGameplaySettings.txt"); string newGameplayFile = Path.Combine(Server.configDirectory, "GameplaySettings.txt"); // Run the conversion BackwardsCompatibility.ConvertSettings(oldSettingsFile, newSettingsFile); if (File.Exists(oldGameplayFile)) { if (!File.Exists(newGameplayFile)) { File.Move(oldGameplayFile, newGameplayFile); } File.Delete(oldGameplayFile); } //Register the server commands CommandHandler.RegisterCommand("exit", Server.ShutDown, "Shuts down the server"); CommandHandler.RegisterCommand("quit", Server.ShutDown, "Shuts down the server"); CommandHandler.RegisterCommand("shutdown", Server.ShutDown, "Shuts down the server"); CommandHandler.RegisterCommand("restart", Server.Restart, "Restarts the server"); CommandHandler.RegisterCommand("kick", KickCommand.KickPlayer, "Kicks a player from the server"); CommandHandler.RegisterCommand("ban", BanSystem.fetch.BanPlayer, "Bans a player from the server"); CommandHandler.RegisterCommand("banip", BanSystem.fetch.BanIP, "Bans an IP Address from the server"); CommandHandler.RegisterCommand("bankey", BanSystem.fetch.BanPublicKey, "Bans a Guid from the server"); CommandHandler.RegisterCommand("pm", PMCommand.HandleCommand, "Sends a message to a player"); CommandHandler.RegisterCommand("admin", AdminCommand.HandleCommand, "Sets a player as admin/removes admin from the player"); CommandHandler.RegisterCommand("whitelist", WhitelistCommand.HandleCommand, "Change the server whitelist"); //Register the ctrl+c event Console.CancelKeyPress += new ConsoleCancelEventHandler(CatchExit); serverStarting = true; //Fix kerbals from 0.23.5 to 0.24 (Now indexed by string, thanks Squad! BackwardsCompatibility.FixKerbals(); //Remove player tokens BackwardsCompatibility.RemoveOldPlayerTokens(); //Add new stock parts BackwardsCompatibility.UpdateModcontrolPartList(); if (System.Net.Sockets.Socket.OSSupportsIPv6) { Settings.settingsStore.address = "::"; } DarkLog.Debug("Loading settings..."); Settings.Load(); if (Settings.settingsStore.gameDifficulty == GameDifficulty.CUSTOM) { GameplaySettings.Reset(); GameplaySettings.Load(); } //Test compression if (Settings.settingsStore.compressionEnabled) { long testTime = Compression.TestSysIOCompression(); Compression.compressionEnabled = true; DarkLog.Debug("System.IO compression works: " + Compression.sysIOCompressionWorks + ", test time: " + testTime + " ms."); } //Set day for log change day = DateTime.Now.Day; //Load plugins DMPPluginHandler.LoadPlugins(); Console.Title = "DMPServer " + Common.PROGRAM_VERSION + ", protocol " + Common.PROTOCOL_VERSION; while (serverStarting || serverRestarting) { if (serverRestarting) { DarkLog.Debug("Reloading settings..."); Settings.Reset(); Settings.Load(); if (Settings.settingsStore.gameDifficulty == GameDifficulty.CUSTOM) { DarkLog.Debug("Reloading gameplay settings..."); GameplaySettings.Reset(); GameplaySettings.Load(); } } serverRestarting = false; DarkLog.Normal("Starting DMPServer " + Common.PROGRAM_VERSION + ", protocol " + Common.PROTOCOL_VERSION); if (Settings.settingsStore.gameDifficulty == GameDifficulty.CUSTOM) { //Generate the config file by accessing the object. DarkLog.Debug("Loading gameplay settings..."); GameplaySettings.Load(); } //Load universe DarkLog.Normal("Loading universe... "); CheckUniverse(); DarkLog.Normal("Starting " + Settings.settingsStore.warpMode + " server on port " + Settings.settingsStore.port + "... "); serverRunning = true; Thread commandThread = new Thread(new ThreadStart(CommandHandler.ThreadMain)); Thread clientThread = new Thread(new ThreadStart(ClientHandler.ThreadMain)); commandThread.Start(); clientThread.Start(); while (serverStarting) { Thread.Sleep(500); } StartHTTPServer(); DarkLog.Normal("Ready!"); DMPPluginHandler.FireOnServerStart(); while (serverRunning) { //Run a garbage collection every 30 seconds. if ((serverClock.ElapsedMilliseconds - lastGarbageCollect) > 30000) { lastGarbageCollect = serverClock.ElapsedMilliseconds; GC.Collect(); } //Run the screenshot expire function every 10 minutes if ((serverClock.ElapsedMilliseconds - lastScreenshotExpiredCheck) > 600000) { lastScreenshotExpiredCheck = serverClock.ElapsedMilliseconds; ScreenshotExpire.ExpireScreenshots(); } //Run the log expire function every 10 minutes if ((serverClock.ElapsedMilliseconds - lastLogExpiredCheck) > 600000) { lastLogExpiredCheck = serverClock.ElapsedMilliseconds; LogExpire.ExpireLogs(); } // Check if the day has changed, every minute if ((serverClock.ElapsedMilliseconds - lastDayCheck) > 60000) { lastDayCheck = serverClock.ElapsedMilliseconds; if (day != DateTime.Now.Day) { DarkLog.LogFilename = Path.Combine(DarkLog.LogFolder, "dmpserver " + DateTime.Now.ToString("yyyy-MM-dd HH-mm-ss") + ".log"); DarkLog.WriteToLog("Continued from logfile " + DateTime.Now.ToString("yyyy-MM-dd HH-mm-ss") + ".log"); day = DateTime.Now.Day; } } Thread.Sleep(500); } DMPPluginHandler.FireOnServerStop(); commandThread.Abort(); clientThread.Join(); } DarkLog.Normal("Goodbye!"); Environment.Exit(0); #if !DEBUG } catch (Exception e) { DarkLog.Fatal("Error in main server thread, Exception: " + e); throw; } #endif }
private static void Load() { DarkLog.Debug("Loading settings"); FieldInfo[] settingFields = typeof(SettingsStore).GetFields(); if (!File.Exists(settingsFile)) { try { if (System.Net.Sockets.Socket.OSSupportsIPv6) { //Default to listening on IPv4 and IPv6 if possible. settingsStore.address = "::"; } } catch { //May throw on Windows XP } Save(); } using (FileStream fs = new FileStream(settingsFile, FileMode.Open)) { using (StreamReader sr = new StreamReader(fs)) { string currentLine; string trimmedLine; string currentKey; string currentValue; while (true) { currentLine = sr.ReadLine(); if (currentLine == null) { break; } trimmedLine = currentLine.Trim(); if (!String.IsNullOrEmpty(trimmedLine)) { if (trimmedLine.Contains(",") && !trimmedLine.StartsWith("#")) { currentKey = trimmedLine.Substring(0, trimmedLine.IndexOf(",")); currentValue = trimmedLine.Substring(trimmedLine.IndexOf(",") + 1); foreach (FieldInfo settingField in settingFields) { if (settingField.Name.ToLower() == currentKey) { if (settingField.FieldType == typeof(string)) { settingField.SetValue(settingsStore, currentValue); } if (settingField.FieldType == typeof(int)) { int intValue = Int32.Parse(currentValue); settingField.SetValue(settingsStore, (int)intValue); } if (settingField.FieldType == typeof(double)) { double doubleValue = Double.Parse(currentValue); settingField.SetValue(settingsStore, (double)doubleValue); } if (settingField.FieldType == typeof(bool)) { if (currentValue == "1") { settingField.SetValue(settingsStore, true); } else { settingField.SetValue(settingsStore, false); } } if (settingField.FieldType.IsEnum) { int intValue = Int32.Parse(currentValue); Array enumValues = settingField.FieldType.GetEnumValues(); if (intValue <= enumValues.Length) { settingField.SetValue(settingsStore, enumValues.GetValue(intValue)); } } //DarkLog.Debug(settingField.Name + ": " + currentValue); } } } } } } } Save(); }
public static void SendToClient(ClientObject client, ServerMessage message, bool highPriority) { //Because we dodge the queue, we need to lock it up again... lock (client.sendLock) { if (message == null) { return; } //All messages have an 8 byte header client.bytesQueuedOut += 8; if (message.data != null) { //Count the payload if we have one. client.bytesQueuedOut += message.data.Length; } if (highPriority) { client.sendMessageQueueHigh.Enqueue(message); } else { client.sendMessageQueueLow.Enqueue(message); //If we need to optimize if (client.bytesQueuedOut > OPTIMIZE_QUEUE_LIMIT) { //And we haven't optimized in the last 5 seconds long currentTime = DateTime.UtcNow.Ticks; long optimizedBytes = 0; if ((currentTime - client.lastQueueOptimizeTime) > 50000000) { client.lastQueueOptimizeTime = currentTime; DarkLog.Debug("Optimizing " + client.playerName + " (" + client.bytesQueuedOut + " bytes queued)"); //Create a temporary filter list List <ServerMessage> oldClientMessagesToSend = new List <ServerMessage>(); List <ServerMessage> newClientMessagesToSend = new List <ServerMessage>(); //Steal all the messages from the queue and put them into a list ServerMessage stealMessage = null; while (client.sendMessageQueueLow.TryDequeue(out stealMessage)) { oldClientMessagesToSend.Add(stealMessage); } //Clear the client send queue List <string> seenProtovesselUpdates = new List <string>(); List <string> seenPositionUpdates = new List <string>(); //Iterate backwards over the list oldClientMessagesToSend.Reverse(); foreach (ServerMessage currentMessage in oldClientMessagesToSend) { if (currentMessage.type != ServerMessageType.VESSEL_PROTO && currentMessage.type != ServerMessageType.VESSEL_UPDATE) { //Message isn't proto or position, don't skip it. newClientMessagesToSend.Add(currentMessage); } else { //Message is proto or position if (currentMessage.type == ServerMessageType.VESSEL_PROTO) { using (MessageReader mr = new MessageReader(currentMessage.data)) { //Don't care about the send time, it's already the latest in the queue. mr.Read <double>(); string vesselID = mr.Read <string>(); if (!seenProtovesselUpdates.Contains(vesselID)) { seenProtovesselUpdates.Add(vesselID); newClientMessagesToSend.Add(currentMessage); } else { optimizedBytes += 8 + currentMessage.data.Length; } } } if (currentMessage.type == ServerMessageType.VESSEL_UPDATE) { using (MessageReader mr = new MessageReader(currentMessage.data)) { //Don't care about the send time, it's already the latest in the queue. mr.Read <double>(); string vesselID = mr.Read <string>(); if (!seenPositionUpdates.Contains(vesselID)) { seenPositionUpdates.Add(vesselID); newClientMessagesToSend.Add(currentMessage); } else { //8 byte message header plus payload optimizedBytes += 8 + currentMessage.data.Length; } } } } } //Flip it back to the right order newClientMessagesToSend.Reverse(); foreach (ServerMessage putBackMessage in newClientMessagesToSend) { client.sendMessageQueueLow.Enqueue(putBackMessage); } float optimizeTime = (DateTime.UtcNow.Ticks - currentTime) / 10000f; client.bytesQueuedOut -= optimizedBytes; DarkLog.Debug("Optimized " + optimizedBytes + " bytes in " + Math.Round(optimizeTime, 3) + " ms."); } } } client.sendEvent.Set(); } }
public static void Load() { FieldInfo[] settingFields = typeof(SettingsStore).GetFields(); if (!File.Exists(Path.Combine(serverPath, SETTINGS_FILE_NAME))) { Save(); } using (FileStream fs = new FileStream(settingsFile, FileMode.Open)) { using (StreamReader sr = new StreamReader(fs)) { string currentLine; string trimmedLine; string currentKey; string currentValue; while (true) { currentLine = sr.ReadLine(); if (currentLine == null) { break; } trimmedLine = currentLine.Trim(); if (!String.IsNullOrEmpty(trimmedLine)) { if (trimmedLine.Contains(",") && !trimmedLine.StartsWith("#")) { currentKey = trimmedLine.Substring(0, trimmedLine.IndexOf(",")); currentValue = trimmedLine.Substring(trimmedLine.IndexOf(",") + 1); foreach (FieldInfo settingField in settingFields) { if (settingField.Name.ToLower() == currentKey) { if (settingField.FieldType == typeof(string)) { settingField.SetValue(settingsStore, currentValue); } if (settingField.FieldType == typeof(int)) { int intValue = Int32.Parse(currentValue); settingField.SetValue(settingsStore, (int)intValue); } if (settingField.FieldType == typeof(bool)) { if (currentValue == "1") { settingField.SetValue(settingsStore, true); } else { settingField.SetValue(settingsStore, false); } } if (settingField.FieldType.IsEnum) { int intValue = Int32.Parse(currentValue); Array enumValues = settingField.FieldType.GetEnumValues(); if (intValue <= enumValues.Length) { settingField.SetValue(settingsStore, enumValues.GetValue(intValue)); } } DarkLog.Debug(settingField.Name + ": " + currentValue); } } } } } } } Save(); }
private static void SendNetworkMessage(ClientObject client, ServerMessage message) { //Write the send times down in SYNC_TIME_REPLY packets if (message.type == ServerMessageType.SYNC_TIME_REPLY) { try { using (MessageWriter mw = new MessageWriter()) { using (MessageReader mr = new MessageReader(message.data)) { client.bytesQueuedOut += 8; //Client send time mw.Write <long>(mr.Read <long>()); //Server receive time mw.Write <long>(mr.Read <long>()); //Server send time mw.Write <long>(DateTime.UtcNow.Ticks); message.data = mw.GetMessageBytes(); } } } catch (Exception e) { DarkLog.Debug("Error rewriting SYNC_TIME packet, Exception " + e); } } //Continue sending byte[] messageBytes = Common.PrependNetworkFrame((int)message.type, message.data); client.lastSendTime = Server.serverClock.ElapsedMilliseconds; client.bytesQueuedOut -= messageBytes.Length; client.bytesSent += messageBytes.Length; if (client.connectionStatus == ConnectionStatus.CONNECTED) { try { client.connection.GetStream().Write(messageBytes, 0, messageBytes.Length); } catch (Exception e) { HandleDisconnectException("Send Network Message", client, e); return; } } DMPPluginHandler.FireOnMessageSent(client, message); if (message.type == ServerMessageType.CONNECTION_END) { using (MessageReader mr = new MessageReader(message.data)) { string reason = mr.Read <string>(); DarkLog.Normal("Disconnecting client " + client.playerName + ", sent CONNECTION_END (" + reason + ") to endpoint " + client.endpoint); client.disconnectClient = true; DisconnectClient(client); } } if (message.type == ServerMessageType.HANDSHAKE_REPLY) { using (MessageReader mr = new MessageReader(message.data)) { int response = mr.Read <int>(); string reason = mr.Read <string>(); if (response != 0) { DarkLog.Normal("Disconnecting client " + client.playerName + ", sent HANDSHAKE_REPLY (" + reason + ") to endpoint " + client.endpoint); client.disconnectClient = true; DisconnectClient(client); } } } }
internal static void HandleMessage(ClientObject client, ClientMessage message) { //Prevent plugins from dodging SPLIT_MESSAGE. If they are modified, every split message will be broken. if (message.type != ClientMessageType.SPLIT_MESSAGE) { DMPPluginHandler.FireOnMessageReceived(client, message); if (message.handled) { //a plugin has handled this message and requested suppression of the default DMP behavior return; } } //Clients can only send HEARTBEATS, HANDSHAKE_REQUEST or CONNECTION_END's until they are authenticated. if (!client.authenticated && !(message.type == ClientMessageType.HEARTBEAT || message.type == ClientMessageType.HANDSHAKE_RESPONSE || message.type == ClientMessageType.CONNECTION_END)) { Messages.ConnectionEnd.SendConnectionEnd(client, "You must authenticate before attempting to send a " + message.type.ToString() + " message"); return; } #if !DEBUG try { #endif switch (message.type) { case ClientMessageType.HEARTBEAT: //Don't do anything for heartbeats, they just keep the connection alive break; case ClientMessageType.HANDSHAKE_RESPONSE: Messages.Handshake.HandleHandshakeResponse(client, message.data); break; case ClientMessageType.CHAT_MESSAGE: Messages.Chat.HandleChatMessage(client, message.data); break; case ClientMessageType.PLAYER_STATUS: Messages.PlayerStatus.HandlePlayerStatus(client, message.data); break; case ClientMessageType.PLAYER_COLOR: Messages.PlayerColor.HandlePlayerColor(client, message.data); break; case ClientMessageType.GROUP: Messages.GroupMessage.HandleMessage(client, message.data); break; case ClientMessageType.SCENARIO_DATA: Messages.ScenarioData.HandleScenarioModuleData(client, message.data); break; case ClientMessageType.SYNC_TIME_REQUEST: Messages.SyncTimeRequest.HandleSyncTimeRequest(client, message.data); break; case ClientMessageType.KERBALS_REQUEST: Messages.KerbalsRequest.HandleKerbalsRequest(client); break; case ClientMessageType.KERBAL_PROTO: Messages.KerbalProto.HandleKerbalProto(client, message.data); break; case ClientMessageType.VESSELS_REQUEST: Messages.VesselRequest.HandleVesselsRequest(client, message.data); break; case ClientMessageType.VESSEL_PROTO: Messages.VesselProto.HandleVesselProto(client, message.data); break; case ClientMessageType.VESSEL_UPDATE: Messages.VesselUpdate.HandleVesselUpdate(client, message.data); break; case ClientMessageType.VESSEL_REMOVE: Messages.VesselRemove.HandleVesselRemoval(client, message.data); break; case ClientMessageType.PERMISSION: Messages.PermissionMessage.HandleMessage(client, message.data); break; case ClientMessageType.CRAFT_LIBRARY: Messages.CraftLibrary.HandleCraftLibrary(client, message.data); break; case ClientMessageType.SCREENSHOT_LIBRARY: Messages.ScreenshotLibrary.HandleScreenshotLibrary(client, message.data); break; case ClientMessageType.FLAG_SYNC: Messages.FlagSync.HandleFlagSync(client, message.data); break; case ClientMessageType.PING_REQUEST: Messages.PingRequest.HandlePingRequest(client, message.data); break; case ClientMessageType.MOTD_REQUEST: Messages.MotdRequest.HandleMotdRequest(client); break; case ClientMessageType.WARP_CONTROL: Messages.WarpControl.HandleWarpControl(client, message.data); break; case ClientMessageType.LOCK_SYSTEM: Messages.LockSystem.HandleLockSystemMessage(client, message.data); break; case ClientMessageType.MOD_DATA: Messages.ModData.HandleModDataMessage(client, message.data); break; case ClientMessageType.KERBAL_REMOVE: Messages.VesselRemove.HandleKerbalRemoval(client, message.data); break; case ClientMessageType.SPLIT_MESSAGE: Messages.SplitMessage.HandleSplitMessage(client, message.data); break; case ClientMessageType.CONNECTION_END: Messages.ConnectionEnd.HandleConnectionEnd(client, message.data); break; case ClientMessageType.MODPACK_DATA: Messages.Modpack.HandleModpackMessage(client, message.data); break; default: DarkLog.Debug("Unhandled message type " + message.type); Messages.ConnectionEnd.SendConnectionEnd(client, "Unhandled message type " + message.type); #if DEBUG throw new NotImplementedException("Message type not implemented"); #else break; #endif } #if !DEBUG } catch (Exception e) { DarkLog.Debug("Error handling " + message.type + " from " + client.playerName + ", exception: " + e); Messages.ConnectionEnd.SendConnectionEnd(client, "Server failed to process " + message.type + " message"); } #endif }
public static void LoadPlugins() { string pluginDirectory = Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "Plugins"); if (!Directory.Exists(pluginDirectory)) { Directory.CreateDirectory(pluginDirectory); } DarkLog.Debug("Loading plugins!"); //Load all the assemblies just in case they depend on each other during instantation List <Assembly> loadedAssemblies = new List <Assembly>(); string[] pluginFiles = Directory.GetFiles(pluginDirectory, "*", SearchOption.AllDirectories); foreach (string pluginFile in pluginFiles) { if (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 Assembly loadedAssembly = Assembly.UnsafeLoadFrom(pluginFile); loadedAssemblies.Add(loadedAssembly); DarkLog.Debug("Loaded " + pluginFile); } catch (NotSupportedException) { //This should only occur if using Assembly.LoadFrom() above instead of Assembly.UnsafeLoadFrom() DarkLog.Debug("Can't load dll, perhaps it is blocked: " + pluginFile); } catch { DarkLog.Debug("Error loading " + pluginFile); } } } //Iterate through the assemblies looking for classes that have the IDMPPlugin interface Type dmpInterfaceType = typeof(IDMPPlugin); foreach (Assembly loadedAssembly in loadedAssemblies) { Type[] loadedTypes = loadedAssembly.GetExportedTypes(); foreach (Type loadedType in loadedTypes) { Type[] typeInterfaces = loadedType.GetInterfaces(); bool containsDMPInterface = false; foreach (Type typeInterface in typeInterfaces) { if (typeInterface == dmpInterfaceType) { containsDMPInterface = true; } } if (containsDMPInterface) { DarkLog.Debug("Loading plugin: " + loadedType.FullName); try { IDMPPlugin pluginInstance = ActivatePluginType(loadedType); if (pluginInstance != null) { DarkLog.Debug("Loaded plugin: " + loadedType.FullName); loadedPlugins.Add(pluginInstance); } } catch (Exception ex) { DarkLog.Error("Error loading plugin " + loadedType.FullName + "(" + loadedType.Assembly.FullName + ") Exception: " + ex.ToString()); } } } } DarkLog.Debug("Done!"); }
public static void ThreadMain() { try { clients = new List <ClientObject>().AsReadOnly(); Messages.WarpControl.Reset(); Messages.Chat.Reset(); Messages.ScreenshotLibrary.Reset(); SetupTCPServer(); while (Server.serverRunning) { //Process current clients foreach (ClientObject client in clients) { Messages.Heartbeat.CheckHeartBeat(client); } ModpackSystem.fetch.SendFilesToClients(); //Check timers NukeKSC.CheckTimer(); Dekessler.CheckTimer(); Messages.WarpControl.CheckTimer(); //Run plugin update DMPPluginHandler.FireOnUpdate(); Thread.Sleep(10); } } catch (Exception e) { DarkLog.Error("Fatal error thrown, exception: " + e); Server.ShutDown("Crashed!"); } try { long disconnectTime = DateTime.UtcNow.Ticks; bool sendingHighPriotityMessages = true; while (sendingHighPriotityMessages) { if ((DateTime.UtcNow.Ticks - disconnectTime) > 50000000) { DarkLog.Debug("Shutting down with " + Server.playerCount + " players, " + clients.Count + " connected clients"); break; } sendingHighPriotityMessages = false; foreach (ClientObject client in clients) { if (client.authenticated && (client.sendMessageQueueHigh.Count > 0)) { sendingHighPriotityMessages = true; } } Thread.Sleep(10); } ShutdownTCPServer(); } catch (Exception e) { DarkLog.Fatal("Fatal error thrown during shutdown, exception: " + e); throw; } }
public static void ThreadMain() { try { //Register commands CommandHandler.RegisterCommand("help", CommandHandler.DisplayHelp, "Displays this help"); CommandHandler.RegisterCommand("say", CommandHandler.Say, "Broadcasts a message to clients"); CommandHandler.RegisterCommand("dekessler", Dekessler.RunDekessler, "Clears out debris from the server"); CommandHandler.RegisterCommand("nukeksc", NukeKSC.RunNukeKSC, "Clears ALL vessels from KSC and the Runway"); CommandHandler.RegisterCommand("listclients", ListClients, "Lists connected clients"); CommandHandler.RegisterCommand("countclients", CountClients, "Counts connected clients"); CommandHandler.RegisterCommand("connectionstats", ConnectionStats, "Displays network traffic usage"); CommandHandler.RegisterCommand("editgroup", Groups.fetch.EditGroupCommand, "Sets the group to edit"); CommandHandler.RegisterCommand("addplayer", Groups.fetch.AddPlayerToGroupCommand, "Adds player to group, first player becomes admin"); CommandHandler.RegisterCommand("removeplayer", Groups.fetch.RemovePlayerFromGroupCommand, "Removes player from group"); CommandHandler.RegisterCommand("addadmin", Groups.fetch.AddPlayerAdminCommand, "Adds admin to group"); CommandHandler.RegisterCommand("removeadmin", Groups.fetch.RemovePlayerAdminCommand, "Removes admin from group"); CommandHandler.RegisterCommand("showgroups", Groups.fetch.ShowGroupsCommand, "Shows group database"); CommandHandler.RegisterCommand("editvessel", Permissions.fetch.EditVesselCommand, "Edits vessel permissions, takes same ID from Universe/Vessels/"); CommandHandler.RegisterCommand("vesselowner", Permissions.fetch.SetVesselOwnerCommand, "Sets a vessel owner"); CommandHandler.RegisterCommand("vesselgroup", Permissions.fetch.SetVesselGroupCommand, "Sets a vessels group"); CommandHandler.RegisterCommand("vesselprotection", Permissions.fetch.SetVesselProtectionCommand, "Sets vessel protection level. Valid levels: public, group, private."); CommandHandler.RegisterCommand("showvessels", Permissions.fetch.ShowVesselsCommand, "Shows vessel protection database"); //Main loop while (Server.serverRunning) { string input = ""; try { input = Console.ReadLine(); if (input == null) { DarkLog.Debug("Terminal may be not attached or broken, Exiting out of command handler"); return; } } catch { if (Server.serverRunning) { DarkLog.Debug("Ignored mono Console.ReadLine() bug"); } Thread.Sleep(500); } DarkLog.Normal("Command input: " + input); if (input.StartsWith("/", StringComparison.Ordinal)) { HandleServerInput(input.Substring(1)); } else { if (input != "") { commands["say"].func(input); } } } } catch (Exception e) { if (Server.serverRunning) { DarkLog.Fatal("Error in command handler thread, Exception: " + e); throw; } } }
public void AdminCommand(string commandArgs) { string func = ""; string playerName = ""; func = commandArgs; if (commandArgs.Contains(" ")) { func = commandArgs.Substring(0, commandArgs.IndexOf(" ")); if (commandArgs.Substring(func.Length).Contains(" ")) { playerName = commandArgs.Substring(func.Length + 1); } } switch (func) { default: DarkLog.Normal("Undefined function. Usage: /admin [add|del] playername or /admin show"); break; case "add": if (File.Exists(Path.Combine(Server.universeDirectory, "Players", playerName + ".txt"))) { if (!serverAdmins.Contains(playerName)) { DarkLog.Debug("Added '" + playerName + "' to admin list."); serverAdmins.Add(playerName); //Notify all players an admin has been added Messages.ServerClient_AdminAddSend msg = new Messages.ServerClient_AdminAddSend(); msg.name = playerName; Broadcast(msg); } else { DarkLog.Normal("'" + playerName + "' is already an admin."); } } else { DarkLog.Normal("'" + playerName + "' does not exist."); } break; case "del": if (serverAdmins.Contains(playerName)) { DarkLog.Normal("Removed '" + playerName + "' from the admin list."); serverAdmins.Remove(playerName); //Notify all players an admin has been removed Messages.ServerClient_AdminRemoveSend msg = new Messages.ServerClient_AdminRemoveSend(); msg.name = playerName; Broadcast(msg); } else { DarkLog.Normal("'" + playerName + "' is not an admin."); } break; case "show": foreach (string player in serverAdmins) { DarkLog.Normal(player); } break; } }
public static void LoadPlugins() { DarkLog.Debug("Loading plugins!"); //Load all the assemblies just in case they depend on each other during instantation List <Assembly> loadedAssemblies = new List <Assembly>(); string[] pluginFiles = Directory.GetFiles(Server.pluginDirectory, "*", SearchOption.AllDirectories); foreach (string pluginFile in pluginFiles) { if (Path.GetExtension(pluginFile).ToLower() == ".dll") { try { Assembly loadedAssembly = Assembly.LoadFile(pluginFile); loadedAssemblies.Add(loadedAssembly); DarkLog.Debug("Loaded " + pluginFile); } catch { DarkLog.Debug("Error loading " + pluginFile); } } } //Add all the event types pluginEvents.Add(typeof(DMPUpdate), new List <Delegate>()); pluginEvents.Add(typeof(DMPOnServerStart), new List <Delegate>()); pluginEvents.Add(typeof(DMPOnServerStop), new List <Delegate>()); pluginEvents.Add(typeof(DMPOnClientConnect), new List <Delegate>()); pluginEvents.Add(typeof(DMPOnClientAuthenticated), new List <Delegate>()); pluginEvents.Add(typeof(DMPOnClientDisconnect), new List <Delegate>()); pluginEvents.Add(typeof(DMPOnMessageReceived), new List <Delegate>()); //Iterate through the assemblies looking for the DMPPlugin attribute foreach (Assembly loadedAssembly in loadedAssemblies) { Type[] loadedTypes = loadedAssembly.GetExportedTypes(); foreach (Type loadedType in loadedTypes) { if (loadedType.IsDefined(typeof(DMPPluginAttribute), false)) { DarkLog.Debug("Loading " + loadedType.Name); object pluginInstance = Activator.CreateInstance(loadedType); MethodInfo[] methodInfos = loadedType.GetMethods(BindingFlags.Public | BindingFlags.Instance); foreach (MethodInfo methodInfo in methodInfos) { try { foreach (Type evT in pluginEvents.Keys) { if (evT.Name.Substring(3) == methodInfo.Name) { DarkLog.Debug("Event registered : " + evT.Name); Delegate deg = Delegate.CreateDelegate(evT, pluginInstance, methodInfo); DMPEventInfo info = new DMPEventInfo(); info.loadedAssembly = loadedAssembly.FullName; info.loadedType = loadedType.Name; delegateInfo.Add(deg, info); pluginEvents[evT].Add(deg); } } } catch (Exception e) { DarkLog.Error("Error loading " + methodInfo.Name + " from " + loadedType.Name + ", Exception: " + e.Message); } } } } } DarkLog.Debug("Done!"); }
public static void HandleCommand(string commandArgs) { string func = ""; string playerName = ""; func = commandArgs; if (commandArgs.Contains(" ")) { func = commandArgs.Substring(0, commandArgs.IndexOf(" ")); if (commandArgs.Substring(func.Length).Contains(" ")) { playerName = commandArgs.Substring(func.Length + 1); } } switch (func) { default: DarkLog.Normal("Undefined function. Usage: /admin [add|del] playername or /admin show"); break; case "add": if (File.Exists(Path.Combine(Server.universeDirectory, "Players", playerName + ".txt"))) { if (!AdminSystem.fetch.IsAdmin(playerName)) { DarkLog.Debug("Added '" + playerName + "' to admin list."); AdminSystem.fetch.AddAdmin(playerName); //Notify all players an admin has been added ServerMessage newMessage = new ServerMessage(); newMessage.type = ServerMessageType.ADMIN_SYSTEM; using (MessageWriter mw = new MessageWriter()) { mw.Write <int>((int)AdminMessageType.ADD); mw.Write <string>(playerName); newMessage.data = mw.GetMessageBytes(); } ClientHandler.SendToAll(null, newMessage, true); } else { DarkLog.Normal("'" + playerName + "' is already an admin."); } } else { DarkLog.Normal("'" + playerName + "' does not exist."); } break; case "del": if (AdminSystem.fetch.IsAdmin(playerName)) { DarkLog.Normal("Removed '" + playerName + "' from the admin list."); AdminSystem.fetch.RemoveAdmin(playerName); //Notify all players an admin has been removed ServerMessage newMessage = new ServerMessage(); newMessage.type = ServerMessageType.ADMIN_SYSTEM; using (MessageWriter mw = new MessageWriter()) { mw.Write <int>((int)AdminMessageType.REMOVE); mw.Write <string>(playerName); newMessage.data = mw.GetMessageBytes(); } ClientHandler.SendToAll(null, newMessage, true); } else { DarkLog.Normal("'" + playerName + "' is not an admin."); } break; case "show": foreach (string player in AdminSystem.fetch.GetAdmins()) { DarkLog.Normal(player); } break; } }
public static void UpdateModcontrolPartList() { if (!File.Exists(Server.modFile)) { return; } bool readingParts = false; string modcontrolVersion = ""; StringBuilder sb = new StringBuilder(); sb.AppendLine("#MODCONTROLVERSION=" + Common.MODCONTROL_VERSION); List <string> stockParts = Common.GetStockParts(); List <string> modParts = new List <string>(); bool partsPrinted = false; using (StreamReader sr = new StreamReader(Server.modFile)) { string currentLine = null; while ((currentLine = sr.ReadLine()) != null) { string trimmedLine = currentLine.Trim(); if (!readingParts) { if (trimmedLine.StartsWith("#MODCONTROLVERSION=")) { modcontrolVersion = trimmedLine.Substring(currentLine.IndexOf("=") + 1); if (modcontrolVersion == Common.MODCONTROL_VERSION) { //Mod control file is up to date. return; } } else { sb.AppendLine(currentLine); } if (trimmedLine == "!partslist") { readingParts = true; } } else { if (trimmedLine.StartsWith("#") || trimmedLine == string.Empty) { sb.AppendLine(currentLine); continue; } //This is an edge case, but it's still possible if someone moves something manually. if (trimmedLine.StartsWith("!")) { if (!partsPrinted) { partsPrinted = true; foreach (string stockPart in stockParts) { sb.AppendLine(stockPart); } foreach (string modPart in modParts) { sb.AppendLine(modPart); } } readingParts = false; sb.AppendLine(currentLine); continue; } if (!stockParts.Contains(currentLine)) { modParts.Add(currentLine); } } } } if (!partsPrinted) { partsPrinted = true; foreach (string stockPart in stockParts) { sb.AppendLine(stockPart); } foreach (string modPart in modParts) { sb.AppendLine(modPart); } } File.WriteAllText(Server.modFile + ".new", sb.ToString()); File.Copy(Server.modFile + ".new", Server.modFile, true); File.Delete(Server.modFile + ".new"); DarkLog.Debug("Added " + Common.MODCONTROL_VERSION + " parts to modcontrol.txt"); }
private static void StopMeshServer() { DarkLog.Debug("Stopping mesh server"); meshServer.Shutdown(); meshServerThread = null; }
public void Load() { if (Settings.settingsStore.modpackMode == DarkMultiPlayerCommon.ModpackMode.GAMEDATA) { DarkLog.Debug("Loading GameData mod list"); if (File.Exists(modpackServerCacheObjects)) { File.Delete(modpackServerCacheObjects); } hashCount = 0; modpackData.Clear(); objectData.Clear(); string[] modFiles = Directory.GetFiles(modpackPath, "*", SearchOption.AllDirectories); foreach (string filePath in modFiles) { hashCount++; if (!filePath.ToLower().StartsWith(modpackPath.ToLower(), StringComparison.Ordinal)) { DarkLog.Error("Not adding file that is in GameData, symlinks are not supported."); DarkLog.Error("File was: " + filePath); continue; } string trimmedPath = filePath.Substring(modpackPath.Length + 1).Replace('\\', '/'); bool skipFile = false; foreach (string excludePath in excludeList) { if (trimmedPath.ToLower().StartsWith(excludePath, StringComparison.Ordinal)) { skipFile = true; } } foreach (string excludePath in containsExcludeList) { if (trimmedPath.ToLower().Contains(excludePath)) { skipFile = true; } } if (skipFile) { continue; } string sha256sum = Common.CalculateSHA256Hash(filePath); if (!modpackData.ContainsKey(trimmedPath)) { if (DateTime.UtcNow.Ticks > nextHashTime) { nextHashTime = DateTime.UtcNow.Ticks + TimeSpan.TicksPerSecond; DarkLog.Debug("Hashing: " + hashCount + "/" + modFiles.Length); } modpackData.Add(trimmedPath, sha256sum); } //Need to check because we may have a duplicate file in GameData if (!objectData.ContainsKey(sha256sum)) { objectData.Add(sha256sum, trimmedPath); } } DarkLog.Debug("Hashed " + modFiles.Length + " files"); using (StreamWriter sw = new StreamWriter(modpackServerCacheObjects)) { foreach (KeyValuePair <string, string> kvp in modpackData) { sw.WriteLine("{0}={1}", kvp.Key, kvp.Value); } } } }