diff options
Diffstat (limited to 'ShiftOS_TheReturn/ServerManager.cs')
| -rw-r--r-- | ShiftOS_TheReturn/ServerManager.cs | 236 |
1 files changed, 190 insertions, 46 deletions
diff --git a/ShiftOS_TheReturn/ServerManager.cs b/ShiftOS_TheReturn/ServerManager.cs index 3059391..abb674d 100644 --- a/ShiftOS_TheReturn/ServerManager.cs +++ b/ShiftOS_TheReturn/ServerManager.cs @@ -34,26 +34,60 @@ using System.Threading; using ShiftOS; using static ShiftOS.Engine.SaveSystem; using Newtonsoft.Json; +using System.Net.Sockets; +using System.Diagnostics; +using System.IO; +using System.Reflection; namespace ShiftOS.Engine { + /// <summary> + /// Digital Society connection management class. + /// </summary> public static class ServerManager { + /// <summary> + /// Print connection diagnostic information. + /// </summary> public static void PrintDiagnostics() { Console.WriteLine($@"{{CLIENT_DIAGNOSTICS}} {{GUID}}: {thisGuid} +Ping: {ServerManager.DigitalSocietyPing} ms {{CLIENT_DATA}}: {JsonConvert.SerializeObject(client, Formatting.Indented)}"); } + /// <summary> + /// Gets the unique identifier for this Digital Society connection. This can be used for peer-to-peer communication between two clients. + /// </summary> public static Guid thisGuid { get; private set; } - private static NetObjectClient client { get; set; } + /// <summary> + /// Gets the underlying NetSockets client for this connection. + /// </summary> + public static NetObjectClient client { get; private set; } + + + private static bool UserDisconnect = false; + + /// <summary> + /// Gets or sets the server response time for the last request made by this client. + /// </summary> + public static long DigitalSocietyPing + { + get; + private set; + } + + /// <summary> + /// Disconnect from the digital society intentionally. + /// </summary> public static void Disconnect() { + UserDisconnect = true; if (client != null) { client.Disconnect(); @@ -62,38 +96,59 @@ namespace ShiftOS.Engine } + /// <summary> + /// Occurs when you are disconnected from the Digital Society. + /// </summary> public static event EmptyEventHandler Disconnected; - - public static void InitiateMUDHack() + + /// <summary> + /// Occurs when the unique ID for this client is sent by the server. + /// </summary> + public static event Action<string> GUIDReceived; + + private static void delegateToServer(ServerMessage msg) { - MessageReceived += ServerManager_MessageReceived; - SendMessage("mudhack_init", ""); + string[] split = msg.GUID.Split('|'); + bool finished = false; + foreach (var exec in Directory.GetFiles(Environment.CurrentDirectory)) + { + if(exec.ToLower().EndsWith(".exe") || exec.ToLower().EndsWith(".dll")) + { + try + { + var asm = Assembly.LoadFile(exec); + foreach(var type in asm.GetTypes().Where(x => x.GetInterfaces().Contains(typeof(Server)))) + { + var attrib = type.GetCustomAttributes().FirstOrDefault(x => x is ServerAttribute) as ServerAttribute; + if(attrib != null) + { + if(split[0] == SaveSystem.CurrentSave.SystemName && split[1] == attrib.Port.ToString()) + { + if (Shiftorium.UpgradeAttributesUnlocked(type)) + { + type.GetMethods(BindingFlags.Public | BindingFlags.Instance).FirstOrDefault(x => x.Name == "MessageReceived")?.Invoke(Activator.CreateInstance(type), null); + finished = true; + } + } + } + } + } + catch { } + } + } + if (finished == false) + { + Forward(split[2], "Error", $"{split[0]}:{split[1]}: connection refused"); + } } - public static event Action<string> ServerPasswordGenerated; - public static event EmptyEventHandler ServerAccessGranted; - public static event EmptyEventHandler ServerAccessDenied; - public static event Action<string> GUIDReceived; - public static event Action<List<OnlineUser>> UsersReceived; private static void ServerManager_MessageReceived(ServerMessage msg) { switch(msg.Name) { - case "mudhack_users": - UsersReceived?.Invoke(JsonConvert.DeserializeObject<List<OnlineUser>>(msg.Contents)); - break; - case "mudhack_init": - ServerPasswordGenerated?.Invoke(msg.Contents); - break; - case "mudhack_denied": - ServerAccessDenied?.Invoke(); - break; - case "mudhack_granted": - ServerAccessGranted?.Invoke(); - break; case "getguid_fromserver": - if(SaveSystem.CurrentSave.Username == msg.Contents) + if(SaveSystem.CurrentUser.Username == msg.Contents) { client.Send(new NetObject("yes_i_am", new ServerMessage { @@ -103,33 +158,93 @@ namespace ShiftOS.Engine })); } break; + case "msgtosys": + try + { + var m = JsonConvert.DeserializeObject<ServerMessage>(msg.Contents); + if(m.GUID.Split('|')[2] != thisGuid.ToString()) + { + delegateToServer(m); + } + } + catch { } + break; case "getguid_reply": GUIDReceived?.Invoke(msg.Contents); break; } } + public static void SendMessageToIngameServer(string sysname, int port, string title, string contents) + { + var smsg = new ServerMessage + { + Name = title, + GUID = $"{sysname}|{port}|{thisGuid.ToString()}", + Contents = contents + }; + Forward("all", "msgtosys", JsonConvert.SerializeObject(smsg)); + + } + public static void Detach_ServerManager_MessageReceived() { MessageReceived -= new ServerMessageReceived(ServerManager_MessageReceived); } + /// <summary> + /// Initiate a new Digital Society connection. + /// </summary> + /// <param name="mud_address">The IP address or hostname of the target server</param> + /// <param name="port">The target port.</param> public static void Initiate(string mud_address, int port) { client = new NetObjectClient(); - + client.OnDisconnected += (o, a) => + { + if (!UserDisconnect) + { + Desktop.PushNotification("digital_society_connection", "Disconnected from Digital Society.", "The ShiftOS kernel has been disconnected from the Digital Society. We are attempting to re-connect you."); + TerminalBackend.PrefixEnabled = true; + ConsoleEx.ForegroundColor = ConsoleColor.Red; + ConsoleEx.Bold = true; + Console.Write($@"Disconnected from MUD: "); + ConsoleEx.Bold = false; + ConsoleEx.Italic = true; + ConsoleEx.ForegroundColor = ConsoleColor.DarkYellow; + Console.WriteLine("You have been disconnected from the multi-user domain for an unknown reason. Your save data is preserved within the kernel and you will be reconnected shortly."); + TerminalBackend.PrefixEnabled = true; + TerminalBackend.PrintPrompt(); + Initiate(mud_address, port); + } + }; client.OnReceived += (o, a) => { + if (PingTimer.IsRunning) + { + DigitalSocietyPing = PingTimer.ElapsedMilliseconds; + PingTimer.Reset(); + } var msg = a.Data.Object as ServerMessage; if (msg.Name == "Welcome") { thisGuid = new Guid(msg.Contents); GUIDReceived?.Invoke(msg.Contents); + TerminalBackend.PrefixEnabled = true; + TerminalBackend.PrintPrompt(); + } + else if(msg.Name == "allusers") + { + foreach(var acc in JsonConvert.DeserializeObject<string[]>(msg.Contents)) + { + Console.WriteLine(acc); + } + TerminalBackend.PrintPrompt(); } else if(msg.Name == "update_your_cp") { var args = JsonConvert.DeserializeObject<Dictionary<string, object>>(msg.Contents); - if(args["username"] as string == SaveSystem.CurrentSave.Username) + if(args["username"] as string == SaveSystem.CurrentUser.Username) { SaveSystem.CurrentSave.Codepoints += (long)args["amount"]; Desktop.InvokeOnWorkerThread(new Action(() => @@ -143,13 +258,23 @@ namespace ShiftOS.Engine { Console.WriteLine(msg.Contents); } + else if(msg.Name == "forward") + { + MessageReceived?.Invoke(JsonConvert.DeserializeObject<ServerMessage>(msg.Contents)); + } else if (msg.Name == "Error") { var ex = JsonConvert.DeserializeObject<Exception>(msg.Contents); TerminalBackend.PrefixEnabled = true; - Console.WriteLine($@"{{MUD_ERROR}}: {ex.Message}"); + ConsoleEx.ForegroundColor = ConsoleColor.Red; + ConsoleEx.Bold = true; + Console.Write($@"{{MUD_ERROR}}: "); + ConsoleEx.Bold = false; + ConsoleEx.Italic = true; + ConsoleEx.ForegroundColor = ConsoleColor.DarkYellow; + Console.WriteLine(ex.Message); TerminalBackend.PrefixEnabled = true; - Console.Write($"{SaveSystem.CurrentSave.Username}@{CurrentSave.SystemName}:~$ "); + TerminalBackend.PrintPrompt(); } else { @@ -157,10 +282,24 @@ namespace ShiftOS.Engine } }; - client.Connect(mud_address, port); - + try + { + client.Connect(mud_address, port); + } + catch(SocketException ex) + { + System.Diagnostics.Debug.Print(ex.ToString()); + Initiate(mud_address, port); + } } + private static Stopwatch PingTimer = new Stopwatch(); + + /// <summary> + /// Send a message to the server. + /// </summary> + /// <param name="name">The message name</param> + /// <param name="contents">The message body</param> public static void SendMessage(string name, string contents) { var sMsg = new ServerMessage @@ -169,7 +308,7 @@ namespace ShiftOS.Engine Contents = contents, GUID = thisGuid.ToString(), }; - + PingTimer.Start(); client.Send(new NetObject("msg", sMsg)); } @@ -177,28 +316,33 @@ namespace ShiftOS.Engine private static bool singleplayer = false; public static bool IsSingleplayer { get { return singleplayer; } } - public static void StartLANServer() + /// <summary> + /// Occurs when the server sends a message to this client. + /// </summary> + public static event ServerMessageReceived MessageReceived; + + /// <summary> + /// Send a message to another client. + /// </summary> + /// <param name="targetGUID">The target client GUID.</param> + /// <param name="title">The message title</param> + /// <param name="message">The message contents</param> + public static void Forward(string targetGUID, string title, string message) { - singleplayer = true; - ShiftOS.Server.Program.ServerStarted += (address) => + var smsg = new ServerMessage { - Console.WriteLine($"Connecting to {address}..."); - Initiate(address, 13370); + GUID = targetGUID, + Name = title, + Contents = message }; - Disconnected += () => - { - ShiftOS.Server.Program.Stop(); - }; - ShiftOS.Server.Program.Main(new[] { "" }); - - + ServerManager.SendMessage("mud_forward", JsonConvert.SerializeObject(smsg)); } - - - public static event ServerMessageReceived MessageReceived; - } + /// <summary> + /// Delegate for handling server messages + /// </summary> + /// <param name="msg">A server message containing the protocol message name, GUID of the sender, and the contents of the message.</param> public delegate void ServerMessageReceived(ServerMessage msg); public class MultiplayerOnlyAttribute : Attribute |
