using Godot; using Network.PacketHandling; using Network.Syncing; using System.Collections.Generic; using System.Threading; using Util; using Thread = System.Threading.Thread; namespace Network { public abstract class Peer : Object { public const float TIMEOUT = 4f; // 4 seconds private static PacketPeerUDP PacketPeer; private static Peer Singleton; public readonly bool IsServer; public bool Initialized { get; private set; } = false; public Protocol Protocol; private int LastConnectionSended = -1; private Thread ListenerThread; public ConnectionList ConnectionList; public PacketDistributor PacketDistributor; private bool ShouldListen = false; public List PeerListeners = new List(); public Peer(PacketPeerUDP packetPeer, bool isServer) { PacketPeer = packetPeer; IsServer = isServer; Protocol = new Protocol(this); ConnectionList = new ConnectionList(this); PacketDistributor = new PacketDistributor(this, 0.5f); } public void Update(float delta) { PacketDistributor.Update(delta); Process(delta); } public void Start(string address, int port) { if (Initialized) { return; } Singleton = this; Initialize(address, port); Initialized = true; foreach (PeerListener listener in PeerListeners) { listener.OnStart(); } } public void Stop() { if (!Initialized) { return; } Uninitialize(); Initialized = false; foreach (PeerListener listener in PeerListeners) { listener.OnStop(); } } public abstract void Initialize(string address, int port); public abstract void Uninitialize(); public abstract void Process(float delta); public abstract void Connected(Connection conn); public abstract void Disconnected(Connection conn, DisconnectReason reason); public int SendBuffer(PacketBuffer packetBuffer, Connection to) { if (LastConnectionSended != to.ID) { PacketPeer.SetDestAddress(to.Address, to.Port); LastConnectionSended = to.ID; } return PacketPeer.PutPacket(packetBuffer.ByteBuffer); } public bool StartListening(int port, string address = "*") { if (PacketPeer.IsListening() || ListenerThread != null) { GD.printerr("The Peer is already listening or the thread is active!"); return false; } ShouldListen = true; PacketPeer.Listen(port, address); ThreadStart ChildRef = new ThreadStart(ListenerThreadMethod); ListenerThread = new Thread(ChildRef); ListenerThread.Start(); return true; } public void StopListening() { if (ShouldListen) { ShouldListen = false; PacketPeer.Close(); } } public Connection GetOrAddConnection(string address, int port) { Optional Conn = ConnectionList.GetOriginal(address, port); if (Conn.isEmpty) { Conn = new Connection(address, port); ConnectionList.AddConnection(Conn); PacketDistributor.AddHandler(Conn); foreach (PeerListener Listener in PeerListeners) { Listener.OnConnect(Conn); } } return Conn; } private static void ListenerThreadMethod() { GD.print("Started Listener Thread."); while (Singleton.ShouldListen) { PacketPeer.Wait(); byte[] Buffer = PacketPeer.GetPacket(); string Address = PacketPeer.GetPacketIp(); int Port = PacketPeer.GetPacketPort(); PacketBuffer PB = PacketBuffer.FromByteBuffer(Buffer); if (PB.Length > PacketBuffer.SignatureBytes.Length) { bool Confirmed = true; foreach (byte B in PacketBuffer.SignatureBytes) { if (PB.Read() != B) { // Ignore packet, confirmation bytes don't match up. Confirmed = false; break; } } if (Confirmed) { Connection Conn = Singleton.GetOrAddConnection(Address, Port); Singleton.PacketDistributor.HandleRawPacket(PB, Singleton.ConnectionList.GetOriginal(Conn)); } } } } public void Disconnect(Connection conn, DisconnectReason reason) { GD.print(conn + " disconnected. Reason:"); switch (reason) { case DisconnectReason.TIMEOUT: { GD.print("TIMEOUT"); break; } case DisconnectReason.MANUAL_DISCONNECT: { GD.print("MANUAL DISCONNECT"); break; } default: { GD.print("Unknown."); break; } } ConnectionList.RemoveConnection(conn); PacketDistributor.RemoveHandler(conn); Disconnected(conn, reason); foreach (PeerListener Listener in PeerListeners) { Listener.OnDisconnect(conn, reason); } } public void AddPeerListener(PeerListener listener) { PeerListeners.Add(listener); } public void RemovePeerListener(PeerListener listener) { PeerListeners.Remove(listener); } } }