using Mirror; using System; using System.Collections; using System.Collections.Generic; using System.Linq; using System.Net; using UnityEngine; namespace LightReflectiveMirror { public partial class LightReflectiveMirrorTransport : Transport { public override bool ServerActive() => _isServer; public override bool Available() => _connectedToRelay; public override void ClientConnect(Uri uri) => ClientConnect(uri.Host); public override int GetMaxPacketSize(int channelId = 0) => clientToServerTransport.GetMaxPacketSize(channelId); public override bool ClientConnected() => _isClient; public override void ServerLateUpdate() { if (_directConnectModule != null) _directConnectModule.directConnectTransport.ServerLateUpdate(); } public override string ServerGetClientAddress(int connectionId) { if (_connectedRelayClients.TryGetBySecond(connectionId, out int relayId)) return relayId.ToString(); if (_connectedDirectClients.TryGetBySecond(connectionId, out int directId)) return "DIRECT-" + directId; // Shouldn't ever get here. return "?"; } public override void ClientEarlyUpdate() { clientToServerTransport.ClientEarlyUpdate(); if (_directConnectModule != null) _directConnectModule.directConnectTransport.ClientEarlyUpdate(); } public override void ClientLateUpdate() { clientToServerTransport.ClientLateUpdate(); if (_directConnectModule != null) _directConnectModule.directConnectTransport.ClientLateUpdate(); } public override void ServerEarlyUpdate() { if (_directConnectModule != null) _directConnectModule.directConnectTransport.ServerEarlyUpdate(); } public override void ClientConnect(string address) { if (!Available() || !int.TryParse(address, out _cachedHostID)) { Debug.Log("Not connected to relay or invalid server id!"); OnClientDisconnected?.Invoke(); return; } if (_isClient || _isServer) throw new Exception("Cannot connect while hosting/already connected!"); var room = GetServerForID(_cachedHostID); if (!useLoadBalancer || room.relayInfo.Address == serverIP) { int pos = 0; _directConnected = false; _clientSendBuffer.WriteByte(ref pos, (byte)OpCodes.JoinServer); _clientSendBuffer.WriteInt(ref pos, _cachedHostID); _clientSendBuffer.WriteBool(ref pos, _directConnectModule != null); if (GetLocalIp() == null) _clientSendBuffer.WriteString(ref pos, "0.0.0.0"); else _clientSendBuffer.WriteString(ref pos, GetLocalIp()); _isClient = true; clientToServerTransport.ClientSend(0, new System.ArraySegment(_clientSendBuffer, 0, pos)); } else { StartCoroutine(JoinOtherRelayAndMatch(room)); } } public override void ClientDisconnect() { _isClient = false; int pos = 0; _clientSendBuffer.WriteByte(ref pos, (byte)OpCodes.LeaveRoom); clientToServerTransport.ClientSend(0, new ArraySegment(_clientSendBuffer, 0, pos)); if (_directConnectModule != null) _directConnectModule.ClientDisconnect(); } public override void ClientSend(int channelId, ArraySegment segment) { if (_directConnected) { _directConnectModule.ClientSend(segment, channelId); } else { int pos = 0; _clientSendBuffer.WriteByte(ref pos, (byte)OpCodes.SendData); _clientSendBuffer.WriteBytes(ref pos, segment.Array.Take(segment.Count).ToArray()); _clientSendBuffer.WriteInt(ref pos, 0); clientToServerTransport.ClientSend(channelId, new ArraySegment(_clientSendBuffer, 0, pos)); } } public override bool ServerDisconnect(int connectionId) { if (_connectedRelayClients.TryGetBySecond(connectionId, out int relayId)) { int pos = 0; _clientSendBuffer.WriteByte(ref pos, (byte)OpCodes.KickPlayer); _clientSendBuffer.WriteInt(ref pos, relayId); return true; } if (_connectedDirectClients.TryGetBySecond(connectionId, out int directId)) return _directConnectModule.KickClient(directId); return false; } public override void ServerSend(int connectionId, int channelId, ArraySegment segment) { if (_directConnectModule != null && _connectedDirectClients.TryGetBySecond(connectionId, out int directId)) { _directConnectModule.ServerSend(directId, segment, channelId); } else { int pos = 0; _clientSendBuffer.WriteByte(ref pos, (byte)OpCodes.SendData); _clientSendBuffer.WriteBytes(ref pos, segment.Array.Take(segment.Count).ToArray()); _clientSendBuffer.WriteInt(ref pos, _connectedRelayClients.GetBySecond(connectionId)); clientToServerTransport.ClientSend(channelId, new ArraySegment(_clientSendBuffer, 0, pos)); } } public override void ServerStart() { if (!Available()) { Debug.Log("Not connected to relay! Server failed to start."); return; } if (_isClient || _isServer) { Debug.Log("Cannot host while already hosting or connected!"); return; } _isServer = true; _connectedRelayClients = new BiDictionary(); _currentMemberId = 1; _connectedDirectClients = new BiDictionary(); var keys = new List(_serverProxies.GetAllKeys()); for (int i = 0; i < keys.Count; i++) { _serverProxies.GetByFirst(keys[i]).Dispose(); _serverProxies.Remove(keys[i]); } int pos = 0; _clientSendBuffer.WriteByte(ref pos, (byte)OpCodes.CreateRoom); _clientSendBuffer.WriteInt(ref pos, maxServerPlayers); _clientSendBuffer.WriteString(ref pos, serverName); _clientSendBuffer.WriteBool(ref pos, isPublicServer); _clientSendBuffer.WriteString(ref pos, extraServerData); // If we have direct connect module, and our local IP isnt null, tell server. Only time local IP is null is on cellular networks, such as IOS and Android. _clientSendBuffer.WriteBool(ref pos, _directConnectModule != null ? GetLocalIp() != null ? true : false : false); if (_directConnectModule != null && GetLocalIp() != null) { _clientSendBuffer.WriteString(ref pos, GetLocalIp()); // Transport port will be NAT port + 1 for the proxy connections. _directConnectModule.StartServer(useNATPunch ? _NATIP.Port + 1 : -1); } else _clientSendBuffer.WriteString(ref pos, "0.0.0.0"); if (useNATPunch) { _clientSendBuffer.WriteBool(ref pos, true); _clientSendBuffer.WriteInt(ref pos, 0); } else { _clientSendBuffer.WriteBool(ref pos, false); _clientSendBuffer.WriteInt(ref pos, _directConnectModule == null ? 1 : _directConnectModule.SupportsNATPunch() ? _directConnectModule.GetTransportPort() : 1); } clientToServerTransport.ClientSend(0, new ArraySegment(_clientSendBuffer, 0, pos)); } public override void ServerStop() { if (_isServer) { _isServer = false; int pos = 0; _clientSendBuffer.WriteByte(ref pos, (byte)OpCodes.LeaveRoom); clientToServerTransport.ClientSend(0, new ArraySegment(_clientSendBuffer, 0, pos)); if (_directConnectModule != null) _directConnectModule.StopServer(); var keys = new List(_serverProxies.GetAllKeys()); for (int i = 0; i < keys.Count; i++) { _serverProxies.GetByFirst(keys[i]).Dispose(); _serverProxies.Remove(keys[i]); } } } public override Uri ServerUri() { UriBuilder builder = new UriBuilder { Scheme = "LRM", Host = serverId.ToString() }; return builder.Uri; } public override void Shutdown() { _isAuthenticated = false; _isClient = false; _isServer = false; _connectedToRelay = false; clientToServerTransport.Shutdown(); } } }