static void Main(string[] args) { Console.Title = "MLAPI.Relay"; string configPath = Path.Combine(Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location), "config.json"); RelayConfig relayConfig = null; if (!File.Exists(configPath)) { Console.WriteLine("================================"); Console.WriteLine("There is no config. Please select a template for the config file:"); Console.WriteLine("[M]LAPI"); Console.WriteLine("[H]LAPI"); Console.WriteLine("[E]mpty"); ConsoleKey key = ConsoleKey.Escape; do { key = Console.ReadKey(true).Key; }while (key != ConsoleKey.M && key != ConsoleKey.H && key != ConsoleKey.E); if (key == ConsoleKey.M) { ConnectionConfig cConfig = new ConnectionConfig() { SendDelay = 0 }; cConfig.AddChannel(QosType.ReliableFragmentedSequenced); cConfig.AddChannel(QosType.StateUpdate); cConfig.AddChannel(QosType.ReliableSequenced); cConfig.AddChannel(QosType.ReliableSequenced); cConfig.AddChannel(QosType.StateUpdate); cConfig.AddChannel(QosType.Unreliable); relayConfig = new RelayConfig() { bufferSize = 4096, connectionConfig = cConfig, globalConfig = new GlobalConfig(), maxConnections = ushort.MaxValue - 1, relayPort = 8888 }; } else if (key == ConsoleKey.H) { ConnectionConfig cConfig = new ConnectionConfig(); cConfig.AddChannel(QosType.ReliableSequenced); cConfig.AddChannel(QosType.Unreliable); relayConfig = new RelayConfig() { bufferSize = 4096, connectionConfig = cConfig, globalConfig = new GlobalConfig(), maxConnections = ushort.MaxValue - 1, relayPort = 8888 }; } else if (key == ConsoleKey.E) { ConnectionConfig cConfig = new ConnectionConfig(); relayConfig = new RelayConfig() { bufferSize = 1024, connectionConfig = cConfig, globalConfig = new GlobalConfig(), maxConnections = ushort.MaxValue - 1, relayPort = 8888 }; } relayConfig.UnSetChannels(); File.WriteAllText(configPath, JsonConvert.SerializeObject(relayConfig, Formatting.Indented).Replace(@", ""ChannelCount"": 0, ""SharedOrderChannelCount"": 0, ""Channels"": []", "")); } else { try { relayConfig = JsonConvert.DeserializeObject <RelayConfig>(File.ReadAllText(configPath)); relayConfig.SetChannels(); } catch (Exception ex) { Console.ForegroundColor = ConsoleColor.Red; Console.WriteLine("[ERROR] Error parsing config file: " + ex.Message); Console.Read(); return; } } try { Start(relayConfig); } catch (DllNotFoundException e) { ReportError("[FATAL] Could not locate one or more shared libraries! Message: \n" + e.Message); } catch (Exception e) { ReportError("[FATAL] An unexpected error occurred! Message: \n" + e.Message); } }
static void Start(RelayConfig rConfig) { RelayConfig.CurrentConfig = rConfig; Console.WriteLine("================================"); Console.WriteLine("[INFO] Starting relay..."); unet = new NetLibraryManager(rConfig.globalConfig); messageBuffer = new byte[RelayConfig.CurrentConfig.bufferSize]; HostTopology hostTopology = new HostTopology(RelayConfig.CurrentConfig.connectionConfig, RelayConfig.CurrentConfig.maxConnections); unet.AddHost(hostTopology, RelayConfig.CurrentConfig.relayPort, null); Console.WriteLine("[INFO] Relay started!"); Console.WriteLine("[INFO] Press [Q] to quit the application"); while ((!Console.KeyAvailable || Console.ReadKey(true).Key != ConsoleKey.Q)) { NetworkEventType @event = unet.Receive(out int hostId, out int connectionId, out int channelId, messageBuffer, RelayConfig.CurrentConfig.bufferSize, out int receivedSize, out byte errorByte); NetworkError error = (NetworkError)errorByte; if (error != NetworkError.Ok) { ConsoleColor previousColor = Console.ForegroundColor; Console.ForegroundColor = ConsoleColor.Red; Console.WriteLine("[ERROR] Relay encountered UNET transport error \"" + error.ToString() + "\" during a \"" + @event.ToString() + "\" event."); Console.ForegroundColor = previousColor; } switch (@event) { case NetworkEventType.DataEvent: { MessageType mType = (MessageType)messageBuffer[receivedSize - 1]; switch (mType) { case MessageType.StartServer: { //Check if they are already connected or perhaps are already hosting, if so return Client client; Room room = new Room(client = new Client() { connectionId = (ushort)connectionId, hostId = (byte)hostId, isServer = true, connectTick = DateTime.UtcNow.Ticks }); rooms.Add(room); unet.GetConnectionInfo(hostId, connectionId, out string address, out int port, out byte byteError); if (RelayConfig.CurrentConfig.enableRuntimeMetaLogging) { Console.WriteLine("[INFO] Server started from address " + address); } addressToRoom.Add(address + ":" + port, room); } break; case MessageType.ConnectToServer: { //Check if they are already connected or perhaps are already hosting; if so, return byte addressLength = (byte)(receivedSize - 1); //messageBuffer[1]; // address length + ip type string addressAndPort = Encoding.ASCII.GetString(messageBuffer, 0, addressLength); addressAndPort = addressAndPort.AsIPv6CompatString(); if (RelayConfig.CurrentConfig.enableRuntimeMetaLogging) { Console.WriteLine("[INFO] Connection requested to address " + addressAndPort); } if (addressToRoom.ContainsKey(addressAndPort)) { if (RelayConfig.CurrentConfig.enableRuntimeMetaLogging) { Console.WriteLine("[INFO] Connection approved"); } Room room = addressToRoom[addressAndPort]; Client client = new Client() { connectionId = (ushort)connectionId, hostId = (byte)hostId, isServer = false, connectTick = DateTime.UtcNow.Ticks }; room.HandleClientConnect(client); } } break; case MessageType.Data: { foreach (var room in rooms) { if (room.HasPeer((ushort)connectionId, out bool isServer)) { // Found a matching client in room if (isServer) { ushort destination = (ushort)(messageBuffer[receivedSize - 3] | (messageBuffer[receivedSize - 2] << 8)); //Safety check. Make sure who they want to send to ACTUALLY belongs to their room if (room.HasPeer(destination, out isServer) && !isServer) { // TODO: Use unsafe to make messageBuffer look smaller //ReverseOffset(messageBuffer, 2, receivedSize); messageBuffer[receivedSize - 3] = (byte)MessageType.Data; // [data, data, data, dest1, dest2, mtype_r, none, none, none] => [{data, data, data, mtype_s}, dest2, mtype_r, none, none, none] room.Send(hostId, destination, connectionId, channelId, messageBuffer, receivedSize - 2, out errorByte); } } else { // Read client message //ForwardOffset(messageBuffer, 2, receivedSize); messageBuffer.ToBytes((ushort)connectionId, receivedSize - 1); // Put connection id at the end of the recieved message (because optimization) messageBuffer[receivedSize + 1] = (byte)MessageType.Data; // Set message type room.Send(hostId, room.ServerID, connectionId, channelId, messageBuffer, receivedSize + 2, out errorByte); } } } } break; case MessageType.ClientDisconnect: { ushort cid = messageBuffer.FromBytes(1); if (RelayConfig.CurrentConfig.enableRuntimeMetaLogging) { Console.WriteLine("[INFO] Client disconnect request"); } foreach (Room room in rooms) { if (room.HandleClientDisconnect((ushort)cid, true)) { --connectedPeers; break; } } } break; } } break; case NetworkEventType.DisconnectEvent: { if (RelayConfig.CurrentConfig.enableRuntimeMetaLogging) { Console.WriteLine("[INFO] Peer disconnected"); } foreach (Room room in rooms) { if (room.HandleClientDisconnect((ushort)connectionId)) { --connectedPeers; break; } } } break; case NetworkEventType.Nothing: Thread.Sleep(1); break; case NetworkEventType.ConnectEvent: { connectedPeers++; } break; } if (lastConnectedClients != connectedPeers && (DateTime.UtcNow.Ticks - lastPrintedConnectedClientsTick) > 30 * TimeSpan.TicksPerSecond) { lastPrintedConnectedClientsTick = DateTime.UtcNow.Ticks; lastConnectedClients = connectedPeers; PrintStatusUpdate(); } } Console.WriteLine("[INFO] Relay shutting down..."); }