using LightReflectiveMirror.Endpoints; using System; using System.Collections.Generic; using System.Net; namespace LightReflectiveMirror { public partial class RelayHandler { /// /// 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, string serverId, bool canDirectConnect, string localIP) { LeaveRoom(clientId); if (_cachedRooms.ContainsKey(serverId)) { var room = _cachedRooms[serverId]; if (room.clients.Count < room.maxPlayers) { room.clients.Add(clientId); _cachedClientRooms.Add(clientId, room); int sendJoinPos = 0; byte[] sendJoinBuffer = _sendBuffers.Rent(500); if (canDirectConnect && Program.instance.NATConnections.ContainsKey(clientId) && room.supportsDirectConnect) { sendJoinBuffer.WriteByte(ref sendJoinPos, (byte)OpCodes.DirectConnectIP); if (Program.instance.NATConnections[clientId].Address.Equals(room.hostIP.Address)) sendJoinBuffer.WriteString(ref sendJoinPos, room.hostLocalIP == localIP ? "127.0.0.1" : room.hostLocalIP); else sendJoinBuffer.WriteString(ref sendJoinPos, room.hostIP.Address.ToString()); sendJoinBuffer.WriteInt(ref sendJoinPos, room.useNATPunch ? room.hostIP.Port : room.port); sendJoinBuffer.WriteBool(ref sendJoinPos, room.useNATPunch); Program.transport.ServerSend(clientId, 0, new ArraySegment(sendJoinBuffer, 0, sendJoinPos)); if (room.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(room.hostId, 0, new ArraySegment(sendJoinBuffer, 0, sendJoinPos)); } _sendBuffers.Return(sendJoinBuffer); Endpoint.RoomsModified(); 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(room.hostId, 0, new ArraySegment(sendJoinBuffer, 0, sendJoinPos)); _sendBuffers.Return(sendJoinBuffer); Endpoint.RoomsModified(); 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(), relayInfo = new RelayAddress { address = Program.publicIP, port = Program.conf.TransportPort, endpointPort = Program.conf.EndpointPort }, serverId = GetRandomServerID(), hostIP = hostIP, hostLocalIP = hostLocalIP, supportsDirectConnect = hostIP == null ? false : useDirectConnect, port = port, useNATPunch = useNatPunch }; rooms.Add(room); _cachedClientRooms.Add(clientId, room); _cachedRooms.Add(room.serverId, room); int pos = 0; byte[] sendBuffer = _sendBuffers.Rent(5); sendBuffer.WriteByte(ref pos, (byte)OpCodes.RoomCreated); sendBuffer.WriteString(ref pos, room.serverId); Program.transport.ServerSend(clientId, 0, new ArraySegment(sendBuffer, 0, pos)); _sendBuffers.Return(sendBuffer); Endpoint.RoomsModified(); } /// /// 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)); _cachedClientRooms.Remove(rooms[i].clients[x]); } _sendBuffers.Return(sendBuffer); rooms[i].clients.Clear(); _cachedRooms.Remove(rooms[i].serverId); rooms.RemoveAt(i); _cachedClientRooms.Remove(clientId); Endpoint.RoomsModified(); return; } else { if (requiredHostId != -1 && 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); Endpoint.RoomsModified(); _cachedClientRooms.Remove(clientId); } } } } } }