New changes!

This commit is contained in:
MrOkiDoki 2023-08-14 12:43:58 +03:00
parent aea0de1eb6
commit bbfbabe2d9
10 changed files with 433 additions and 167 deletions

View file

@ -0,0 +1,18 @@
using System;
namespace BattleBitAPI.Common
{
public class PlayerJoiningArguments
{
public PlayerStats Stats;
public Team Team;
public Squads Squad;
public void Write(BattleBitAPI.Common.Serialization.Stream ser)
{
this.Stats.Write(ser);
ser.Write((byte)this.Team);
ser.Write((byte)this.Squad);
}
}
}

View file

@ -0,0 +1,7 @@
namespace BattleBitAPI.Common
{
public enum LeaningSide
{
Left, None, Right
}
}

View file

@ -0,0 +1,12 @@
namespace BattleBitAPI.Common
{
public enum LoadoutIndex : byte
{
Primary = 0,
Secondary = 1,
FirstAid = 2,
LightGadget = 3,
HeavyGadget = 4,
Throwable = 5,
}
}

View file

@ -20,7 +20,7 @@
PlayerDisconnected = 51, PlayerDisconnected = 51,
OnPlayerTypedMessage = 52, OnPlayerTypedMessage = 52,
OnPlayerKilledAnotherPlayer = 53, OnPlayerKilledAnotherPlayer = 53,
GetPlayerStats = 54, OnPlayerJoining = 54,
SavePlayerStats = 55, SavePlayerStats = 55,
OnPlayerAskingToChangeRole = 56, OnPlayerAskingToChangeRole = 56,
OnPlayerChangedRole = 57, OnPlayerChangedRole = 57,
@ -34,5 +34,7 @@
NotifyNewMapRotation = 65, NotifyNewMapRotation = 65,
NotifyNewGamemodeRotation = 66, NotifyNewGamemodeRotation = 66,
NotifyNewRoundState = 67, NotifyNewRoundState = 67,
OnPlayerAskingToChangeTeam = 68,
GameTick = 69,
} }
} }

View file

