Consistent player - gameserver instances.
This commit is contained in:
parent
9f5f0d5259
commit
1326cd85e4
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
|
@ -2,7 +2,7 @@
|
|||
|
||||
namespace BattleBitAPI.Common
|
||||
{
|
||||
public struct OnPlayerKillArguments<TPlayer> where TPlayer : Player
|
||||
public struct OnPlayerKillArguments<TPlayer> where TPlayer : Player<TPlayer>
|
||||
{
|
||||
public TPlayer Killer;
|
||||
public Vector3 KillerPosition;
|
||||
|
|
|
@ -5,12 +5,12 @@ using System.Numerics;
|
|||
|
||||
namespace BattleBitAPI
|
||||
{
|
||||
public class Player
|
||||
public class Player<TPlayer> where TPlayer : Player<TPlayer>
|
||||
{
|
||||
public ulong SteamID { get; internal set; }
|
||||
public string Name { get; internal set; }
|
||||
public IPAddress IP { get; internal set; }
|
||||
public GameServer GameServer { get; internal set; }
|
||||
public GameServer<TPlayer> GameServer { get; internal set; }
|
||||
public GameRole Role { get; internal set; }
|
||||
public Team Team { get; internal set; }
|
||||
public Squads Squad { get; internal set; }
|
||||
|
@ -18,15 +18,23 @@ namespace BattleBitAPI
|
|||
public PlayerLoadout CurrentLoadout { get; internal set; } = new PlayerLoadout();
|
||||
public PlayerWearings CurrentWearings { get; internal set; } = new PlayerWearings();
|
||||
|
||||
internal virtual async Task OnInitialized()
|
||||
public virtual void OnCreated()
|
||||
{
|
||||
|
||||
}
|
||||
internal virtual async Task OnSpawned()
|
||||
public virtual async Task OnConnected()
|
||||
{
|
||||
|
||||
}
|
||||
internal virtual async Task OnDied()
|
||||
public virtual async Task OnSpawned()
|
||||
{
|
||||
|
||||
}
|
||||
public virtual async Task OnDied()
|
||||
{
|
||||
|
||||
}
|
||||
public virtual async Task OnDisconnected()
|
||||
{
|
||||
|
||||
}
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
using System.Net;
|
||||
using System.Net.Sockets;
|
||||
using System.Numerics;
|
||||
using System.Resources;
|
||||
using System.Text;
|
||||
using BattleBitAPI.Common;
|
||||
using BattleBitAPI.Common.Extentions;
|
||||
|
@ -9,112 +10,40 @@ using CommunityServerAPI.BattleBitAPI;
|
|||
|
||||
namespace BattleBitAPI.Server
|
||||
{
|
||||
public class GameServer : IDisposable
|
||||
public class GameServer<TPlayer> : System.IDisposable where TPlayer : Player<TPlayer>
|
||||
{
|
||||
// ---- Public Variables ----
|
||||
public TcpClient Socket { get; private set; }
|
||||
public ulong ServerHash => mInternal.ServerHash;
|
||||
public bool IsConnected => mInternal.IsConnected;
|
||||
public IPAddress GameIP => mInternal.GameIP;
|
||||
public int GamePort => mInternal.GamePort;
|
||||
|
||||
public ulong ServerHash { get; private set; }
|
||||
/// <summary>
|
||||
/// Is game server connected to our server?
|
||||
/// </summary>
|
||||
public bool IsConnected { get; private set; }
|
||||
public IPAddress GameIP { get; private set; }
|
||||
public int GamePort { get; private set; }
|
||||
public bool IsPasswordProtected { get; private set; }
|
||||
public string ServerName { get; private set; }
|
||||
public string Gamemode { get; private set; }
|
||||
public string Map { get; private set; }
|
||||
public MapSize MapSize { get; private set; }
|
||||
public MapDayNight DayNight { get; private set; }
|
||||
public int CurrentPlayers { get; private set; }
|
||||
public int InQueuePlayers { get; private set; }
|
||||
public int MaxPlayers { get; private set; }
|
||||
public string LoadingScreenText { get; private set; }
|
||||
public string ServerRulesText { get; private set; }
|
||||
public ServerSettings Settings { get; private set; }
|
||||
public MapRotation MapRotation { get; private set; }
|
||||
public GamemodeRotation GamemodeRotation { get; private set; }
|
||||
|
||||
/// <summary>
|
||||
/// Reason why connection was terminated.
|
||||
/// </summary>
|
||||
public string TerminationReason { get; private set; }
|
||||
internal bool ReconnectFlag { get; set; }
|
||||
public TcpClient Socket => mInternal.Socket;
|
||||
public bool IsPasswordProtected => mInternal.IsPasswordProtected;
|
||||
public string ServerName => mInternal.ServerName;
|
||||
public string Gamemode => mInternal.Gamemode;
|
||||
public string Map => mInternal.Map;
|
||||
public MapSize MapSize => mInternal.MapSize;
|
||||
public MapDayNight DayNight => mInternal.DayNight;
|
||||
public int CurrentPlayers => mInternal.CurrentPlayers;
|
||||
public int InQueuePlayers => mInternal.InQueuePlayers;
|
||||
public int MaxPlayers => mInternal.MaxPlayers;
|
||||
public string LoadingScreenText => mInternal.LoadingScreenText;
|
||||
public string ServerRulesText => mInternal.ServerRulesText;
|
||||
public ServerSettings<TPlayer> Settings => mInternal.Settings;
|
||||
public MapRotation<TPlayer> MapRotation => mInternal.MapRotation;
|
||||
public GamemodeRotation<TPlayer> GamemodeRotation => mInternal.GamemodeRotation;
|
||||
public string TerminationReason => mInternal.TerminationReason;
|
||||
public bool ReconnectFlag => mInternal.ReconnectFlag;
|
||||
|
||||
// ---- Private Variables ----
|
||||
private byte[] mKeepAliveBuffer;
|
||||
private Func<GameServer, mInternalResources, Common.Serialization.Stream, Task> mExecutionFunc;
|
||||
private Common.Serialization.Stream mWriteStream;
|
||||
private Common.Serialization.Stream mReadStream;
|
||||
private uint mReadPackageSize;
|
||||
private long mLastPackageReceived;
|
||||
private long mLastPackageSent;
|
||||
private bool mIsDisposed;
|
||||
private mInternalResources mInternal;
|
||||
private StringBuilder mBuilder;
|
||||
private bool mWantsToCloseConnection;
|
||||
|
||||
// ---- Construction ----
|
||||
public GameServer(TcpClient socket, mInternalResources resources, Func<GameServer, mInternalResources, Common.Serialization.Stream, Task> func, IPAddress iP, int port, bool isPasswordProtected, string serverName, string gamemode, string map, MapSize mapSize, MapDayNight dayNight, int currentPlayers, int inQueuePlayers, int maxPlayers, string loadingScreenText, string serverRulesText)
|
||||
{
|
||||
this.IsConnected = true;
|
||||
this.Socket = socket;
|
||||
this.mInternal = resources;
|
||||
this.mExecutionFunc = func;
|
||||
this.mBuilder = new StringBuilder(1024);
|
||||
|
||||
this.GameIP = iP;
|
||||
this.GamePort = port;
|
||||
this.IsPasswordProtected = isPasswordProtected;
|
||||
this.ServerName = serverName;
|
||||
this.Gamemode = gamemode;
|
||||
this.Map = map;
|
||||
this.MapSize = mapSize;
|
||||
this.DayNight = dayNight;
|
||||
this.CurrentPlayers = currentPlayers;
|
||||
this.InQueuePlayers = inQueuePlayers;
|
||||
this.MaxPlayers = maxPlayers;
|
||||
this.LoadingScreenText = loadingScreenText;
|
||||
this.ServerRulesText = serverRulesText;
|
||||
|
||||
this.TerminationReason = string.Empty;
|
||||
|
||||
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;
|
||||
|
||||
this.ServerHash = ((ulong)port << 32) | (ulong)iP.ToUInt();
|
||||
this.Settings = new ServerSettings(resources);
|
||||
this.MapRotation = new MapRotation(resources);
|
||||
this.GamemodeRotation = new GamemodeRotation(resources);
|
||||
}
|
||||
private Internal mInternal;
|
||||
|
||||
// ---- Tick ----
|
||||
public async Task Tick()
|
||||
{
|
||||
if (!this.IsConnected)
|
||||
return;
|
||||
if (this.mIsDisposed)
|
||||
return;
|
||||
|
||||
if (this.mInternal.IsDirtySettings)
|
||||
{
|
||||
|
@ -124,37 +53,39 @@ namespace BattleBitAPI.Server
|
|||
using (var pck = Common.Serialization.Stream.Get())
|
||||
{
|
||||
pck.Write((byte)NetworkCommuncation.SetNewRoomSettings);
|
||||
this.mInternal.Settings.Write(pck);
|
||||
this.mInternal._Settings.Write(pck);
|
||||
WriteToSocket(pck);
|
||||
}
|
||||
}
|
||||
if (this.mInternal.MapRotationDirty)
|
||||
{
|
||||
this.mInternal.MapRotationDirty = false;
|
||||
this.mBuilder.Clear();
|
||||
this.mInternal.mBuilder.Clear();
|
||||
|
||||
this.mBuilder.Append("setmaprotation ");
|
||||
lock (this.mInternal.MapRotation)
|
||||
foreach (var map in this.mInternal.MapRotation)
|
||||
this.mInternal.mBuilder.Append("setmaprotation ");
|
||||
lock (this.mInternal._MapRotation)
|
||||
foreach (var map in this.mInternal._MapRotation)
|
||||
{
|
||||
this.mBuilder.Append(map);
|
||||
this.mBuilder.Append(',');
|
||||
this.mInternal.mBuilder.Append(map);
|
||||
this.mInternal.mBuilder.Append(',');
|
||||
}
|
||||
this.ExecuteCommand(this.mBuilder.ToString());
|
||||
this.ExecuteCommand(this.mInternal.mBuilder.ToString());
|
||||
}
|
||||
if (this.mInternal.GamemodeRotationDirty)
|
||||
{
|
||||
this.mInternal.GamemodeRotationDirty = false;
|
||||
this.mBuilder.Clear();
|
||||
this.mInternal.mBuilder.Clear();
|
||||
|
||||
this.mBuilder.Append("setgamemoderotation ");
|
||||
lock (this.mInternal.GamemodeRotation)
|
||||
foreach (var gamemode in this.mInternal.GamemodeRotation)
|
||||
this.mInternal.mBuilder.Append("setgamemoderotation ");
|
||||
lock (this.mInternal._GamemodeRotation)
|
||||
{
|
||||
foreach (var gamemode in this.mInternal._GamemodeRotation)
|
||||
{
|
||||
this.mBuilder.Append(gamemode);
|
||||
this.mBuilder.Append(',');
|
||||
this.mInternal.mBuilder.Append(gamemode);
|
||||
this.mInternal.mBuilder.Append(',');
|
||||
}
|
||||
this.ExecuteCommand(this.mBuilder.ToString());
|
||||
}
|
||||
this.ExecuteCommand(this.mInternal.mBuilder.ToString());
|
||||
}
|
||||
|
||||
try
|
||||
|
@ -167,7 +98,7 @@ namespace BattleBitAPI.Server
|
|||
}
|
||||
|
||||
//Did user requested to close connection?
|
||||
if (this.mWantsToCloseConnection)
|
||||
if (this.mInternal.mWantsToCloseConnection)
|
||||
{
|
||||
mClose(this.TerminationReason);
|
||||
return;
|
||||
|
@ -178,82 +109,82 @@ namespace BattleBitAPI.Server
|
|||
//Read network packages.
|
||||
while (Socket.Available > 0)
|
||||
{
|
||||
this.mLastPackageReceived = Extentions.TickCount;
|
||||
this.mInternal.mLastPackageReceived = Extentions.TickCount;
|
||||
|
||||
//Do we know the package size?
|
||||
if (this.mReadPackageSize == 0)
|
||||
if (this.mInternal.mReadPackageSize == 0)
|
||||
{
|
||||
const int sizeToRead = 4;
|
||||
int leftSizeToRead = sizeToRead - this.mReadStream.WritePosition;
|
||||
int leftSizeToRead = sizeToRead - this.mInternal.mReadStream.WritePosition;
|
||||
|
||||
int read = await networkStream.ReadAsync(this.mReadStream.Buffer, this.mReadStream.WritePosition, leftSizeToRead);
|
||||
int read = await networkStream.ReadAsync(this.mInternal.mReadStream.Buffer, this.mInternal.mReadStream.WritePosition, leftSizeToRead);
|
||||
if (read <= 0)
|
||||
throw new Exception("Connection was terminated.");
|
||||
|
||||
this.mReadStream.WritePosition += read;
|
||||
this.mInternal.mReadStream.WritePosition += read;
|
||||
|
||||
//Did we receive the package?
|
||||
if (this.mReadStream.WritePosition >= 4)
|
||||
if (this.mInternal.mReadStream.WritePosition >= 4)
|
||||
{
|
||||
//Read the package size
|
||||
this.mReadPackageSize = this.mReadStream.ReadUInt32();
|
||||
this.mInternal.mReadPackageSize = this.mInternal.mReadStream.ReadUInt32();
|
||||
|
||||
if (this.mReadPackageSize > Const.MaxNetworkPackageSize)
|
||||
if (this.mInternal.mReadPackageSize > Const.MaxNetworkPackageSize)
|
||||
throw new Exception("Incoming package was larger than 'Conts.MaxNetworkPackageSize'");
|
||||
|
||||
this.mReadStream.Reset();
|
||||
this.mInternal.mReadStream.Reset();
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
int sizeToRead = (int)mReadPackageSize;
|
||||
int leftSizeToRead = sizeToRead - this.mReadStream.WritePosition;
|
||||
int sizeToRead = (int)this.mInternal.mReadPackageSize;
|
||||
int leftSizeToRead = sizeToRead - this.mInternal.mReadStream.WritePosition;
|
||||
|
||||
int read = await networkStream.ReadAsync(this.mReadStream.Buffer, this.mReadStream.WritePosition, leftSizeToRead);
|
||||
int read = await networkStream.ReadAsync(this.mInternal.mReadStream.Buffer, this.mInternal.mReadStream.WritePosition, leftSizeToRead);
|
||||
if (read <= 0)
|
||||
throw new Exception("Connection was terminated.");
|
||||
|
||||
this.mReadStream.WritePosition += read;
|
||||
this.mInternal.mReadStream.WritePosition += read;
|
||||
|
||||
//Do we have the package?
|
||||
if (this.mReadStream.WritePosition >= mReadPackageSize)
|
||||
if (this.mInternal.mReadStream.WritePosition >= this.mInternal.mReadPackageSize)
|
||||
{
|
||||
this.mReadPackageSize = 0;
|
||||
this.mInternal.mReadPackageSize = 0;
|
||||
|
||||
await this.mExecutionFunc(this, this.mInternal, this.mReadStream);
|
||||
await this.mInternal.mExecutionFunc(this, this.mInternal, this.mInternal.mReadStream);
|
||||
|
||||
//Reset
|
||||
this.mReadStream.Reset();
|
||||
this.mInternal.mReadStream.Reset();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//Send the network packages.
|
||||
if (this.mWriteStream.WritePosition > 0)
|
||||
if (this.mInternal.mWriteStream.WritePosition > 0)
|
||||
{
|
||||
lock (this.mWriteStream)
|
||||
lock (this.mInternal.mWriteStream)
|
||||
{
|
||||
if (this.mWriteStream.WritePosition > 0)
|
||||
if (this.mInternal.mWriteStream.WritePosition > 0)
|
||||
{
|
||||
networkStream.WriteAsync(this.mWriteStream.Buffer, 0, this.mWriteStream.WritePosition);
|
||||
this.mWriteStream.WritePosition = 0;
|
||||
networkStream.WriteAsync(this.mInternal.mWriteStream.Buffer, 0, this.mInternal.mWriteStream.WritePosition);
|
||||
this.mInternal.mWriteStream.WritePosition = 0;
|
||||
|
||||
this.mLastPackageSent = Extentions.TickCount;
|
||||
this.mInternal.mLastPackageSent = Extentions.TickCount;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//Are we timed out?
|
||||
if ((Extentions.TickCount - this.mLastPackageReceived) > Const.NetworkTimeout)
|
||||
if ((Extentions.TickCount - this.mInternal.mLastPackageReceived) > Const.NetworkTimeout)
|
||||
throw new Exception("Timedout.");
|
||||
|
||||
//Send keep alive if needed
|
||||
if ((Extentions.TickCount - this.mLastPackageSent) > Const.NetworkKeepAlive)
|
||||
if ((Extentions.TickCount - this.mInternal.mLastPackageSent) > Const.NetworkKeepAlive)
|
||||
{
|
||||
//Send keep alive.
|
||||
await networkStream.WriteAsync(this.mKeepAliveBuffer, 0, 4);
|
||||
await networkStream.WriteAsync(this.mInternal.mKeepAliveBuffer, 0, 4);
|
||||
await networkStream.FlushAsync();
|
||||
this.mLastPackageSent = Extentions.TickCount;
|
||||
this.mInternal.mLastPackageSent = Extentions.TickCount;
|
||||
}
|
||||
}
|
||||
catch (Exception e)
|
||||
|
@ -263,20 +194,100 @@ namespace BattleBitAPI.Server
|
|||
}
|
||||
|
||||
// ---- Team ----
|
||||
public IEnumerable<Player> GetAllPlayers()
|
||||
public IEnumerable<TPlayer> GetAllPlayers()
|
||||
{
|
||||
var list = new List<Player>(254);
|
||||
list.AddRange(this.mInternal.Players.Values);
|
||||
var list = new List<TPlayer>(this.mInternal.Players.Values.Count);
|
||||
foreach (var item in this.mInternal.Players.Values)
|
||||
list.Add((TPlayer)item);
|
||||
return list;
|
||||
}
|
||||
|
||||
// ---- Virtual ----
|
||||
public virtual async Task OnConnected()
|
||||
{
|
||||
|
||||
}
|
||||
public virtual async Task OnTick()
|
||||
{
|
||||
|
||||
}
|
||||
public virtual async Task OnReconnected()
|
||||
{
|
||||
|
||||
}
|
||||
public virtual async Task OnDisconnected()
|
||||
{
|
||||
|
||||
}
|
||||
public virtual async Task OnPlayerConnected(TPlayer player)
|
||||
{
|
||||
|
||||
}
|
||||
public virtual async Task OnPlayerDisconnected(TPlayer player)
|
||||
{
|
||||
|
||||
}
|
||||
public virtual async Task<bool> OnPlayerTypedMessage(TPlayer player, ChatChannel channel, string msg)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
public virtual async Task<PlayerStats> OnGetPlayerStats(ulong steamID, PlayerStats officialStats)
|
||||
{
|
||||
return officialStats;
|
||||
}
|
||||
public virtual async Task OnSavePlayerStats(ulong steamID, PlayerStats stats)
|
||||
{
|
||||
|
||||
}
|
||||
public virtual async Task<bool> OnPlayerRequestingToChangeRole(TPlayer player, GameRole role)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
public virtual async Task OnPlayerChangedRole(TPlayer player, GameRole role)
|
||||
{
|
||||
|
||||
}
|
||||
public virtual async Task OnPlayerJoinedSquad(TPlayer player, Squads squad)
|
||||
{
|
||||
|
||||
}
|
||||
public virtual async Task OnPlayerLeftSquad(TPlayer player, Squads squad)
|
||||
{
|
||||
|
||||
}
|
||||
public virtual async Task OnPlayerChangeTeam(TPlayer player, Team team)
|
||||
{
|
||||
|
||||
}
|
||||
public virtual async Task<PlayerSpawnRequest> OnPlayerSpawning(TPlayer player, PlayerSpawnRequest request)
|
||||
{
|
||||
return request;
|
||||
}
|
||||
public virtual async Task OnPlayerSpawned(TPlayer player)
|
||||
{
|
||||
|
||||
}
|
||||
public virtual async Task OnPlayerDied(TPlayer player)
|
||||
{
|
||||
|
||||
}
|
||||
public virtual async Task OnAPlayerKilledAnotherPlayer(OnPlayerKillArguments<TPlayer> args)
|
||||
{
|
||||
|
||||
}
|
||||
public virtual async Task OnPlayerReported(TPlayer from, TPlayer to, ReportReason reason, string additional)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
|
||||
// ---- Functions ----
|
||||
public void WriteToSocket(Common.Serialization.Stream pck)
|
||||
{
|
||||
lock (mWriteStream)
|
||||
lock (this.mInternal.mWriteStream)
|
||||
{
|
||||
mWriteStream.Write((uint)pck.WritePosition);
|
||||
mWriteStream.Write(pck.Buffer, 0, pck.WritePosition);
|
||||
this.mInternal.mWriteStream.Write((uint)pck.WritePosition);
|
||||
this.mInternal.mWriteStream.Write(pck.Buffer, 0, pck.WritePosition);
|
||||
}
|
||||
}
|
||||
public void ExecuteCommand(string cmd)
|
||||
|
@ -285,11 +296,11 @@ namespace BattleBitAPI.Server
|
|||
return;
|
||||
|
||||
int bytesLong = System.Text.Encoding.UTF8.GetByteCount(cmd);
|
||||
lock (mWriteStream)
|
||||
lock (this.mInternal.mWriteStream)
|
||||
{
|
||||
mWriteStream.Write((uint)(1 + 2 + bytesLong));
|
||||
mWriteStream.Write((byte)NetworkCommuncation.ExecuteCommand);
|
||||
mWriteStream.Write(cmd);
|
||||
this.mInternal.mWriteStream.Write((uint)(1 + 2 + bytesLong));
|
||||
this.mInternal.mWriteStream.Write((byte)NetworkCommuncation.ExecuteCommand);
|
||||
this.mInternal.mWriteStream.Write(cmd);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -342,7 +353,7 @@ namespace BattleBitAPI.Server
|
|||
{
|
||||
ExecuteCommand("kick " + steamID + " " + reason);
|
||||
}
|
||||
public void Kick(Player player, string reason)
|
||||
public void Kick(Player<TPlayer> player, string reason)
|
||||
{
|
||||
Kick(player.SteamID, reason);
|
||||
}
|
||||
|
@ -350,7 +361,7 @@ namespace BattleBitAPI.Server
|
|||
{
|
||||
ExecuteCommand("kill " + steamID);
|
||||
}
|
||||
public void Kill(Player player)
|
||||
public void Kill(Player<TPlayer> player)
|
||||
{
|
||||
Kill(player.SteamID);
|
||||
}
|
||||
|
@ -358,7 +369,7 @@ namespace BattleBitAPI.Server
|
|||
{
|
||||
ExecuteCommand("changeteam " + steamID);
|
||||
}
|
||||
public void ChangeTeam(Player player)
|
||||
public void ChangeTeam(Player<TPlayer> player)
|
||||
{
|
||||
ChangeTeam(player.SteamID);
|
||||
}
|
||||
|
@ -366,7 +377,7 @@ namespace BattleBitAPI.Server
|
|||
{
|
||||
ExecuteCommand("squadkick " + steamID);
|
||||
}
|
||||
public void KickFromSquad(Player player)
|
||||
public void KickFromSquad(Player<TPlayer> player)
|
||||
{
|
||||
KickFromSquad(player.SteamID);
|
||||
}
|
||||
|
@ -374,7 +385,7 @@ namespace BattleBitAPI.Server
|
|||
{
|
||||
ExecuteCommand("squaddisband " + steamID);
|
||||
}
|
||||
public void DisbandPlayerCurrentSquad(Player player)
|
||||
public void DisbandPlayerCurrentSquad(Player<TPlayer> player)
|
||||
{
|
||||
DisbandPlayerSSquad(player.SteamID);
|
||||
}
|
||||
|
@ -382,7 +393,7 @@ namespace BattleBitAPI.Server
|
|||
{
|
||||
ExecuteCommand("squadpromote " + steamID);
|
||||
}
|
||||
public void PromoteSquadLeader(Player player)
|
||||
public void PromoteSquadLeader(Player<TPlayer> player)
|
||||
{
|
||||
PromoteSquadLeader(player.SteamID);
|
||||
}
|
||||
|
@ -390,7 +401,7 @@ namespace BattleBitAPI.Server
|
|||
{
|
||||
ExecuteCommand("warn " + steamID + " " + msg);
|
||||
}
|
||||
public void WarnPlayer(Player player, string msg)
|
||||
public void WarnPlayer(Player<TPlayer> player, string msg)
|
||||
{
|
||||
WarnPlayer(player.SteamID, msg);
|
||||
}
|
||||
|
@ -398,7 +409,7 @@ namespace BattleBitAPI.Server
|
|||
{
|
||||
ExecuteCommand("msg " + steamID + " " + msg);
|
||||
}
|
||||
public void MessageToPlayer(Player player, string msg)
|
||||
public void MessageToPlayer(Player<TPlayer> player, string msg)
|
||||
{
|
||||
MessageToPlayer(player.SteamID, msg);
|
||||
}
|
||||
|
@ -406,7 +417,7 @@ namespace BattleBitAPI.Server
|
|||
{
|
||||
ExecuteCommand("setrole " + steamID + " " + role);
|
||||
}
|
||||
public void SetRoleTo(Player player, GameRole role)
|
||||
public void SetRoleTo(Player<TPlayer> player, GameRole role)
|
||||
{
|
||||
SetRoleTo(player.SteamID, role);
|
||||
}
|
||||
|
@ -434,52 +445,36 @@ namespace BattleBitAPI.Server
|
|||
WriteToSocket(response);
|
||||
}
|
||||
}
|
||||
public void SpawnPlayer(Player player, PlayerLoadout loadout, PlayerWearings wearings, Vector3 position, Vector3 lookDirection, PlayerStand stand, float spawnProtection)
|
||||
public void SpawnPlayer(Player<TPlayer> player, PlayerLoadout loadout, PlayerWearings wearings, Vector3 position, Vector3 lookDirection, PlayerStand stand, float spawnProtection)
|
||||
{
|
||||
SpawnPlayer(player.SteamID, loadout, wearings, position, lookDirection, stand, spawnProtection);
|
||||
}
|
||||
|
||||
// ---- Closing ----
|
||||
public void CloseConnection(string additionInfo = string.Empty)
|
||||
public void CloseConnection(string additionInfo = "")
|
||||
{
|
||||
if (string.IsNullOrWhiteSpace(additionInfo))
|
||||
this.TerminationReason = additionInfo;
|
||||
this.mInternal.TerminationReason = additionInfo;
|
||||
else
|
||||
this.TerminationReason = "User requested to terminate the connection";
|
||||
this.mWantsToCloseConnection = true;
|
||||
this.mInternal.TerminationReason = "User requested to terminate the connection";
|
||||
this.mInternal.mWantsToCloseConnection = true;
|
||||
}
|
||||
private void mClose(string reason)
|
||||
{
|
||||
if (this.IsConnected)
|
||||
{
|
||||
this.TerminationReason = reason;
|
||||
this.IsConnected = false;
|
||||
this.mInternal.TerminationReason = reason;
|
||||
this.mInternal.IsConnected = false;
|
||||
}
|
||||
}
|
||||
|
||||
// ---- Disposing ----
|
||||
public void Dispose()
|
||||
{
|
||||
if (this.mIsDisposed)
|
||||
return;
|
||||
this.mIsDisposed = true;
|
||||
|
||||
if (this.mWriteStream != null)
|
||||
if (this.mInternal.Socket != null)
|
||||
{
|
||||
this.mWriteStream.Dispose();
|
||||
this.mWriteStream = null;
|
||||
}
|
||||
|
||||
if (this.mReadStream != null)
|
||||
{
|
||||
this.mReadStream.Dispose();
|
||||
this.mReadStream = null;
|
||||
}
|
||||
|
||||
if (this.Socket != null)
|
||||
{
|
||||
this.Socket.SafeClose();
|
||||
this.Socket = null;
|
||||
this.mInternal.Socket.SafeClose();
|
||||
this.mInternal.Socket = null;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -491,23 +486,141 @@ namespace BattleBitAPI.Server
|
|||
this.ServerName;
|
||||
}
|
||||
|
||||
|
||||
// ---- Static ----
|
||||
public static TGameServer CreateInstance<TGameServer>(Internal @internal) where TGameServer : GameServer<TPlayer>
|
||||
{
|
||||
TGameServer gameServer = (TGameServer)Activator.CreateInstance(typeof(TGameServer));
|
||||
gameServer.mInternal = @internal;
|
||||
return gameServer;
|
||||
}
|
||||
|
||||
// ---- Internal ----
|
||||
public class mInternalResources
|
||||
public class Internal
|
||||
{
|
||||
public Dictionary<ulong, Player> Players = new Dictionary<ulong, Player>(254);
|
||||
// ---- Variables ----
|
||||
public ulong ServerHash;
|
||||
public bool IsConnected;
|
||||
public IPAddress GameIP;
|
||||
public int GamePort;
|
||||
public TcpClient Socket;
|
||||
public Func<GameServer<TPlayer>, Internal, Common.Serialization.Stream, Task> mExecutionFunc;
|
||||
public bool IsPasswordProtected;
|
||||
public string ServerName;
|
||||
public string Gamemode;
|
||||
public string Map;
|
||||
public MapSize MapSize;
|
||||
public MapDayNight DayNight;
|
||||
public int CurrentPlayers;
|
||||
public int InQueuePlayers;
|
||||
public int MaxPlayers;
|
||||
public string LoadingScreenText;
|
||||
public string ServerRulesText;
|
||||
public ServerSettings<TPlayer> Settings;
|
||||
public MapRotation<TPlayer> MapRotation;
|
||||
public GamemodeRotation<TPlayer> GamemodeRotation;
|
||||
public string TerminationReason;
|
||||
public bool ReconnectFlag;
|
||||
|
||||
public mRoomSettings Settings = new mRoomSettings();
|
||||
// ---- Private Variables ----
|
||||
public byte[] mKeepAliveBuffer;
|
||||
public Common.Serialization.Stream mWriteStream;
|
||||
public Common.Serialization.Stream mReadStream;
|
||||
public uint mReadPackageSize;
|
||||
public long mLastPackageReceived;
|
||||
public long mLastPackageSent;
|
||||
public bool mWantsToCloseConnection;
|
||||
public StringBuilder mBuilder;
|
||||
|
||||
public Internal()
|
||||
{
|
||||
this.TerminationReason = string.Empty;
|
||||
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;
|
||||
this.mBuilder = new StringBuilder(4096);
|
||||
|
||||
this.Settings = new ServerSettings<TPlayer>(this);
|
||||
this.MapRotation = new MapRotation<TPlayer>(this);
|
||||
this.GamemodeRotation = new GamemodeRotation<TPlayer>(this);
|
||||
}
|
||||
|
||||
// ---- Players In Room ----
|
||||
public Dictionary<ulong, Player<TPlayer>> Players = new Dictionary<ulong, Player<TPlayer>>(254);
|
||||
|
||||
// ---- Room Settings ----
|
||||
public mRoomSettings _Settings = new mRoomSettings();
|
||||
public bool IsDirtySettings;
|
||||
|
||||
public HashSet<string> MapRotation = new HashSet<string>(8);
|
||||
// ---- Map Rotation ----
|
||||
public HashSet<string> _MapRotation = new HashSet<string>(8);
|
||||
public bool MapRotationDirty = false;
|
||||
|
||||
public HashSet<string> GamemodeRotation = new HashSet<string>(8);
|
||||
// ---- Gamemode Rotation ----
|
||||
public HashSet<string> _GamemodeRotation = new HashSet<string>(8);
|
||||
public bool GamemodeRotationDirty = false;
|
||||
|
||||
public void AddPlayer<TPlayer>(TPlayer player) where TPlayer : Player
|
||||
// ---- Public Functions ----
|
||||
public void Set(Func<GameServer<TPlayer>, Internal, Common.Serialization.Stream, Task> func, TcpClient socket, IPAddress iP, int port, bool isPasswordProtected, string serverName, string gamemode, string map, MapSize mapSize, MapDayNight dayNight, int currentPlayers, int inQueuePlayers, int maxPlayers, string loadingScreenText, string serverRulesText)
|
||||
{
|
||||
this.ServerHash = ((ulong)port << 32) | (ulong)iP.ToUInt();
|
||||
this.IsConnected = true;
|
||||
this.GameIP = iP;
|
||||
this.GamePort = port;
|
||||
this.Socket = socket;
|
||||
this.mExecutionFunc = func;
|
||||
this.IsPasswordProtected = isPasswordProtected;
|
||||
this.ServerName = serverName;
|
||||
this.Gamemode = gamemode;
|
||||
this.Map = map;
|
||||
this.MapSize = mapSize;
|
||||
this.DayNight = dayNight;
|
||||
this.CurrentPlayers = currentPlayers;
|
||||
this.InQueuePlayers = inQueuePlayers;
|
||||
this.MaxPlayers = maxPlayers;
|
||||
this.LoadingScreenText = loadingScreenText;
|
||||
this.ServerRulesText = serverRulesText;
|
||||
|
||||
this.Settings.Reset();
|
||||
this._Settings.Reset();
|
||||
this.IsDirtySettings = false;
|
||||
|
||||
this.MapRotation.Reset();
|
||||
this._MapRotation.Clear();
|
||||
this.MapRotationDirty = false;
|
||||
|
||||
this.GamemodeRotation.Reset();
|
||||
this._GamemodeRotation.Clear();
|
||||
this.GamemodeRotationDirty = false;
|
||||
|
||||
this.TerminationReason = string.Empty;
|
||||
this.ReconnectFlag = false;
|
||||
|
||||
this.mWriteStream.Reset();
|
||||
this.mReadStream.Reset();
|
||||
this.mReadPackageSize = 0;
|
||||
this.mLastPackageReceived = Extentions.TickCount;
|
||||
this.mLastPackageSent = Extentions.TickCount;
|
||||
this.mWantsToCloseConnection = false;
|
||||
this.mBuilder.Clear();
|
||||
}
|
||||
public void AddPlayer(Player<TPlayer> player)
|
||||
{
|
||||
lock (Players)
|
||||
{
|
||||
|
@ -515,12 +628,12 @@ namespace BattleBitAPI.Server
|
|||
Players.Add(player.SteamID, player);
|
||||
}
|
||||
}
|
||||
public void RemovePlayer<TPlayer>(TPlayer player) where TPlayer : Player
|
||||
public void RemovePlayer<TPlayer>(TPlayer player) where TPlayer : Player<TPlayer>
|
||||
{
|
||||
lock (Players)
|
||||
Players.Remove(player.SteamID);
|
||||
}
|
||||
public bool TryGetPlayer(ulong steamID, out Player result)
|
||||
public bool TryGetPlayer(ulong steamID, out Player<TPlayer> result)
|
||||
{
|
||||
lock (Players)
|
||||
return Players.TryGetValue(steamID, out result);
|
||||
|
@ -576,6 +689,23 @@ namespace BattleBitAPI.Server
|
|||
this.SupportLimitPerSquad = ser.ReadInt8();
|
||||
this.ReconLimitPerSquad = ser.ReadInt8();
|
||||
}
|
||||
public void Reset()
|
||||
{
|
||||
this.DamageMultiplier = 1.0f;
|
||||
this.BleedingEnabled = true;
|
||||
this.StamineEnabled = false;
|
||||
this.FriendlyFireEnabled = false;
|
||||
this.HideMapVotes = true;
|
||||
this.OnlyWinnerTeamCanVote = false;
|
||||
this.HitMarkersEnabled = true;
|
||||
this.PointLogEnabled = true;
|
||||
this.SpectatorEnabled = true;
|
||||
|
||||
this.MedicLimitPerSquad = 8;
|
||||
this.EngineerLimitPerSquad = 8;
|
||||
this.SupportLimitPerSquad = 8;
|
||||
this.ReconLimitPerSquad = 8;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,38 +1,42 @@
|
|||
namespace BattleBitAPI.Server
|
||||
{
|
||||
public class GamemodeRotation
|
||||
public class GamemodeRotation<TPlayer> where TPlayer : Player<TPlayer>
|
||||
{
|
||||
private GameServer.mInternalResources mResources;
|
||||
public GamemodeRotation(GameServer.mInternalResources resources)
|
||||
private GameServer<TPlayer>.Internal mResources;
|
||||
public GamemodeRotation(GameServer<TPlayer>.Internal resources)
|
||||
{
|
||||
mResources = resources;
|
||||
}
|
||||
|
||||
public IEnumerable<string> GetGamemodeRotation()
|
||||
{
|
||||
lock (mResources.GamemodeRotation)
|
||||
return new List<string>(mResources.GamemodeRotation);
|
||||
lock (mResources._GamemodeRotation)
|
||||
return new List<string>(mResources._GamemodeRotation);
|
||||
}
|
||||
public bool InRotation(string gamemode)
|
||||
{
|
||||
lock (mResources.GamemodeRotation)
|
||||
return mResources.GamemodeRotation.Contains(gamemode);
|
||||
lock (mResources._GamemodeRotation)
|
||||
return mResources._GamemodeRotation.Contains(gamemode);
|
||||
}
|
||||
public bool RemoveFromRotation(string gamemode)
|
||||
{
|
||||
lock (mResources.GamemodeRotation)
|
||||
if (!mResources.GamemodeRotation.Remove(gamemode))
|
||||
lock (mResources._GamemodeRotation)
|
||||
if (!mResources._GamemodeRotation.Remove(gamemode))
|
||||
return false;
|
||||
mResources.GamemodeRotationDirty = true;
|
||||
return true;
|
||||
}
|
||||
public bool AddToRotation(string gamemode)
|
||||
{
|
||||
lock (mResources.GamemodeRotation)
|
||||
if (!mResources.GamemodeRotation.Add(gamemode))
|
||||
lock (mResources._GamemodeRotation)
|
||||
if (!mResources._GamemodeRotation.Add(gamemode))
|
||||
return false;
|
||||
mResources.GamemodeRotationDirty = true;
|
||||
return true;
|
||||
}
|
||||
|
||||
public void Reset()
|
||||
{
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,31 +1,31 @@
|
|||
namespace BattleBitAPI.Server
|
||||
{
|
||||
public class MapRotation
|
||||
public class MapRotation<TPlayer> where TPlayer : Player<TPlayer>
|
||||
{
|
||||
private GameServer.mInternalResources mResources;
|
||||
public MapRotation(GameServer.mInternalResources resources)
|
||||
private GameServer<TPlayer>.Internal mResources;
|
||||
public MapRotation(GameServer<TPlayer>.Internal resources)
|
||||
{
|
||||
mResources = resources;
|
||||
}
|
||||
|
||||
public IEnumerable<string> GetMapRotation()
|
||||
{
|
||||
lock (mResources.MapRotation)
|
||||
return new List<string>(mResources.MapRotation);
|
||||
lock (mResources._MapRotation)
|
||||
return new List<string>(mResources._MapRotation);
|
||||
}
|
||||
public bool InRotation(string map)
|
||||
{
|
||||
map = map.ToUpperInvariant();
|
||||
|
||||
lock (mResources.MapRotation)
|
||||
return mResources.MapRotation.Contains(map);
|
||||
lock (mResources._MapRotation)
|
||||
return mResources._MapRotation.Contains(map);
|
||||
}
|
||||
public bool RemoveFromRotation(string map)
|
||||
{
|
||||
map = map.ToUpperInvariant();
|
||||
|
||||
lock (mResources.MapRotation)
|
||||
if (!mResources.MapRotation.Remove(map))
|
||||
lock (mResources._MapRotation)
|
||||
if (!mResources._MapRotation.Remove(map))
|
||||
return false;
|
||||
mResources.MapRotationDirty = true;
|
||||
return true;
|
||||
|
@ -34,11 +34,15 @@
|
|||
{
|
||||
map = map.ToUpperInvariant();
|
||||
|
||||
lock (mResources.MapRotation)
|
||||
if (!mResources.MapRotation.Add(map))
|
||||
lock (mResources._MapRotation)
|
||||
if (!mResources._MapRotation.Add(map))
|
||||
return false;
|
||||
mResources.MapRotationDirty = true;
|
||||
return true;
|
||||
}
|
||||
|
||||
public void Reset()
|
||||
{
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,86 +1,89 @@
|
|||
namespace BattleBitAPI.Server
|
||||
{
|
||||
public class ServerSettings
|
||||
public class ServerSettings<TPlayer> where TPlayer : Player<TPlayer>
|
||||
{
|
||||
private GameServer.mInternalResources mResources;
|
||||
public ServerSettings(GameServer.mInternalResources resources)
|
||||
private GameServer<TPlayer>.Internal mResources;
|
||||
public ServerSettings(GameServer<TPlayer>.Internal resources)
|
||||
{
|
||||
mResources = resources;
|
||||
}
|
||||
|
||||
public float DamageMultiplier
|
||||
{
|
||||
get => mResources.Settings.DamageMultiplier;
|
||||
get => mResources._Settings.DamageMultiplier;
|
||||
set
|
||||
{
|
||||
mResources.Settings.DamageMultiplier = value;
|
||||
mResources._Settings.DamageMultiplier = value;
|
||||
mResources.IsDirtySettings = true;
|
||||
}
|
||||
}
|
||||
public bool BleedingEnabled
|
||||
{
|
||||
get => mResources.Settings.BleedingEnabled;
|
||||
get => mResources._Settings.BleedingEnabled;
|
||||
set
|
||||
{
|
||||
mResources.Settings.BleedingEnabled = value;
|
||||
mResources._Settings.BleedingEnabled = value;
|
||||
mResources.IsDirtySettings = true;
|
||||
}
|
||||
}
|
||||
public bool StamineEnabled
|
||||
{
|
||||
get => mResources.Settings.StamineEnabled;
|
||||
get => mResources._Settings.StamineEnabled;
|
||||
set
|
||||
{
|
||||
mResources.Settings.StamineEnabled = value;
|
||||
mResources._Settings.StamineEnabled = value;
|
||||
mResources.IsDirtySettings = true;
|
||||
}
|
||||
}
|
||||
public bool FriendlyFireEnabled
|
||||
{
|
||||
get => mResources.Settings.FriendlyFireEnabled;
|
||||
get => mResources._Settings.FriendlyFireEnabled;
|
||||
set
|
||||
{
|
||||
mResources.Settings.FriendlyFireEnabled = value;
|
||||
mResources._Settings.FriendlyFireEnabled = value;
|
||||
mResources.IsDirtySettings = true;
|
||||
}
|
||||
}
|
||||
public bool OnlyWinnerTeamCanVote
|
||||
{
|
||||
get => mResources.Settings.OnlyWinnerTeamCanVote;
|
||||
get => mResources._Settings.OnlyWinnerTeamCanVote;
|
||||
set
|
||||
{
|
||||
mResources.Settings.OnlyWinnerTeamCanVote = value;
|
||||
mResources._Settings.OnlyWinnerTeamCanVote = value;
|
||||
mResources.IsDirtySettings = true;
|
||||
}
|
||||
}
|
||||
public bool HitMarkersEnabled
|
||||
{
|
||||
get => mResources.Settings.HitMarkersEnabled;
|
||||
get => mResources._Settings.HitMarkersEnabled;
|
||||
set
|
||||
{
|
||||
mResources.Settings.HitMarkersEnabled = value;
|
||||
mResources._Settings.HitMarkersEnabled = value;
|
||||
mResources.IsDirtySettings = true;
|
||||
}
|
||||
}
|
||||
public bool PointLogEnabled
|
||||
{
|
||||
get => mResources.Settings.PointLogEnabled;
|
||||
get => mResources._Settings.PointLogEnabled;
|
||||
set
|
||||
{
|
||||
mResources.Settings.PointLogEnabled = value;
|
||||
mResources._Settings.PointLogEnabled = value;
|
||||
mResources.IsDirtySettings = true;
|
||||
}
|
||||
}
|
||||
public bool SpectatorEnabled
|
||||
{
|
||||
get => mResources.Settings.SpectatorEnabled;
|
||||
get => mResources._Settings.SpectatorEnabled;
|
||||
set
|
||||
{
|
||||
mResources.Settings.SpectatorEnabled = value;
|
||||
mResources._Settings.SpectatorEnabled = value;
|
||||
mResources.IsDirtySettings = true;
|
||||
}
|
||||
}
|
||||
|
||||
public void Reset()
|
||||
{
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,4 +1,5 @@
|
|||
using System.Net;
|
||||
using System.Net.Security;
|
||||
using System.Net.Sockets;
|
||||
using System.Numerics;
|
||||
using BattleBitAPI.Common;
|
||||
|
@ -9,7 +10,7 @@ using CommunityServerAPI.BattleBitAPI;
|
|||
|
||||
namespace BattleBitAPI.Server
|
||||
{
|
||||
public class ServerListener<TPlayer> : IDisposable where TPlayer : Player
|
||||
public class ServerListener<TPlayer, TGameServer> : IDisposable where TPlayer : Player<TPlayer> where TGameServer : GameServer<TPlayer>
|
||||
{
|
||||
// --- Public ---
|
||||
public bool IsListening { get; private set; }
|
||||
|
@ -17,11 +18,6 @@ namespace BattleBitAPI.Server
|
|||
public int ListeningPort { get; private set; }
|
||||
|
||||
// --- Events ---
|
||||
/// <summary>
|
||||
/// Fired when game server is ticking (~100hz)<br/>
|
||||
/// </summary>
|
||||
public Func<GameServer, Task> OnGameServerTick { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Fired when an attempt made to connect to the server.<br/>
|
||||
/// Default, any connection attempt will be accepted
|
||||
|
@ -36,206 +32,16 @@ namespace BattleBitAPI.Server
|
|||
/// </value>
|
||||
public Func<IPAddress, Task<bool>> OnGameServerConnecting { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Fired when a game server connects.
|
||||
/// </summary>
|
||||
///
|
||||
/// <remarks>
|
||||
/// GameServer: Game server that is connecting.<br/>
|
||||
/// </remarks>
|
||||
public Func<GameServer, 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, Task> OnGameServerReconnected { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Fired when a game server disconnects. Check (GameServer.TerminationReason) to see the reason.
|
||||
/// </summary>
|
||||
///
|
||||
/// <remarks>
|
||||
/// GameServer: Game server that disconnected.<br/>
|
||||
/// </remarks>
|
||||
public Func<GameServer, Task> OnGameServerDisconnected { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Fired when a player connects to a server.<br/>
|
||||
/// Check player.GameServer get the server that player joined.
|
||||
/// </summary>
|
||||
///
|
||||
/// <remarks>
|
||||
/// Player: The player that connected to the server<br/>
|
||||
/// </remarks>
|
||||
public Func<TPlayer, Task> OnPlayerConnected { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Fired when a player disconnects from a server.<br/>
|
||||
/// Check player.GameServer get the server that player left.
|
||||
/// </summary>
|
||||
///
|
||||
/// <remarks>
|
||||
/// Player: The player that disconnected from the server<br/>
|
||||
/// </remarks>
|
||||
public Func<TPlayer, Task> OnPlayerDisconnected { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Fired when a player types a message to text chat.<br/>
|
||||
/// </summary>
|
||||
///
|
||||
/// <remarks>
|
||||
/// Player: The player that typed the message <br/>
|
||||
/// ChatChannel: The channel the message was sent <br/>
|
||||
/// string - Message: The message<br/>
|
||||
/// </remarks>
|
||||
/// <value>
|
||||
/// Returns: True if you let the message broadcasted, false if you don't it to be broadcasted.
|
||||
/// </value>
|
||||
public Func<TPlayer, ChatChannel, string, Task<bool>> OnPlayerTypedMessage { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Fired when a player kills another player.
|
||||
/// </summary>
|
||||
///
|
||||
/// <remarks>
|
||||
/// OnPlayerKillArguments: Details about the kill<br/>
|
||||
/// </remarks>
|
||||
public Func<OnPlayerKillArguments<TPlayer>, Task> OnAPlayerKilledAnotherPlayer { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Fired when game server requests the stats of a player, this function should return in 3000ms or player will not able to join to server.
|
||||
/// </summary>
|
||||
///
|
||||
/// <remarks>
|
||||
/// ulong - SteamID of the player<br/>
|
||||
/// PlayerStats - The official stats of the player<br/>
|
||||
/// </remarks>
|
||||
/// <value>
|
||||
/// Returns: The modified stats of the player.
|
||||
/// </value>
|
||||
public Func<ulong, PlayerStats, Task<PlayerStats>> OnGetPlayerStats { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Fired when game server requests to save the stats of a player.
|
||||
/// </summary>
|
||||
///
|
||||
/// <remarks>
|
||||
/// ulong - SteamID of the player<br/>
|
||||
/// PlayerStats - Stats of the player<br/>
|
||||
/// </remarks>
|
||||
/// <value>
|
||||
/// Returns: The stats of the player.
|
||||
/// </value>
|
||||
public Func<ulong, PlayerStats, Task> OnSavePlayerStats { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Fired when a player requests server to change role.
|
||||
/// </summary>
|
||||
///
|
||||
/// <remarks>
|
||||
/// TPlayer - The player requesting<br/>
|
||||
/// GameRole - The role the player asking to change<br/>
|
||||
/// </remarks>
|
||||
/// <value>
|
||||
/// Returns: True if you accept if, false if you don't.
|
||||
/// </value>
|
||||
public Func<TPlayer, GameRole, Task<bool>> OnPlayerRequestingToChangeRole { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Fired when a player changes their game role.
|
||||
/// </summary>
|
||||
///
|
||||
/// <remarks>
|
||||
/// TPlayer - The player<br/>
|
||||
/// GameRole - The new role of the player<br/>
|
||||
/// </remarks>
|
||||
public Func<TPlayer, GameRole, Task> OnPlayerChangedRole { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Fired when a player joins a squad.
|
||||
/// </summary>
|
||||
///
|
||||
/// <remarks>
|
||||
/// TPlayer - The player<br/>
|
||||
/// Squads - The squad player joined<br/>
|
||||
/// </remarks>
|
||||
public Func<TPlayer, Squads, Task> OnPlayerJoinedASquad { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Fired when a player leaves their squad.
|
||||
/// </summary>
|
||||
///
|
||||
/// <remarks>
|
||||
/// TPlayer - The player<br/>
|
||||
/// Squads - The squad that player left<br/>
|
||||
/// </remarks>
|
||||
public Func<TPlayer, Squads, Task> OnPlayerLeftSquad { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Fired when a player changes team.
|
||||
/// </summary>
|
||||
///
|
||||
/// <remarks>
|
||||
/// TPlayer - The player<br/>
|
||||
/// Team - The new team that player joined<br/>
|
||||
/// </remarks>
|
||||
public Func<TPlayer, Team, Task> OnPlayerChangedTeam { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Fired when a player is spawning.
|
||||
/// </summary>
|
||||
///
|
||||
/// <remarks>
|
||||
/// TPlayer - The player<br/>
|
||||
/// PlayerSpawnRequest - The request<br/>
|
||||
/// </remarks>
|
||||
/// <value>
|
||||
/// Returns: The new spawn response
|
||||
/// </value>
|
||||
public Func<TPlayer, PlayerSpawnRequest, Task<PlayerSpawnRequest>> OnPlayerSpawning { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Fired when a player is spawns
|
||||
/// </summary>
|
||||
///
|
||||
/// <remarks>
|
||||
/// TPlayer - The player<br/>
|
||||
/// </remarks>
|
||||
public Func<TPlayer, Task> OnPlayerSpawned { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Fired when a player dies
|
||||
/// </summary>
|
||||
///
|
||||
/// <remarks>
|
||||
/// TPlayer - The player<br/>
|
||||
/// </remarks>
|
||||
public Func<TPlayer, Task> OnPlayerDied { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Fired when a player reports another player.
|
||||
/// </summary>
|
||||
///
|
||||
/// <remarks>
|
||||
/// TPlayer - The reporter player<br/>
|
||||
/// TPlayer - The reported player<br/>
|
||||
/// ReportReason - The reason of report<br/>
|
||||
/// String - Additional detail<br/>
|
||||
/// </remarks>
|
||||
public Func<TPlayer, TPlayer, ReportReason, string, Task> OnPlayerReported { get; set; }
|
||||
|
||||
// --- Private ---
|
||||
private TcpListener mSocket;
|
||||
private Dictionary<ulong, GameServer> mActiveConnections;
|
||||
private Dictionary<ulong, (TGameServer server, GameServer<TPlayer>.Internal resources)> mActiveConnections;
|
||||
private mInstances<TPlayer, TGameServer> mInstanceDatabase;
|
||||
|
||||
// --- Construction ---
|
||||
public ServerListener()
|
||||
{
|
||||
this.mActiveConnections = new Dictionary<ulong, GameServer>(16);
|
||||
this.mActiveConnections = new Dictionary<ulong, (TGameServer, GameServer<TPlayer>.Internal)>(16);
|
||||
this.mInstanceDatabase = new mInstances<TPlayer, TGameServer>();
|
||||
}
|
||||
|
||||
// --- Starting ---
|
||||
|
@ -304,8 +110,8 @@ namespace BattleBitAPI.Server
|
|||
return;
|
||||
}
|
||||
|
||||
GameServer server = null;
|
||||
GameServer.mInternalResources resources;
|
||||
TGameServer server = null;
|
||||
GameServer<TPlayer>.Internal resources;
|
||||
try
|
||||
{
|
||||
using (CancellationTokenSource source = new CancellationTokenSource(Const.HailConnectTimeout))
|
||||
|
@ -491,8 +297,25 @@ namespace BattleBitAPI.Server
|
|||
}
|
||||
}
|
||||
|
||||
resources = new GameServer.mInternalResources();
|
||||
server = new GameServer(client, resources, mExecutePackage, ip, gamePort, isPasswordProtected, serverName, gameMode, gamemap, size, dayNight, currentPlayers, queuePlayers, maxPlayers, loadingScreenText, serverRulesText);
|
||||
var hash = ((ulong)gamePort << 32) | (ulong)ip.ToUInt();
|
||||
server = this.mInstanceDatabase.GetServerInstance(hash, out resources);
|
||||
resources.Set(
|
||||
this.mExecutePackage,
|
||||
client,
|
||||
ip,
|
||||
gamePort,
|
||||
isPasswordProtected,
|
||||
serverName,
|
||||
gameMode,
|
||||
gamemap,
|
||||
size,
|
||||
dayNight,
|
||||
currentPlayers,
|
||||
queuePlayers,
|
||||
maxPlayers,
|
||||
loadingScreenText,
|
||||
serverRulesText
|
||||
);
|
||||
|
||||
//Room settings
|
||||
{
|
||||
|
@ -504,7 +327,7 @@ namespace BattleBitAPI.Server
|
|||
readStream.Reset();
|
||||
if (!await networkStream.TryRead(readStream, roomSize, source.Token))
|
||||
throw new Exception("Unable to read the room");
|
||||
resources.Settings.Read(readStream);
|
||||
resources._Settings.Read(readStream);
|
||||
}
|
||||
|
||||
//Map&gamemode rotation
|
||||
|
@ -523,7 +346,7 @@ namespace BattleBitAPI.Server
|
|||
{
|
||||
count--;
|
||||
if (readStream.TryReadString(out var item))
|
||||
resources.MapRotation.Add(item.ToUpperInvariant());
|
||||
resources._MapRotation.Add(item.ToUpperInvariant());
|
||||
}
|
||||
|
||||
count = readStream.ReadUInt32();
|
||||
|
@ -531,7 +354,7 @@ namespace BattleBitAPI.Server
|
|||
{
|
||||
count--;
|
||||
if (readStream.TryReadString(out var item))
|
||||
resources.GamemodeRotation.Add(item);
|
||||
resources._GamemodeRotation.Add(item);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -640,11 +463,11 @@ namespace BattleBitAPI.Server
|
|||
wearings.Read(readStream);
|
||||
}
|
||||
|
||||
TPlayer player = Activator.CreateInstance<TPlayer>();
|
||||
TPlayer player = mInstanceDatabase.GetPlayerInstance(steamid);
|
||||
player.SteamID = steamid;
|
||||
player.Name = username;
|
||||
player.IP = new IPAddress(ipHash);
|
||||
player.GameServer = server;
|
||||
player.GameServer = (GameServer<TPlayer>)server;
|
||||
player.Team = team;
|
||||
player.Squad = squad;
|
||||
player.Role = role;
|
||||
|
@ -652,8 +475,6 @@ namespace BattleBitAPI.Server
|
|||
player.CurrentLoadout = loadout;
|
||||
player.CurrentWearings = wearings;
|
||||
|
||||
await player.OnInitialized();
|
||||
|
||||
resources.AddPlayer(player);
|
||||
}
|
||||
|
||||
|
@ -679,12 +500,6 @@ namespace BattleBitAPI.Server
|
|||
}
|
||||
catch { }
|
||||
|
||||
if (server != null)
|
||||
{
|
||||
server.Dispose();
|
||||
server = null;
|
||||
}
|
||||
|
||||
client.SafeClose();
|
||||
return;
|
||||
}
|
||||
|
@ -697,25 +512,23 @@ namespace BattleBitAPI.Server
|
|||
//An old connection exist with same IP + Port?
|
||||
if (connectionExist = this.mActiveConnections.TryGetValue(server.ServerHash, out var oldServer))
|
||||
{
|
||||
oldServer.ReconnectFlag = true;
|
||||
oldServer.resources.ReconnectFlag = true;
|
||||
this.mActiveConnections.Remove(server.ServerHash);
|
||||
}
|
||||
|
||||
this.mActiveConnections.Add(server.ServerHash, server);
|
||||
this.mActiveConnections.Add(server.ServerHash, (server, resources));
|
||||
}
|
||||
|
||||
//Call the callback.
|
||||
if (!connectionExist)
|
||||
{
|
||||
//New connection!
|
||||
if (OnGameServerConnected != null)
|
||||
await OnGameServerConnected.Invoke(server);
|
||||
await server.OnConnected();
|
||||
}
|
||||
else
|
||||
{
|
||||
//Reconnection
|
||||
if (OnGameServerReconnected != null)
|
||||
await OnGameServerReconnected.Invoke(server);
|
||||
await server.OnReconnected();
|
||||
}
|
||||
|
||||
//Set the buffer sizes.
|
||||
|
@ -725,20 +538,19 @@ namespace BattleBitAPI.Server
|
|||
//Join to main server loop.
|
||||
await mHandleGameServer(server);
|
||||
}
|
||||
private async Task mHandleGameServer(GameServer server)
|
||||
private async Task mHandleGameServer(TGameServer server)
|
||||
{
|
||||
using (server)
|
||||
{
|
||||
while (server.IsConnected)
|
||||
{
|
||||
if (OnGameServerTick != null)
|
||||
await OnGameServerTick(server);
|
||||
await server.OnTick();
|
||||
await server.Tick();
|
||||
await Task.Delay(10);
|
||||
}
|
||||
|
||||
if (OnGameServerDisconnected != null && !server.ReconnectFlag)
|
||||
await OnGameServerDisconnected.Invoke(server);
|
||||
if (!server.ReconnectFlag)
|
||||
await server.OnDisconnected();
|
||||
}
|
||||
|
||||
//Remove from list.
|
||||
|
@ -748,7 +560,7 @@ namespace BattleBitAPI.Server
|
|||
}
|
||||
|
||||
// --- Logic Executing ---
|
||||
private async Task mExecutePackage(GameServer server, GameServer.mInternalResources resources, Common.Serialization.Stream stream)
|
||||
private async Task mExecutePackage(GameServer<TPlayer> server, GameServer<TPlayer>.Internal resources, Common.Serialization.Stream stream)
|
||||
{
|
||||
var communcation = (NetworkCommuncation)stream.ReadInt8();
|
||||
switch (communcation)
|
||||
|
@ -765,21 +577,19 @@ namespace BattleBitAPI.Server
|
|||
Squads squad = (Squads)stream.ReadInt8();
|
||||
GameRole role = (GameRole)stream.ReadInt8();
|
||||
|
||||
TPlayer player = Activator.CreateInstance<TPlayer>();
|
||||
TPlayer player = mInstanceDatabase.GetPlayerInstance(steamID);
|
||||
player.SteamID = steamID;
|
||||
player.Name = username;
|
||||
player.IP = new IPAddress(ip);
|
||||
player.GameServer = server;
|
||||
player.GameServer = (GameServer<TPlayer>)server;
|
||||
|
||||
player.Team = team;
|
||||
player.Squad = squad;
|
||||
player.Role = role;
|
||||
|
||||
await player.OnInitialized();
|
||||
|
||||
resources.AddPlayer(player);
|
||||
if (OnPlayerConnected != null)
|
||||
await OnPlayerConnected.Invoke(player);
|
||||
await server.OnPlayerConnected(player);
|
||||
await player.OnConnected();
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
@ -790,14 +600,14 @@ namespace BattleBitAPI.Server
|
|||
{
|
||||
ulong steamID = stream.ReadUInt64();
|
||||
bool exist;
|
||||
Player player;
|
||||
Player<TPlayer> player;
|
||||
lock (resources.Players)
|
||||
exist = resources.Players.Remove(steamID, out player);
|
||||
|
||||
if (exist)
|
||||
{
|
||||
if (OnPlayerDisconnected != null)
|
||||
await OnPlayerDisconnected.Invoke((TPlayer)player);
|
||||
await server.OnPlayerDisconnected((TPlayer)player);
|
||||
await player.OnDisconnected();
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
@ -814,9 +624,7 @@ namespace BattleBitAPI.Server
|
|||
ChatChannel chat = (ChatChannel)stream.ReadInt8();
|
||||
if (stream.TryReadString(out var msg))
|
||||
{
|
||||
bool pass = true;
|
||||
if (OnPlayerTypedMessage != null)
|
||||
pass = await OnPlayerTypedMessage.Invoke((TPlayer)player, chat, msg);
|
||||
var pass = await server.OnPlayerTypedMessage((TPlayer)player, chat, msg);
|
||||
|
||||
//Respond back.
|
||||
using (var response = Common.Serialization.Stream.Get())
|
||||
|
@ -850,22 +658,17 @@ namespace BattleBitAPI.Server
|
|||
{
|
||||
if (resources.TryGetPlayer(victim, out var victimClient))
|
||||
{
|
||||
if (OnAPlayerKilledAnotherPlayer != null)
|
||||
var args = new OnPlayerKillArguments<TPlayer>()
|
||||
{
|
||||
var args = new OnPlayerKillArguments<TPlayer>()
|
||||
{
|
||||
Killer = (TPlayer)killerClient,
|
||||
KillerPosition = killerPos,
|
||||
Victim = (TPlayer)victimClient,
|
||||
VictimPosition = victimPos,
|
||||
BodyPart = body,
|
||||
SourceOfDamage = source,
|
||||
KillerTool = tool,
|
||||
};
|
||||
|
||||
await OnAPlayerKilledAnotherPlayer.Invoke(args);
|
||||
|
||||
}
|
||||
Killer = (TPlayer)killerClient,
|
||||
KillerPosition = killerPos,
|
||||
Victim = (TPlayer)victimClient,
|
||||
VictimPosition = victimPos,
|
||||
BodyPart = body,
|
||||
SourceOfDamage = source,
|
||||
KillerTool = tool,
|
||||
};
|
||||
await server.OnAPlayerKilledAnotherPlayer(args);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -881,9 +684,7 @@ namespace BattleBitAPI.Server
|
|||
|
||||
var stats = new PlayerStats();
|
||||
stats.Read(stream);
|
||||
|
||||
if (OnGetPlayerStats != null)
|
||||
stats = await OnGetPlayerStats.Invoke(steamID, stats);
|
||||
stats = await server.OnGetPlayerStats(steamID, stats);
|
||||
|
||||
using (var response = Common.Serialization.Stream.Get())
|
||||
{
|
||||
|
@ -903,8 +704,7 @@ namespace BattleBitAPI.Server
|
|||
PlayerStats stats = new PlayerStats();
|
||||
stats.Read(stream);
|
||||
|
||||
if (OnSavePlayerStats != null)
|
||||
await OnSavePlayerStats.Invoke(steamID, stats);
|
||||
await server.OnSavePlayerStats(steamID, stats);
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
@ -919,8 +719,7 @@ namespace BattleBitAPI.Server
|
|||
{
|
||||
bool accepted = true;
|
||||
|
||||
if (OnPlayerRequestingToChangeRole != null)
|
||||
accepted = await OnPlayerRequestingToChangeRole.Invoke((TPlayer)client, role);
|
||||
accepted = await server.OnPlayerRequestingToChangeRole((TPlayer)client, role);
|
||||
|
||||
if (accepted)
|
||||
server.SetRoleTo(steamID, role);
|
||||
|
@ -938,8 +737,7 @@ namespace BattleBitAPI.Server
|
|||
if (resources.TryGetPlayer(steamID, out var client))
|
||||
{
|
||||
client.Role = role;
|
||||
if (OnPlayerChangedRole != null)
|
||||
await OnPlayerChangedRole.Invoke((TPlayer)client, role);
|
||||
await server.OnPlayerChangedRole((TPlayer)client, role);
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
@ -954,8 +752,7 @@ namespace BattleBitAPI.Server
|
|||
if (resources.TryGetPlayer(steamID, out var client))
|
||||
{
|
||||
client.Squad = squad;
|
||||
if (OnPlayerJoinedASquad != null)
|
||||
await OnPlayerJoinedASquad.Invoke((TPlayer)client, squad);
|
||||
await server.OnPlayerJoinedSquad((TPlayer)client, squad);
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
@ -973,12 +770,10 @@ namespace BattleBitAPI.Server
|
|||
client.Squad = Squads.NoSquad;
|
||||
client.Role = GameRole.Assault;
|
||||
|
||||
if (OnPlayerLeftSquad != null)
|
||||
await OnPlayerLeftSquad.Invoke((TPlayer)client, oldSquad);
|
||||
await server.OnPlayerLeftSquad((TPlayer)client, oldSquad);
|
||||
|
||||
if (oldRole != GameRole.Assault)
|
||||
if (OnPlayerChangedRole != null)
|
||||
await OnPlayerChangedRole.Invoke((TPlayer)client, GameRole.Assault);
|
||||
await server.OnPlayerChangedRole((TPlayer)client, GameRole.Assault);
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
@ -993,8 +788,7 @@ namespace BattleBitAPI.Server
|
|||
if (resources.TryGetPlayer(steamID, out var client))
|
||||
{
|
||||
client.Team = team;
|
||||
if (OnPlayerChangedTeam != null)
|
||||
await OnPlayerChangedTeam.Invoke((TPlayer)client, team);
|
||||
await server.OnPlayerChangeTeam((TPlayer)client, team);
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
@ -1010,8 +804,7 @@ namespace BattleBitAPI.Server
|
|||
ushort vehicleID = stream.ReadUInt16();
|
||||
|
||||
if (resources.TryGetPlayer(steamID, out var client))
|
||||
if (this.OnPlayerSpawning != null)
|
||||
request = await OnPlayerSpawning.Invoke((TPlayer)client, request);
|
||||
request = await server.OnPlayerSpawning((TPlayer)client, request);
|
||||
|
||||
//Respond back.
|
||||
using (var response = Common.Serialization.Stream.Get())
|
||||
|
@ -1038,8 +831,7 @@ namespace BattleBitAPI.Server
|
|||
{
|
||||
if (resources.TryGetPlayer(reported, out var reportedClient))
|
||||
{
|
||||
if (OnPlayerReported != null)
|
||||
await OnPlayerReported.Invoke((TPlayer)reporterClient, (TPlayer)reportedClient, reason, additionalInfo);
|
||||
await server.OnPlayerReported((TPlayer)reporterClient, (TPlayer)reportedClient, reason, additionalInfo);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -1063,9 +855,7 @@ namespace BattleBitAPI.Server
|
|||
client.IsAlive = true;
|
||||
|
||||
await client.OnSpawned();
|
||||
|
||||
if (OnPlayerSpawned != null)
|
||||
await OnPlayerSpawned.Invoke((TPlayer)client);
|
||||
await server.OnPlayerSpawned((TPlayer)client);
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
@ -1083,8 +873,7 @@ namespace BattleBitAPI.Server
|
|||
|
||||
await client.OnDied();
|
||||
|
||||
if (OnPlayerDied != null)
|
||||
await OnPlayerDied.Invoke((TPlayer)client);
|
||||
await server.OnPlayerDied((TPlayer)client);
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
@ -1094,14 +883,14 @@ namespace BattleBitAPI.Server
|
|||
if (stream.CanRead(4))
|
||||
{
|
||||
uint count = stream.ReadUInt32();
|
||||
lock (resources.MapRotation)
|
||||
lock (resources._MapRotation)
|
||||
{
|
||||
resources.MapRotation.Clear();
|
||||
resources._MapRotation.Clear();
|
||||
while (count > 0)
|
||||
{
|
||||
count--;
|
||||
if (stream.TryReadString(out var map))
|
||||
resources.MapRotation.Add(map.ToUpperInvariant());
|
||||
resources._MapRotation.Add(map.ToUpperInvariant());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -1112,14 +901,14 @@ namespace BattleBitAPI.Server
|
|||
if (stream.CanRead(4))
|
||||
{
|
||||
uint count = stream.ReadUInt32();
|
||||
lock (resources.GamemodeRotation)
|
||||
lock (resources._GamemodeRotation)
|
||||
{
|
||||
resources.GamemodeRotation.Clear();
|
||||
resources._GamemodeRotation.Clear();
|
||||
while (count > 0)
|
||||
{
|
||||
count--;
|
||||
if (stream.TryReadString(out var map))
|
||||
resources.GamemodeRotation.Add(map);
|
||||
resources._GamemodeRotation.Add(map);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -1139,5 +928,49 @@ namespace BattleBitAPI.Server
|
|||
if (IsListening)
|
||||
Stop();
|
||||
}
|
||||
|
||||
// --- Classes ---
|
||||
private class mInstances<TPlayer, TGameServer> where TPlayer : Player<TPlayer> where TGameServer : GameServer<TPlayer>
|
||||
{
|
||||
private Dictionary<ulong, (TGameServer, GameServer<TPlayer>.Internal)> mGameServerInstances;
|
||||
private Dictionary<ulong, TPlayer> mPlayerInstances;
|
||||
|
||||
public mInstances()
|
||||
{
|
||||
this.mGameServerInstances = new Dictionary<ulong, (TGameServer, GameServer<TPlayer>.Internal)>(64);
|
||||
this.mPlayerInstances = new Dictionary<ulong, TPlayer>(1024 * 16);
|
||||
}
|
||||
|
||||
public TGameServer GetServerInstance(ulong hash, out GameServer<TPlayer>.Internal @internal)
|
||||
{
|
||||
lock (mGameServerInstances)
|
||||
{
|
||||
if (mGameServerInstances.TryGetValue(hash, out var data))
|
||||
{
|
||||
@internal = data.Item2;
|
||||
return data.Item1;
|
||||
}
|
||||
|
||||
@internal = new GameServer<TPlayer>.Internal();
|
||||
TGameServer gameServer = GameServer<TPlayer>.CreateInstance<TGameServer>(@internal);
|
||||
|
||||
mGameServerInstances.Add(hash, (gameServer, @internal));
|
||||
return gameServer;
|
||||
}
|
||||
}
|
||||
public TPlayer GetPlayerInstance(ulong steamID)
|
||||
{
|
||||
lock (this.mPlayerInstances)
|
||||
{
|
||||
if (this.mPlayerInstances.TryGetValue(steamID, out var player))
|
||||
return player;
|
||||
|
||||
player = Activator.CreateInstance<TPlayer>();
|
||||
player.OnCreated();
|
||||
mPlayerInstances.Add(steamID, player);
|
||||
return player;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
29
Program.cs
29
Program.cs
|
@ -1,22 +1,39 @@
|
|||
using BattleBitAPI;
|
||||
using BattleBitAPI.Common;
|
||||
using BattleBitAPI.Server;
|
||||
using System.Diagnostics;
|
||||
using System.Net;
|
||||
using System.Text;
|
||||
|
||||
class Program
|
||||
{
|
||||
static void Main(string[] args)
|
||||
{
|
||||
var listener = new ServerListener<MyPlayer>();
|
||||
var listener = new ServerListener<MyPlayer, MyGameServer>();
|
||||
listener.Start(29294);
|
||||
listener.OnGameServerConnecting += OnGameServerConnecting;
|
||||
|
||||
Thread.Sleep(-1);
|
||||
}
|
||||
|
||||
private static async Task<bool> OnGameServerConnecting(IPAddress ip)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
}
|
||||
class MyPlayer : Player
|
||||
class MyPlayer : Player<MyPlayer>
|
||||
{
|
||||
public int NumberOfSpawns = 0;
|
||||
|
||||
}
|
||||
public override async Task OnSpawned()
|
||||
{
|
||||
this.NumberOfSpawns++;
|
||||
base.GameServer.CloseConnection();
|
||||
|
||||
await Console.Out.WriteLineAsync("Spawn: " + this.NumberOfSpawns);
|
||||
}
|
||||
}
|
||||
class MyGameServer : GameServer<MyPlayer>
|
||||
{
|
||||
public override async Task OnConnected()
|
||||
{
|
||||
Console.WriteLine(base.GameIP + " connected");
|
||||
}
|
||||
}
|
||||
|
|
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Loading…
Reference in New Issue