diff --git a/BattleBitAPI/Common/Arguments/OnPlayerSpawnArguments.cs b/BattleBitAPI/Common/Arguments/OnPlayerSpawnArguments.cs index bb2f6a8..1c49d1d 100644 --- a/BattleBitAPI/Common/Arguments/OnPlayerSpawnArguments.cs +++ b/BattleBitAPI/Common/Arguments/OnPlayerSpawnArguments.cs @@ -4,7 +4,7 @@ namespace BattleBitAPI.Common { public struct OnPlayerSpawnArguments { - public PlayerSpawningPosition RequestedPoint; + public PlayerSpawningPosition RequestedPoint { get; private set; } public PlayerLoadout Loadout; public PlayerWearings Wearings; public Vector3 SpawnPosition; diff --git a/BattleBitAPI/Common/Enums/SpawningRule.cs b/BattleBitAPI/Common/Enums/SpawningRule.cs new file mode 100644 index 0000000..a053200 --- /dev/null +++ b/BattleBitAPI/Common/Enums/SpawningRule.cs @@ -0,0 +1,22 @@ +namespace BattleBitAPI.Common +{ + [System.Flags] + public enum SpawningRule : ulong + { + None = 0, + + Flags = 1 << 0, + SquadMates = 1 << 1, + SquadCaptain = 1 << 2, + + Tanks = 1 << 3, + Transports = 1 << 4, + Boats = 1 << 5, + Helicopters = 1 << 6, + APCs = 1 << 7, + + RallyPoints = 1 << 8, + + All = ulong.MaxValue, + } +} diff --git a/BattleBitAPI/Common/Enums/VehicleType.cs b/BattleBitAPI/Common/Enums/VehicleType.cs new file mode 100644 index 0000000..dcf2eee --- /dev/null +++ b/BattleBitAPI/Common/Enums/VehicleType.cs @@ -0,0 +1,13 @@ +[System.Flags] +public enum VehicleType : byte +{ + None = 0, + + Tank = 1 << 1, + Transport = 1 << 2, + SeaVehicle = 1 << 3, + APC = 1 << 4, + Helicopters = 1 << 5, + + All = 255, +} \ No newline at end of file diff --git a/BattleBitAPI/Networking/NetworkCommuncation.cs b/BattleBitAPI/Networking/NetworkCommuncation.cs index f9c1be8..b687440 100644 --- a/BattleBitAPI/Networking/NetworkCommuncation.cs +++ b/BattleBitAPI/Networking/NetworkCommuncation.cs @@ -42,5 +42,6 @@ OnSquadPointsChanged = 72, NotifyNewRoundID = 73, Log = 74, + OnSquadLeaderChanged = 75, } } diff --git a/BattleBitAPI/Server/GameServer.cs b/BattleBitAPI/Server/GameServer.cs index ff45b59..3624e9a 100644 --- a/BattleBitAPI/Server/GameServer.cs +++ b/BattleBitAPI/Server/GameServer.cs @@ -1,6 +1,7 @@ using System.Net; using System.Net.Sockets; using System.Numerics; +using System.Runtime.CompilerServices; using System.Text; using BattleBitAPI.Common; using BattleBitAPI.Common.Extentions; @@ -26,8 +27,6 @@ namespace BattleBitAPI.Server public int CurrentPlayerCount => mInternal.CurrentPlayerCount; public int InQueuePlayerCount => mInternal.InQueuePlayerCount; public int MaxPlayerCount => mInternal.MaxPlayerCount; - public string LoadingScreenText => mInternal.LoadingScreenText; - public string ServerRulesText => mInternal.ServerRulesText; public uint RoundIndex => mInternal.RoundIndex; public long SessionID => mInternal.SessionID; public ServerSettings ServerSettings => mInternal.ServerSettings; @@ -36,6 +35,24 @@ namespace BattleBitAPI.Server public RoundSettings RoundSettings => mInternal.RoundSettings; public string TerminationReason => mInternal.TerminationReason; public bool ReconnectFlag => mInternal.ReconnectFlag; + public string LoadingScreenText + { + get => mInternal.LoadingScreenText; + set + { + mInternal.LoadingScreenText = value; + SetLoadingScreenText(value); + } + } + public string ServerRulesText + { + get => mInternal.ServerRulesText; + set + { + mInternal.ServerRulesText = value; + SetRulesScreenText(value); + } + } public IEnumerable> TeamASquads { get @@ -445,6 +462,10 @@ namespace BattleBitAPI.Server public virtual async Task OnPlayerJoinedSquad(TPlayer player, Squad squad) { + } + public virtual async Task OnSquadLeaderChanged(Squad squad, TPlayer newLeader) + { + } public virtual async Task OnPlayerLeftSquad(TPlayer player, Squad squad) { @@ -567,6 +588,14 @@ namespace BattleBitAPI.Server SayToChat(msg, player.SteamID); } + public void SetLoadingScreenText(string newText) + { + ExecuteCommand("setloadingscreentext " + newText); + } + public void SetRulesScreenText(string newText) + { + ExecuteCommand("setrulesscreentext " + newText); + } public void StopServer() { ExecuteCommand("stop"); @@ -684,7 +713,6 @@ namespace BattleBitAPI.Server { Loadout = loadout, Wearings = wearings, - RequestedPoint = PlayerSpawningPosition.Null, SpawnPosition = position, LookDirection = lookDirection, SpawnStand = stand, diff --git a/BattleBitAPI/Server/Internal/PlayerModifications.cs b/BattleBitAPI/Server/Internal/PlayerModifications.cs index ff48e86..91c5da6 100644 --- a/BattleBitAPI/Server/Internal/PlayerModifications.cs +++ b/BattleBitAPI/Server/Internal/PlayerModifications.cs @@ -1,4 +1,6 @@ -namespace BattleBitAPI.Server +using BattleBitAPI.Common; + +namespace BattleBitAPI.Server { public class PlayerModifications where TPlayer : Player { @@ -279,6 +281,39 @@ @internal._Modifications.IsDirtyFlag = true; } } + public bool IsExposedOnMap + { + get => @internal._Modifications.IsExposedOnMap; + set + { + if (@internal._Modifications.IsExposedOnMap == value) + return; + @internal._Modifications.IsExposedOnMap = value; + @internal._Modifications.IsDirtyFlag = true; + } + } + public SpawningRule SpawningRule + { + get => @internal._Modifications.SpawningRule; + set + { + if (@internal._Modifications.SpawningRule == value) + return; + @internal._Modifications.SpawningRule = value; + @internal._Modifications.IsDirtyFlag = true; + } + } + public VehicleType AllowedVehicles + { + get => @internal._Modifications.AllowedVehicles; + set + { + if (@internal._Modifications.AllowedVehicles == value) + return; + @internal._Modifications.AllowedVehicles = value; + @internal._Modifications.IsDirtyFlag = true; + } + } public void DisableBleeding() { @@ -318,6 +353,9 @@ public float CaptureFlagSpeedMultiplier = 1f; public bool PointLogHudEnabled = true; public bool KillFeed = false; + public bool IsExposedOnMap = false; + public SpawningRule SpawningRule; + public VehicleType AllowedVehicles; public bool IsDirtyFlag = false; public void Write(BattleBitAPI.Common.Serialization.Stream ser) @@ -347,6 +385,9 @@ ser.Write(this.CaptureFlagSpeedMultiplier); ser.Write(this.PointLogHudEnabled); ser.Write(this.KillFeed); + ser.Write(this.IsExposedOnMap); + ser.Write((ulong)this.SpawningRule); + ser.Write((byte)this.AllowedVehicles); } public void Read(BattleBitAPI.Common.Serialization.Stream ser) { @@ -378,6 +419,9 @@ this.CaptureFlagSpeedMultiplier = ser.ReadFloat(); this.PointLogHudEnabled = ser.ReadBool(); this.KillFeed = ser.ReadBool(); + this.IsExposedOnMap = ser.ReadBool(); + this.SpawningRule = (SpawningRule)ser.ReadUInt64(); + this.AllowedVehicles = (VehicleType)ser.ReadInt8(); } public void Reset() { @@ -405,6 +449,8 @@ this.CaptureFlagSpeedMultiplier = 1f; this.PointLogHudEnabled = true; this.KillFeed = false; + this.SpawningRule = SpawningRule.All; + this.AllowedVehicles = VehicleType.All; } } } diff --git a/BattleBitAPI/Server/Internal/ServerSettings.cs b/BattleBitAPI/Server/Internal/ServerSettings.cs index 64eee73..ed889f2 100644 --- a/BattleBitAPI/Server/Internal/ServerSettings.cs +++ b/BattleBitAPI/Server/Internal/ServerSettings.cs @@ -1,4 +1,6 @@ -namespace BattleBitAPI.Server +using System.Runtime.ConstrainedExecution; + +namespace BattleBitAPI.Server { public class ServerSettings where TPlayer : Player { @@ -54,6 +56,129 @@ mResources.IsDirtyRoomSettings = true; } } + public bool CanVoteDay + { + get => mResources._RoomSettings.CanVoteDay; + set + { + if (mResources._RoomSettings.CanVoteDay == value) + return; + mResources._RoomSettings.CanVoteDay = value; + mResources.IsDirtyRoomSettings = true; + } + } + public bool CanVoteNight + { + get => mResources._RoomSettings.CanVoteNight; + set + { + if (mResources._RoomSettings.CanVoteNight == value) + return; + mResources._RoomSettings.CanVoteNight = value; + mResources.IsDirtyRoomSettings = true; + } + } + + public byte MedicLimitPerSquad + { + get => mResources._RoomSettings.MedicLimitPerSquad; + set + { + if (mResources._RoomSettings.MedicLimitPerSquad == value) + return; + mResources._RoomSettings.MedicLimitPerSquad = value; + mResources.IsDirtyRoomSettings = true; + } + } + public byte EngineerLimitPerSquad + { + get => mResources._RoomSettings.EngineerLimitPerSquad; + set + { + if (mResources._RoomSettings.EngineerLimitPerSquad == value) + return; + mResources._RoomSettings.EngineerLimitPerSquad = value; + mResources.IsDirtyRoomSettings = true; + } + } + public byte SupportLimitPerSquad + { + get => mResources._RoomSettings.SupportLimitPerSquad; + set + { + if (mResources._RoomSettings.SupportLimitPerSquad == value) + return; + mResources._RoomSettings.SupportLimitPerSquad = value; + mResources.IsDirtyRoomSettings = true; + } + } + public byte ReconLimitPerSquad + { + get => mResources._RoomSettings.ReconLimitPerSquad; + set + { + if (mResources._RoomSettings.ReconLimitPerSquad == value) + return; + mResources._RoomSettings.ReconLimitPerSquad = value; + mResources.IsDirtyRoomSettings = true; + } + } + + public float TankSpawnDelayMultipler + { + get => mResources._RoomSettings.TankSpawnDelayMultipler; + set + { + if (mResources._RoomSettings.TankSpawnDelayMultipler == value) + return; + mResources._RoomSettings.TankSpawnDelayMultipler = value; + mResources.IsDirtyRoomSettings = true; + } + } + public float TransportSpawnDelayMultipler + { + get => mResources._RoomSettings.TransportSpawnDelayMultipler; + set + { + if (mResources._RoomSettings.TransportSpawnDelayMultipler == value) + return; + mResources._RoomSettings.TransportSpawnDelayMultipler = value; + mResources.IsDirtyRoomSettings = true; + } + } + public float SeaVehicleSpawnDelayMultipler + { + get => mResources._RoomSettings.SeaVehicleSpawnDelayMultipler; + set + { + if (mResources._RoomSettings.SeaVehicleSpawnDelayMultipler == value) + return; + mResources._RoomSettings.SeaVehicleSpawnDelayMultipler = value; + mResources.IsDirtyRoomSettings = true; + } + } + public float APCSpawnDelayMultipler + { + get => mResources._RoomSettings.APCSpawnDelayMultipler; + set + { + if (mResources._RoomSettings.APCSpawnDelayMultipler == value) + return; + mResources._RoomSettings.APCSpawnDelayMultipler = value; + mResources.IsDirtyRoomSettings = true; + } + } + public float HelicopterSpawnDelayMultipler + { + get => mResources._RoomSettings.HelicopterSpawnDelayMultipler; + set + { + if (mResources._RoomSettings.HelicopterSpawnDelayMultipler == value) + return; + mResources._RoomSettings.HelicopterSpawnDelayMultipler = value; + mResources.IsDirtyRoomSettings = true; + } + } // ---- Reset ---- public void Reset() @@ -69,11 +194,21 @@ public bool HideMapVotes = true; public bool OnlyWinnerTeamCanVote = false; public bool PlayerCollision = false; + public byte MedicLimitPerSquad = 8; public byte EngineerLimitPerSquad = 8; public byte SupportLimitPerSquad = 8; public byte ReconLimitPerSquad = 8; + public bool CanVoteDay = true; + public bool CanVoteNight = true; + + public float TankSpawnDelayMultipler = 1.0f; + public float TransportSpawnDelayMultipler = 1.0f; + public float SeaVehicleSpawnDelayMultipler = 1.0f; + public float APCSpawnDelayMultipler = 1.0f; + public float HelicopterSpawnDelayMultipler = 1.0f; + public void Write(Common.Serialization.Stream ser) { ser.Write(this.DamageMultiplier); @@ -86,6 +221,15 @@ ser.Write(this.EngineerLimitPerSquad); ser.Write(this.SupportLimitPerSquad); ser.Write(this.ReconLimitPerSquad); + + ser.Write(this.CanVoteDay); + ser.Write(this.CanVoteNight); + + ser.Write(this.TankSpawnDelayMultipler); + ser.Write(this.TransportSpawnDelayMultipler); + ser.Write(this.SeaVehicleSpawnDelayMultipler); + ser.Write(this.APCSpawnDelayMultipler); + ser.Write(this.HelicopterSpawnDelayMultipler); } public void Read(Common.Serialization.Stream ser) { @@ -99,6 +243,15 @@ this.EngineerLimitPerSquad = ser.ReadInt8(); this.SupportLimitPerSquad = ser.ReadInt8(); this.ReconLimitPerSquad = ser.ReadInt8(); + + this.CanVoteDay = ser.ReadBool(); + this.CanVoteNight = ser.ReadBool(); + + this.TankSpawnDelayMultipler = ser.ReadFloat(); + this.TransportSpawnDelayMultipler = ser.ReadFloat(); + this.SeaVehicleSpawnDelayMultipler = ser.ReadFloat(); + this.APCSpawnDelayMultipler = ser.ReadFloat(); + this.HelicopterSpawnDelayMultipler = ser.ReadFloat(); } public void Reset() { @@ -112,6 +265,15 @@ this.EngineerLimitPerSquad = 8; this.SupportLimitPerSquad = 8; this.ReconLimitPerSquad = 8; + + this.CanVoteDay = true; + this.CanVoteNight = true; + + this.TankSpawnDelayMultipler = 1.0f; + this.TransportSpawnDelayMultipler = 1.0f; + this.SeaVehicleSpawnDelayMultipler = 1.0f; + this.APCSpawnDelayMultipler = 1.0f; + this.HelicopterSpawnDelayMultipler = 1.0f; } } } diff --git a/BattleBitAPI/Server/Internal/Squad.cs b/BattleBitAPI/Server/Internal/Squad.cs index c21089c..ca01a3e 100644 --- a/BattleBitAPI/Server/Internal/Squad.cs +++ b/BattleBitAPI/Server/Internal/Squad.cs @@ -20,6 +20,23 @@ namespace BattleBitAPI.Server Server.SetSquadPointsOf(@internal.Team, @internal.Name, value); } } + public TPlayer Leader + { + get + { + if (this.@internal.SquadLeader != 0 && this.Server.TryGetPlayer(this.@internal.SquadLeader, out var captain)) + return captain; + return null; + } + set + { + if (value != null) + { + if (!value.IsSquadLeader) + value.PromoteToSquadLeader(); + } + } + } private Internal @internal; public Squad(Internal @internal) @@ -27,6 +44,13 @@ namespace BattleBitAPI.Server this.@internal = @internal; } + public void DisbandSquad() + { + var leader = this.Leader; + if (leader != null) + leader.DisbandTheSquad(); + } + public override string ToString() { return "Squad " + Name; @@ -40,6 +64,7 @@ namespace BattleBitAPI.Server public int SquadPoints; public GameServer Server; public HashSet Members; + public ulong SquadLeader; public Internal(GameServer server, Team team, Squads squads) { @@ -47,6 +72,7 @@ namespace BattleBitAPI.Server this.Name = squads; this.Server = server; this.Members = new HashSet(8); + this.SquadLeader = 0; } public void Reset() diff --git a/BattleBitAPI/Server/Player.cs b/BattleBitAPI/Server/Player.cs index 880548f..650d0b6 100644 --- a/BattleBitAPI/Server/Player.cs +++ b/BattleBitAPI/Server/Player.cs @@ -67,6 +67,18 @@ namespace BattleBitAPI public bool InSquad => mInternal.SquadName != Squads.NoSquad; public int PingMs => mInternal.PingMs; public long CurrentSessionID => mInternal.SessionID; + public bool IsSquadLeader + { + get + { + if (this.SquadName != Squads.NoSquad) + { + var squad = this.Squad; + return squad.Leader == this; + } + return false; + } + } public bool IsConnected => mInternal.SessionID != 0; public float HP @@ -150,6 +162,10 @@ namespace BattleBitAPI public virtual async Task OnJoinedSquad(Squad newSquad) { + } + public virtual async Task OnPlayerPromotedToSquadLeader() + { + } public virtual async Task OnLeftSquad(Squad oldSquad) { diff --git a/BattleBitAPI/Server/ServerListener.cs b/BattleBitAPI/Server/ServerListener.cs index d63ae12..b2eb487 100644 --- a/BattleBitAPI/Server/ServerListener.cs +++ b/BattleBitAPI/Server/ServerListener.cs @@ -1119,10 +1119,11 @@ namespace BattleBitAPI.Server } case NetworkCommuncation.OnPlayerJoinedASquad: { - if (stream.CanRead(8 + 1)) + if (stream.CanRead(8 + 1 + 1)) { ulong steamID = stream.ReadUInt64(); Squads squad = (Squads)stream.ReadInt8(); + bool asCaptain = stream.ReadBool(); if (resources.TryGetPlayer(steamID, out var player)) { @@ -1134,11 +1135,24 @@ namespace BattleBitAPI.Server lock (rsquad.Members) rsquad.Members.Add((TPlayer)player); + //Assign as leader if needed. + if (asCaptain) + rsquad.SquadLeader = steamID; + player.OnJoinedSquad(msquad); server.OnPlayerJoinedSquad((TPlayer)player, msquad); if (this.LogLevel.HasFlag(LogLevel.Squads)) OnLog(LogLevel.Squads, $"{player} has joined to {msquad}", msquad); + + if (asCaptain) + { + player.OnPlayerPromotedToSquadLeader(); + server.OnSquadLeaderChanged(msquad, (TPlayer)player); + + if (this.LogLevel.HasFlag(LogLevel.Squads)) + OnLog(LogLevel.Squads, $"{player} has promoted to squad leader", player); + } } } break; @@ -1444,7 +1458,7 @@ namespace BattleBitAPI.Server //Heal OnLog(LogLevel.HealtChanges, $"{player} was healed by {dtHP} HP (new HP is {newHP} HP)", player); } - else if(dtHP < 0) + else if (dtHP < 0) { //Damage OnLog(LogLevel.HealtChanges, $"{player} was damaged by {(-dtHP)} HP (new HP is {newHP} HP)", player); @@ -1572,6 +1586,29 @@ namespace BattleBitAPI.Server } break; } + case NetworkCommuncation.OnSquadLeaderChanged: + { + if (stream.CanRead(8 + 1)) + { + ulong steamID = stream.ReadUInt64(); + byte squadIndex = stream.ReadInt8(); + + if (resources.TryGetPlayer(steamID, out var player)) + { + var msquad = server.GetSquad(player.Team, (Squads)squadIndex); + var rsquad = resources.GetSquadInternal(msquad); + + rsquad.SquadLeader = steamID; + + player.OnPlayerPromotedToSquadLeader(); + server.OnSquadLeaderChanged(msquad, (TPlayer)player); + + if (this.LogLevel.HasFlag(LogLevel.Squads)) + OnLog(LogLevel.Squads, $"{player} has promoted to squad leader", player); + } + } + break; + } } }