From d0981e6f6ff19b9b222971a7efcf3de911134deb Mon Sep 17 00:00:00 2001
From: MrOkiDoki <0mrokidoki@gmail.com>
Date: Sun, 20 Aug 2023 11:21:22 +0300
Subject: [PATCH 1/3] namespace fix.
---
BattleBitAPI/Common/Conts.cs | 2 +-
BattleBitAPI/Server/GameServer.cs | 6 +-----
BattleBitAPI/Server/ServerListener.cs | 1 -
CommunityServerAPI.csproj | 1 +
4 files changed, 3 insertions(+), 7 deletions(-)
diff --git a/BattleBitAPI/Common/Conts.cs b/BattleBitAPI/Common/Conts.cs
index e339257..122f18d 100644
--- a/BattleBitAPI/Common/Conts.cs
+++ b/BattleBitAPI/Common/Conts.cs
@@ -1,4 +1,4 @@
-namespace CommunityServerAPI.BattleBitAPI
+namespace BattleBitAPI
{
public static class Const
{
diff --git a/BattleBitAPI/Server/GameServer.cs b/BattleBitAPI/Server/GameServer.cs
index c437f95..e9c9916 100644
--- a/BattleBitAPI/Server/GameServer.cs
+++ b/BattleBitAPI/Server/GameServer.cs
@@ -1,7 +1,4 @@
-using System.ComponentModel.DataAnnotations;
-using System.Diagnostics;
-using System.Linq;
-using System.Net;
+using System.Net;
using System.Net.Sockets;
using System.Numerics;
using System.Text;
@@ -9,7 +6,6 @@ using BattleBitAPI.Common;
using BattleBitAPI.Common.Extentions;
using BattleBitAPI.Networking;
using BattleBitAPI.Pooling;
-using CommunityServerAPI.BattleBitAPI;
namespace BattleBitAPI.Server
{
diff --git a/BattleBitAPI/Server/ServerListener.cs b/BattleBitAPI/Server/ServerListener.cs
index 6bdd385..c7ad39d 100644
--- a/BattleBitAPI/Server/ServerListener.cs
+++ b/BattleBitAPI/Server/ServerListener.cs
@@ -5,7 +5,6 @@ using System.Runtime.CompilerServices;
using BattleBitAPI.Common;
using BattleBitAPI.Common.Extentions;
using BattleBitAPI.Networking;
-using CommunityServerAPI.BattleBitAPI;
namespace BattleBitAPI.Server
{
diff --git a/CommunityServerAPI.csproj b/CommunityServerAPI.csproj
index 10c18d1..52a520b 100644
--- a/CommunityServerAPI.csproj
+++ b/CommunityServerAPI.csproj
@@ -18,6 +18,7 @@
https://github.com/MrOkiDoki/BattleBit-Community-Server-API
https://github.com/MrOkiDoki/BattleBit-Community-Server-API
BattleBit
+ 1.0.1
From 0ee058910159db2404631876e3460339716de2c1 Mon Sep 17 00:00:00 2001
From: MrOkiDoki <0mrokidoki@gmail.com>
Date: Sun, 20 Aug 2023 14:53:28 +0300
Subject: [PATCH 2/3] Callbacks for session changes.
---
BattleBitAPI/Common/Extentions/Extentions.cs | 6 +
.../Networking/NetworkCommuncation.cs | 1 +
BattleBitAPI/Server/GameServer.cs | 39 ++-
BattleBitAPI/Server/Player.cs | 84 +++--
BattleBitAPI/Server/ServerListener.cs | 293 +++++++++++++-----
5 files changed, 305 insertions(+), 118 deletions(-)
diff --git a/BattleBitAPI/Common/Extentions/Extentions.cs b/BattleBitAPI/Common/Extentions/Extentions.cs
index 3ef94dd..ae5b7ec 100644
--- a/BattleBitAPI/Common/Extentions/Extentions.cs
+++ b/BattleBitAPI/Common/Extentions/Extentions.cs
@@ -25,6 +25,12 @@ namespace BattleBitAPI.Common.Extentions
#endif
}
+ public static void Replace(this Dictionary dic, TKey key, TValue value)
+ {
+ dic.Remove(key);
+ dic.Add(key, value);
+ }
+
public static void SafeClose(this TcpClient client)
{
try { client.Close(); } catch { }
diff --git a/BattleBitAPI/Networking/NetworkCommuncation.cs b/BattleBitAPI/Networking/NetworkCommuncation.cs
index 69f4304..f30cbe0 100644
--- a/BattleBitAPI/Networking/NetworkCommuncation.cs
+++ b/BattleBitAPI/Networking/NetworkCommuncation.cs
@@ -40,5 +40,6 @@
OnPlayerGivenUp = 70,
OnPlayerRevivedAnother = 71,
OnSquadPointsChanged = 72,
+ NotifyNewRoundID = 73,
}
}
diff --git a/BattleBitAPI/Server/GameServer.cs b/BattleBitAPI/Server/GameServer.cs
index e9c9916..ff45b59 100644
--- a/BattleBitAPI/Server/GameServer.cs
+++ b/BattleBitAPI/Server/GameServer.cs
@@ -17,7 +17,6 @@ namespace BattleBitAPI.Server
public IPAddress GameIP => mInternal.GameIP;
public int GamePort => mInternal.GamePort;
- public TcpClient Socket => mInternal.Socket;
public bool IsPasswordProtected => mInternal.IsPasswordProtected;
public string ServerName => mInternal.ServerName;
public string Gamemode => mInternal.Gamemode;
@@ -29,6 +28,8 @@ namespace BattleBitAPI.Server
public int MaxPlayerCount => mInternal.MaxPlayerCount;
public string LoadingScreenText => mInternal.LoadingScreenText;
public string ServerRulesText => mInternal.ServerRulesText;
+ public uint RoundIndex => mInternal.RoundIndex;
+ public long SessionID => mInternal.SessionID;
public ServerSettings ServerSettings => mInternal.ServerSettings;
public MapRotation MapRotation => mInternal.MapRotation;
public GamemodeRotation GamemodeRotation => mInternal.GamemodeRotation;
@@ -158,7 +159,7 @@ namespace BattleBitAPI.Server
try
{
//Are we still connected on socket level?
- if (!Socket.Connected)
+ if (mInternal.Socket == null || !mInternal.Socket.Connected)
{
mClose("Connection was terminated.");
return;
@@ -171,10 +172,10 @@ namespace BattleBitAPI.Server
return;
}
- var networkStream = Socket.GetStream();
+ var networkStream = mInternal.Socket.GetStream();
//Read network packages.
- while (Socket.Available > 0)
+ while (mInternal.Socket.Available > 0)
{
this.mInternal.mLastPackageReceived = Extentions.TickCount;
@@ -405,10 +406,6 @@ namespace BattleBitAPI.Server
public virtual async Task OnTick()
{
- }
- public virtual async Task OnReconnected()
- {
-
}
public virtual async Task OnDisconnected()
{
@@ -500,6 +497,10 @@ namespace BattleBitAPI.Server
public virtual async Task OnRoundEnded()
{
+ }
+ public virtual async Task OnSessionChanged(long oldSessionID, long newSessionID)
+ {
+
}
// ---- Functions ----
@@ -553,10 +554,18 @@ namespace BattleBitAPI.Server
{
ExecuteCommand("endgame");
}
- public void SayToChat(string msg)
+ public void SayToAllChat(string msg)
{
ExecuteCommand("say " + msg);
}
+ public void SayToChat(string msg, ulong steamID)
+ {
+ ExecuteCommand("sayto " + steamID + " " + msg);
+ }
+ public void SayToChat(string msg, Player player)
+ {
+ SayToChat(msg, player.SteamID);
+ }
public void StopServer()
{
@@ -897,7 +906,7 @@ namespace BattleBitAPI.Server
}
// ---- Static ----
- public static void SetInstance(GameServer server, Internal @internal)
+ internal static void SetInstance(GameServer server, Internal @internal)
{
server.mInternal = @internal;
}
@@ -908,6 +917,7 @@ namespace BattleBitAPI.Server
// ---- Variables ----
public ulong ServerHash;
public bool IsConnected;
+ public bool HasActiveConnectionSession;
public IPAddress GameIP;
public int GamePort;
public TcpClient Socket;
@@ -924,6 +934,8 @@ namespace BattleBitAPI.Server
public int MaxPlayerCount;
public string LoadingScreenText;
public string ServerRulesText;
+ public uint RoundIndex;
+ public long SessionID;
public ServerSettings ServerSettings;
public MapRotation MapRotation;
public GamemodeRotation GamemodeRotation;
@@ -944,6 +956,7 @@ namespace BattleBitAPI.Server
public long mLastPackageReceived;
public long mLastPackageSent;
public bool mWantsToCloseConnection;
+ public long mPreviousSessionID;
public StringBuilder mBuilder;
public Queue<(ulong steamID, PlayerModifications.mPlayerModifications)> mChangedModifications;
@@ -1290,7 +1303,9 @@ namespace BattleBitAPI.Server
int inQueuePlayers,
int maxPlayers,
string loadingScreenText,
- string serverRulesText
+ string serverRulesText,
+ uint roundIndex,
+ long sessionID
)
{
this.ServerHash = ((ulong)port << 32) | (ulong)iP.ToUInt();
@@ -1311,6 +1326,8 @@ namespace BattleBitAPI.Server
this.MaxPlayerCount = maxPlayers;
this.LoadingScreenText = loadingScreenText;
this.ServerRulesText = serverRulesText;
+ this.RoundIndex = roundIndex;
+ this.SessionID = sessionID;
this.ServerSettings.Reset();
this._RoomSettings.Reset();
diff --git a/BattleBitAPI/Server/Player.cs b/BattleBitAPI/Server/Player.cs
index 4bea9c5..880548f 100644
--- a/BattleBitAPI/Server/Player.cs
+++ b/BattleBitAPI/Server/Player.cs
@@ -58,7 +58,7 @@ namespace BattleBitAPI
KickFromSquad();
else
{
- if(value.Team != this.Team)
+ if (value.Team != this.Team)
ChangeTeam(value.Team);
JoinSquad(value.Name);
}
@@ -66,6 +66,8 @@ namespace BattleBitAPI
}
public bool InSquad => mInternal.SquadName != Squads.NoSquad;
public int PingMs => mInternal.PingMs;
+ public long CurrentSessionID => mInternal.SessionID;
+ public bool IsConnected => mInternal.SessionID != 0;
public float HP
{
@@ -156,56 +158,78 @@ namespace BattleBitAPI
public virtual async Task OnDisconnected()
{
+ }
+ public virtual async Task OnSessionChanged(long oldSessionID, long newSessionID)
+ {
+
}
// ---- Functions ----
public void Kick(string reason = "")
{
- GameServer.Kick(this, reason);
+ if (IsConnected)
+ GameServer.Kick(this, reason);
}
public void Kill()
{
- GameServer.Kill(this);
+ if (IsConnected)
+ GameServer.Kill(this);
}
public void ChangeTeam()
{
- GameServer.ChangeTeam(this);
+ if (IsConnected)
+ GameServer.ChangeTeam(this);
}
public void ChangeTeam(Team team)
{
- GameServer.ChangeTeam(this, team);
+ if (IsConnected)
+ GameServer.ChangeTeam(this, team);
}
public void KickFromSquad()
{
- GameServer.KickFromSquad(this);
+ if (IsConnected)
+ GameServer.KickFromSquad(this);
}
public void JoinSquad(Squads targetSquad)
{
- GameServer.JoinSquad(this, targetSquad);
+ if (IsConnected)
+ GameServer.JoinSquad(this, targetSquad);
}
public void DisbandTheSquad()
{
- GameServer.DisbandPlayerCurrentSquad(this);
+ if (IsConnected)
+ GameServer.DisbandPlayerCurrentSquad(this);
}
public void PromoteToSquadLeader()
{
- GameServer.PromoteSquadLeader(this);
+ if (IsConnected)
+ GameServer.PromoteSquadLeader(this);
}
public void WarnPlayer(string msg)
{
- GameServer.WarnPlayer(this, msg);
+ if (IsConnected)
+ GameServer.WarnPlayer(this, msg);
}
public void Message(string msg)
{
- GameServer.MessageToPlayer(this, msg);
+ if (IsConnected)
+ GameServer.MessageToPlayer(this, msg);
}
+ public void SayToChat(string msg)
+ {
+ if (IsConnected)
+ GameServer.SayToChat(msg, this);
+ }
+
public void Message(string msg, float fadeoutTime)
{
- GameServer.MessageToPlayer(this, msg, fadeoutTime);
+ if (IsConnected)
+ GameServer.MessageToPlayer(this, msg, fadeoutTime);
}
public void SetNewRole(GameRole role)
{
- GameServer.SetRoleTo(this, role);
+ if (IsConnected)
+ GameServer.SetRoleTo(this, role);
}
public void Teleport(Vector3 target)
{
@@ -213,47 +237,57 @@ namespace BattleBitAPI
}
public void SpawnPlayer(PlayerLoadout loadout, PlayerWearings wearings, Vector3 position, Vector3 lookDirection, PlayerStand stand, float spawnProtection)
{
- GameServer.SpawnPlayer(this, loadout, wearings, position, lookDirection, stand, spawnProtection);
+ if (IsConnected)
+ GameServer.SpawnPlayer(this, loadout, wearings, position, lookDirection, stand, spawnProtection);
}
public void SetHP(float newHP)
{
- GameServer.SetHP(this, newHP);
+ if (IsConnected)
+ GameServer.SetHP(this, newHP);
}
public void GiveDamage(float damage)
{
- GameServer.GiveDamage(this, damage);
+ if (IsConnected)
+ GameServer.GiveDamage(this, damage);
}
public void Heal(float hp)
{
- GameServer.Heal(this, hp);
+ if (IsConnected)
+ GameServer.Heal(this, hp);
}
public void SetPrimaryWeapon(WeaponItem item, int extraMagazines, bool clear = false)
{
- GameServer.SetPrimaryWeapon(this, item, extraMagazines, clear);
+ if (IsConnected)
+ GameServer.SetPrimaryWeapon(this, item, extraMagazines, clear);
}
public void SetSecondaryWeapon(WeaponItem item, int extraMagazines, bool clear = false)
{
- GameServer.SetSecondaryWeapon(this, item, extraMagazines, clear);
+ if (IsConnected)
+ GameServer.SetSecondaryWeapon(this, item, extraMagazines, clear);
}
public void SetFirstAidGadget(string item, int extra, bool clear = false)
{
- GameServer.SetFirstAid(this, item, extra, clear);
+ if (IsConnected)
+ GameServer.SetFirstAid(this, item, extra, clear);
}
public void SetLightGadget(string item, int extra, bool clear = false)
{
- GameServer.SetLightGadget(this, item, extra, clear);
+ if (IsConnected)
+ GameServer.SetLightGadget(this, item, extra, clear);
}
public void SetHeavyGadget(string item, int extra, bool clear = false)
{
- GameServer.SetHeavyGadget(this, item, extra, clear);
+ if (IsConnected)
+ GameServer.SetHeavyGadget(this, item, extra, clear);
}
public void SetThrowable(string item, int extra, bool clear = false)
{
- GameServer.SetThrowable(this, item, extra, clear);
+ if (IsConnected)
+ GameServer.SetThrowable(this, item, extra, clear);
}
// ---- Static ----
- public static void SetInstance(TPlayer player, Player.Internal @internal)
+ internal static void SetInstance(TPlayer player, Player.Internal @internal)
{
player.mInternal = @internal;
}
@@ -275,6 +309,8 @@ namespace BattleBitAPI
public Team Team;
public Squads SquadName;
public int PingMs = 999;
+ public long PreviousSessionID = 0;
+ public long SessionID = 0;
public bool IsAlive;
public float HP;
diff --git a/BattleBitAPI/Server/ServerListener.cs b/BattleBitAPI/Server/ServerListener.cs
index c7ad39d..b75c3b3 100644
--- a/BattleBitAPI/Server/ServerListener.cs
+++ b/BattleBitAPI/Server/ServerListener.cs
@@ -1,10 +1,11 @@
using System.Net;
using System.Net.Sockets;
using System.Numerics;
-using System.Runtime.CompilerServices;
+using System.Resources;
using BattleBitAPI.Common;
using BattleBitAPI.Common.Extentions;
using BattleBitAPI.Networking;
+using BattleBitAPI.Pooling;
namespace BattleBitAPI.Server
{
@@ -55,15 +56,6 @@ namespace BattleBitAPI.Server
///
public Func, Task> OnGameServerConnected { get; set; }
- ///
- /// Fired when a game server reconnects. (When game server connects while a socket is already open)
- ///
- ///
- ///
- /// GameServer: Game server that is reconnecting.
- ///
- public Func, Task> OnGameServerReconnected { get; set; }
-
///
/// Fired when a game server disconnects. Check (GameServer.TerminationReason) to see the reason.
///
@@ -97,12 +89,14 @@ namespace BattleBitAPI.Server
private TcpListener mSocket;
private Dictionary.Internal resources)> mActiveConnections;
private mInstances mInstanceDatabase;
+ private ItemPooling> mGameServerPool;
// --- Construction ---
public ServerListener()
{
this.mActiveConnections = new Dictionary.Internal)>(16);
this.mInstanceDatabase = new mInstances();
+ this.mGameServerPool = new ItemPooling>(64);
}
// --- Starting ---
@@ -160,10 +154,12 @@ namespace BattleBitAPI.Server
{
var ip = (client.Client.RemoteEndPoint as IPEndPoint).Address;
+ //Is this IP allowed?
bool allow = true;
if (OnGameServerConnecting != null)
allow = await OnGameServerConnecting(ip);
+ //Close connection if it was not allowed.
if (!allow)
{
//Connection is not allowed from this IP.
@@ -171,11 +167,13 @@ namespace BattleBitAPI.Server
return;
}
- TGameServer server = null;
- GameServer.Internal resources;
+ //Read port,token,version
+ string token;
+ string version;
+ int gamePort;
try
{
- using (CancellationTokenSource source = new CancellationTokenSource(Const.HailConnectTimeout))
+ using (var source = new CancellationTokenSource(2000))
{
using (var readStream = Common.Serialization.Stream.Get())
{
@@ -186,13 +184,13 @@ namespace BattleBitAPI.Server
readStream.Reset();
if (!await networkStream.TryRead(readStream, 1, source.Token))
throw new Exception("Unable to read the package type");
+
NetworkCommuncation type = (NetworkCommuncation)readStream.ReadInt8();
if (type != NetworkCommuncation.Hail)
throw new Exception("Incoming package wasn't hail.");
}
//Read the server token
- string token;
{
readStream.Reset();
if (!await networkStream.TryRead(readStream, 2, source.Token))
@@ -210,7 +208,6 @@ namespace BattleBitAPI.Server
}
//Read the server version
- string version;
{
readStream.Reset();
if (!await networkStream.TryRead(readStream, 2, source.Token))
@@ -227,23 +224,59 @@ namespace BattleBitAPI.Server
version = readStream.ReadString(stringSize);
}
- if (version != Const.Version)
- throw new Exception("Incoming server's version `" + version + "` does not match with current API version `" + Const.Version + "`");
-
//Read port
- int gamePort;
{
readStream.Reset();
if (!await networkStream.TryRead(readStream, 2, source.Token))
throw new Exception("Unable to read the Port");
gamePort = readStream.ReadUInt16();
}
+ }
+ }
+ }
+ catch { client.SafeClose(); return; }
- if (OnValidateGameServerToken != null)
- allow = await OnValidateGameServerToken(ip, (ushort)gamePort, token);
+ var hash = ((ulong)gamePort << 32) | (ulong)ip.ToUInt();
+ TGameServer server = null;
+ GameServer.Internal resources = null;
+ try
+ {
+ //Does versions match?
+ if (version != Const.Version)
+ throw new Exception("Incoming server's version `" + version + "` does not match with current API version `" + Const.Version + "`");
- if (!allow)
- throw new Exception("Token was not valid!");
+ //Is valid token?
+ if (OnValidateGameServerToken != null)
+ {
+ if (!await OnValidateGameServerToken(ip, (ushort)gamePort, token))
+ throw new Exception("Token was not valid!");
+ }
+
+ //Are there any connections with same IP and port?
+ {
+ bool sessionExist = false;
+ (TGameServer server, GameServer.Internal resources) oldSession;
+
+ //Any sessions with this IP:Port?
+ lock (this.mActiveConnections)
+ sessionExist = this.mActiveConnections.TryGetValue(hash, out oldSession);
+
+ if (sessionExist)
+ {
+ //Close old session.
+ oldSession.server.CloseConnection("Reconnecting.");
+
+ //Wait until session is fully closed.
+ while (oldSession.resources.HasActiveConnectionSession)
+ await Task.Delay(1);
+ }
+ }
+
+ using (var source = new CancellationTokenSource(Const.HailConnectTimeout))
+ {
+ using (var readStream = Common.Serialization.Stream.Get())
+ {
+ var networkStream = client.GetStream();
//Read is server protected
bool isPasswordProtected;
@@ -403,7 +436,28 @@ namespace BattleBitAPI.Server
}
}
- var hash = ((ulong)gamePort << 32) | (ulong)ip.ToUInt();
+ //Round index
+ uint roundIndex;
+ {
+ readStream.Reset();
+ if (!await networkStream.TryRead(readStream, 4, source.Token))
+ throw new Exception("Unable to read the Server Round Index");
+ roundIndex = readStream.ReadUInt32();
+ }
+
+ //Round index
+ long sessionID;
+ {
+ readStream.Reset();
+ if (!await networkStream.TryRead(readStream, 8, source.Token))
+ throw new Exception("Unable to read the Server Round ID");
+ sessionID = readStream.ReadInt64();
+ }
+
+
+
+
+
server = this.mInstanceDatabase.GetServerInstance(hash, out resources, this.OnCreatingGameServerInstance, ip, (ushort)gamePort);
resources.Set(
this.mExecutePackage,
@@ -421,7 +475,9 @@ namespace BattleBitAPI.Server
queuePlayers,
maxPlayers,
loadingScreenText,
- serverRulesText
+ serverRulesText,
+ roundIndex,
+ sessionID
);
//Room settings
@@ -583,7 +639,6 @@ namespace BattleBitAPI.Server
playerInternal.SteamID = steamid;
playerInternal.Name = username;
playerInternal.IP = new IPAddress(ipHash);
- playerInternal.GameServer = (GameServer)server;
playerInternal.Team = team;
playerInternal.SquadName = squad;
playerInternal.Role = role;
@@ -604,6 +659,9 @@ namespace BattleBitAPI.Server
playerInternal._Modifications.Read(readStream);
}
+ playerInternal.GameServer = (GameServer)server;
+ playerInternal.SessionID = server.SessionID;
+
resources.AddPlayer(player);
}
@@ -669,37 +727,6 @@ namespace BattleBitAPI.Server
return;
}
- bool connectionExist = false;
-
- //Track the connection
- lock (this.mActiveConnections)
- {
- //An old connection exist with same IP + Port?
- if (connectionExist = this.mActiveConnections.TryGetValue(server.ServerHash, out var oldServer))
- {
- oldServer.resources.ReconnectFlag = true;
- this.mActiveConnections.Remove(server.ServerHash);
- }
-
- this.mActiveConnections.Add(server.ServerHash, (server, resources));
- }
-
- //Call the callback.
- if (!connectionExist)
- {
- //New connection!
- server.OnConnected();
- if (this.OnGameServerConnected != null)
- this.OnGameServerConnected(server);
- }
- else
- {
- //Reconnection
- server.OnReconnected();
- if (this.OnGameServerReconnected != null)
- this.OnGameServerReconnected(server);
- }
-
//Set the buffer sizes.
client.ReceiveBufferSize = Const.MaxNetworkPackageSize;
client.SendBufferSize = Const.MaxNetworkPackageSize;
@@ -709,39 +736,77 @@ namespace BattleBitAPI.Server
}
private async Task mHandleGameServer(TGameServer server, GameServer.Internal @internal)
{
- bool isTicking = false;
-
- using (server)
+ @internal.HasActiveConnectionSession = true;
{
- async Task mTickAsync()
+ // ---- Connected ----
{
- isTicking = true;
- await server.OnTick();
- isTicking = false;
+ lock (this.mActiveConnections)
+ this.mActiveConnections.Replace(server.ServerHash, (server, @internal));
+
+ server.OnConnected();
+ if (this.OnGameServerConnected != null)
+ this.OnGameServerConnected(server);
}
- while (server.IsConnected)
+ //Update sessions
{
- if (!isTicking)
- mTickAsync();
+ if (@internal.mPreviousSessionID != @internal.SessionID)
+ {
+ var oldSession = @internal.mPreviousSessionID;
+ @internal.mPreviousSessionID = @internal.SessionID;
- await server.Tick();
- await Task.Delay(10);
+ if (oldSession != 0)
+ server.OnSessionChanged(oldSession, @internal.SessionID);
+ }
+
+ foreach (var item in @internal.Players)
+ {
+ var @player_internal = mInstanceDatabase.GetPlayerInternals(item.Key);
+ if (@player_internal.PreviousSessionID != @player_internal.SessionID)
+ {
+ var previousID = @player_internal.PreviousSessionID;
+ @player_internal.PreviousSessionID = @player_internal.SessionID;
+
+ if (previousID != 0)
+ item.Value.OnSessionChanged(previousID, @player_internal.SessionID);
+ }
+ }
}
- if (!server.ReconnectFlag)
+ // ---- Ticking ----
+ using (server)
{
+ var isTicking = false;
+ async Task mTickAsync()
+ {
+ isTicking = true;
+ await server.OnTick();
+ isTicking = false;
+ }
+
+ while (server.IsConnected)
+ {
+ if (!isTicking)
+ mTickAsync();
+
+ await server.Tick();
+ await Task.Delay(10);
+ }
+ }
+
+ // ---- Disconnected ----
+ {
+ mCleanup(server, @internal);
+
+ lock (this.mActiveConnections)
+ this.mActiveConnections.Remove(server.ServerHash);
+
server.OnDisconnected();
-
if (this.OnGameServerDisconnected != null)
this.OnGameServerDisconnected(server);
}
}
-
- //Remove from list.
- if (!server.ReconnectFlag)
- lock (this.mActiveConnections)
- this.mActiveConnections.Remove(server.ServerHash);
+ @internal.HasActiveConnectionSession = false;
}
// --- Logic Executing ---
@@ -766,8 +831,6 @@ namespace BattleBitAPI.Server
playerInternal.SteamID = steamID;
playerInternal.Name = username;
playerInternal.IP = new IPAddress(ip);
- playerInternal.GameServer = (GameServer)server;
-
playerInternal.Team = team;
playerInternal.SquadName = squad;
playerInternal.Role = role;
@@ -775,9 +838,21 @@ namespace BattleBitAPI.Server
//Start from default.
playerInternal._Modifications.Reset();
+ playerInternal.GameServer = (GameServer)server;
+ playerInternal.SessionID = server.SessionID;
+
resources.AddPlayer(player);
player.OnConnected();
server.OnPlayerConnected(player);
+
+ if (playerInternal.PreviousSessionID != playerInternal.SessionID)
+ {
+ var previousID = playerInternal.PreviousSessionID;
+ playerInternal.PreviousSessionID = playerInternal.SessionID;
+
+ if (previousID != 0)
+ player.OnSessionChanged(previousID, playerInternal.SessionID);
+ }
}
}
break;
@@ -816,6 +891,9 @@ namespace BattleBitAPI.Server
server.OnPlayerLeftSquad((TPlayer)player, msquad);
}
+ @internal.SessionID = 0;
+ @internal.GameServer = null;
+
player.OnDisconnected();
server.OnPlayerDisconnected((TPlayer)player);
}
@@ -1330,10 +1408,55 @@ namespace BattleBitAPI.Server
}
break;
}
+ case NetworkCommuncation.NotifyNewRoundID:
+ {
+ if (stream.CanRead(4 + 8))
+ {
+ resources.RoundIndex = stream.ReadUInt32();
+ resources.SessionID = stream.ReadInt64();
+
+ if (resources.mPreviousSessionID != resources.SessionID)
+ {
+ var oldSession = resources.mPreviousSessionID;
+ resources.mPreviousSessionID = resources.SessionID;
+
+ if (oldSession != 0)
+ server.OnSessionChanged(oldSession, resources.SessionID);
+ }
+
+ foreach (var item in resources.Players)
+ {
+ var @player_internal = mInstanceDatabase.GetPlayerInternals(item.Key);
+ @player_internal.SessionID = resources.SessionID;
+
+ if (@player_internal.PreviousSessionID != @player_internal.SessionID)
+ {
+ var previousID = @player_internal.PreviousSessionID;
+ @player_internal.PreviousSessionID = @player_internal.SessionID;
+
+ if (previousID != 0)
+ item.Value.OnSessionChanged(previousID, @player_internal.SessionID);
+ }
+ }
+ }
+ break;
+ }
}
}
// --- Private ---
+ private void mCleanup(GameServer server, GameServer.Internal @internal)
+ {
+ lock (@internal.Players)
+ {
+ foreach (var item in @internal.Players)
+ {
+ var @player_internal = mInstanceDatabase.GetPlayerInternals(item.Key);
+ @player_internal.SessionID = 0;
+ @player_internal.GameServer = null;
+ }
+ }
+ }
private Player.Internal mGetPlayerInternals(ulong steamID)
{
return mInstanceDatabase.GetPlayerInternals(steamID);
@@ -1344,13 +1467,17 @@ namespace BattleBitAPI.Server
{
get
{
- var list = new List(mActiveConnections.Count);
- lock (mActiveConnections)
+ using (var list = this.mGameServerPool.Get())
{
- foreach (var item in mActiveConnections.Values)
- list.Add(item.server);
+ //Get a copy
+ lock (mActiveConnections)
+ foreach (var item in mActiveConnections.Values)
+ list.ListItems.Add(item.server);
+
+ //Iterate
+ for (int i = 0; i < list.ListItems.Count; i++)
+ yield return (TGameServer)list.ListItems[i];
}
- return list;
}
}
public bool TryGetGameServer(IPAddress ip, ushort port, out TGameServer server)
From c603b80d26128aa12761c998665a59d91434804d Mon Sep 17 00:00:00 2001
From: MrOkiDoki <0mrokidoki@gmail.com>
Date: Sun, 20 Aug 2023 16:00:51 +0300
Subject: [PATCH 3/3] Logging added.
---
BattleBitAPI/Common/Enums/LogLevel.cs | 53 +++++
.../Networking/NetworkCommuncation.cs | 1 +
BattleBitAPI/Server/Internal/Squad.cs | 2 +-
BattleBitAPI/Server/ServerListener.cs | 197 +++++++++++++++---
CommunityServerAPI.csproj | 2 +-
5 files changed, 220 insertions(+), 35 deletions(-)
create mode 100644 BattleBitAPI/Common/Enums/LogLevel.cs
diff --git a/BattleBitAPI/Common/Enums/LogLevel.cs b/BattleBitAPI/Common/Enums/LogLevel.cs
new file mode 100644
index 0000000..5ed5849
--- /dev/null
+++ b/BattleBitAPI/Common/Enums/LogLevel.cs
@@ -0,0 +1,53 @@
+namespace BattleBitAPI.Common
+{
+ [System.Flags]
+ public enum LogLevel : ulong
+ {
+ None = 0,
+
+ ///
+ /// Output logs from low level sockets.
+ ///
+ Sockets = 1 << 0,
+
+ ///
+ /// Output logs from remote game server (Highly recommended)
+ ///
+ GameServerErrors = 1 << 1,
+
+ ///
+ /// Output logs of game server connects, reconnects.
+ ///
+ GameServers = 1 << 2,
+
+ ///
+ /// Output logs of player connects, disconnects
+ ///
+ Players = 1 << 3,
+
+ ///
+ /// Output logs of squad changes (someone joining, leaving etc)
+ ///
+ Squads = 1 << 4,
+
+ ///
+ /// Output logs of kills/giveups/revives.
+ ///
+ KillsAndSpawns = 1 << 5,
+
+ ///
+ /// Output logs of role changes (player changing role to medic, support etc).
+ ///
+ Roles = 1 << 6,
+
+ ///
+ /// Output logs player's healt changes. (When received damage or healed)
+ ///
+ HealtChanges = 1 << 7,
+
+ ///
+ /// Output everything.
+ ///
+ All = ulong.MaxValue,
+ }
+}
diff --git a/BattleBitAPI/Networking/NetworkCommuncation.cs b/BattleBitAPI/Networking/NetworkCommuncation.cs
index f30cbe0..f9c1be8 100644
--- a/BattleBitAPI/Networking/NetworkCommuncation.cs
+++ b/BattleBitAPI/Networking/NetworkCommuncation.cs
@@ -41,5 +41,6 @@
OnPlayerRevivedAnother = 71,
OnSquadPointsChanged = 72,
NotifyNewRoundID = 73,
+ Log = 74,
}
}
diff --git a/BattleBitAPI/Server/Internal/Squad.cs b/BattleBitAPI/Server/Internal/Squad.cs
index b29583d..c21089c 100644
--- a/BattleBitAPI/Server/Internal/Squad.cs
+++ b/BattleBitAPI/Server/Internal/Squad.cs
@@ -29,7 +29,7 @@ namespace BattleBitAPI.Server
public override string ToString()
{
- return Team + " : " + Name;
+ return "Squad " + Name;
}
// ---- Internal ----
diff --git a/BattleBitAPI/Server/ServerListener.cs b/BattleBitAPI/Server/ServerListener.cs
index b75c3b3..8845126 100644
--- a/BattleBitAPI/Server/ServerListener.cs
+++ b/BattleBitAPI/Server/ServerListener.cs
@@ -1,4 +1,5 @@
-using System.Net;
+using System.Data;
+using System.Net;
using System.Net.Sockets;
using System.Numerics;
using System.Resources;
@@ -15,6 +16,7 @@ namespace BattleBitAPI.Server
public bool IsListening { get; private set; }
public bool IsDisposed { get; private set; }
public int ListeningPort { get; private set; }
+ public LogLevel LogLevel { get; set; } = LogLevel.None;
// --- Events ---
///
@@ -85,6 +87,17 @@ namespace BattleBitAPI.Server
///
public Func OnCreatingPlayerInstance { get; set; }
+ ///
+ /// Fired on log
+ ///
+ ///
+ ///
+ /// LogLevel: The level of log
+ /// string: The message
+ /// object: The object that will be carried on log
+ ///
+ public Action OnLog { get; set; }
+
// --- Private ---
private TcpListener mSocket;
private Dictionary.Internal resources)> mActiveConnections;
@@ -115,6 +128,9 @@ namespace BattleBitAPI.Server
this.ListeningPort = port;
this.IsListening = true;
+ if (this.LogLevel.HasFlag(LogLevel.Sockets))
+ OnLog(LogLevel.Sockets, $"Listening TCP connections on port " + port, null);
+
mMainLoop();
}
public void Start(int port)
@@ -136,6 +152,9 @@ namespace BattleBitAPI.Server
}
catch { }
+ if (this.LogLevel.HasFlag(LogLevel.Sockets))
+ OnLog(LogLevel.Sockets, $"Stopped listening TCP connection.", null);
+
this.mSocket = null;
this.ListeningPort = 0;
this.IsListening = true;
@@ -154,6 +173,9 @@ namespace BattleBitAPI.Server
{
var ip = (client.Client.RemoteEndPoint as IPEndPoint).Address;
+ if (this.LogLevel.HasFlag(LogLevel.Sockets))
+ OnLog(LogLevel.Sockets, $"Incoming TCP connection from {ip}", client);
+
//Is this IP allowed?
bool allow = true;
if (OnGameServerConnecting != null)
@@ -162,6 +184,9 @@ namespace BattleBitAPI.Server
//Close connection if it was not allowed.
if (!allow)
{
+ if (this.LogLevel.HasFlag(LogLevel.Sockets))
+ OnLog(LogLevel.Sockets, $"Incoming connection from {ip} was denied", client);
+
//Connection is not allowed from this IP.
client.SafeClose();
return;
@@ -234,7 +259,14 @@ namespace BattleBitAPI.Server
}
}
}
- catch { client.SafeClose(); return; }
+ catch (Exception e)
+ {
+ if (this.LogLevel.HasFlag(LogLevel.Sockets))
+ OnLog(LogLevel.Sockets, $"{ip} failed to connected because " + e.Message, client);
+
+ client.SafeClose();
+ return;
+ }
var hash = ((ulong)gamePort << 32) | (ulong)ip.ToUInt();
TGameServer server = null;
@@ -723,6 +755,9 @@ namespace BattleBitAPI.Server
}
catch { }
+ if (this.LogLevel.HasFlag(LogLevel.Sockets))
+ OnLog(LogLevel.Sockets, $"{ip} failed to connected because " + e.Message, client);
+
client.SafeClose();
return;
}
@@ -731,6 +766,9 @@ namespace BattleBitAPI.Server
client.ReceiveBufferSize = Const.MaxNetworkPackageSize;
client.SendBufferSize = Const.MaxNetworkPackageSize;
+ if (this.LogLevel.HasFlag(LogLevel.Sockets))
+ OnLog(LogLevel.Sockets, $"Incoming game server from {ip}:{gamePort} accepted.", client);
+
//Join to main server loop.
await mHandleGameServer(server, resources);
}
@@ -773,6 +811,9 @@ namespace BattleBitAPI.Server
}
}
+ if (this.LogLevel.HasFlag(LogLevel.GameServers))
+ OnLog(LogLevel.GameServers, $"{server} has connected", server);
+
// ---- Ticking ----
using (server)
{
@@ -805,6 +846,9 @@ namespace BattleBitAPI.Server
if (this.OnGameServerDisconnected != null)
this.OnGameServerDisconnected(server);
}
+
+ if (this.LogLevel.HasFlag(LogLevel.GameServers))
+ OnLog(LogLevel.GameServers, $"{server} has disconnected", server);
}
@internal.HasActiveConnectionSession = false;
}
@@ -853,6 +897,9 @@ namespace BattleBitAPI.Server
if (previousID != 0)
player.OnSessionChanged(previousID, playerInternal.SessionID);
}
+
+ if (this.LogLevel.HasFlag(LogLevel.Players))
+ OnLog(LogLevel.Players, $"{player} has connected", player);
}
}
break;
@@ -896,6 +943,9 @@ namespace BattleBitAPI.Server
player.OnDisconnected();
server.OnPlayerDisconnected((TPlayer)player);
+
+ if (this.LogLevel.HasFlag(LogLevel.Players))
+ OnLog(LogLevel.Players, $"{player} has disconnected", player);
}
}
break;
@@ -965,6 +1015,9 @@ namespace BattleBitAPI.Server
victimClient.OnDowned();
server.OnAPlayerDownedAnotherPlayer(args);
+
+ if (this.LogLevel.HasFlag(LogLevel.KillsAndSpawns))
+ OnLog(LogLevel.KillsAndSpawns, $"{killer} downed {victim} in {(Vector3.Distance(killerPos, victimPos))} meters", null);
}
}
}
@@ -1023,13 +1076,19 @@ namespace BattleBitAPI.Server
ulong steamID = stream.ReadUInt64();
GameRole role = (GameRole)stream.ReadInt8();
- if (resources.TryGetPlayer(steamID, out var client))
+ if (resources.TryGetPlayer(steamID, out var player))
{
async Task mHandle()
{
- bool accepted = await server.OnPlayerRequestingToChangeRole((TPlayer)client, role);
+ if (this.LogLevel.HasFlag(LogLevel.Roles))
+ OnLog(LogLevel.Roles, $"{player} asking to change role to {role}", player);
+
+ bool accepted = await server.OnPlayerRequestingToChangeRole((TPlayer)player, role);
if (accepted)
server.SetRoleTo(steamID, role);
+
+ if (this.LogLevel.HasFlag(LogLevel.Roles))
+ OnLog(LogLevel.Roles, $"{player}'s request to change role to {role} was {(accepted ? "accepted" : "denied")}", player);
}
mHandle();
@@ -1044,13 +1103,16 @@ namespace BattleBitAPI.Server
ulong steamID = stream.ReadUInt64();
GameRole role = (GameRole)stream.ReadInt8();
- if (resources.TryGetPlayer(steamID, out var client))
+ if (resources.TryGetPlayer(steamID, out var player))
{
var @internal = mInstanceDatabase.GetPlayerInternals(steamID);
@internal.Role = role;
- client.OnChangedRole(role);
- server.OnPlayerChangedRole((TPlayer)client, role);
+ player.OnChangedRole(role);
+ server.OnPlayerChangedRole((TPlayer)player, role);
+
+ if (this.LogLevel.HasFlag(LogLevel.Roles))
+ OnLog(LogLevel.Roles, $"{player} changed role to {role}", player);
}
}
break;
@@ -1062,18 +1124,21 @@ namespace BattleBitAPI.Server
ulong steamID = stream.ReadUInt64();
Squads squad = (Squads)stream.ReadInt8();
- if (resources.TryGetPlayer(steamID, out var client))
+ if (resources.TryGetPlayer(steamID, out var player))
{
var @internal = mInstanceDatabase.GetPlayerInternals(steamID);
@internal.SquadName = squad;
- var msquad = server.GetSquad(client.Team, squad);
+ var msquad = server.GetSquad(player.Team, squad);
var rsquad = resources.GetSquadInternal(msquad);
lock (rsquad.Members)
- rsquad.Members.Add((TPlayer)client);
+ rsquad.Members.Add((TPlayer)player);
- client.OnJoinedSquad(msquad);
- server.OnPlayerJoinedSquad((TPlayer)client, msquad);
+ player.OnJoinedSquad(msquad);
+ server.OnPlayerJoinedSquad((TPlayer)player, msquad);
+
+ if (this.LogLevel.HasFlag(LogLevel.Squads))
+ OnLog(LogLevel.Squads, $"{player} has joined to {msquad}", msquad);
}
}
break;
@@ -1084,30 +1149,33 @@ namespace BattleBitAPI.Server
{
ulong steamID = stream.ReadUInt64();
- if (resources.TryGetPlayer(steamID, out var client))
+ if (resources.TryGetPlayer(steamID, out var player))
{
var @internal = mInstanceDatabase.GetPlayerInternals(steamID);
- var oldSquad = client.SquadName;
- var oldRole = client.Role;
+ var oldSquad = player.SquadName;
+ var oldRole = player.Role;
@internal.SquadName = Squads.NoSquad;
@internal.Role = GameRole.Assault;
- var msquad = server.GetSquad(client.Team, oldSquad);
+ var msquad = server.GetSquad(player.Team, oldSquad);
var rsquad = resources.GetSquadInternal(msquad);
@internal.SquadName = Squads.NoSquad;
lock (rsquad.Members)
- rsquad.Members.Remove((TPlayer)client);
+ rsquad.Members.Remove((TPlayer)player);
- client.OnLeftSquad(msquad);
- server.OnPlayerLeftSquad((TPlayer)client, msquad);
+ player.OnLeftSquad(msquad);
+ server.OnPlayerLeftSquad((TPlayer)player, msquad);
if (oldRole != GameRole.Assault)
{
- client.OnChangedRole(GameRole.Assault);
- server.OnPlayerChangedRole((TPlayer)client, GameRole.Assault);
+ player.OnChangedRole(GameRole.Assault);
+ server.OnPlayerChangedRole((TPlayer)player, GameRole.Assault);
}
+
+ if (this.LogLevel.HasFlag(LogLevel.Squads))
+ OnLog(LogLevel.Squads, $"{player} has left the {msquad}", msquad);
}
}
break;
@@ -1141,11 +1209,14 @@ namespace BattleBitAPI.Server
request.Read(stream);
ushort vehicleID = stream.ReadUInt16();
- if (resources.TryGetPlayer(steamID, out var client))
+ if (resources.TryGetPlayer(steamID, out var player))
{
async Task mHandle()
{
- var responseSpawn = await server.OnPlayerSpawning((TPlayer)client, request);
+ if (this.LogLevel.HasFlag(LogLevel.KillsAndSpawns))
+ OnLog(LogLevel.KillsAndSpawns, $"{player} asking to spawn at {request.SpawnPosition} ({request.RequestedPoint})", player);
+
+ var responseSpawn = await server.OnPlayerSpawning((TPlayer)player, request);
//Respond back.
using (var response = Common.Serialization.Stream.Get())
@@ -1166,6 +1237,15 @@ namespace BattleBitAPI.Server
server.WriteToSocket(response);
}
+
+ if (this.LogLevel.HasFlag(LogLevel.KillsAndSpawns))
+ {
+ if (responseSpawn == null)
+ OnLog(LogLevel.KillsAndSpawns, $"{player}'s spawn request was denied", player);
+ else
+ OnLog(LogLevel.KillsAndSpawns, $"{player}'s spawn request was accepted at {responseSpawn.Value.SpawnPosition}", player);
+ }
+
}
mHandle();
@@ -1197,7 +1277,7 @@ namespace BattleBitAPI.Server
if (stream.CanRead(8 + 2))
{
ulong steamID = stream.ReadUInt64();
- if (resources.TryGetPlayer(steamID, out var client))
+ if (resources.TryGetPlayer(steamID, out var player))
{
var @internal = mInstanceDatabase.GetPlayerInternals(steamID);
@@ -1209,10 +1289,21 @@ namespace BattleBitAPI.Server
wearings.Read(stream);
@internal.CurrentWearings = wearings;
+ Vector3 position = new Vector3()
+ {
+ X = stream.ReadFloat(),
+ Y = stream.ReadFloat(),
+ Z = stream.ReadFloat(),
+ };
+
+ @internal.Position = position;
@internal.IsAlive = true;
- client.OnSpawned();
- server.OnPlayerSpawned((TPlayer)client);
+ player.OnSpawned();
+ server.OnPlayerSpawned((TPlayer)player);
+
+ if (this.LogLevel.HasFlag(LogLevel.KillsAndSpawns))
+ OnLog(LogLevel.KillsAndSpawns, $"{player} has spawned at {player.Position}", player);
}
}
break;
@@ -1222,13 +1313,16 @@ namespace BattleBitAPI.Server
if (stream.CanRead(8))
{
ulong steamid = stream.ReadUInt64();
- if (resources.TryGetPlayer(steamid, out var client))
+ if (resources.TryGetPlayer(steamid, out var player))
{
var @internal = mInstanceDatabase.GetPlayerInternals(steamid);
@internal.OnDie();
- client.OnDied();
- server.OnPlayerDied((TPlayer)client);
+ player.OnDied();
+ server.OnPlayerDied((TPlayer)player);
+
+ if (this.LogLevel.HasFlag(LogLevel.KillsAndSpawns))
+ OnLog(LogLevel.KillsAndSpawns, $"{player} has died", player);
}
}
break;
@@ -1339,19 +1433,38 @@ namespace BattleBitAPI.Server
var @internal = mInstanceDatabase.GetPlayerInternals(steamID);
if (@internal.IsAlive)
{
+ float newHP = (com_healt * 0.5f) - 1f;
+
+ if (this.LogLevel.HasFlag(LogLevel.HealtChanges))
+ {
+ var player = resources.Players[steamID];
+ float dtHP = newHP - @internal.HP;
+ if (dtHP > 0)
+ {
+ //Heal
+ OnLog(LogLevel.HealtChanges, $"{player} was healed by {dtHP} HP (new HP is {newHP} HP)", player);
+ }
+ else if(dtHP < 0)
+ {
+ //Damage
+ OnLog(LogLevel.HealtChanges, $"{player} was damaged by {(-dtHP)} HP (new HP is {newHP} HP)", player);
+ }
+ }
+
@internal.Position = new Vector3()
{
X = com_posX * decompressX,
Y = com_posY * decompressY,
Z = com_posZ * decompressZ,
};
- @internal.HP = (com_healt * 0.5f) - 1f;
+ @internal.HP = newHP;
@internal.Standing = standing;
@internal.Leaning = side;
@internal.CurrentLoadoutIndex = loadoutIndex;
@internal.InVehicle = inSeat;
@internal.IsBleeding = isBleeding;
@internal.PingMs = ping;
+
}
}
}
@@ -1362,10 +1475,13 @@ namespace BattleBitAPI.Server
if (stream.CanRead(8))
{
ulong steamID = stream.ReadUInt64();
- if (resources.TryGetPlayer(steamID, out var client))
+ if (resources.TryGetPlayer(steamID, out var player))
{
- client.OnGivenUp();
- server.OnPlayerGivenUp((TPlayer)client);
+ player.OnGivenUp();
+ server.OnPlayerGivenUp((TPlayer)player);
+
+ if (this.LogLevel.HasFlag(LogLevel.KillsAndSpawns))
+ OnLog(LogLevel.KillsAndSpawns, $"{player} has givenup", player);
}
}
break;
@@ -1384,6 +1500,9 @@ namespace BattleBitAPI.Server
{
fromClient.OnRevivedAnotherPlayer();
server.OnAPlayerRevivedAnotherPlayer((TPlayer)fromClient, (TPlayer)toClient);
+
+ if (this.LogLevel.HasFlag(LogLevel.KillsAndSpawns))
+ OnLog(LogLevel.KillsAndSpawns, $"{fromClient} revived {toClient}", null);
}
}
}
@@ -1405,6 +1524,9 @@ namespace BattleBitAPI.Server
rsquad.SquadPoints = points;
server.OnSquadPointsChanged(msquad, points);
}
+
+ if (this.LogLevel.HasFlag(LogLevel.Squads))
+ OnLog(LogLevel.Squads, $"{msquad} now has {points} points", msquad);
}
break;
}
@@ -1441,6 +1563,15 @@ namespace BattleBitAPI.Server
}
break;
}
+ case NetworkCommuncation.Log:
+ {
+ if (this.LogLevel.HasFlag(LogLevel.GameServerErrors))
+ {
+ if (stream.TryReadString(out var log))
+ OnLog(LogLevel.GameServerErrors, log, server);
+ }
+ break;
+ }
}
}
diff --git a/CommunityServerAPI.csproj b/CommunityServerAPI.csproj
index 52a520b..6c2fbc5 100644
--- a/CommunityServerAPI.csproj
+++ b/CommunityServerAPI.csproj
@@ -18,7 +18,7 @@
https://github.com/MrOkiDoki/BattleBit-Community-Server-API
https://github.com/MrOkiDoki/BattleBit-Community-Server-API
BattleBit
- 1.0.1
+ 1.0.2