@ -8,21 +8,40 @@ namespace BattleBitAPI
{ {
public class Player<TPlayer> where TPlayer : Player<TPlayer> public class Player<TPlayer> where TPlayer : Player<TPlayer>
{ {
public ulong SteamID { get; internal set; } private Internal mInternal;
public string Name { get; internal set; }
public IPAddress IP { 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; }
public bool IsAlive { get; internal set; }
public PlayerLoadout CurrentLoadout { get; internal set; } = new PlayerLoadout();
public PlayerWearings CurrentWearings { get; internal set; } = new PlayerWearings();
// ---- Variables ----
public ulong SteamID => mInternal.SteamID;
public string Name => mInternal.Name;
public IPAddress IP => mInternal.IP;
public GameServer<TPlayer> GameServer => mInternal.GameServer;
public GameRole Role => mInternal.Role;
public Team Team => mInternal.Team;
public Squads Squad => mInternal.Squad;
public bool InSquad => mInternal.Squad != Squads.NoSquad;
public int PingMs => mInternal.PingMs;
public float HP => mInternal.HP;
public bool IsAlive => mInternal.HP >= 0f;
public bool IsUp => mInternal.HP > 0f;
public bool IsDown => mInternal.HP == 0f;
public bool IsDead => mInternal.HP == -1f;
public Vector3 Position => mInternal.Position;
public PlayerStand Standing => mInternal.Standing;
public LeaningSide Leaning => mInternal.Leaning;
public LoadoutIndex CurrentLoadoutIndex => mInternal.CurrentLoadoutIndex;
public bool InVehicle => mInternal.InVehicle;
public bool IsBleeding => mInternal.IsBleeding;
public PlayerLoadout CurrentLoadout => mInternal.CurrentLoadout;
public PlayerWearings CurrentWearings => mInternal.CurrentWearings;
// ---- Events ----
public virtual void OnCreated() public virtual void OnCreated()
{ {
} }
public virtual async Task OnConnected() public virtual async Task OnConnected()
{ {
@ -34,12 +53,29 @@ namespace BattleBitAPI
public virtual async Task OnDied() public virtual async Task OnDied()
{ {
}
public virtual async Task OnChangedTeam()
{
}
public virtual async Task OnChangedRole(GameRole newRole)
{
}
public virtual async Task OnJoinedSquad(Squads newSquad)
{
}
public virtual async Task OnLeftSquad(Squads oldSquad)
{
} }
public virtual async Task OnDisconnected() public virtual async Task OnDisconnected()
{ {
} }
// ---- Functions ----
public void Kick(string reason = "") public void Kick(string reason = "")
{ {
this.GameServer.Kick(this, reason); this.GameServer.Kick(this, reason);
@ -52,6 +88,10 @@ namespace BattleBitAPI
{ {
this.GameServer.ChangeTeam(this); this.GameServer.ChangeTeam(this);
} }
public void ChangeTeam(Team team)
{
this.GameServer.ChangeTeam(this, team);
}
public void KickFromSquad() public void KickFromSquad()
{ {
this.GameServer.KickFromSquad(this); this.GameServer.KickFromSquad(this);
@ -72,6 +112,10 @@ namespace BattleBitAPI
{ {
this.GameServer.MessageToPlayer(this, msg); this.GameServer.MessageToPlayer(this, msg);
} }
public void Message(string msg, float fadeoutTime)
{
this.GameServer.MessageToPlayer(this, msg, fadeoutTime);
}
public void SetNewRole(GameRole role) public void SetNewRole(GameRole role)
{ {
this.GameServer.SetRoleTo(this, role); this.GameServer.SetRoleTo(this, role);
@ -116,7 +160,7 @@ namespace BattleBitAPI
{ {
GameServer.SetFallDamageMultiplier(this, value); GameServer.SetFallDamageMultiplier(this, value);
} }
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); GameServer.SetPrimaryWeapon(this, item, extraMagazines, clear);
} }
@ -140,9 +184,57 @@ namespace BattleBitAPI
{ {
GameServer.SetThrowable(this, item, extra, clear); GameServer.SetThrowable(this, item, extra, clear);
} }
// ---- Static ----
public static TPlayer CreateInstance<TPlayer>(Player<TPlayer>.Internal @internal) where TPlayer : Player<TPlayer>
{
TPlayer player = (TPlayer)Activator.CreateInstance(typeof(TPlayer));
player.mInternal = @internal;
return player;
}
// ---- Overrides ----
public override string ToString() public override string ToString()
{ {
return this.Name + " (" + this.SteamID + ")"; return this.Name + " (" + this.SteamID + ")";
} }
// ---- Internal ----
public class Internal
{
public ulong SteamID;
public string Name;
public IPAddress IP;
public GameServer<TPlayer> GameServer;
public GameRole Role;
public Team Team;
public Squads Squad;
public int PingMs = 999;
public bool IsAlive;
public float HP;
public Vector3 Position;
public PlayerStand Standing;
public LeaningSide Leaning;
public LoadoutIndex CurrentLoadoutIndex;
public bool InVehicle;
public bool IsBleeding;
public PlayerLoadout CurrentLoadout;
public PlayerWearings CurrentWearings;
public void OnDie()
{
this.IsAlive = false;
this.HP = -1f;
this.Position = default;
this.Standing = PlayerStand.Standing;
this.Leaning = LeaningSide.None;
this.CurrentLoadoutIndex = LoadoutIndex.Primary;
this.InVehicle = false;
this.IsBleeding = false;
this.CurrentLoadout = new PlayerLoadout();
this.CurrentWearings = new PlayerWearings();
}
}
} }
} }

View file

@ -25,9 +25,9 @@ namespace BattleBitAPI.Server
public string Map => mInternal.Map; public string Map => mInternal.Map;
public MapSize MapSize => mInternal.MapSize; public MapSize MapSize => mInternal.MapSize;
public MapDayNight DayNight => mInternal.DayNight; public MapDayNight DayNight => mInternal.DayNight;
public int CurrentPlayers => mInternal.CurrentPlayers; public int CurrentPlayerCount => mInternal.CurrentPlayerCount;
public int InQueuePlayers => mInternal.InQueuePlayers; public int InQueuePlayerCount => mInternal.InQueuePlayerCount;
public int MaxPlayers => mInternal.MaxPlayers; 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 ServerSettings<TPlayer> ServerSettings => mInternal.ServerSettings; public ServerSettings<TPlayer> ServerSettings => mInternal.ServerSettings;
@ -264,15 +264,18 @@ namespace BattleBitAPI.Server
{ {
return true; return true;
} }
public virtual async Task<PlayerStats> OnGetPlayerStats(ulong steamID, PlayerStats officialStats) public virtual async Task OnPlayerJoiningToServer(ulong steamID, PlayerJoiningArguments args)
{ {
return officialStats;
} }
public virtual async Task OnSavePlayerStats(ulong steamID, PlayerStats stats) public virtual async Task OnSavePlayerStats(ulong steamID, PlayerStats stats)
{ {
} }
public virtual async Task<bool> OnPlayerRequestingToChangeRole(TPlayer player, GameRole role) public virtual async Task<bool> OnPlayerRequestingToChangeRole(TPlayer player, GameRole requestedRole)
{
return true;
}
public virtual async Task<bool> OnPlayerRequestingToChangeTeam(TPlayer player, Team requestedTeam)
{ {
return true; return true;
} }
@ -417,6 +420,17 @@ namespace BattleBitAPI.Server
{ {
ChangeTeam(player.SteamID); ChangeTeam(player.SteamID);
} }
public void ChangeTeam(ulong steamID, Team team)
{
if (team == Team.TeamA)
ExecuteCommand("changeteam " + steamID + " a");
else if (team == Team.TeamB)
ExecuteCommand("changeteam " + steamID + " b");
}
public void ChangeTeam(Player<TPlayer> player, Team team)
{
ChangeTeam(player.SteamID, team);
}
public void KickFromSquad(ulong steamID) public void KickFromSquad(ulong steamID)
{ {
ExecuteCommand("squadkick " + steamID); ExecuteCommand("squadkick " + steamID);
@ -425,13 +439,13 @@ namespace BattleBitAPI.Server
{ {
KickFromSquad(player.SteamID); KickFromSquad(player.SteamID);
} }
public void DisbandPlayerSSquad(ulong steamID) public void DisbandPlayerSquad(ulong steamID)
{ {
ExecuteCommand("squaddisband " + steamID); ExecuteCommand("squaddisband " + steamID);
} }
public void DisbandPlayerCurrentSquad(Player<TPlayer> player) public void DisbandPlayerCurrentSquad(Player<TPlayer> player)
{ {
DisbandPlayerSSquad(player.SteamID); DisbandPlayerSquad(player.SteamID);
} }
public void PromoteSquadLeader(ulong steamID) public void PromoteSquadLeader(ulong steamID)
{ {
@ -457,6 +471,14 @@ namespace BattleBitAPI.Server
{ {
MessageToPlayer(player.SteamID, msg); MessageToPlayer(player.SteamID, msg);
} }
public void MessageToPlayer(ulong steamID, string msg, float fadeOutTime)
{
ExecuteCommand("msgf " + steamID + " " + fadeOutTime + " " + msg);
}
public void MessageToPlayer(Player<TPlayer> player, string msg, float fadeOutTime)
{
MessageToPlayer(player.SteamID, msg, fadeOutTime);
}
public void SetRoleTo(ulong steamID, GameRole role) public void SetRoleTo(ulong steamID, GameRole role)
{ {
ExecuteCommand("setrole " + steamID + " " + role); ExecuteCommand("setrole " + steamID + " " + role);
@ -664,7 +686,7 @@ namespace BattleBitAPI.Server
} }
public void SetThrowable(Player<TPlayer> player, string tool, int extra, bool clear = false) public void SetThrowable(Player<TPlayer> player, string tool, int extra, bool clear = false)
{ {
SetThrowable(player.SteamID, tool, extra,clear); SetThrowable(player.SteamID, tool, extra, clear);
} }
// ---- Closing ---- // ---- Closing ----
@ -727,9 +749,9 @@ namespace BattleBitAPI.Server
public string Map; public string Map;
public MapSize MapSize; public MapSize MapSize;
public MapDayNight DayNight; public MapDayNight DayNight;
public int CurrentPlayers; public int CurrentPlayerCount;
public int InQueuePlayers; public int InQueuePlayerCount;
public int MaxPlayers; public int MaxPlayerCount;
public string LoadingScreenText; public string LoadingScreenText;
public string ServerRulesText; public string ServerRulesText;
public ServerSettings<TPlayer> ServerSettings; public ServerSettings<TPlayer> ServerSettings;
@ -814,9 +836,9 @@ namespace BattleBitAPI.Server
this.Map = map; this.Map = map;
this.MapSize = mapSize; this.MapSize = mapSize;
this.DayNight = dayNight; this.DayNight = dayNight;
this.CurrentPlayers = currentPlayers; this.CurrentPlayerCount = currentPlayers;
this.InQueuePlayers = inQueuePlayers; this.InQueuePlayerCount = inQueuePlayers;
this.MaxPlayers = maxPlayers; this.MaxPlayerCount = maxPlayers;
this.LoadingScreenText = loadingScreenText; this.LoadingScreenText = loadingScreenText;
this.ServerRulesText = serverRulesText; this.ServerRulesText = serverRulesText;

View file

@ -1,4 +1,6 @@
namespace BattleBitAPI.Server using BattleBitAPI.Common;
namespace BattleBitAPI.Server
{ {
public class GamemodeRotation<TPlayer> where TPlayer : Player<TPlayer> public class GamemodeRotation<TPlayer> where TPlayer : Player<TPlayer>
{ {
@ -34,6 +36,27 @@
mResources.IsDirtyGamemodeRotation = true; mResources.IsDirtyGamemodeRotation = true;
return true; return true;
} }
public void SetRotation(params string[] gamemodes)
{
lock (mResources._GamemodeRotation)
{
mResources._GamemodeRotation.Clear();
foreach (var item in gamemodes)
mResources._GamemodeRotation.Add(item);
}
mResources.IsDirtyGamemodeRotation = true;
}
public void ClearRotation()
{
lock (mResources._GamemodeRotation)
{
if (mResources._GamemodeRotation.Count == 0)
return;
mResources._GamemodeRotation.Clear();
}
mResources.IsDirtyGamemodeRotation = true;
}
public void Reset() public void Reset()
{ {

View file

@ -40,6 +40,27 @@
mResources.IsDirtyMapRotation = true; mResources.IsDirtyMapRotation = true;
return true; return true;
} }
public void SetRotation(params string[] maps)
{
lock (mResources._MapRotation)
{
mResources._MapRotation.Clear();
foreach (var item in maps)
mResources._MapRotation.Add(item);
}
mResources.IsDirtyMapRotation = true;
}
public void ClearRotation()
{
lock (mResources._MapRotation)
{
if (mResources._MapRotation.Count == 0)
return;
mResources._MapRotation.Clear();
}
mResources.IsDirtyMapRotation = true;
}
public void Reset() public void Reset()
{ {

View file

@ -1,7 +1,9 @@
using System.Net; using System.Diagnostics;
using System.Net;
using System.Net.Security; using System.Net.Security;
using System.Net.Sockets; using System.Net.Sockets;
using System.Numerics; using System.Numerics;
using System.Xml;
using BattleBitAPI.Common; using BattleBitAPI.Common;
using BattleBitAPI.Common.Extentions; using BattleBitAPI.Common.Extentions;
using BattleBitAPI.Common.Serialization; using BattleBitAPI.Common.Serialization;
@ -59,6 +61,24 @@ namespace BattleBitAPI.Server
/// </remarks> /// </remarks>
public Func<GameServer<TPlayer>, Task> OnGameServerDisconnected { get; set; } public Func<GameServer<TPlayer>, Task> OnGameServerDisconnected { get; set; }
/// <summary>
/// Fired when a new instance of game server created.
/// </summary>
///
/// <remarks>
/// GameServer: Game server that has been just created.<br/>
/// </remarks>
public Func<GameServer<TPlayer>, Task> OnCreatingGameServerInstance { get; set; }
/// <summary>
/// Fired when a new instance of player instance created.
/// </summary>
///
/// <remarks>
/// TPlayer: The player instance that was created<br/>
/// </remarks>
public Func<TPlayer, Task> OnCreatingPlayerInstance { get; set; }
// --- Private --- // --- Private ---
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;
@ -91,7 +111,7 @@ namespace BattleBitAPI.Server
} }
public void Start(int port) public void Start(int port)
{ {
Start(IPAddress.Loopback, port); Start(IPAddress.Any, port);
} }
// --- Stopping --- // --- Stopping ---
@ -325,7 +345,7 @@ namespace BattleBitAPI.Server
} }
var hash = ((ulong)gamePort << 32) | (ulong)ip.ToUInt(); var hash = ((ulong)gamePort << 32) | (ulong)ip.ToUInt();
server = this.mInstanceDatabase.GetServerInstance(hash, out resources); server = this.mInstanceDatabase.GetServerInstance(hash, out bool isNew, out resources);
resources.Set( resources.Set(
this.mExecutePackage, this.mExecutePackage,
client, client,
@ -498,23 +518,37 @@ namespace BattleBitAPI.Server
wearings.Read(readStream); wearings.Read(readStream);
} }
TPlayer player = mInstanceDatabase.GetPlayerInstance(steamid); TPlayer player = mInstanceDatabase.GetPlayerInstance(steamid, out bool isNewClient, out var playerInternal);
player.SteamID = steamid; playerInternal.SteamID = steamid;
player.Name = username; playerInternal.Name = username;
player.IP = new IPAddress(ipHash); playerInternal.IP = new IPAddress(ipHash);
player.GameServer = (GameServer<TPlayer>)server; playerInternal.GameServer = (GameServer<TPlayer>)server;
player.Team = team; playerInternal.Team = team;
player.Squad = squad; playerInternal.Squad = squad;
player.Role = role; playerInternal.Role = role;
player.IsAlive = isAlive; playerInternal.IsAlive = isAlive;
player.CurrentLoadout = loadout; playerInternal.CurrentLoadout = loadout;
player.CurrentWearings = wearings; playerInternal.CurrentWearings = wearings;
if (isNewClient)
{
if (this.OnCreatingPlayerInstance != null)
this.OnCreatingPlayerInstance(player);
}
resources.AddPlayer(player); resources.AddPlayer(player);
} }
//Send accepted notification. //Send accepted notification.
networkStream.WriteByte((byte)NetworkCommuncation.Accepted); networkStream.WriteByte((byte)NetworkCommuncation.Accepted);
if (isNew)
{
if (this.OnCreatingGameServerInstance != null)
this.OnCreatingGameServerInstance(server);
}
} }
} }
} }
@ -575,9 +609,9 @@ namespace BattleBitAPI.Server
client.SendBufferSize = Const.MaxNetworkPackageSize; client.SendBufferSize = Const.MaxNetworkPackageSize;
//Join to main server loop. //Join to main server loop.
await mHandleGameServer(server); await mHandleGameServer(server, resources);
} }
private async Task mHandleGameServer(TGameServer server) private async Task mHandleGameServer(TGameServer server, GameServer<TPlayer>.Internal @internal)
{ {
bool isTicking = false; bool isTicking = false;
@ -632,19 +666,25 @@ namespace BattleBitAPI.Server
Squads squad = (Squads)stream.ReadInt8(); Squads squad = (Squads)stream.ReadInt8();
GameRole role = (GameRole)stream.ReadInt8(); GameRole role = (GameRole)stream.ReadInt8();
TPlayer player = mInstanceDatabase.GetPlayerInstance(steamID); TPlayer player = mInstanceDatabase.GetPlayerInstance(steamID, out bool isNewClient, out var playerInternal);
player.SteamID = steamID; playerInternal.SteamID = steamID;
player.Name = username; playerInternal.Name = username;
player.IP = new IPAddress(ip); playerInternal.IP = new IPAddress(ip);
player.GameServer = (GameServer<TPlayer>)server; playerInternal.GameServer = (GameServer<TPlayer>)server;
player.Team = team; playerInternal.Team = team;
player.Squad = squad; playerInternal.Squad = squad;
player.Role = role; playerInternal.Role = role;
if (isNewClient)
{
if (this.OnCreatingPlayerInstance != null)
this.OnCreatingPlayerInstance(player);
}
resources.AddPlayer(player); resources.AddPlayer(player);
server.OnPlayerConnected(player);
player.OnConnected(); player.OnConnected();
server.OnPlayerConnected(player);
} }
} }
break; break;
@ -661,8 +701,8 @@ namespace BattleBitAPI.Server
if (exist) if (exist)
{ {
server.OnPlayerDisconnected((TPlayer)player);
player.OnDisconnected(); player.OnDisconnected();
server.OnPlayerDisconnected((TPlayer)player);
} }
} }
break; break;
@ -738,7 +778,7 @@ namespace BattleBitAPI.Server
break; break;
} }
case NetworkCommuncation.GetPlayerStats: case NetworkCommuncation.OnPlayerJoining:
{ {
if (stream.CanRead(8 + 2)) if (stream.CanRead(8 + 2))
{ {
@ -746,14 +786,22 @@ namespace BattleBitAPI.Server
var stats = new PlayerStats(); var stats = new PlayerStats();
stats.Read(stream); stats.Read(stream);
async Task mHandle() async Task mHandle()
{ {
stats = await server.OnGetPlayerStats(steamID, stats); var args = new PlayerJoiningArguments()
{
Stats = stats,
Squad = Squads.NoSquad,
Team = Team.None
};
await server.OnPlayerJoiningToServer(steamID, args);
using (var response = Common.Serialization.Stream.Get()) using (var response = Common.Serialization.Stream.Get())
{ {
response.Write((byte)NetworkCommuncation.SendPlayerStats); response.Write((byte)NetworkCommuncation.SendPlayerStats);
response.Write(steamID); response.Write(steamID);
stats.Write(response); args.Write(response);
server.WriteToSocket(response); server.WriteToSocket(response);
} }
} }
@ -804,7 +852,10 @@ namespace BattleBitAPI.Server
if (resources.TryGetPlayer(steamID, out var client)) if (resources.TryGetPlayer(steamID, out var client))
{ {
client.Role = role; var @internal = mInstanceDatabase.GetPlayerInternals(steamID);
@internal.Role = role;
client.OnChangedRole(role);
server.OnPlayerChangedRole((TPlayer)client, role); server.OnPlayerChangedRole((TPlayer)client, role);
} }
} }
@ -819,7 +870,10 @@ namespace BattleBitAPI.Server
if (resources.TryGetPlayer(steamID, out var client)) if (resources.TryGetPlayer(steamID, out var client))
{ {
client.Squad = squad; var @internal = mInstanceDatabase.GetPlayerInternals(steamID);
@internal.Squad = squad;
client.OnJoinedSquad(squad);
server.OnPlayerJoinedSquad((TPlayer)client, squad); server.OnPlayerJoinedSquad((TPlayer)client, squad);
} }
} }
@ -833,14 +887,21 @@ namespace BattleBitAPI.Server
if (resources.TryGetPlayer(steamID, out var client)) if (resources.TryGetPlayer(steamID, out var client))
{ {
var @internal = mInstanceDatabase.GetPlayerInternals(steamID);
var oldSquad = client.Squad; var oldSquad = client.Squad;
var oldRole = client.Role; var oldRole = client.Role;
client.Squad = Squads.NoSquad; @internal.Squad = Squads.NoSquad;
client.Role = GameRole.Assault; @internal.Role = GameRole.Assault;
client.OnLeftSquad(oldSquad);
server.OnPlayerLeftSquad((TPlayer)client, oldSquad); server.OnPlayerLeftSquad((TPlayer)client, oldSquad);
if (oldRole != GameRole.Assault) if (oldRole != GameRole.Assault)
{
client.OnChangedRole(GameRole.Assault);
server.OnPlayerChangedRole((TPlayer)client, GameRole.Assault); server.OnPlayerChangedRole((TPlayer)client, GameRole.Assault);
}
} }
} }
break; break;
@ -854,7 +915,11 @@ namespace BattleBitAPI.Server
if (resources.TryGetPlayer(steamID, out var client)) if (resources.TryGetPlayer(steamID, out var client))
{ {
client.Team = team; var @internal = mInstanceDatabase.GetPlayerInternals(steamID);
@internal.Team = team;
client.OnChangedTeam();
server.OnPlayerChangeTeam((TPlayer)client, team); server.OnPlayerChangeTeam((TPlayer)client, team);
} }
} }
@ -915,18 +980,20 @@ namespace BattleBitAPI.Server
{ {
if (stream.CanRead(8 + 2)) if (stream.CanRead(8 + 2))
{ {
ulong reporter = stream.ReadUInt64(); ulong steamID = stream.ReadUInt64();
if (resources.TryGetPlayer(reporter, out var client)) if (resources.TryGetPlayer(steamID, out var client))
{ {
var @internal = mInstanceDatabase.GetPlayerInternals(steamID);
var loadout = new PlayerLoadout(); var loadout = new PlayerLoadout();
loadout.Read(stream); loadout.Read(stream);
client.CurrentLoadout = loadout; @internal.CurrentLoadout = loadout;
var wearings = new PlayerWearings(); var wearings = new PlayerWearings();
wearings.Read(stream); wearings.Read(stream);
client.CurrentWearings = wearings; @internal.CurrentWearings = wearings;
client.IsAlive = true; @internal.IsAlive = true;
client.OnSpawned(); client.OnSpawned();
server.OnPlayerSpawned((TPlayer)client); server.OnPlayerSpawned((TPlayer)client);
@ -938,12 +1005,11 @@ namespace BattleBitAPI.Server
{ {
if (stream.CanRead(8)) if (stream.CanRead(8))
{ {
ulong reporter = stream.ReadUInt64(); ulong steamid = stream.ReadUInt64();
if (resources.TryGetPlayer(reporter, out var client)) if (resources.TryGetPlayer(steamid, out var client))
{ {
client.CurrentLoadout = new PlayerLoadout(); var @internal = mInstanceDatabase.GetPlayerInternals(steamid);
client.CurrentWearings = new PlayerWearings(); @internal.OnDie();
client.IsAlive = false;
client.OnDied(); client.OnDied();
server.OnPlayerDied((TPlayer)client); server.OnPlayerDied((TPlayer)client);
@ -1007,6 +1073,74 @@ namespace BattleBitAPI.Server
} }
break; break;
} }
case NetworkCommuncation.OnPlayerAskingToChangeTeam:
{
if (stream.CanRead(8 + 1))
{
ulong steamID = stream.ReadUInt64();
Team team = (Team)stream.ReadInt8();
if (resources.TryGetPlayer(steamID, out var client))
{
async Task mHandle()
{
bool accepted = await server.OnPlayerRequestingToChangeTeam((TPlayer)client, team);
if (accepted)
server.ChangeTeam(steamID, team);
}
mHandle();
}
}
break;
}
case NetworkCommuncation.GameTick:
{
if (stream.CanRead(4 + 4 + 4))
{
float decompressX = stream.ReadFloat();
float decompressY = stream.ReadFloat();
float decompressZ = stream.ReadFloat();
int playerCount = stream.ReadInt8();
while (playerCount > 0)
{
playerCount--;
ulong steamID = stream.ReadUInt64();
//TODO, can compressed further later.
ushort com_posX = stream.ReadUInt16();
ushort com_posY = stream.ReadUInt16();
ushort com_posZ = stream.ReadUInt16();
byte com_healt = stream.ReadInt8();
PlayerStand standing = (PlayerStand)stream.ReadInt8();
LeaningSide side = (LeaningSide)stream.ReadInt8();
LoadoutIndex loadoutIndex = (LoadoutIndex)stream.ReadInt8();
bool inSeat = stream.ReadBool();
bool isBleeding = stream.ReadBool();
ushort ping = stream.ReadUInt16();
var @internal = mInstanceDatabase.GetPlayerInternals(steamID);
if (@internal.IsAlive)
{
@internal.Position = new Vector3()
{
X = com_posX * decompressX,
Y = com_posY * decompressY,
Z = com_posZ * decompressZ,
};
@internal.HP = (com_healt * 0.5f) - 1f;
@internal.Standing = standing;
@internal.Leaning = side;
@internal.CurrentLoadoutIndex = loadoutIndex;
@internal.InVehicle = inSeat;
@internal.IsBleeding = isBleeding;
@internal.PingMs = ping;
}
}
}
break;
}
} }
} }
@ -1056,44 +1190,57 @@ namespace BattleBitAPI.Server
private class mInstances<TPlayer, TGameServer> where TPlayer : Player<TPlayer> where TGameServer : GameServer<TPlayer> private class mInstances<TPlayer, TGameServer> where TPlayer : Player<TPlayer> where TGameServer : GameServer<TPlayer>
{ {
private Dictionary<ulong, (TGameServer, GameServer<TPlayer>.Internal)> mGameServerInstances; private Dictionary<ulong, (TGameServer, GameServer<TPlayer>.Internal)> mGameServerInstances;
private Dictionary<ulong, TPlayer> mPlayerInstances; private Dictionary<ulong, (TPlayer, Player<TPlayer>.Internal)> mPlayerInstances;
public mInstances() public mInstances()
{ {
this.mGameServerInstances = new Dictionary<ulong, (TGameServer, GameServer<TPlayer>.Internal)>(64); this.mGameServerInstances = new Dictionary<ulong, (TGameServer, GameServer<TPlayer>.Internal)>(64);
this.mPlayerInstances = new Dictionary<ulong, TPlayer>(1024 * 16); this.mPlayerInstances = new Dictionary<ulong, (TPlayer, Player<TPlayer>.Internal)>(1024 * 16);
} }
public TGameServer GetServerInstance(ulong hash, out GameServer<TPlayer>.Internal @internal) public TGameServer GetServerInstance(ulong hash, out bool isNew, out GameServer<TPlayer>.Internal @internal)
{ {
lock (mGameServerInstances) lock (mGameServerInstances)
{ {
if (mGameServerInstances.TryGetValue(hash, out var data)) if (mGameServerInstances.TryGetValue(hash, out var data))
{ {
@internal = data.Item2; @internal = data.Item2;
isNew = false;
return data.Item1; return data.Item1;
} }
@internal = new GameServer<TPlayer>.Internal(); @internal = new GameServer<TPlayer>.Internal();
TGameServer gameServer = GameServer<TPlayer>.CreateInstance<TGameServer>(@internal); TGameServer gameServer = GameServer<TPlayer>.CreateInstance<TGameServer>(@internal);
isNew = true;
mGameServerInstances.Add(hash, (gameServer, @internal)); mGameServerInstances.Add(hash, (gameServer, @internal));
return gameServer; return gameServer;
} }
} }
public TPlayer GetPlayerInstance(ulong steamID) public TPlayer GetPlayerInstance(ulong steamID, out bool isNew, out Player<TPlayer>.Internal @internal)
{ {
lock (this.mPlayerInstances) lock (this.mPlayerInstances)
{ {
if (this.mPlayerInstances.TryGetValue(steamID, out var player)) if (this.mPlayerInstances.TryGetValue(steamID, out var player))
return player; {
isNew = false;
@internal = player.Item2;
return player.Item1;
}
player = Activator.CreateInstance<TPlayer>(); @internal = new Player<TPlayer>.Internal();
player.OnCreated(); var pplayer = Player<TPlayer>.CreateInstance(@internal);
mPlayerInstances.Add(steamID, player);
return player; isNew = true;
mPlayerInstances.Add(steamID, (pplayer, @internal));
return pplayer;
} }
} }
public Player<TPlayer>.Internal GetPlayerInternals(ulong steamID)
{
lock (mPlayerInstances)
return mPlayerInstances[steamID].Item2;
}
} }
} }
} }

