From 6793245822cea8c345525fa3ea892717a4221a18 Mon Sep 17 00:00:00 2001 From: Derek S <44935661+Derek-R-S@users.noreply.github.com> Date: Mon, 5 Apr 2021 23:18:44 -0500 Subject: [PATCH] Partials and Comments --- .../LRM/Endpoint.cs | 3 +- .../LRM/{ => Program}/Program.cs | 98 +---- .../LRM/Program/ProgramExtra.cs | 38 ++ .../LRM/Program/ProgramNATHandler.cs | 50 +++ .../LRM/Program/ProgramVariables.cs | 36 ++ .../LRM/RelayHandler.cs | 349 ------------------ .../LRM/RelayHandler/RelayHandler.cs | 113 ++++++ .../LRM/RelayHandler/RelayHandlerCallbacks.cs | 110 ++++++ .../RelayHandler/RelayHandlerRoomMethods.cs | 199 ++++++++++ .../LRM/RelayHandler/RelayHandlerVariables.cs | 13 + 10 files changed, 562 insertions(+), 447 deletions(-) rename ServerProject-DONT-IMPORT-INTO-UNITY/LRM/{ => Program}/Program.cs (74%) create mode 100644 ServerProject-DONT-IMPORT-INTO-UNITY/LRM/Program/ProgramExtra.cs create mode 100644 ServerProject-DONT-IMPORT-INTO-UNITY/LRM/Program/ProgramNATHandler.cs create mode 100644 ServerProject-DONT-IMPORT-INTO-UNITY/LRM/Program/ProgramVariables.cs delete mode 100644 ServerProject-DONT-IMPORT-INTO-UNITY/LRM/RelayHandler.cs create mode 100644 ServerProject-DONT-IMPORT-INTO-UNITY/LRM/RelayHandler/RelayHandler.cs create mode 100644 ServerProject-DONT-IMPORT-INTO-UNITY/LRM/RelayHandler/RelayHandlerCallbacks.cs create mode 100644 ServerProject-DONT-IMPORT-INTO-UNITY/LRM/RelayHandler/RelayHandlerRoomMethods.cs create mode 100644 ServerProject-DONT-IMPORT-INTO-UNITY/LRM/RelayHandler/RelayHandlerVariables.cs diff --git a/ServerProject-DONT-IMPORT-INTO-UNITY/LRM/Endpoint.cs b/ServerProject-DONT-IMPORT-INTO-UNITY/LRM/Endpoint.cs index 86af7ac..fddac18 100644 --- a/ServerProject-DONT-IMPORT-INTO-UNITY/LRM/Endpoint.cs +++ b/ServerProject-DONT-IMPORT-INTO-UNITY/LRM/Endpoint.cs @@ -6,6 +6,7 @@ using Microsoft.Extensions.Logging; using Newtonsoft.Json; using System; using System.Collections.Generic; +using System.Linq; using System.Threading.Tasks; namespace LightReflectiveMirror.Endpoints @@ -22,7 +23,7 @@ namespace LightReflectiveMirror.Endpoints [RestResource] public class Endpoint { - private List _rooms { get => Program.instance.GetRooms(); } + private List _rooms { get => Program.instance.GetRooms().Where(x => x.isPublic).ToList(); } private RelayStats _stats { get => new RelayStats { diff --git a/ServerProject-DONT-IMPORT-INTO-UNITY/LRM/Program.cs b/ServerProject-DONT-IMPORT-INTO-UNITY/LRM/Program/Program.cs similarity index 74% rename from ServerProject-DONT-IMPORT-INTO-UNITY/LRM/Program.cs rename to ServerProject-DONT-IMPORT-INTO-UNITY/LRM/Program/Program.cs index bc4d8f3..62fa926 100644 --- a/ServerProject-DONT-IMPORT-INTO-UNITY/LRM/Program.cs +++ b/ServerProject-DONT-IMPORT-INTO-UNITY/LRM/Program/Program.cs @@ -13,32 +13,8 @@ using Newtonsoft.Json; namespace LightReflectiveMirror { - class Program + partial class Program { - public static Transport transport; - public static Program instance; - public static Config conf; - - private RelayHandler _relay; - private MethodInfo _awakeMethod; - private MethodInfo _startMethod; - private MethodInfo _updateMethod; - private MethodInfo _lateUpdateMethod; - - private DateTime _startupTime; - public static string publicIP; - private List _currentConnections = new List(); - public Dictionary NATConnections = new Dictionary(); - private BiDictionary _pendingNATPunches = new BiDictionary(); - private int _currentHeartbeatTimer = 0; - - private byte[] _NATRequest = new byte[500]; - private int _NATRequestPosition = 0; - - private UdpClient _punchServer; - - private const string CONFIG_PATH = "config.json"; - public static void Main(string[] args) => new Program().MainAsync().GetAwaiter().GetResult(); public int GetConnections() => _currentConnections.Count; @@ -245,57 +221,6 @@ namespace LightReflectiveMirror } - void RunNATPunchLoop() - { - WriteLogMessage("OK\n", ConsoleColor.Green); - IPEndPoint remoteEndpoint = new(IPAddress.Any, conf.NATPunchtroughPort); - - // Stock Data server sends to everyone: - var serverResponse = new byte[1] { 1 }; - - byte[] readData; - bool isConnectionEstablishment; - int pos; - string connectionID; - - while (true) - { - readData = _punchServer.Receive(ref remoteEndpoint); - pos = 0; - try - { - isConnectionEstablishment = readData.ReadBool(ref pos); - - if (isConnectionEstablishment) - { - connectionID = readData.ReadString(ref pos); - - if (_pendingNATPunches.TryGetBySecond(connectionID, out pos)) - { - NATConnections.Add(pos, new IPEndPoint(remoteEndpoint.Address, remoteEndpoint.Port)); - _pendingNATPunches.Remove(pos); - Console.WriteLine("Client Successfully Established Puncher Connection. " + remoteEndpoint.ToString()); - } - } - - _punchServer.Send(serverResponse, 1, remoteEndpoint); - } - catch - { - // ignore, packet got fucked up or something. - } - } - } - - static void WriteLogMessage(string message, ConsoleColor color = ConsoleColor.White, bool oneLine = false) - { - Console.ForegroundColor = color; - if (oneLine) - Console.Write(message); - else - Console.WriteLine(message); - } - void CheckMethods(Type type) { _awakeMethod = type.GetMethod("Awake", BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic); @@ -303,26 +228,5 @@ namespace LightReflectiveMirror _updateMethod = type.GetMethod("Update", BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic); _lateUpdateMethod = type.GetMethod("LateUpdate", BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic); } - - void WriteTitle() - { - string t = @" - w c(..)o ( - _ _____ __ __ \__(-) __) - | | | __ \ | \/ | /\ ( - | | | |__) || \ / | /(_)___) - | | | _ / | |\/| | w /| - | |____ | | \ \ | | | | | \ - |______||_| \_\|_| |_| m m copyright monkesoft 2021 - -"; - - string load = $"Chimp Event Listener Initializing... OK" + - "\nHarambe Memorial Initializing... OK" + - "\nBananas Initializing... OK\n"; - - WriteLogMessage(t, ConsoleColor.Green); - WriteLogMessage(load, ConsoleColor.Cyan); - } } } diff --git a/ServerProject-DONT-IMPORT-INTO-UNITY/LRM/Program/ProgramExtra.cs b/ServerProject-DONT-IMPORT-INTO-UNITY/LRM/Program/ProgramExtra.cs new file mode 100644 index 0000000..b2d830a --- /dev/null +++ b/ServerProject-DONT-IMPORT-INTO-UNITY/LRM/Program/ProgramExtra.cs @@ -0,0 +1,38 @@ +using System; + +namespace LightReflectiveMirror +{ + partial class Program + { + + static void WriteLogMessage(string message, ConsoleColor color = ConsoleColor.White, bool oneLine = false) + { + Console.ForegroundColor = color; + if (oneLine) + Console.Write(message); + else + Console.WriteLine(message); + } + + void WriteTitle() + { + string t = @" + w c(..)o ( + _ _____ __ __ \__(-) __) + | | | __ \ | \/ | /\ ( + | | | |__) || \ / | /(_)___) + | | | _ / | |\/| | w /| + | |____ | | \ \ | | | | | \ + |______||_| \_\|_| |_| m m copyright monkesoft 2021 + +"; + + string load = $"Chimp Event Listener Initializing... OK" + + "\nHarambe Memorial Initializing... OK" + + "\nBananas Initializing... OK\n"; + + WriteLogMessage(t, ConsoleColor.Green); + WriteLogMessage(load, ConsoleColor.Cyan); + } + } +} diff --git a/ServerProject-DONT-IMPORT-INTO-UNITY/LRM/Program/ProgramNATHandler.cs b/ServerProject-DONT-IMPORT-INTO-UNITY/LRM/Program/ProgramNATHandler.cs new file mode 100644 index 0000000..968cc15 --- /dev/null +++ b/ServerProject-DONT-IMPORT-INTO-UNITY/LRM/Program/ProgramNATHandler.cs @@ -0,0 +1,50 @@ +using System; +using System.Net; + +namespace LightReflectiveMirror +{ + partial class Program + { + void RunNATPunchLoop() + { + WriteLogMessage("OK\n", ConsoleColor.Green); + IPEndPoint remoteEndpoint = new(IPAddress.Any, conf.NATPunchtroughPort); + + // Stock Data server sends to everyone: + var serverResponse = new byte[1] { 1 }; + + byte[] readData; + bool isConnectionEstablishment; + int pos; + string connectionID; + + while (true) + { + readData = _punchServer.Receive(ref remoteEndpoint); + pos = 0; + try + { + isConnectionEstablishment = readData.ReadBool(ref pos); + + if (isConnectionEstablishment) + { + connectionID = readData.ReadString(ref pos); + + if (_pendingNATPunches.TryGetBySecond(connectionID, out pos)) + { + NATConnections.Add(pos, new IPEndPoint(remoteEndpoint.Address, remoteEndpoint.Port)); + _pendingNATPunches.Remove(pos); + Console.WriteLine("Client Successfully Established Puncher Connection. " + remoteEndpoint.ToString()); + } + } + + _punchServer.Send(serverResponse, 1, remoteEndpoint); + } + catch + { + // ignore, packet got fucked up or something. + } + } + } + } +} diff --git a/ServerProject-DONT-IMPORT-INTO-UNITY/LRM/Program/ProgramVariables.cs b/ServerProject-DONT-IMPORT-INTO-UNITY/LRM/Program/ProgramVariables.cs new file mode 100644 index 0000000..44f1f6f --- /dev/null +++ b/ServerProject-DONT-IMPORT-INTO-UNITY/LRM/Program/ProgramVariables.cs @@ -0,0 +1,36 @@ +using Mirror; +using System; +using System.Collections.Generic; +using System.Net; +using System.Net.Sockets; +using System.Reflection; + +namespace LightReflectiveMirror +{ + partial class Program + { + public static Transport transport; + public static Program instance; + public static Config conf; + + private RelayHandler _relay; + private MethodInfo _awakeMethod; + private MethodInfo _startMethod; + private MethodInfo _updateMethod; + private MethodInfo _lateUpdateMethod; + + private DateTime _startupTime; + public static string publicIP; + private List _currentConnections = new List(); + public Dictionary NATConnections = new Dictionary(); + private BiDictionary _pendingNATPunches = new BiDictionary(); + private int _currentHeartbeatTimer = 0; + + private byte[] _NATRequest = new byte[500]; + private int _NATRequestPosition = 0; + + private UdpClient _punchServer; + + private const string CONFIG_PATH = "config.json"; + } +} diff --git a/ServerProject-DONT-IMPORT-INTO-UNITY/LRM/RelayHandler.cs b/ServerProject-DONT-IMPORT-INTO-UNITY/LRM/RelayHandler.cs deleted file mode 100644 index 1fb61e6..0000000 --- a/ServerProject-DONT-IMPORT-INTO-UNITY/LRM/RelayHandler.cs +++ /dev/null @@ -1,349 +0,0 @@ -using System; -using System.Buffers; -using System.Collections.Generic; -using System.Net; -using System.Text; - -namespace LightReflectiveMirror -{ - public class RelayHandler - { - public List rooms = new List(); - private List _pendingAuthentication = new List(); - private ArrayPool _sendBuffers; - private int _maxPacketSize = 0; - - public RelayHandler(int maxPacketSize) - { - this._maxPacketSize = maxPacketSize; - _sendBuffers = ArrayPool.Create(maxPacketSize, 50); - } - - public void ClientConnected(int clientId) - { - _pendingAuthentication.Add(clientId); - var buffer = _sendBuffers.Rent(1); - int pos = 0; - buffer.WriteByte(ref pos, (byte)OpCodes.AuthenticationRequest); - Program.transport.ServerSend(clientId, 0, new ArraySegment(buffer, 0, pos)); - _sendBuffers.Return(buffer); - } - - public void HandleMessage(int clientId, ArraySegment segmentData, int channel) - { - try - { - var data = segmentData.Array; - int pos = segmentData.Offset; - - OpCodes opcode = (OpCodes)data.ReadByte(ref pos); - - if (_pendingAuthentication.Contains(clientId)) - { - if (opcode == OpCodes.AuthenticationResponse) - { - string authResponse = data.ReadString(ref pos); - if (authResponse == Program.conf.AuthenticationKey) - { - _pendingAuthentication.Remove(clientId); - int writePos = 0; - var sendBuffer = _sendBuffers.Rent(1); - sendBuffer.WriteByte(ref writePos, (byte)OpCodes.Authenticated); - Program.transport.ServerSend(clientId, 0, new ArraySegment(sendBuffer, 0, writePos)); - } - } - return; - } - - switch (opcode) - { - case OpCodes.CreateRoom: - CreateRoom(clientId, data.ReadInt(ref pos), data.ReadString(ref pos), data.ReadBool(ref pos), data.ReadString(ref pos), data.ReadBool(ref pos), data.ReadString(ref pos), data.ReadBool(ref pos), data.ReadInt(ref pos)); - break; - case OpCodes.RequestID: - SendClientID(clientId); - break; - case OpCodes.LeaveRoom: - LeaveRoom(clientId); - break; - case OpCodes.JoinServer: - JoinRoom(clientId, data.ReadInt(ref pos), data.ReadBool(ref pos), data.ReadString(ref pos)); - break; - case OpCodes.KickPlayer: - LeaveRoom(data.ReadInt(ref pos), clientId); - break; - case OpCodes.SendData: - ProcessData(clientId, data.ReadBytes(ref pos), channel, data.ReadInt(ref pos)); - break; - case OpCodes.UpdateRoomData: - var plyRoom = GetRoomForPlayer(clientId); - - if (plyRoom == null) - return; - - bool newName = data.ReadBool(ref pos); - if (newName) - plyRoom.serverName = data.ReadString(ref pos); - - bool newData = data.ReadBool(ref pos); - if (newData) - plyRoom.serverData = data.ReadString(ref pos); - - bool newPublicStatus = data.ReadBool(ref pos); - if (newPublicStatus) - plyRoom.isPublic = data.ReadBool(ref pos); - - bool newPlayerCap = data.ReadBool(ref pos); - if (newPlayerCap) - plyRoom.maxPlayers = data.ReadInt(ref pos); - - break; - } - } - catch - { - // Do Nothing. Client probably sent some invalid data. - } - } - - public void HandleDisconnect(int clientId) => LeaveRoom(clientId); - - void ProcessData(int clientId, byte[] clientData, int channel, int sendTo = -1) - { - Room playersRoom = GetRoomForPlayer(clientId); - - if(playersRoom != null) - { - Room room = playersRoom; - - if(room.hostId == clientId) - { - if (room.clients.Contains(sendTo)) - { - int pos = 0; - byte[] sendBuffer = _sendBuffers.Rent(_maxPacketSize); - - sendBuffer.WriteByte(ref pos, (byte)OpCodes.GetData); - sendBuffer.WriteBytes(ref pos, clientData); - - Program.transport.ServerSend(sendTo, channel, new ArraySegment(sendBuffer, 0, pos)); - _sendBuffers.Return(sendBuffer); - } - } - else - { - // We are not the host, so send the data to the host. - int pos = 0; - byte[] sendBuffer = _sendBuffers.Rent(_maxPacketSize); - - sendBuffer.WriteByte(ref pos, (byte)OpCodes.GetData); - sendBuffer.WriteBytes(ref pos, clientData); - sendBuffer.WriteInt(ref pos, clientId); - - Program.transport.ServerSend(room.hostId, channel, new ArraySegment(sendBuffer, 0, pos)); - _sendBuffers.Return(sendBuffer); - } - } - } - - Room GetRoomForPlayer(int clientId) - { - for(int i = 0; i < rooms.Count; i++) - { - if (rooms[i].hostId == clientId) - return rooms[i]; - - if (rooms[i].clients.Contains(clientId)) - return rooms[i]; - } - - return null; - } - - void JoinRoom(int clientId, int serverId, bool canDirectConnect, string localIP) - { - LeaveRoom(clientId); - - for(int i = 0; i < rooms.Count; i++) - { - if(rooms[i].serverId == serverId) - { - if(rooms[i].clients.Count < rooms[i].maxPlayers) - { - rooms[i].clients.Add(clientId); - - int sendJoinPos = 0; - byte[] sendJoinBuffer = _sendBuffers.Rent(500); - - if (canDirectConnect && Program.instance.NATConnections.ContainsKey(clientId)) - { - sendJoinBuffer.WriteByte(ref sendJoinPos, (byte)OpCodes.DirectConnectIP); - - if (Program.instance.NATConnections[clientId].Address.Equals(rooms[i].hostIP.Address)) - sendJoinBuffer.WriteString(ref sendJoinPos, rooms[i].hostLocalIP == localIP ? "127.0.0.1" : rooms[i].hostLocalIP); - else - sendJoinBuffer.WriteString(ref sendJoinPos, rooms[i].hostIP.Address.ToString()); - - sendJoinBuffer.WriteInt(ref sendJoinPos, rooms[i].useNATPunch ? rooms[i].hostIP.Port : rooms[i].port); - sendJoinBuffer.WriteBool(ref sendJoinPos, rooms[i].useNATPunch); - - Program.transport.ServerSend(clientId, 0, new ArraySegment(sendJoinBuffer, 0, sendJoinPos)); - - if (rooms[i].useNATPunch) - { - sendJoinPos = 0; - sendJoinBuffer.WriteByte(ref sendJoinPos, (byte)OpCodes.DirectConnectIP); - Console.WriteLine(Program.instance.NATConnections[clientId].Address.ToString()); - sendJoinBuffer.WriteString(ref sendJoinPos, Program.instance.NATConnections[clientId].Address.ToString()); - sendJoinBuffer.WriteInt(ref sendJoinPos, Program.instance.NATConnections[clientId].Port); - sendJoinBuffer.WriteBool(ref sendJoinPos, true); - - Program.transport.ServerSend(rooms[i].hostId, 0, new ArraySegment(sendJoinBuffer, 0, sendJoinPos)); - } - - _sendBuffers.Return(sendJoinBuffer); - - return; - } - else - { - - sendJoinBuffer.WriteByte(ref sendJoinPos, (byte)OpCodes.ServerJoined); - sendJoinBuffer.WriteInt(ref sendJoinPos, clientId); - - Program.transport.ServerSend(clientId, 0, new ArraySegment(sendJoinBuffer, 0, sendJoinPos)); - Program.transport.ServerSend(rooms[i].hostId, 0, new ArraySegment(sendJoinBuffer, 0, sendJoinPos)); - _sendBuffers.Return(sendJoinBuffer); - return; - } - } - } - } - - // If it got to here, then the server was not found, or full. Tell the client. - int pos = 0; - byte[] sendBuffer = _sendBuffers.Rent(1); - - sendBuffer.WriteByte(ref pos, (byte)OpCodes.ServerLeft); - - Program.transport.ServerSend(clientId, 0, new ArraySegment(sendBuffer, 0, pos)); - _sendBuffers.Return(sendBuffer); - } - - void CreateRoom(int clientId, int maxPlayers, string serverName, bool isPublic, string serverData, bool useDirectConnect, string hostLocalIP, bool useNatPunch, int port) - { - LeaveRoom(clientId); - Program.instance.NATConnections.TryGetValue(clientId, out IPEndPoint hostIP); - - Room room = new Room - { - hostId = clientId, - maxPlayers = maxPlayers, - serverName = serverName, - isPublic = isPublic, - serverData = serverData, - clients = new List(), - - // hard coded for now REMEMBER TO UN-HARDCODE RETARD - // this is needed for load balancer to know which server this room - // belongs to - relayInfo = new RelayAddress { Address = Program.publicIP, Port = 7777, EndpointPort = Program.conf.EndpointPort }, - - serverId = GetRandomServerID(), - hostIP = hostIP, - hostLocalIP = hostLocalIP, - supportsDirectConnect = hostIP == null ? false : useDirectConnect, - port = port, - useNATPunch = useNatPunch - }; - - rooms.Add(room); - - int pos = 0; - byte[] sendBuffer = _sendBuffers.Rent(5); - - sendBuffer.WriteByte(ref pos, (byte)OpCodes.RoomCreated); - sendBuffer.WriteInt(ref pos, clientId); - - Program.transport.ServerSend(clientId, 0, new ArraySegment(sendBuffer, 0, pos)); - _sendBuffers.Return(sendBuffer); - } - - void LeaveRoom(int clientId, int requiredHostId = -1) - { - for(int i = 0; i < rooms.Count; i++) - { - if(rooms[i].hostId == clientId) - { - int pos = 0; - byte[] sendBuffer = _sendBuffers.Rent(1); - sendBuffer.WriteByte(ref pos, (byte)OpCodes.ServerLeft); - - for(int x = 0; x < rooms[i].clients.Count; x++) - Program.transport.ServerSend(rooms[i].clients[x], 0, new ArraySegment(sendBuffer, 0, pos)); - - _sendBuffers.Return(sendBuffer); - rooms[i].clients.Clear(); - rooms.RemoveAt(i); - return; - } - else - { - if (requiredHostId >= 0 && rooms[i].hostId != requiredHostId) - continue; - - if(rooms[i].clients.RemoveAll(x => x == clientId) > 0) - { - int pos = 0; - byte[] sendBuffer = _sendBuffers.Rent(5); - - sendBuffer.WriteByte(ref pos, (byte)OpCodes.PlayerDisconnected); - sendBuffer.WriteInt(ref pos, clientId); - - Program.transport.ServerSend(rooms[i].hostId, 0, new ArraySegment(sendBuffer, 0, pos)); - _sendBuffers.Return(sendBuffer); - } - } - } - } - - void SendClientID(int clientId) - { - int pos = 0; - byte[] sendBuffer = _sendBuffers.Rent(5); - - sendBuffer.WriteByte(ref pos, (byte)OpCodes.GetID); - sendBuffer.WriteInt(ref pos, clientId); - - Program.transport.ServerSend(clientId, 0, new ArraySegment(sendBuffer, 0, pos)); - _sendBuffers.Return(sendBuffer); - } - - int GetRandomServerID() - { - Random rand = new Random(); - int temp = rand.Next(int.MinValue, int.MaxValue); - - while (DoesServerIdExist(temp)) - temp = rand.Next(int.MinValue, int.MaxValue); - - return temp; - } - - bool DoesServerIdExist(int id) - { - for (int i = 0; i < rooms.Count; i++) - if (rooms[i].serverId == id) - return true; - - return false; - } - } - - public enum OpCodes - { - Default = 0, RequestID = 1, JoinServer = 2, SendData = 3, GetID = 4, ServerJoined = 5, GetData = 6, CreateRoom = 7, ServerLeft = 8, PlayerDisconnected = 9, RoomCreated = 10, - LeaveRoom = 11, KickPlayer = 12, AuthenticationRequest = 13, AuthenticationResponse = 14, Authenticated = 17, UpdateRoomData = 18, ServerConnectionData = 19, RequestNATConnection = 20, - DirectConnectIP = 21 - } -} diff --git a/ServerProject-DONT-IMPORT-INTO-UNITY/LRM/RelayHandler/RelayHandler.cs b/ServerProject-DONT-IMPORT-INTO-UNITY/LRM/RelayHandler/RelayHandler.cs new file mode 100644 index 0000000..0789853 --- /dev/null +++ b/ServerProject-DONT-IMPORT-INTO-UNITY/LRM/RelayHandler/RelayHandler.cs @@ -0,0 +1,113 @@ +using System; +using System.Buffers; + +namespace LightReflectiveMirror +{ + public partial class RelayHandler + { + + public RelayHandler(int maxPacketSize) + { + this._maxPacketSize = maxPacketSize; + _sendBuffers = ArrayPool.Create(maxPacketSize, 50); + } + + /// + /// This is called when a client wants to send data to another player. + /// + /// The ID of the client who is sending the data + /// The binary data the client is sending + /// The channel the client is sending this data on + /// Who to relay the data to + void ProcessData(int clientId, byte[] clientData, int channel, int sendTo = -1) + { + Room playersRoom = GetRoomForPlayer(clientId); + + if(playersRoom != null) + { + Room room = playersRoom; + + if(room.hostId == clientId) + { + if (room.clients.Contains(sendTo)) + { + int pos = 0; + byte[] sendBuffer = _sendBuffers.Rent(_maxPacketSize); + + sendBuffer.WriteByte(ref pos, (byte)OpCodes.GetData); + sendBuffer.WriteBytes(ref pos, clientData); + + Program.transport.ServerSend(sendTo, channel, new ArraySegment(sendBuffer, 0, pos)); + _sendBuffers.Return(sendBuffer); + } + } + else + { + // We are not the host, so send the data to the host. + int pos = 0; + byte[] sendBuffer = _sendBuffers.Rent(_maxPacketSize); + + sendBuffer.WriteByte(ref pos, (byte)OpCodes.GetData); + sendBuffer.WriteBytes(ref pos, clientData); + sendBuffer.WriteInt(ref pos, clientId); + + Program.transport.ServerSend(room.hostId, channel, new ArraySegment(sendBuffer, 0, pos)); + _sendBuffers.Return(sendBuffer); + } + } + } + + + /// + /// Called when a client wants to request their own ID. + /// + /// The client requesting their ID + void SendClientID(int clientId) + { + int pos = 0; + byte[] sendBuffer = _sendBuffers.Rent(5); + + sendBuffer.WriteByte(ref pos, (byte)OpCodes.GetID); + sendBuffer.WriteInt(ref pos, clientId); + + Program.transport.ServerSend(clientId, 0, new ArraySegment(sendBuffer, 0, pos)); + _sendBuffers.Return(sendBuffer); + } + + /// + /// Generates a random server ID. + /// + /// + int GetRandomServerID() + { + Random rand = new Random(); + int temp = rand.Next(int.MinValue, int.MaxValue); + + while (DoesServerIdExist(temp)) + temp = rand.Next(int.MinValue, int.MaxValue); + + return temp; + } + + /// + /// Checks if a server id already is in use. + /// + /// The ID to check for + /// + bool DoesServerIdExist(int id) + { + for (int i = 0; i < rooms.Count; i++) + if (rooms[i].serverId == id) + return true; + + return false; + } + } + + public enum OpCodes + { + Default = 0, RequestID = 1, JoinServer = 2, SendData = 3, GetID = 4, ServerJoined = 5, GetData = 6, CreateRoom = 7, ServerLeft = 8, PlayerDisconnected = 9, RoomCreated = 10, + LeaveRoom = 11, KickPlayer = 12, AuthenticationRequest = 13, AuthenticationResponse = 14, Authenticated = 17, UpdateRoomData = 18, ServerConnectionData = 19, RequestNATConnection = 20, + DirectConnectIP = 21 + } +} diff --git a/ServerProject-DONT-IMPORT-INTO-UNITY/LRM/RelayHandler/RelayHandlerCallbacks.cs b/ServerProject-DONT-IMPORT-INTO-UNITY/LRM/RelayHandler/RelayHandlerCallbacks.cs new file mode 100644 index 0000000..ca8fdc8 --- /dev/null +++ b/ServerProject-DONT-IMPORT-INTO-UNITY/LRM/RelayHandler/RelayHandlerCallbacks.cs @@ -0,0 +1,110 @@ +using System; + +namespace LightReflectiveMirror +{ + public partial class RelayHandler + { + /// + /// Invoked when a client connects to this LRM server. + /// + /// The ID of the client who connected. + public void ClientConnected(int clientId) + { + _pendingAuthentication.Add(clientId); + var buffer = _sendBuffers.Rent(1); + int pos = 0; + buffer.WriteByte(ref pos, (byte)OpCodes.AuthenticationRequest); + Program.transport.ServerSend(clientId, 0, new ArraySegment(buffer, 0, pos)); + _sendBuffers.Return(buffer); + } + + /// + /// Handles the processing of data from a client. + /// + /// The client who sent the data + /// The binary data + /// The channel the client sent the data on + public void HandleMessage(int clientId, ArraySegment segmentData, int channel) + { + try + { + var data = segmentData.Array; + int pos = segmentData.Offset; + + OpCodes opcode = (OpCodes)data.ReadByte(ref pos); + + if (_pendingAuthentication.Contains(clientId)) + { + if (opcode == OpCodes.AuthenticationResponse) + { + string authResponse = data.ReadString(ref pos); + if (authResponse == Program.conf.AuthenticationKey) + { + _pendingAuthentication.Remove(clientId); + int writePos = 0; + var sendBuffer = _sendBuffers.Rent(1); + sendBuffer.WriteByte(ref writePos, (byte)OpCodes.Authenticated); + Program.transport.ServerSend(clientId, 0, new ArraySegment(sendBuffer, 0, writePos)); + } + } + return; + } + + switch (opcode) + { + case OpCodes.CreateRoom: + CreateRoom(clientId, data.ReadInt(ref pos), data.ReadString(ref pos), data.ReadBool(ref pos), data.ReadString(ref pos), data.ReadBool(ref pos), data.ReadString(ref pos), data.ReadBool(ref pos), data.ReadInt(ref pos)); + break; + case OpCodes.RequestID: + SendClientID(clientId); + break; + case OpCodes.LeaveRoom: + LeaveRoom(clientId); + break; + case OpCodes.JoinServer: + JoinRoom(clientId, data.ReadInt(ref pos), data.ReadBool(ref pos), data.ReadString(ref pos)); + break; + case OpCodes.KickPlayer: + LeaveRoom(data.ReadInt(ref pos), clientId); + break; + case OpCodes.SendData: + ProcessData(clientId, data.ReadBytes(ref pos), channel, data.ReadInt(ref pos)); + break; + case OpCodes.UpdateRoomData: + var plyRoom = GetRoomForPlayer(clientId); + + if (plyRoom == null) + return; + + bool newName = data.ReadBool(ref pos); + if (newName) + plyRoom.serverName = data.ReadString(ref pos); + + bool newData = data.ReadBool(ref pos); + if (newData) + plyRoom.serverData = data.ReadString(ref pos); + + bool newPublicStatus = data.ReadBool(ref pos); + if (newPublicStatus) + plyRoom.isPublic = data.ReadBool(ref pos); + + bool newPlayerCap = data.ReadBool(ref pos); + if (newPlayerCap) + plyRoom.maxPlayers = data.ReadInt(ref pos); + + break; + } + } + catch + { + // Do Nothing. Client probably sent some invalid data. + } + } + + /// + /// Invoked when a client disconnects from the relay. + /// + /// The ID of the client who disconnected + public void HandleDisconnect(int clientId) => LeaveRoom(clientId); + } +} diff --git a/ServerProject-DONT-IMPORT-INTO-UNITY/LRM/RelayHandler/RelayHandlerRoomMethods.cs b/ServerProject-DONT-IMPORT-INTO-UNITY/LRM/RelayHandler/RelayHandlerRoomMethods.cs new file mode 100644 index 0000000..59ce180 --- /dev/null +++ b/ServerProject-DONT-IMPORT-INTO-UNITY/LRM/RelayHandler/RelayHandlerRoomMethods.cs @@ -0,0 +1,199 @@ +using System; +using System.Collections.Generic; +using System.Net; + +namespace LightReflectiveMirror +{ + public partial class RelayHandler + { + /// + /// Returns the current room the client is in, null if client is not in a room. + /// + /// The client we are getting the room for + /// + Room GetRoomForPlayer(int clientId) + { + for (int i = 0; i < rooms.Count; i++) + { + if (rooms[i].hostId == clientId) + return rooms[i]; + + if (rooms[i].clients.Contains(clientId)) + return rooms[i]; + } + + return null; + } + + /// + /// Attempts to join a room for a client. + /// + /// The client requesting to join the room + /// The server ID of the room + /// If the client is capable of a direct connection + /// The local IP of the client joining + void JoinRoom(int clientId, int serverId, bool canDirectConnect, string localIP) + { + LeaveRoom(clientId); + + for (int i = 0; i < rooms.Count; i++) + { + if (rooms[i].serverId == serverId) + { + if (rooms[i].clients.Count < rooms[i].maxPlayers) + { + rooms[i].clients.Add(clientId); + + int sendJoinPos = 0; + byte[] sendJoinBuffer = _sendBuffers.Rent(500); + + if (canDirectConnect && Program.instance.NATConnections.ContainsKey(clientId)) + { + sendJoinBuffer.WriteByte(ref sendJoinPos, (byte)OpCodes.DirectConnectIP); + + if (Program.instance.NATConnections[clientId].Address.Equals(rooms[i].hostIP.Address)) + sendJoinBuffer.WriteString(ref sendJoinPos, rooms[i].hostLocalIP == localIP ? "127.0.0.1" : rooms[i].hostLocalIP); + else + sendJoinBuffer.WriteString(ref sendJoinPos, rooms[i].hostIP.Address.ToString()); + + sendJoinBuffer.WriteInt(ref sendJoinPos, rooms[i].useNATPunch ? rooms[i].hostIP.Port : rooms[i].port); + sendJoinBuffer.WriteBool(ref sendJoinPos, rooms[i].useNATPunch); + + Program.transport.ServerSend(clientId, 0, new ArraySegment(sendJoinBuffer, 0, sendJoinPos)); + + if (rooms[i].useNATPunch) + { + sendJoinPos = 0; + sendJoinBuffer.WriteByte(ref sendJoinPos, (byte)OpCodes.DirectConnectIP); + Console.WriteLine(Program.instance.NATConnections[clientId].Address.ToString()); + sendJoinBuffer.WriteString(ref sendJoinPos, Program.instance.NATConnections[clientId].Address.ToString()); + sendJoinBuffer.WriteInt(ref sendJoinPos, Program.instance.NATConnections[clientId].Port); + sendJoinBuffer.WriteBool(ref sendJoinPos, true); + + Program.transport.ServerSend(rooms[i].hostId, 0, new ArraySegment(sendJoinBuffer, 0, sendJoinPos)); + } + + _sendBuffers.Return(sendJoinBuffer); + + return; + } + else + { + + sendJoinBuffer.WriteByte(ref sendJoinPos, (byte)OpCodes.ServerJoined); + sendJoinBuffer.WriteInt(ref sendJoinPos, clientId); + + Program.transport.ServerSend(clientId, 0, new ArraySegment(sendJoinBuffer, 0, sendJoinPos)); + Program.transport.ServerSend(rooms[i].hostId, 0, new ArraySegment(sendJoinBuffer, 0, sendJoinPos)); + _sendBuffers.Return(sendJoinBuffer); + return; + } + } + } + } + + // If it got to here, then the server was not found, or full. Tell the client. + int pos = 0; + byte[] sendBuffer = _sendBuffers.Rent(1); + + sendBuffer.WriteByte(ref pos, (byte)OpCodes.ServerLeft); + + Program.transport.ServerSend(clientId, 0, new ArraySegment(sendBuffer, 0, pos)); + _sendBuffers.Return(sendBuffer); + } + + /// + /// Creates a room on the LRM node. + /// + /// The client requesting to create a room + /// The maximum amount of players for this room + /// The name for the server + /// Weather or not the server should show up on the server list + /// Extra data the host can include + /// Weather or not, the host is capable of doing direct connections + /// The hosts local IP + /// Weather or not, the host is supporting NAT Punch + /// The port of the direct connect transport on the host + void CreateRoom(int clientId, int maxPlayers, string serverName, bool isPublic, string serverData, bool useDirectConnect, string hostLocalIP, bool useNatPunch, int port) + { + LeaveRoom(clientId); + Program.instance.NATConnections.TryGetValue(clientId, out IPEndPoint hostIP); + + Room room = new Room + { + hostId = clientId, + maxPlayers = maxPlayers, + serverName = serverName, + isPublic = isPublic, + serverData = serverData, + clients = new List(), + + // hard coded for now REMEMBER TO UN-HARDCODE RETARD + // this is needed for load balancer to know which server this room + // belongs to + relayInfo = new RelayAddress { Address = Program.publicIP, Port = 7777, EndpointPort = Program.conf.EndpointPort }, + + serverId = GetRandomServerID(), + hostIP = hostIP, + hostLocalIP = hostLocalIP, + supportsDirectConnect = hostIP == null ? false : useDirectConnect, + port = port, + useNATPunch = useNatPunch + }; + + rooms.Add(room); + + int pos = 0; + byte[] sendBuffer = _sendBuffers.Rent(5); + + sendBuffer.WriteByte(ref pos, (byte)OpCodes.RoomCreated); + sendBuffer.WriteInt(ref pos, clientId); + + Program.transport.ServerSend(clientId, 0, new ArraySegment(sendBuffer, 0, pos)); + _sendBuffers.Return(sendBuffer); + } + + /// + /// Makes the client leave their room. + /// + /// The client of which to remove from their room + /// The ID of the client who kicked the client. -1 if the client left on their own terms + void LeaveRoom(int clientId, int requiredHostId = -1) + { + for (int i = 0; i < rooms.Count; i++) + { + if (rooms[i].hostId == clientId) + { + int pos = 0; + byte[] sendBuffer = _sendBuffers.Rent(1); + sendBuffer.WriteByte(ref pos, (byte)OpCodes.ServerLeft); + + for (int x = 0; x < rooms[i].clients.Count; x++) + Program.transport.ServerSend(rooms[i].clients[x], 0, new ArraySegment(sendBuffer, 0, pos)); + + _sendBuffers.Return(sendBuffer); + rooms[i].clients.Clear(); + rooms.RemoveAt(i); + return; + } + else + { + if (requiredHostId >= 0 && rooms[i].hostId != requiredHostId) + continue; + + if (rooms[i].clients.RemoveAll(x => x == clientId) > 0) + { + int pos = 0; + byte[] sendBuffer = _sendBuffers.Rent(5); + + sendBuffer.WriteByte(ref pos, (byte)OpCodes.PlayerDisconnected); + sendBuffer.WriteInt(ref pos, clientId); + + Program.transport.ServerSend(rooms[i].hostId, 0, new ArraySegment(sendBuffer, 0, pos)); + _sendBuffers.Return(sendBuffer); + } + } + } + } + } +} diff --git a/ServerProject-DONT-IMPORT-INTO-UNITY/LRM/RelayHandler/RelayHandlerVariables.cs b/ServerProject-DONT-IMPORT-INTO-UNITY/LRM/RelayHandler/RelayHandlerVariables.cs new file mode 100644 index 0000000..abe5267 --- /dev/null +++ b/ServerProject-DONT-IMPORT-INTO-UNITY/LRM/RelayHandler/RelayHandlerVariables.cs @@ -0,0 +1,13 @@ +using System.Buffers; +using System.Collections.Generic; + +namespace LightReflectiveMirror +{ + public partial class RelayHandler + { + public List rooms = new List(); + private List _pendingAuthentication = new List(); + private ArrayPool _sendBuffers; + private int _maxPacketSize = 0; + } +}