Callbacks for session changes.

This commit is contained in:
MrOkiDoki 2023-08-20 14:53:28 +03:00
parent d0981e6f6f
commit 0ee0589101
5 changed files with 305 additions and 118 deletions

View File

@ -25,6 +25,12 @@ namespace BattleBitAPI.Common.Extentions
#endif #endif
} }
public static void Replace<TKey, TValue>(this Dictionary<TKey, TValue> dic, TKey key, TValue value)
{
dic.Remove(key);
dic.Add(key, value);
}
public static void SafeClose(this TcpClient client) public static void SafeClose(this TcpClient client)
{ {
try { client.Close(); } catch { } try { client.Close(); } catch { }

View File

@ -40,5 +40,6 @@
OnPlayerGivenUp = 70, OnPlayerGivenUp = 70,
OnPlayerRevivedAnother = 71, OnPlayerRevivedAnother = 71,
OnSquadPointsChanged = 72, OnSquadPointsChanged = 72,
NotifyNewRoundID = 73,
} }
} }

View File

@ -17,7 +17,6 @@ namespace BattleBitAPI.Server
public IPAddress GameIP => mInternal.GameIP; public IPAddress GameIP => mInternal.GameIP;
public int GamePort => mInternal.GamePort; public int GamePort => mInternal.GamePort;
public TcpClient Socket => mInternal.Socket;
public bool IsPasswordProtected => mInternal.IsPasswordProtected; public bool IsPasswordProtected => mInternal.IsPasswordProtected;
public string ServerName => mInternal.ServerName; public string ServerName => mInternal.ServerName;
public string Gamemode => mInternal.Gamemode; public string Gamemode => mInternal.Gamemode;
@ -29,6 +28,8 @@ namespace BattleBitAPI.Server
public int MaxPlayerCount => mInternal.MaxPlayerCount; public int MaxPlayerCount => mInternal.MaxPlayerCount;
public string LoadingScreenText => mInternal.LoadingScreenText; public string LoadingScreenText => mInternal.LoadingScreenText;
public string ServerRulesText => mInternal.ServerRulesText; public string ServerRulesText => mInternal.ServerRulesText;
public uint RoundIndex => mInternal.RoundIndex;
public long SessionID => mInternal.SessionID;
public ServerSettings<TPlayer> ServerSettings => mInternal.ServerSettings; public ServerSettings<TPlayer> ServerSettings => mInternal.ServerSettings;
public MapRotation<TPlayer> MapRotation => mInternal.MapRotation; public MapRotation<TPlayer> MapRotation => mInternal.MapRotation;
public GamemodeRotation<TPlayer> GamemodeRotation => mInternal.GamemodeRotation; public GamemodeRotation<TPlayer> GamemodeRotation => mInternal.GamemodeRotation;
@ -158,7 +159,7 @@ namespace BattleBitAPI.Server
try try
{ {
//Are we still connected on socket level? //Are we still connected on socket level?
if (!Socket.Connected) if (mInternal.Socket == null || !mInternal.Socket.Connected)
{ {
mClose("Connection was terminated."); mClose("Connection was terminated.");
return; return;
@ -171,10 +172,10 @@ namespace BattleBitAPI.Server
return; return;
} }
var networkStream = Socket.GetStream(); var networkStream = mInternal.Socket.GetStream();
//Read network packages. //Read network packages.
while (Socket.Available > 0) while (mInternal.Socket.Available > 0)
{ {
this.mInternal.mLastPackageReceived = Extentions.TickCount; this.mInternal.mLastPackageReceived = Extentions.TickCount;
@ -405,10 +406,6 @@ namespace BattleBitAPI.Server
public virtual async Task OnTick() public virtual async Task OnTick()
{ {
}
public virtual async Task OnReconnected()
{
} }
public virtual async Task OnDisconnected() public virtual async Task OnDisconnected()
{ {
@ -500,6 +497,10 @@ namespace BattleBitAPI.Server
public virtual async Task OnRoundEnded() public virtual async Task OnRoundEnded()
{ {
}
public virtual async Task OnSessionChanged(long oldSessionID, long newSessionID)
{
} }
// ---- Functions ---- // ---- Functions ----
@ -553,10 +554,18 @@ namespace BattleBitAPI.Server
{ {
ExecuteCommand("endgame"); ExecuteCommand("endgame");
} }
public void SayToChat(string msg) public void SayToAllChat(string msg)
{ {
ExecuteCommand("say " + msg); ExecuteCommand("say " + msg);
} }
public void SayToChat(string msg, ulong steamID)
{
ExecuteCommand("sayto " + steamID + " " + msg);
}
public void SayToChat(string msg, Player<TPlayer> player)
{
SayToChat(msg, player.SteamID);
}
public void StopServer() public void StopServer()
{ {
@ -897,7 +906,7 @@ namespace BattleBitAPI.Server
} }
// ---- Static ---- // ---- Static ----
public static void SetInstance(GameServer<TPlayer> server, Internal @internal) internal static void SetInstance(GameServer<TPlayer> server, Internal @internal)
{ {
server.mInternal = @internal; server.mInternal = @internal;
} }
@ -908,6 +917,7 @@ namespace BattleBitAPI.Server
// ---- Variables ---- // ---- Variables ----
public ulong ServerHash; public ulong ServerHash;
public bool IsConnected; public bool IsConnected;
public bool HasActiveConnectionSession;
public IPAddress GameIP; public IPAddress GameIP;
public int GamePort; public int GamePort;
public TcpClient Socket; public TcpClient Socket;
@ -924,6 +934,8 @@ namespace BattleBitAPI.Server
public int MaxPlayerCount; public int MaxPlayerCount;
public string LoadingScreenText; public string LoadingScreenText;
public string ServerRulesText; public string ServerRulesText;
public uint RoundIndex;
public long SessionID;
public ServerSettings<TPlayer> ServerSettings; public ServerSettings<TPlayer> ServerSettings;
public MapRotation<TPlayer> MapRotation; public MapRotation<TPlayer> MapRotation;
public GamemodeRotation<TPlayer> GamemodeRotation; public GamemodeRotation<TPlayer> GamemodeRotation;
@ -944,6 +956,7 @@ namespace BattleBitAPI.Server
public long mLastPackageReceived; public long mLastPackageReceived;
public long mLastPackageSent; public long mLastPackageSent;
public bool mWantsToCloseConnection; public bool mWantsToCloseConnection;
public long mPreviousSessionID;
public StringBuilder mBuilder; public StringBuilder mBuilder;
public Queue<(ulong steamID, PlayerModifications<TPlayer>.mPlayerModifications)> mChangedModifications; public Queue<(ulong steamID, PlayerModifications<TPlayer>.mPlayerModifications)> mChangedModifications;
@ -1290,7 +1303,9 @@ namespace BattleBitAPI.Server
int inQueuePlayers, int inQueuePlayers,
int maxPlayers, int maxPlayers,
string loadingScreenText, string loadingScreenText,
string serverRulesText string serverRulesText,
uint roundIndex,
long sessionID
) )
{ {
this.ServerHash = ((ulong)port << 32) | (ulong)iP.ToUInt(); this.ServerHash = ((ulong)port << 32) | (ulong)iP.ToUInt();
@ -1311,6 +1326,8 @@ namespace BattleBitAPI.Server
this.MaxPlayerCount = maxPlayers; this.MaxPlayerCount = maxPlayers;
this.LoadingScreenText = loadingScreenText; this.LoadingScreenText = loadingScreenText;
this.ServerRulesText = serverRulesText; this.ServerRulesText = serverRulesText;
this.RoundIndex = roundIndex;
this.SessionID = sessionID;
this.ServerSettings.Reset(); this.ServerSettings.Reset();
this._RoomSettings.Reset(); this._RoomSettings.Reset();

View File

@ -58,7 +58,7 @@ namespace BattleBitAPI
KickFromSquad(); KickFromSquad();
else else
{ {
if(value.Team != this.Team) if (value.Team != this.Team)
ChangeTeam(value.Team); ChangeTeam(value.Team);
JoinSquad(value.Name); JoinSquad(value.Name);
} }
@ -66,6 +66,8 @@ namespace BattleBitAPI
} }
public bool InSquad => mInternal.SquadName != Squads.NoSquad; public bool InSquad => mInternal.SquadName != Squads.NoSquad;
public int PingMs => mInternal.PingMs; public int PingMs => mInternal.PingMs;
public long CurrentSessionID => mInternal.SessionID;
public bool IsConnected => mInternal.SessionID != 0;
public float HP public float HP
{ {
@ -156,56 +158,78 @@ namespace BattleBitAPI
public virtual async Task OnDisconnected() public virtual async Task OnDisconnected()
{ {
}
public virtual async Task OnSessionChanged(long oldSessionID, long newSessionID)
{
} }
// ---- Functions ---- // ---- Functions ----
public void Kick(string reason = "") public void Kick(string reason = "")
{ {
GameServer.Kick(this, reason); if (IsConnected)
GameServer.Kick(this, reason);
} }
public void Kill() public void Kill()
{ {
GameServer.Kill(this); if (IsConnected)
GameServer.Kill(this);
} }
public void ChangeTeam() public void ChangeTeam()
{ {
GameServer.ChangeTeam(this); if (IsConnected)
GameServer.ChangeTeam(this);
} }
public void ChangeTeam(Team team) public void ChangeTeam(Team team)
{ {
GameServer.ChangeTeam(this, team); if (IsConnected)
GameServer.ChangeTeam(this, team);
} }
public void KickFromSquad() public void KickFromSquad()
{ {
GameServer.KickFromSquad(this); if (IsConnected)
GameServer.KickFromSquad(this);
} }
public void JoinSquad(Squads targetSquad) public void JoinSquad(Squads targetSquad)
{ {
GameServer.JoinSquad(this, targetSquad); if (IsConnected)
GameServer.JoinSquad(this, targetSquad);
} }
public void DisbandTheSquad() public void DisbandTheSquad()
{ {
GameServer.DisbandPlayerCurrentSquad(this); if (IsConnected)
GameServer.DisbandPlayerCurrentSquad(this);
} }
public void PromoteToSquadLeader() public void PromoteToSquadLeader()
{ {
GameServer.PromoteSquadLeader(this); if (IsConnected)
GameServer.PromoteSquadLeader(this);
} }
public void WarnPlayer(string msg) public void WarnPlayer(string msg)
{ {
GameServer.WarnPlayer(this, msg); if (IsConnected)
GameServer.WarnPlayer(this, msg);
} }
public void Message(string 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) public void Message(string msg, float fadeoutTime)
{ {
GameServer.MessageToPlayer(this, msg, fadeoutTime); if (IsConnected)
GameServer.MessageToPlayer(this, msg, fadeoutTime);
} }
public void SetNewRole(GameRole role) public void SetNewRole(GameRole role)
{ {
GameServer.SetRoleTo(this, role); if (IsConnected)
GameServer.SetRoleTo(this, role);
} }
public void Teleport(Vector3 target) 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) 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) public void SetHP(float newHP)
{ {
GameServer.SetHP(this, newHP); if (IsConnected)
GameServer.SetHP(this, newHP);
} }
public void GiveDamage(float damage) public void GiveDamage(float damage)
{ {
GameServer.GiveDamage(this, damage); if (IsConnected)
GameServer.GiveDamage(this, damage);
} }
public void Heal(float hp) 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) 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) 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) 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) 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) 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) 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 ---- // ---- Static ----
public static void SetInstance(TPlayer player, Player<TPlayer>.Internal @internal) internal static void SetInstance(TPlayer player, Player<TPlayer>.Internal @internal)
{ {
player.mInternal = @internal; player.mInternal = @internal;
} }
@ -275,6 +309,8 @@ namespace BattleBitAPI
public Team Team; public Team Team;
public Squads SquadName; public Squads SquadName;
public int PingMs = 999; public int PingMs = 999;
public long PreviousSessionID = 0;
public long SessionID = 0;
public bool IsAlive; public bool IsAlive;
public float HP; public float HP;

