diff --git a/.vs/CommunityServerAPI/FileContentIndex/48ba5e31-9a7c-4cdb-ab00-e17e1a0be5b7.vsidx b/.vs/CommunityServerAPI/FileContentIndex/48ba5e31-9a7c-4cdb-ab00-e17e1a0be5b7.vsidx deleted file mode 100644 index 7e34476..0000000 Binary files a/.vs/CommunityServerAPI/FileContentIndex/48ba5e31-9a7c-4cdb-ab00-e17e1a0be5b7.vsidx and /dev/null differ diff --git a/.vs/CommunityServerAPI/FileContentIndex/f4042593-05ec-4dc7-81c3-1c24ca90aaaf.vsidx b/.vs/CommunityServerAPI/FileContentIndex/f4042593-05ec-4dc7-81c3-1c24ca90aaaf.vsidx new file mode 100644 index 0000000..0949463 Binary files /dev/null and b/.vs/CommunityServerAPI/FileContentIndex/f4042593-05ec-4dc7-81c3-1c24ca90aaaf.vsidx differ diff --git a/.vs/CommunityServerAPI/v17/.suo b/.vs/CommunityServerAPI/v17/.suo index 37b490d..e70a2fb 100644 Binary files a/.vs/CommunityServerAPI/v17/.suo and b/.vs/CommunityServerAPI/v17/.suo differ diff --git a/BattleBitAPI/Client/Client.cs b/BattleBitAPI/Client/Client.cs index 0be34e4..6593de8 100644 --- a/BattleBitAPI/Client/Client.cs +++ b/BattleBitAPI/Client/Client.cs @@ -1,4 +1,5 @@ using BattleBitAPI.Common.Enums; +using BattleBitAPI.Common.Extentions; using BattleBitAPI.Common.Serialization; using BattleBitAPI.Networking; using CommunityServerAPI.BattleBitAPI; @@ -13,24 +14,30 @@ namespace BattleBitAPI.Client public class Client { // ---- Public Variables ---- - public bool IsConnected { get; set; } - public int GamePort { get; set; } - public bool IsPasswordProtected { get; set; } - public string ServerName { get; set; } - public string Gamemode { get; set; } - public string Map { get; set; } - public MapSize MapSize { get; set; } - public MapDayNight DayNight { get; set; } - public int CurrentPlayers { get; set; } - public int InQueuePlayers { get; set; } - public int MaxPlayers { get; set; } - public string LoadingScreenText { get; set; } - public string ServerRulesText { get; set; } + public bool IsConnected { get; private set; } + public int GamePort { get; set; } = 30000; + public bool IsPasswordProtected { get; set; } = false; + public string ServerName { get; set; } = ""; + public string Gamemode { get; set; } = ""; + public string Map { get; set; } = ""; + public MapSize MapSize { get; set; } = MapSize._16vs16; + public MapDayNight DayNight { get; set; } = MapDayNight.Day; + public int CurrentPlayers { get; set; } = 0; + public int InQueuePlayers { get; set; } = 0; + public int MaxPlayers { get; set; } = 16; + public string LoadingScreenText { get; set; } = ""; + public string ServerRulesText { get; set; } = ""; // ---- Private Variables ---- - private TcpClient mClient; + private TcpClient mSocket; private string mDestination; private int mPort; + private byte[] mKeepAliveBuffer; + private Common.Serialization.Stream mWriteStream; + private Common.Serialization.Stream mReadStream; + private uint mReadPackageSize; + private long mLastPackageReceived; + private long mLastPackageSent; private bool mIsConnectingFlag; // ---- Construction ---- @@ -38,6 +45,28 @@ namespace BattleBitAPI.Client { this.mDestination = destination; this.mPort = port; + + this.mWriteStream = new Common.Serialization.Stream() + { + Buffer = new byte[Const.MaxNetworkPackageSize], + InPool = false, + ReadPosition = 0, + WritePosition = 0, + }; + this.mReadStream = new Common.Serialization.Stream() + { + Buffer = new byte[Const.MaxNetworkPackageSize], + InPool = false, + ReadPosition = 0, + WritePosition = 0, + }; + this.mKeepAliveBuffer = new byte[4] + { + 0,0,0,0, + }; + + this.mLastPackageReceived = Extentions.TickCount; + this.mLastPackageSent = Extentions.TickCount; } // ---- Main Tick ---- @@ -54,111 +83,121 @@ namespace BattleBitAPI.Client this.mIsConnectingFlag = true; //Dispose old client if exist. - if (this.mClient != null) + if (this.mSocket != null) { - try { this.mClient.Close(); } catch { } - try { this.mClient.Dispose(); } catch { } - this.mClient = null; + try { this.mSocket.Close(); } catch { } + try { this.mSocket.Dispose(); } catch { } + this.mSocket = null; } //Create new client - this.mClient = new TcpClient(); - this.mClient.SendBufferSize = Const.MaxNetworkPackageSize; - this.mClient.ReceiveBufferSize = Const.MaxNetworkPackageSize; + this.mSocket = new TcpClient(); + this.mSocket.SendBufferSize = Const.MaxNetworkPackageSize; + this.mSocket.ReceiveBufferSize = Const.MaxNetworkPackageSize; //Attempt to connect. - var state = mClient.BeginConnect(mDestination, mPort, (x) => + try + { + var state = mSocket.BeginConnect(mDestination, mPort, (x) => + { + + try + { + //Did we connect? + mSocket.EndConnect(x); + + var networkStream = mSocket.GetStream(); + + //Prepare our hail package and send it. + using (var hail = BattleBitAPI.Common.Serialization.Stream.Get()) + { + hail.Write((byte)NetworkCommuncation.Hail); + hail.Write((ushort)this.GamePort); + hail.Write(this.IsPasswordProtected); + hail.Write(this.ServerName); + hail.Write(this.Gamemode); + hail.Write(this.Map); + hail.Write((byte)this.MapSize); + hail.Write((byte)this.DayNight); + hail.Write((byte)this.CurrentPlayers); + hail.Write((byte)this.InQueuePlayers); + hail.Write((byte)this.MaxPlayers); + hail.Write(this.LoadingScreenText); + hail.Write(this.ServerRulesText); + + //Send our hail package. + networkStream.Write(hail.Buffer, 0, hail.WritePosition); + networkStream.Flush(); + } + + //Sadly can not use Task Async here, Unity isn't great with tasks. + var watch = Stopwatch.StartNew(); + + //Read the first byte. + NetworkCommuncation response = NetworkCommuncation.None; + while (watch.ElapsedMilliseconds < Const.HailConnectTimeout) + { + if (mSocket.Available > 0) + { + var data = networkStream.ReadByte(); + if (data >= 0) + { + response = (NetworkCommuncation)data; + break; + } + } + Thread.Sleep(1); + } + + //Were we accepted. + if (response == NetworkCommuncation.Accepted) + { + //We are accepted. + this.mIsConnectingFlag = false; + this.IsConnected = true; + + mOnConnectedToServer(); + } + else + { + //Did we at least got a response? + if (response == NetworkCommuncation.None) + throw new Exception("Server did not respond to your connect request."); + + //Try to read our deny reason. + if (response == NetworkCommuncation.Denied && mSocket.Available > 0) + { + string errorString = null; + + using (var readStream = BattleBitAPI.Common.Serialization.Stream.Get()) + { + readStream.WritePosition = networkStream.Read(readStream.Buffer, 0, mSocket.Available); + if (!readStream.TryReadString(out errorString)) + errorString = null; + } + + if (errorString != null) + throw new Exception(errorString); + } + + throw new Exception("Server denied our connect request with an unknown reason."); + } + } + catch (Exception e) + { + + this.mIsConnectingFlag = false; + + mLogError("Unable to connect to API server: " + e.Message); + return; + } + + }, null); + } + catch { this.mIsConnectingFlag = false; - - try - { - //Did we connect? - mClient.EndConnect(x); - - var networkStream = mClient.GetStream(); - - //Prepare our hail package and send it. - using (var hail = BattleBitAPI.Common.Serialization.Stream.Get()) - { - hail.Write((byte)NetworkCommuncation.Hail); - hail.Write((ushort)this.GamePort); - hail.Write(this.IsPasswordProtected); - hail.Write(this.ServerName); - hail.Write(this.Gamemode); - hail.Write(this.Map); - hail.Write((byte)this.MapSize); - hail.Write((byte)this.DayNight); - hail.Write((byte)this.CurrentPlayers); - hail.Write((byte)this.InQueuePlayers); - hail.Write((byte)this.MaxPlayers); - hail.Write(this.LoadingScreenText); - hail.Write(this.ServerRulesText); - - //Send our hail package. - networkStream.Write(hail.Buffer, 0, hail.WritePosition); - networkStream.Flush(); - } - - //Sadly can not use Task Async here, Unity isn't great with tasks. - var watch = Stopwatch.StartNew(); - - //Read the first byte. - NetworkCommuncation response = NetworkCommuncation.None; - while (watch.ElapsedMilliseconds < Const.HailConnectTimeout) - { - if (mClient.Available > 0) - { - var data = networkStream.ReadByte(); - if (data >= 0) - { - response = (NetworkCommuncation)data; - break; - } - } - Thread.Sleep(1); - } - - //Were we accepted. - if (response == NetworkCommuncation.Accepted) - { - //We are accepted. - this.IsConnected = true; - - mOnConnectedToServer(); - } - else - { - //Did we at least got a response? - if (response == NetworkCommuncation.None) - throw new Exception("Server did not respond to your connect request."); - - //Try to read our deny reason. - if (response == NetworkCommuncation.Denied && mClient.Available > 0) - { - string errorString = null; - - using (var readStream = BattleBitAPI.Common.Serialization.Stream.Get()) - { - readStream.WritePosition = networkStream.Read(readStream.Buffer, 0, mClient.Available); - if (!readStream.TryReadString(out errorString)) - errorString = null; - } - - if (errorString != null) - throw new Exception(errorString); - } - - throw new Exception("Server denied our connect request with an unknown reason."); - } - } - catch (Exception e) - { - mLogError("Unable to connect to API server: " + e.Message); - return; - } - - }, null); + } //We haven't connected yet. return; @@ -166,6 +205,121 @@ namespace BattleBitAPI.Client //We are connected at this point. + try + { + //Are we still connected on socket level? + if (!mSocket.Connected) + { + mClose("Connection was terminated."); + return; + } + + var networkStream = mSocket.GetStream(); + + //Read network packages. + while (mSocket.Available > 0) + { + this.mLastPackageReceived = Extentions.TickCount; + + //Do we know the package size? + if (this.mReadPackageSize == 0) + { + const int sizeToRead = 4; + int leftSizeToRead = sizeToRead - this.mReadStream.WritePosition; + + int read = networkStream.Read(this.mReadStream.Buffer, this.mReadStream.WritePosition, leftSizeToRead); + if (read <= 0) + throw new Exception("Connection was terminated."); + + this.mReadStream.WritePosition += read; + + //Did we receive the package? + if (this.mReadStream.WritePosition >= 4) + { + //Read the package size + this.mReadPackageSize = this.mReadStream.ReadUInt32(); + + if (this.mReadPackageSize > Const.MaxNetworkPackageSize) + throw new Exception("Incoming package was larger than 'Conts.MaxNetworkPackageSize'"); + + //Is this keep alive package? + if (this.mReadPackageSize == 0) + { + Console.WriteLine("Keep alive was received."); + } + + //Reset the stream. + this.mReadStream.Reset(); + } + } + else + { + int sizeToRead = (int)mReadPackageSize; + int leftSizeToRead = sizeToRead - this.mReadStream.WritePosition; + + int read = networkStream.Read(this.mReadStream.Buffer, this.mReadStream.WritePosition, leftSizeToRead); + if (read <= 0) + throw new Exception("Connection was terminated."); + + this.mReadStream.WritePosition += read; + + //Do we have the package? + if (this.mReadStream.WritePosition >= mReadPackageSize) + { + this.mReadPackageSize = 0; + + mExecutePackage(this.mReadStream); + + //Reset + this.mReadStream.Reset(); + } + } + } + + //Send the network packages. + if (this.mWriteStream.WritePosition > 0) + { + lock (this.mWriteStream) + { + if (this.mWriteStream.WritePosition > 0) + { + networkStream.Write(this.mWriteStream.Buffer, 0, this.mWriteStream.WritePosition); + this.mWriteStream.WritePosition = 0; + + this.mLastPackageSent = Extentions.TickCount; + } + } + } + + //Are we timed out? + if ((Extentions.TickCount - this.mLastPackageReceived) > Const.NetworkTimeout) + throw new Exception("server timedout."); + + //Send keep alive if needed + if ((Extentions.TickCount - this.mLastPackageSent) > Const.NetworkKeepAlive) + { + //Send keep alive. + networkStream.Write(this.mKeepAliveBuffer, 0, 4); + + this.mLastPackageSent = Extentions.TickCount; + + Console.WriteLine("Keep alive was sent."); + } + } + catch (Exception e) + { + mClose(e.Message); + } + } + + // ---- Internal ---- + private void mExecutePackage(Common.Serialization.Stream stream) + { + var communcation = (NetworkCommuncation)stream.ReadInt8(); + switch (communcation) + { + + } } // ---- Callbacks ---- @@ -183,18 +337,18 @@ namespace BattleBitAPI.Client { } - private void mCloseConnection(string reason) + private void mClose(string reason) { if (this.IsConnected) { this.IsConnected = false; //Dispose old client if exist. - if (this.mClient != null) + if (this.mSocket != null) { - try { this.mClient.Close(); } catch { } - try { this.mClient.Dispose(); } catch { } - this.mClient = null; + try { this.mSocket.Close(); } catch { } + try { this.mSocket.Dispose(); } catch { } + this.mSocket = null; } mOnDisconnectedFromServer(reason); diff --git a/BattleBitAPI/Server/GameServer.cs b/BattleBitAPI/Server/GameServer.cs index 68aff28..7b7f218 100644 --- a/BattleBitAPI/Server/GameServer.cs +++ b/BattleBitAPI/Server/GameServer.cs @@ -83,6 +83,9 @@ namespace BattleBitAPI.Server { 0,0,0,0, }; + + this.mLastPackageReceived = Extentions.TickCount; + this.mLastPackageSent = Extentions.TickCount; } // ---- Tick ---- @@ -128,6 +131,12 @@ namespace BattleBitAPI.Server if (this.mReadPackageSize > Const.MaxNetworkPackageSize) throw new Exception("Incoming package was larger than 'Conts.MaxNetworkPackageSize'"); + //Is this keep alive package? + if (this.mReadPackageSize == 0) + { + Console.WriteLine("Keep alive was received."); + } + //Reset the stream. this.mReadStream.Reset(); } @@ -182,6 +191,8 @@ namespace BattleBitAPI.Server networkStream.Write(this.mKeepAliveBuffer, 0, 4); this.mLastPackageSent = Extentions.TickCount; + + Console.WriteLine("Keep alive was sent."); } } catch (Exception e) diff --git a/BattleBitAPI/Server/ServerListener.cs b/BattleBitAPI/Server/ServerListener.cs index 362cd1b..8dcb513 100644 --- a/BattleBitAPI/Server/ServerListener.cs +++ b/BattleBitAPI/Server/ServerListener.cs @@ -301,6 +301,8 @@ namespace BattleBitAPI.Server { try { + Console.WriteLine(e.Message); + var networkStream = client.GetStream(); using (var pck = BattleBitAPI.Common.Serialization.Stream.Get()) { diff --git a/Program.cs b/Program.cs index 3f2aac5..780c45b 100644 --- a/Program.cs +++ b/Program.cs @@ -1,28 +1,47 @@ -using BattleBitAPI.Server; +using BattleBitAPI.Client; +using BattleBitAPI.Server; using System.Net; class Program { static void Main(string[] args) { - ServerListener server = new ServerListener(); - server.OnGameServerConnecting += OnClientConnecting; - server.OnGameServerConnected += OnGameServerConnected; - server.OnGameServerDisconnected += OnGameServerDisconnected; + if (Console.ReadLine().Contains("h")) + { + ServerListener server = new ServerListener(); + server.OnGameServerConnecting += OnClientConnecting; + server.OnGameServerConnected += OnGameServerConnected; + server.OnGameServerDisconnected += OnGameServerDisconnected; + server.Start(29294); - server.Start(29294); + Thread.Sleep(-1); + } + else + { + Client c = new Client("127.0.0.1", 29294); + c.ServerName = "Test Server"; + c.Gamemode = "TDP"; + c.Map = "DustyDew"; + + while (true) + { + c.Tick(); + Thread.Sleep(1); + } + } } private static async Task OnClientConnecting(IPAddress ip) { + Console.WriteLine(ip + " is connecting."); return true; } private static async Task OnGameServerConnected(GameServer server) { - Console.WriteLine("Server "+server.ServerName+" was connected."); + Console.WriteLine("Server " + server.ServerName + " was connected."); } private static async Task OnGameServerDisconnected(GameServer server) { - Console.WriteLine("Server " + server.ServerName + " was disconnected."); + Console.WriteLine("Server " + server.ServerName + " was disconnected. (" + server.TerminationReason + ")"); } } \ No newline at end of file diff --git a/bin/Debug/net6.0/CommunityServerAPI.dll b/bin/Debug/net6.0/CommunityServerAPI.dll index fc5e0cd..fefa4bc 100644 Binary files a/bin/Debug/net6.0/CommunityServerAPI.dll and b/bin/Debug/net6.0/CommunityServerAPI.dll differ diff --git a/bin/Debug/net6.0/CommunityServerAPI.pdb b/bin/Debug/net6.0/CommunityServerAPI.pdb index e51269f..b92d91f 100644 Binary files a/bin/Debug/net6.0/CommunityServerAPI.pdb and b/bin/Debug/net6.0/CommunityServerAPI.pdb differ diff --git a/obj/Debug/net6.0/CommunityServerAPI.csproj.BuildWithSkipAnalyzers b/obj/Debug/net6.0/CommunityServerAPI.csproj.BuildWithSkipAnalyzers new file mode 100644 index 0000000..e69de29 diff --git a/obj/Debug/net6.0/CommunityServerAPI.dll b/obj/Debug/net6.0/CommunityServerAPI.dll index fc5e0cd..fefa4bc 100644 Binary files a/obj/Debug/net6.0/CommunityServerAPI.dll and b/obj/Debug/net6.0/CommunityServerAPI.dll differ diff --git a/obj/Debug/net6.0/CommunityServerAPI.pdb b/obj/Debug/net6.0/CommunityServerAPI.pdb index e51269f..b92d91f 100644 Binary files a/obj/Debug/net6.0/CommunityServerAPI.pdb and b/obj/Debug/net6.0/CommunityServerAPI.pdb differ diff --git a/obj/Debug/net6.0/ref/CommunityServerAPI.dll b/obj/Debug/net6.0/ref/CommunityServerAPI.dll index 58ddf54..e96bef3 100644 Binary files a/obj/Debug/net6.0/ref/CommunityServerAPI.dll and b/obj/Debug/net6.0/ref/CommunityServerAPI.dll differ diff --git a/obj/Debug/net6.0/refint/CommunityServerAPI.dll b/obj/Debug/net6.0/refint/CommunityServerAPI.dll index 58ddf54..e96bef3 100644 Binary files a/obj/Debug/net6.0/refint/CommunityServerAPI.dll and b/obj/Debug/net6.0/refint/CommunityServerAPI.dll differ