GodotTicTacToe/scripts/net/Peer.cs

175 lines
5.8 KiB
C#

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<PeerListener> PeerListeners = new List<PeerListener>();
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<Connection> 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);
}
}
}