using System.Collections.Generic; using UnityEngine; using System; using System.Net; using System.Net.Sockets; using NeonTea.Quakeball.TeaNet.Packets; namespace NeonTea.Quakeball.TeaNet.Peers { /// Main class for networking. Remember to register a protocol before using. public class Peer : PeerMessageListener { /// Underlying UdpClient. Do not touch unless you know what you are doing. public UdpClient UdpClient { get; private set; } /// The fingerprint for networking. Used to make sure incoming bytes are from a correct source. public byte[] Fingerprint { get; private set; } /// Shorthand for ConnectionManager.Timeout: The amount of milliseconds before a connection is timed out. public long Timeout { get { return ConnectionManager.Timeout; } set { ConnectionManager.Timeout = value; } } /// Shorthand for ConnectionManager.Interval: The interval of updates and rate of re-sending reliable messages. public long UpdateInterval { get { return ConnectionManager.Interval; } set { ConnectionManager.Interval = value; } } public ListenerThread ListenerThread; public ConnectionManager ConnectionManager; public Dictionary RegisteredProtocols = new Dictionary(); /// Listener for messages and errors from within the Peer. public PeerMessageListener MessageListener; /// Creates a new Peer with the given fingerprint. The fingerprint can be anything, it just must be same on both peers. public Peer(byte[] fingerprint) { Fingerprint = fingerprint; ConnectionManager = new ConnectionManager(this); MessageListener = this; } /// Starts the UdpClient, but does no networking as is. public void Start(int sending_port) { UdpClient = new UdpClient(sending_port); MessageListener.Message("UdpClient Started"); } /// Abruptly stops the UdpClient and all relevant threads. public void Stop() { ConnectionManager.StopThread(); if (ListenerThread != null) { ListenerThread.Stop(); } UdpClient.Dispose(); UdpClient.Close(); } /// Start listening to a given address and port. Usually 0.0.0.0, 0 for clients and 0.0.0.0, port for servers public void StartListen(string address, int port) { IPEndPoint endpoint = new IPEndPoint(FindAddress(address), port); StartListen(endpoint); } private void StartListen(IPEndPoint endpoint) { if (ListenerThread != null) { return; // Cant listen twice } ListenerThread = new ListenerThread(this, endpoint); ListenerThread.Start(); MessageListener.Message($"Started listening to {endpoint}"); } /// Connect to a remote host. Will initialize a listener to 0.0.0.0:0 if no listener is started. public void Connect(string address, int port, byte protocolIdent, bool startListening = true) { if (startListening) { IPEndPoint listenEndpoint = (IPEndPoint)UdpClient.Client.LocalEndPoint; StartListen(listenEndpoint); } IPEndPoint endpoint = new IPEndPoint(FindAddress(address), port); ConnectionManager.StartConnection(endpoint, protocolIdent); MessageListener.Message($"Connecting to {endpoint}"); } /// Send a reliable packet, meaning it will reliably be delivered. public void SendReliable(ulong uid, Packet packet) { ConnectionManager.AddPacketToQueue(uid, packet); ConnectionManager.SendPacketQueue(uid); } /// Add reliable packet to queue, so that it will be sent on the next update. public void SendReliableLater(ulong uid, Packet packet) { ConnectionManager.AddPacketToQueue(uid, packet); } /// Send an unreliable packet, meaning its delivery is not reliable. public void SendUnreliable(ulong uid, Packet packet) { ConnectionManager.SendSingleUnreliable(uid, packet); } /// Get a Connection instance from the given uid, if such exists. Null otherwise. public Connection GetConnection(ulong uid) { return ConnectionManager.GetConnection(uid); } /// Register a given protocol. Returns protocol.Identifier if successful, 0 otherwise. public byte RegisterProtocol(Protocol protocol) { byte ident = protocol.Identifier; if (RegisteredProtocols.ContainsKey(ident)) { return 0; } RegisteredProtocols.Add(ident, protocol); protocol.Peer = this; return ident; } /// Get protocol instance from the given identifier, if such exists. public Protocol GetProtocol(byte ident) { if (RegisteredProtocols.ContainsKey(ident)) { return RegisteredProtocols[ident]; } return null; } public void Message(string msg) { } public void Err(string msg) { } private IPAddress FindAddress(string host) { IPAddress addr; try { addr = Dns.GetHostAddresses(host)[0]; } catch (ArgumentException) { addr = IPAddress.Parse(host); } return addr; } } /// Listener for messages and errors from the Peer. public interface PeerMessageListener { void Message(string msg); void Err(string msg); } }