View File

@ -1,10 +1,11 @@
using System.Net; using System.Net;
using System.Net.Sockets; using System.Net.Sockets;
using System.Numerics; using System.Numerics;
using System.Runtime.CompilerServices; using System.Resources;
using BattleBitAPI.Common; using BattleBitAPI.Common;
using BattleBitAPI.Common.Extentions; using BattleBitAPI.Common.Extentions;
using BattleBitAPI.Networking; using BattleBitAPI.Networking;
using BattleBitAPI.Pooling;
namespace BattleBitAPI.Server namespace BattleBitAPI.Server
{ {
@ -55,15 +56,6 @@ namespace BattleBitAPI.Server
/// </remarks> /// </remarks>
public Func<GameServer<TPlayer>, Task> OnGameServerConnected { get; set; } public Func<GameServer<TPlayer>, Task> OnGameServerConnected { get; set; }
/// <summary>
/// Fired when a game server reconnects. (When game server connects while a socket is already open)
/// </summary>
///
/// <remarks>
/// GameServer: Game server that is reconnecting.<br/>
/// </remarks>
public Func<GameServer<TPlayer>, Task> OnGameServerReconnected { get; set; }
/// <summary> /// <summary>
/// Fired when a game server disconnects. Check (GameServer.TerminationReason) to see the reason. /// Fired when a game server disconnects. Check (GameServer.TerminationReason) to see the reason.
/// </summary> /// </summary>
@ -97,12 +89,14 @@ namespace BattleBitAPI.Server
private TcpListener mSocket; private TcpListener mSocket;
private Dictionary<ulong, (TGameServer server, GameServer<TPlayer>.Internal resources)> mActiveConnections; private Dictionary<ulong, (TGameServer server, GameServer<TPlayer>.Internal resources)> mActiveConnections;
private mInstances<TPlayer, TGameServer> mInstanceDatabase; private mInstances<TPlayer, TGameServer> mInstanceDatabase;
private ItemPooling<GameServer<TPlayer>> mGameServerPool;
// --- Construction --- // --- Construction ---
public ServerListener() public ServerListener()
{ {
this.mActiveConnections = new Dictionary<ulong, (TGameServer, GameServer<TPlayer>.Internal)>(16); this.mActiveConnections = new Dictionary<ulong, (TGameServer, GameServer<TPlayer>.Internal)>(16);
this.mInstanceDatabase = new mInstances<TPlayer, TGameServer>(); this.mInstanceDatabase = new mInstances<TPlayer, TGameServer>();
this.mGameServerPool = new ItemPooling<GameServer<TPlayer>>(64);
} }
// --- Starting --- // --- Starting ---
@ -160,10 +154,12 @@ namespace BattleBitAPI.Server
{ {
var ip = (client.Client.RemoteEndPoint as IPEndPoint).Address; var ip = (client.Client.RemoteEndPoint as IPEndPoint).Address;
//Is this IP allowed?
bool allow = true; bool allow = true;
if (OnGameServerConnecting != null) if (OnGameServerConnecting != null)
allow = await OnGameServerConnecting(ip); allow = await OnGameServerConnecting(ip);
//Close connection if it was not allowed.
if (!allow) if (!allow)
{ {
//Connection is not allowed from this IP. //Connection is not allowed from this IP.
@ -171,11 +167,13 @@ namespace BattleBitAPI.Server
return; return;
} }
TGameServer server = null; //Read port,token,version
GameServer<TPlayer>.Internal resources; string token;
string version;
int gamePort;
try try
{ {
using (CancellationTokenSource source = new CancellationTokenSource(Const.HailConnectTimeout)) using (var source = new CancellationTokenSource(2000))
{ {
using (var readStream = Common.Serialization.Stream.Get()) using (var readStream = Common.Serialization.Stream.Get())
{ {
@ -186,13 +184,13 @@ namespace BattleBitAPI.Server
readStream.Reset(); readStream.Reset();
if (!await networkStream.TryRead(readStream, 1, source.Token)) if (!await networkStream.TryRead(readStream, 1, source.Token))
throw new Exception("Unable to read the package type"); throw new Exception("Unable to read the package type");
NetworkCommuncation type = (NetworkCommuncation)readStream.ReadInt8(); NetworkCommuncation type = (NetworkCommuncation)readStream.ReadInt8();
if (type != NetworkCommuncation.Hail) if (type != NetworkCommuncation.Hail)
throw new Exception("Incoming package wasn't hail."); throw new Exception("Incoming package wasn't hail.");
} }
//Read the server token //Read the server token
string token;
{ {
readStream.Reset(); readStream.Reset();
if (!await networkStream.TryRead(readStream, 2, source.Token)) if (!await networkStream.TryRead(readStream, 2, source.Token))
@ -210,7 +208,6 @@ namespace BattleBitAPI.Server
} }
//Read the server version //Read the server version
string version;
{ {
readStream.Reset(); readStream.Reset();
if (!await networkStream.TryRead(readStream, 2, source.Token)) if (!await networkStream.TryRead(readStream, 2, source.Token))
@ -227,23 +224,59 @@ namespace BattleBitAPI.Server
version = readStream.ReadString(stringSize); 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 //Read port
int gamePort;
{ {
readStream.Reset(); readStream.Reset();
if (!await networkStream.TryRead(readStream, 2, source.Token)) if (!await networkStream.TryRead(readStream, 2, source.Token))
throw new Exception("Unable to read the Port"); throw new Exception("Unable to read the Port");
gamePort = readStream.ReadUInt16(); gamePort = readStream.ReadUInt16();
} }
}
}
}
catch { client.SafeClose(); return; }
if (OnValidateGameServerToken != null) var hash = ((ulong)gamePort << 32) | (ulong)ip.ToUInt();
allow = await OnValidateGameServerToken(ip, (ushort)gamePort, token); TGameServer server = null;
GameServer<TPlayer>.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) //Is valid token?
throw new Exception("Token was not valid!"); 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<TPlayer>.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 //Read is server protected
bool isPasswordProtected; 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); server = this.mInstanceDatabase.GetServerInstance(hash, out resources, this.OnCreatingGameServerInstance, ip, (ushort)gamePort);
resources.Set( resources.Set(
this.mExecutePackage, this.mExecutePackage,
@ -421,7 +475,9 @@ namespace BattleBitAPI.Server
queuePlayers, queuePlayers,
maxPlayers, maxPlayers,
loadingScreenText, loadingScreenText,
serverRulesText serverRulesText,
roundIndex,
sessionID
); );
//Room settings //Room settings
@ -583,7 +639,6 @@ namespace BattleBitAPI.Server
playerInternal.SteamID = steamid; playerInternal.SteamID = steamid;
playerInternal.Name = username; playerInternal.Name = username;
playerInternal.IP = new IPAddress(ipHash); playerInternal.IP = new IPAddress(ipHash);
playerInternal.GameServer = (GameServer<TPlayer>)server;
playerInternal.Team = team; playerInternal.Team = team;
playerInternal.SquadName = squad; playerInternal.SquadName = squad;
playerInternal.Role = role; playerInternal.Role = role;
@ -604,6 +659,9 @@ namespace BattleBitAPI.Server
playerInternal._Modifications.Read(readStream); playerInternal._Modifications.Read(readStream);
} }
playerInternal.GameServer = (GameServer<TPlayer>)server;
playerInternal.SessionID = server.SessionID;
resources.AddPlayer(player); resources.AddPlayer(player);
} }
@ -669,37 +727,6 @@ namespace BattleBitAPI.Server
return; 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. //Set the buffer sizes.
client.ReceiveBufferSize = Const.MaxNetworkPackageSize; client.ReceiveBufferSize = Const.MaxNetworkPackageSize;
client.SendBufferSize = Const.MaxNetworkPackageSize; client.SendBufferSize = Const.MaxNetworkPackageSize;
@ -709,39 +736,77 @@ namespace BattleBitAPI.Server
} }
private async Task mHandleGameServer(TGameServer server, GameServer<TPlayer>.Internal @internal) private async Task mHandleGameServer(TGameServer server, GameServer<TPlayer>.Internal @internal)
{ {
bool isTicking = false; @internal.HasActiveConnectionSession = true;
using (server)
{ {
async Task mTickAsync() // ---- Connected ----
{ {
isTicking = true; lock (this.mActiveConnections)
await server.OnTick(); this.mActiveConnections.Replace(server.ServerHash, (server, @internal));
isTicking = false;
server.OnConnected();
if (this.OnGameServerConnected != null)
this.OnGameServerConnected(server);
} }
while (server.IsConnected) //Update sessions
{ {
if (!isTicking) if (@internal.mPreviousSessionID != @internal.SessionID)
mTickAsync(); {
var oldSession = @internal.mPreviousSessionID;
@internal.mPreviousSessionID = @internal.SessionID;
await server.Tick(); if (oldSession != 0)
await Task.Delay(10); 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(); server.OnDisconnected();
if (this.OnGameServerDisconnected != null) if (this.OnGameServerDisconnected != null)
this.OnGameServerDisconnected(server); this.OnGameServerDisconnected(server);
} }
} }
@internal.HasActiveConnectionSession = false;
//Remove from list.
if (!server.ReconnectFlag)
lock (this.mActiveConnections)
this.mActiveConnections.Remove(server.ServerHash);
} }
// --- Logic Executing --- // --- Logic Executing ---
@ -766,8 +831,6 @@ namespace BattleBitAPI.Server
playerInternal.SteamID = steamID; playerInternal.SteamID = steamID;
playerInternal.Name = username; playerInternal.Name = username;
playerInternal.IP = new IPAddress(ip); playerInternal.IP = new IPAddress(ip);
playerInternal.GameServer = (GameServer<TPlayer>)server;
playerInternal.Team = team; playerInternal.Team = team;
playerInternal.SquadName = squad; playerInternal.SquadName = squad;
playerInternal.Role = role; playerInternal.Role = role;
@ -775,9 +838,21 @@ namespace BattleBitAPI.Server
//Start from default. //Start from default.
playerInternal._Modifications.Reset(); playerInternal._Modifications.Reset();
playerInternal.GameServer = (GameServer<TPlayer>)server;
playerInternal.SessionID = server.SessionID;
resources.AddPlayer(player); resources.AddPlayer(player);
player.OnConnected(); player.OnConnected();
server.OnPlayerConnected(player); 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; break;
@ -816,6 +891,9 @@ namespace BattleBitAPI.Server
server.OnPlayerLeftSquad((TPlayer)player, msquad); server.OnPlayerLeftSquad((TPlayer)player, msquad);
} }
@internal.SessionID = 0;
@internal.GameServer = null;
player.OnDisconnected(); player.OnDisconnected();
server.OnPlayerDisconnected((TPlayer)player); server.OnPlayerDisconnected((TPlayer)player);
} }
@ -1330,10 +1408,55 @@ namespace BattleBitAPI.Server
} }
break; 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 ---
private void mCleanup(GameServer<TPlayer> server, GameServer<TPlayer>.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<TPlayer>.Internal mGetPlayerInternals(ulong steamID) private Player<TPlayer>.Internal mGetPlayerInternals(ulong steamID)
{ {
return mInstanceDatabase.GetPlayerInternals(steamID); return mInstanceDatabase.GetPlayerInternals(steamID);
@ -1344,13 +1467,17 @@ namespace BattleBitAPI.Server
{ {
get get
{ {
var list = new List<TGameServer>(mActiveConnections.Count); using (var list = this.mGameServerPool.Get())
lock (mActiveConnections)
{ {
foreach (var item in mActiveConnections.Values) //Get a copy
list.Add(item.server); 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) public bool TryGetGameServer(IPAddress ip, ushort port, out TGameServer server)