View file

@ -13,101 +13,23 @@ class Program
Thread.Sleep(-1); Thread.Sleep(-1);
} }
} }
class MyPlayer : Player<MyPlayer> class MyPlayer : Player<MyPlayer>
{ {
public bool IsZombie;
} }
class MyGameServer : GameServer<MyPlayer> class MyGameServer : GameServer<MyPlayer>
{ {
public override async Task OnRoundStarted()
{
}
public override async Task OnRoundEnded()
{
}
public override async Task OnPlayerConnected(MyPlayer player)
{
bool anyZombiePlayer = false;
foreach (var item in AllPlayers)
{
if (item.IsZombie)
{
anyZombiePlayer = true;
break;
}
}
if (!anyZombiePlayer)
{
player.IsZombie = true;
player.Message("You are the zombie.");
player.Kill();
}
}
public override async Task OnAPlayerKilledAnotherPlayer(OnPlayerKillArguments<MyPlayer> args)
{
if (args.Victim.IsZombie)
{
args.Victim.IsZombie = false;
args.Victim.Message("You are no longer zombie");
AnnounceShort("Choosing new zombie in 5");
await Task.Delay(1000);
AnnounceShort("Choosing new zombie in 4");
await Task.Delay(1000);
AnnounceShort("Choosing new zombie in 3");
await Task.Delay(1000);
AnnounceShort("Choosing new zombie in 2");
await Task.Delay(1000);
AnnounceShort("Choosing new zombie in 1");
await Task.Delay(1000);
args.Killer.IsZombie = true;
args.Killer.SetHeavyGadget(Gadgets.SledgeHammer.ToString(), 0, true);
var position = args.Killer.GetPosition();
}
}
public override async Task<OnPlayerSpawnArguments> OnPlayerSpawning(MyPlayer player, OnPlayerSpawnArguments request)
{
if (player.IsZombie)
{
request.Loadout.PrimaryWeapon = default;
request.Loadout.SecondaryWeapon = default;
request.Loadout.LightGadget = null;
request.Loadout.HeavyGadget = Gadgets.SledgeHammer;
request.Loadout.Throwable = null;
}
return request;
}
public override async Task OnPlayerSpawned(MyPlayer player)
{
if(player.IsZombie)
{
player.SetRunningSpeedMultiplier(2f);
player.SetJumpMultiplier(2f);
player.SetFallDamageMultiplier(0f);
player.SetReceiveDamageMultiplier(0.1f);
player.SetGiveDamageMultiplier(4f);
}
}
public override async Task OnConnected() public override async Task OnConnected()
{ {
await Console.Out.WriteLineAsync("Current state: " + RoundSettings.State); ForceStartGame();
} }
public override async Task OnGameStateChanged(GameState oldState, GameState newState) public override async Task OnTick()
{ {
await Console.Out.WriteLineAsync("State changed to -> " + newState); foreach (var player in AllPlayers)
{
await Console.Out.WriteLineAsync(player + " : " + player.HP + " : " + player.Position);
}
} }
} }