From 7677a018f65bedd1483b80cea47534b05bb65a0c Mon Sep 17 00:00:00 2001 From: Julgers <141361545+Julgers@users.noreply.github.com> Date: Tue, 15 Aug 2023 16:05:55 +0200 Subject: [PATCH 1/6] Update README for clarification about ports --- README.md | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/README.md b/README.md index c4d533cc..5515f627 100644 --- a/README.md +++ b/README.md @@ -26,8 +26,12 @@ The easiest way to get started with all of this, is to use `Program.cs` and add This project can either be built by using [`dotnet build`](https://learn.microsoft.com/en-us/dotnet/core/tools/dotnet-build) on the command-line or by using the run / build options inside your preferred IDE. +Alternatively, you can use Docker to run it. An easy way to do this it to run `docker compose up`. + ### Connecting to the gameserver(s) After writing and compiling this project. You will want to host it somewhere. This could be on the same server that the gameservers run on, or somewhere completely different. We do recommend to keep the latency to the gameserver minimal for smoother and faster communication. The same `ServerListener` can be used for *multiple* gameservers at the same time. You can specify the API server (address & port) in the launch options of the gameserver. The gameserver connects to the API with the launch argument `"-apiendpoint=:"`, where `` is the port that the listener listens on and the `` is the IP of the API server. + +The project is currently configured to have the API listen on port `29294`. If you want to change this, make sure to change it in the code (on your `listener.start(port)`). Port `29294` is also exposed in Docker and bound to the same port on the host in Docker Compose. This means that when using Docker, you will have to change the port in the `Dockerfile` and in `docker-compose.yml` (when using Compose) as well. See [EXPOSE in the Dockerfile reference](https://docs.docker.com/engine/reference/builder/#expose) and [networking in Compose](https://docs.docker.com/compose/networking/). From 484897d7ab554595f8448b7dbdabd2a0db7bea42 Mon Sep 17 00:00:00 2001 From: devhalfdog Date: Wed, 16 Aug 2023 00:26:47 +0900 Subject: [PATCH 2/6] edit readme --- README_koKR.md => README-koKR.md | 6 +++++- README-zhCN.md | 2 +- README.md | 2 +- 3 files changed, 7 insertions(+), 3 deletions(-) rename README_koKR.md => README-koKR.md (75%) diff --git a/README_koKR.md b/README-koKR.md similarity index 75% rename from README_koKR.md rename to README-koKR.md index b7576c1a..3f7fa291 100644 --- a/README_koKR.md +++ b/README-koKR.md @@ -28,8 +28,12 @@ Language [English](/README.md) | [中文](/README-zhCN.md) | 한국어 이 프로젝트는 CMD에서 [`dotnet build`](https://learn.microsoft.com/en-us/dotnet/core/tools/dotnet-build)를 사용하거나 선호하는 IDE에서 Run / Build 옵션을 이용하여 빌드할 수 있습니다. +또는, Docker를 사용할 수 있습니다. 이를 사용하는 쉬운 방법은 `docker compose up`을 실행하는 것입니다. + ### Connecting to the gameserver API를 작성하고 컴파일한 후, 다른 곳에서 호스팅하고 싶을 수도 있습니다. 게임 서버가 실행되는 서버와 동일한 서버일 수 있으며 완전히 다른 서버일 수도 있습니다. 보다 원활하고 빠른 통신을 위해 게임 서버와의 지연 시간을 최소화하는 것이 좋습니다. 동일한 `ServerListener`를 동시에 *여러* 게임 서버에 사용할 수 있습니다. 게임 서버의 실행 옵션에서 API 서버(주소와 포트)를 지정할 수 있습니다. -게임 서버는 실행 인수 `-apiendpoint=:`를 사용하여 API에 연결합니다. 여기서 는 리스터가 수신하는 포트이고, IP는 API 서버의 IP입니다. \ No newline at end of file +게임 서버는 실행 인수 `-apiendpoint=:`를 사용하여 API에 연결합니다. 여기서 는 리스터가 수신하는 포트이고, IP는 API 서버의 IP입니다. + +현재 프로젝트의 API는 `29294` 포트에서 수신 대기하도록 구성되어 있습니다. 이를 변경하려면 `listener.start(port)`에서 변경해야 합니다. `29294` 포트는 Docker에 노출되며 Docker Compose에서 호스트의 동일한 포트에 바인딩됩니다. 즉, Docker를 사용할 때 `Dockerfile` 및 `docker-compose.yml` (Compose를 사용할 때)에서도 포트를 변경해야 합니다. [EXPOSE 문서](https://docs.docker.com/engine/reference/builder/#expose) 와 [NETWORKING 문서](https://docs.docker.com/compose/networking/)를 참고하세요. \ No newline at end of file diff --git a/README-zhCN.md b/README-zhCN.md index a9eaa5ad..f2e440e7 100644 --- a/README-zhCN.md +++ b/README-zhCN.md @@ -3,7 +3,7 @@ [![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](https://opensource.org/licenses/MIT) -Language [English](/README.md) | 中文 | [한국어](/README_koKR.md) +Language [English](/README.md) | 中文 | [한국어](/README-koKR.md) 这个 repo 是 BBR(像素战地)的服务端 API diff --git a/README.md b/README.md index 5515f627..8451b0c5 100644 --- a/README.md +++ b/README.md @@ -2,7 +2,7 @@ [![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](https://opensource.org/licenses/MIT) -Language English | [中文](/README-zhCN.md) | [한국어](/README_koKR.md) +Language English | [中文](/README-zhCN.md) | [한국어](/README-koKR.md) This repository provides an API that can be used to handle events on your community server(s) and manipulate them. From baf2a8381e9268c2c9049bcd81d49a088522a1d1 Mon Sep 17 00:00:00 2001 From: Maple Gao Date: Wed, 16 Aug 2023 09:42:33 +0800 Subject: [PATCH 3/6] Update README-zhCN.md up to date with the latest README and some proofreading --- README-zhCN.md | 20 ++++++++++++-------- 1 file changed, 12 insertions(+), 8 deletions(-) diff --git a/README-zhCN.md b/README-zhCN.md index f2e440e7..285ccd9e 100644 --- a/README-zhCN.md +++ b/README-zhCN.md @@ -1,11 +1,11 @@ -# BattleBit Remastered 服务器 API +# BattleBit Remastered 服务端 API [![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](https://opensource.org/licenses/MIT) Language [English](/README.md) | 中文 | [한국어](/README-koKR.md) -这个 repo 是 BBR(像素战地)的服务端 API +BBR(像素战地)的服务端 API 在部署后可以提供`社区服`所需要的游戏服务端事件处理以及事件控制。 ## 如何开始 @@ -15,19 +15,23 @@ Language [English](/README.md) | 中文 | [한국어](/README-koKR.md) - 可以写基于 [.NET 6.0](https://dotnet.microsoft.com/en-us/download/dotnet/6.0) 的 C# 代码。 - 可以在生产环境中部署此代码。 -### 如何制作功能 +### 制作功能 制作对应的功能可以 [查看维基(制作中)](https://github.com/MrOkiDoki/BattleBit-Community-Server-API/wiki). -使用这个 API 将在运行本程序后开启一个`ServerListener` 的监听进程,传递你*自己定义*的`Player` 和 `GameServer` 类型覆盖原本游戏自身的`Player` 和 `GameServer`类型。在这些类型中添加任何你想要的功能,以此来定制属于你自己的游戏玩法。 -如果想给你的服务端添加功能,可以直接把覆盖的功能写在 `Program.cs` 的 `MyPlayer` 和 `MyGameServer`中,当然也可以按照框架规范进行其他的功能纂写。 - +本 API 将在运行后开启一个`ServerListener` 的监听进程,传递你 *自己定义* 的 `Player` 和 `GameServer` 类型覆盖原本游戏自身的 `Player` 和 `GameServer` 类型。在这些类型中添加任何你想要的功能,以此来定制属于你自己的游戏玩法。 +如果想给你的游戏服务端添加功能,可以直接把覆盖的功能写入 `Program.cs` 的 `MyPlayer` 和 `MyGameServer`中,当然你也可以按照框架规范进行其他的功能纂写。 ### 编译 -可以直接使用 [`dotnet build`](https://learn.microsoft.com/en-us/dotnet/core/tools/dotnet-build) 的命令进行编译,或者在你的 IDE 中自定义编译. +可以直接使用 [`dotnet build`](https://learn.microsoft.com/en-us/dotnet/core/tools/dotnet-build) 的命令进行编译,或者在你的 IDE 中自定义编译。 -### 连接服务端 +### 连接游戏服务端 当你将此项目的功能写完并进行了编译后,需要将此 API 服务进行部署。此 API 服务可以部署在本地网络、本机网络或者广域网中。我们强烈建议以「最低延迟」为基准进行部署,以保证 `ServerListener` 可以同时监听 *多个* 游戏服务端。 你可以在游戏服务端的启动配置中对 API 的地址和端口进行设定。 + +游戏服务端通过启动参数 `"-apiEndpoint=:<端口>"` 来与本 API 实例进行通信, 启动参数中的 `<端口>` 指的是本 API 服务中指定的端口 `` 指的是本 API 服务部署实例的 IP 地址。 + +如果游戏服务端实例与本 API 实例不在同一个实例上进行部署,且你想修改本 API 实例的端口 `29294`,你可以查看 `Progran.cs` 中 `listener.Start(29294);` 并把 `29294` 修改为你想指定或防火墙等安全策略已通过的端口号。 +如果你的实例运行在 Docker 容器中,端口 `29294` (或你修改的其他端口)也同时需要在 Docker 容器配置中进行修改并对外暴露。也就是说你需要修改 `Dockerfile` 且(如果有使用到容器集群编排)还有需要修改 `docker-compose.yml` 。相关参考资料可以查看 Docker 官方文档 [EXPOSE in the Dockerfile reference](https://docs.docker.com/engine/reference/builder/#expose) 以及 [networking in Compose](https://docs.docker.com/compose/networking/)。 From 9647a36486127b3bc133e7dbaa62ac64195ddee4 Mon Sep 17 00:00:00 2001 From: Julgers <141361545+Julgers@users.noreply.github.com> Date: Wed, 16 Aug 2023 12:26:00 +0200 Subject: [PATCH 4/6] Add GH actions to do a build on push/PR to main --- .github/workflows/dotnet.yml | 26 ++++++++++++++++++++++++++ 1 file changed, 26 insertions(+) create mode 100644 .github/workflows/dotnet.yml diff --git a/.github/workflows/dotnet.yml b/.github/workflows/dotnet.yml new file mode 100644 index 00000000..abbfbeb8 --- /dev/null +++ b/.github/workflows/dotnet.yml @@ -0,0 +1,26 @@ +# This workflow will build a .NET project +# For more information see: https://docs.github.com/en/actions/automating-builds-and-tests/building-and-testing-net + +name: .NET build + +on: + push: + branches: [ "main" ] + pull_request: + branches: [ "main" ] + +jobs: + build: + + runs-on: ubuntu-latest + + steps: + - uses: actions/checkout@v3 + - name: Setup .NET + uses: actions/setup-dotnet@v3 + with: + dotnet-version: 6.0.x + - name: Restore dependencies + run: dotnet restore + - name: Build + run: dotnet build --no-restore From 4a87c1e13a9b02e179c69c8a9ad6b6b89f41087d Mon Sep 17 00:00:00 2001 From: MrOkiDoki <0mrokidoki@gmail.com> Date: Thu, 17 Aug 2023 18:39:20 +0300 Subject: [PATCH 5/6] Tons of new stuff. --- .../Common/Arguments/OnPlayerKillArguments.cs | 1 - BattleBitAPI/Common/Conts.cs | 2 + BattleBitAPI/Common/Data/PlayerLoadout.cs | 4 +- .../Networking/NetworkCommuncation.cs | 1 + BattleBitAPI/Server/GameServer.cs | 211 +++------ .../Server/Internal/GamemodeRotation.cs | 1 - BattleBitAPI/Server/Internal/MapRotation.cs | 3 +- .../Server/Internal/PlayerModifications.cs | 415 +++++++++++++++++- BattleBitAPI/Server/Internal/RoundSettings.cs | 46 +- .../Server/Internal/ServerSettings.cs | 105 +++-- BattleBitAPI/Server/Player.cs | 104 +---- BattleBitAPI/Server/ServerListener.cs | 76 +++- Program.cs | 30 +- 13 files changed, 685 insertions(+), 314 deletions(-) diff --git a/BattleBitAPI/Common/Arguments/OnPlayerKillArguments.cs b/BattleBitAPI/Common/Arguments/OnPlayerKillArguments.cs index a0e0e2cf..ca8389a7 100644 --- a/BattleBitAPI/Common/Arguments/OnPlayerKillArguments.cs +++ b/BattleBitAPI/Common/Arguments/OnPlayerKillArguments.cs @@ -1,5 +1,4 @@ using System.Numerics; -using CommunityServerAPI.BattleBitAPI.Server; namespace BattleBitAPI.Common { diff --git a/BattleBitAPI/Common/Conts.cs b/BattleBitAPI/Common/Conts.cs index d7577ea2..4abba283 100644 --- a/BattleBitAPI/Common/Conts.cs +++ b/BattleBitAPI/Common/Conts.cs @@ -28,6 +28,8 @@ public static class Const public const int MinServerNameLength = 5; public const int MaxServerNameLength = 400; + public const int MaxTokenSize = 512; + public const int MinGamemodeNameLength = 2; public const int MaxGamemodeNameLength = 12; diff --git a/BattleBitAPI/Common/Data/PlayerLoadout.cs b/BattleBitAPI/Common/Data/PlayerLoadout.cs index c6f8a0e6..abd14f9b 100644 --- a/BattleBitAPI/Common/Data/PlayerLoadout.cs +++ b/BattleBitAPI/Common/Data/PlayerLoadout.cs @@ -282,7 +282,7 @@ public bool HasAttachment(Attachment attachment) case AttachmentType.Barrel: return this.Barrel == attachment; case AttachmentType.UnderRail: - return this.Barrel == attachment; + return this.UnderRail == attachment; case AttachmentType.SideRail: return this.SideRail == attachment; case AttachmentType.Bolt: @@ -307,7 +307,7 @@ public void SetAttachment(Attachment attachment) this.Barrel = attachment; break; case AttachmentType.UnderRail: - this.Barrel = attachment; + this.UnderRail = attachment; break; case AttachmentType.SideRail: this.SideRail = attachment; diff --git a/BattleBitAPI/Networking/NetworkCommuncation.cs b/BattleBitAPI/Networking/NetworkCommuncation.cs index 428f1a9b..1199b5ac 100644 --- a/BattleBitAPI/Networking/NetworkCommuncation.cs +++ b/BattleBitAPI/Networking/NetworkCommuncation.cs @@ -15,6 +15,7 @@ public enum NetworkCommuncation : byte SetNewRoundState = 15, SetPlayerWeapon = 16, SetPlayerGadget = 17, + SetPlayerModifications = 18, PlayerConnected = 50, PlayerDisconnected = 51, diff --git a/BattleBitAPI/Server/GameServer.cs b/BattleBitAPI/Server/GameServer.cs index c3c01695..6b92ed77 100644 --- a/BattleBitAPI/Server/GameServer.cs +++ b/BattleBitAPI/Server/GameServer.cs @@ -101,6 +101,35 @@ public async Task Tick() } } + //Gather all changes. + this.mInternal.mChangedModifications.Clear(); + lock (this.mInternal.Players) + { + foreach (var steamid in this.mInternal.Players.Keys) + { + var @internal = this.mInternal.mGetInternals(steamid); + if (@internal._Modifications.IsDirtyFlag) + this.mInternal.mChangedModifications.Enqueue((steamid, @internal._Modifications)); + } + } + + //Send all changes. + while (this.mInternal.mChangedModifications.Count > 0) + { + (ulong steamID, PlayerModifications.mPlayerModifications modifications) item = this.mInternal.mChangedModifications.Dequeue(); + + item.modifications.IsDirtyFlag = false; + + //Send new settings + using (var pck = Common.Serialization.Stream.Get()) + { + pck.Write((byte)NetworkCommuncation.SetPlayerModifications); + pck.Write(item.steamID); + item.modifications.Write(pck); + WriteToSocket(pck); + } + } + try { //Are we still connected on socket level? @@ -315,7 +344,7 @@ public virtual async Task OnAPlayerDownedAnotherPlayer(OnPlayerKillArguments player, float heal) { Heal(player.SteamID, heal); } - public void SetRunningSpeedMultiplier(ulong steamID, float value) - { - ExecuteCommand("setrunningspeed " + steamID + " " + value); - } - public void SetRunningSpeedMultiplier(Player player, float value) - { - SetRunningSpeedMultiplier(player.SteamID, value); - } - public void SetReceiveDamageMultiplier(ulong steamID, float value) - { - ExecuteCommand("setreceivedamagemultiplier " + steamID + " " + value); - } - public void SetReceiveDamageMultiplier(Player player, float value) - { - SetReceiveDamageMultiplier(player.SteamID, value); - } - public void SetGiveDamageMultiplier(ulong steamID, float value) - { - ExecuteCommand("setgivedamagemultiplier " + steamID + " " + value); - } - public void SetGiveDamageMultiplier(Player player, float value) - { - SetGiveDamageMultiplier(player.SteamID, value); - } - public void SetJumpMultiplier(ulong steamID, float value) - { - ExecuteCommand("setjumpmultiplier " + steamID + " " + value); - } - public void SetJumpMultiplier(Player player, float value) - { - SetJumpMultiplier(player.SteamID, value); - } - public void SetFallDamageMultiplier(ulong steamID, float value) - { - ExecuteCommand("setfalldamagemultiplier " + steamID + " " + value); - } - public void SetFallDamageMultiplier(Player player, float value) - { - SetFallDamageMultiplier(player.SteamID, value); - } public void SetPrimaryWeapon(ulong steamID, WeaponItem item, int extraMagazines, bool clear = false) { @@ -759,6 +748,7 @@ public class Internal public int GamePort; public TcpClient Socket; public Func, Internal, Common.Serialization.Stream, Task> mExecutionFunc; + public Func.Internal> mGetInternals; public bool IsPasswordProtected; public string ServerName; public string Gamemode; @@ -786,6 +776,7 @@ public class Internal public long mLastPackageSent; public bool mWantsToCloseConnection; public StringBuilder mBuilder; + public Queue<(ulong steamID, PlayerModifications.mPlayerModifications)> mChangedModifications; public Internal() { @@ -816,17 +807,18 @@ public Internal() this.MapRotation = new MapRotation(this); this.GamemodeRotation = new GamemodeRotation(this); this.RoundSettings = new RoundSettings(this); + this.mChangedModifications = new Queue<(ulong steamID, PlayerModifications.mPlayerModifications)>(254); } // ---- Players In Room ---- public Dictionary> Players = new Dictionary>(254); // ---- Room Settings ---- - public mRoomSettings _RoomSettings = new mRoomSettings(); + public ServerSettings.mRoomSettings _RoomSettings = new ServerSettings.mRoomSettings(); public bool IsDirtyRoomSettings; // ---- Round Settings ---- - public mRoundSettings _RoundSettings = new mRoundSettings(); + public RoundSettings.mRoundSettings _RoundSettings = new RoundSettings.mRoundSettings(); public bool IsDirtyRoundSettings; // ---- Map Rotation ---- @@ -838,7 +830,24 @@ public Internal() public bool IsDirtyGamemodeRotation = false; // ---- Public Functions ---- - public void Set(Func, 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) + public void Set( + Func, Internal, Common.Serialization.Stream, Task> func, + Func.Internal> internalGetFunc, + 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; @@ -846,6 +855,7 @@ public void Set(Func, Internal, Common.Serialization.Stream, this.GamePort = port; this.Socket = socket; this.mExecutionFunc = func; + this.mGetInternals = internalGetFunc; this.IsPasswordProtected = isPasswordProtected; this.ServerName = serverName; this.Gamemode = gamemode; @@ -884,6 +894,7 @@ public void Set(Func, Internal, Common.Serialization.Stream, this.mLastPackageSent = Extentions.TickCount; this.mWantsToCloseConnection = false; this.mBuilder.Clear(); + this.mChangedModifications.Clear(); } public void AddPlayer(Player player) { @@ -904,117 +915,5 @@ public bool TryGetPlayer(ulong steamID, out Player result) return Players.TryGetValue(steamID, out result); } } - public class mRoomSettings - { - public float DamageMultiplier = 1.0f; - public bool BleedingEnabled = true; - public bool StaminaEnabled = false; - public bool FriendlyFireEnabled = false; - public bool HideMapVotes = true; - public bool OnlyWinnerTeamCanVote = false; - public bool HitMarkersEnabled = true; - public bool PointLogEnabled = true; - public bool SpectatorEnabled = true; - public float CaptureFlagSpeedMultiplier = 1f; - - public byte MedicLimitPerSquad = 8; - public byte EngineerLimitPerSquad = 8; - public byte SupportLimitPerSquad = 8; - public byte ReconLimitPerSquad = 8; - - public void Write(Common.Serialization.Stream ser) - { - ser.Write(this.DamageMultiplier); - ser.Write(this.BleedingEnabled); - ser.Write(this.StaminaEnabled); - ser.Write(this.FriendlyFireEnabled); - ser.Write(this.HideMapVotes); - ser.Write(this.OnlyWinnerTeamCanVote); - ser.Write(this.HitMarkersEnabled); - ser.Write(this.PointLogEnabled); - ser.Write(this.SpectatorEnabled); - ser.Write(this.CaptureFlagSpeedMultiplier); - - ser.Write(this.MedicLimitPerSquad); - ser.Write(this.EngineerLimitPerSquad); - ser.Write(this.SupportLimitPerSquad); - ser.Write(this.ReconLimitPerSquad); - } - public void Read(Common.Serialization.Stream ser) - { - this.DamageMultiplier = ser.ReadFloat(); - this.BleedingEnabled = ser.ReadBool(); - this.StaminaEnabled = ser.ReadBool(); - this.FriendlyFireEnabled = ser.ReadBool(); - this.HideMapVotes = ser.ReadBool(); - this.OnlyWinnerTeamCanVote = ser.ReadBool(); - this.HitMarkersEnabled = ser.ReadBool(); - this.PointLogEnabled = ser.ReadBool(); - this.SpectatorEnabled = ser.ReadBool(); - this.CaptureFlagSpeedMultiplier = ser.ReadFloat(); - - this.MedicLimitPerSquad = ser.ReadInt8(); - this.EngineerLimitPerSquad = ser.ReadInt8(); - this.SupportLimitPerSquad = ser.ReadInt8(); - this.ReconLimitPerSquad = ser.ReadInt8(); - } - public void Reset() - { - this.DamageMultiplier = 1.0f; - this.BleedingEnabled = true; - this.StaminaEnabled = 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; - } - } - public class mRoundSettings - { - public const int Size = 1 + 8 + 8 + 8 + 4 + 4; - - public GameState State = GameState.WaitingForPlayers; - public double TeamATickets = 0; - public double TeamBTickets = 0; - public double MaxTickets = 1; - public int PlayersToStart = 16; - public int SecondsLeft = 60; - - public void Write(Common.Serialization.Stream ser) - { - ser.Write((byte)this.State); - ser.Write(this.TeamATickets); - ser.Write(this.TeamBTickets); - ser.Write(this.MaxTickets); - ser.Write(this.PlayersToStart); - ser.Write(this.SecondsLeft); - } - public void Read(Common.Serialization.Stream ser) - { - this.State = (GameState)ser.ReadInt8(); - this.TeamATickets = ser.ReadDouble(); - this.TeamBTickets = ser.ReadDouble(); - this.MaxTickets = ser.ReadDouble(); - this.PlayersToStart = ser.ReadInt32(); - this.SecondsLeft = ser.ReadInt32(); - } - - public void Reset() - { - this.State = GameState.WaitingForPlayers; - this.TeamATickets = 0; - this.TeamBTickets = 0; - this.MaxTickets = 1; - this.PlayersToStart = 16; - this.SecondsLeft = 60; - } - } } } diff --git a/BattleBitAPI/Server/Internal/GamemodeRotation.cs b/BattleBitAPI/Server/Internal/GamemodeRotation.cs index 7c5ee4d0..999b11b6 100644 --- a/BattleBitAPI/Server/Internal/GamemodeRotation.cs +++ b/BattleBitAPI/Server/Internal/GamemodeRotation.cs @@ -1,5 +1,4 @@ using BattleBitAPI.Common; -using CommunityServerAPI.BattleBitAPI.Server; namespace BattleBitAPI.Server { diff --git a/BattleBitAPI/Server/Internal/MapRotation.cs b/BattleBitAPI/Server/Internal/MapRotation.cs index c7180057..3361e56b 100644 --- a/BattleBitAPI/Server/Internal/MapRotation.cs +++ b/BattleBitAPI/Server/Internal/MapRotation.cs @@ -1,5 +1,4 @@ -using CommunityServerAPI.BattleBitAPI.Server; - + namespace BattleBitAPI.Server { public class MapRotation where TPlayer : Player diff --git a/BattleBitAPI/Server/Internal/PlayerModifications.cs b/BattleBitAPI/Server/Internal/PlayerModifications.cs index 4f9c77ee..ff48e867 100644 --- a/BattleBitAPI/Server/Internal/PlayerModifications.cs +++ b/BattleBitAPI/Server/Internal/PlayerModifications.cs @@ -2,27 +2,410 @@ { public class PlayerModifications where TPlayer : Player { + // ---- Construction ---- private Player.Internal @internal; public PlayerModifications(Player.Internal @internal) { this.@internal = @internal; } - public float RunningSpeedMultiplier { get; set; } - public float ReceiveDamageMultiplier { get; set; } - public float GiveDamageMultiplier { get; set; } - public float JumpHeightMultiplier { get; set; } - public float FallDamageMultiplier { get; set; } - public float ReloadSpeedMultiplier { get; set; } - public bool CanUseNightVision { get; set; } - public bool HasCollision { get; set; } - public float DownTimeGiveUpTime { get; set; } - public bool AirStrafe { get; set; } - public bool CanSpawn { get; set; } - public bool CanSpectate { get; set; } - public bool IsTextChatMuted { get; set; } - public bool IsVoiceChatMuted { get; set; } - public float RespawnTime { get; set; } - public bool CanRespawn { get; set; } + // ---- Variables ---- + public float RunningSpeedMultiplier + { + get => @internal._Modifications.RunningSpeedMultiplier; + set + { + if (@internal._Modifications.RunningSpeedMultiplier == value) + return; + @internal._Modifications.RunningSpeedMultiplier = value; + @internal._Modifications.IsDirtyFlag = true; + } + } + public float ReceiveDamageMultiplier + { + get => @internal._Modifications.ReceiveDamageMultiplier; + set + { + if (@internal._Modifications.ReceiveDamageMultiplier == value) + return; + @internal._Modifications.ReceiveDamageMultiplier = value; + @internal._Modifications.IsDirtyFlag = true; + } + } + public float GiveDamageMultiplier + { + get => @internal._Modifications.GiveDamageMultiplier; + set + { + if (@internal._Modifications.GiveDamageMultiplier == value) + return; + @internal._Modifications.GiveDamageMultiplier = value; + @internal._Modifications.IsDirtyFlag = true; + } + } + public float JumpHeightMultiplier + { + get => @internal._Modifications.JumpHeightMultiplier; + set + { + if (@internal._Modifications.JumpHeightMultiplier == value) + return; + @internal._Modifications.JumpHeightMultiplier = value; + @internal._Modifications.IsDirtyFlag = true; + } + } + public float FallDamageMultiplier + { + get => @internal._Modifications.FallDamageMultiplier; + set + { + if (@internal._Modifications.FallDamageMultiplier == value) + return; + @internal._Modifications.FallDamageMultiplier = value; + @internal._Modifications.IsDirtyFlag = true; + } + } + public float ReloadSpeedMultiplier + { + get => @internal._Modifications.ReloadSpeedMultiplier; + set + { + if (@internal._Modifications.ReloadSpeedMultiplier == value) + return; + @internal._Modifications.ReloadSpeedMultiplier = value; + @internal._Modifications.IsDirtyFlag = true; + } + } + public bool CanUseNightVision + { + get => @internal._Modifications.CanUseNightVision; + set + { + if (@internal._Modifications.CanUseNightVision == value) + return; + @internal._Modifications.CanUseNightVision = value; + @internal._Modifications.IsDirtyFlag = true; + } + } + public float DownTimeGiveUpTime + { + get => @internal._Modifications.DownTimeGiveUpTime; + set + { + if (@internal._Modifications.DownTimeGiveUpTime == value) + return; + @internal._Modifications.DownTimeGiveUpTime = value; + @internal._Modifications.IsDirtyFlag = true; + } + } + public bool AirStrafe + { + get => @internal._Modifications.AirStrafe; + set + { + if (@internal._Modifications.AirStrafe == value) + return; + @internal._Modifications.AirStrafe = value; + @internal._Modifications.IsDirtyFlag = true; + } + } + public bool CanDeploy + { + get => @internal._Modifications.CanDeploy; + set + { + if (@internal._Modifications.CanDeploy == value) + return; + @internal._Modifications.CanDeploy = value; + @internal._Modifications.IsDirtyFlag = true; + } + } + public bool CanSpectate + { + get => @internal._Modifications.CanSpectate; + set + { + if (@internal._Modifications.CanSpectate == value) + return; + @internal._Modifications.CanSpectate = value; + @internal._Modifications.IsDirtyFlag = true; + } + } + public bool IsTextChatMuted + { + get => @internal._Modifications.IsTextChatMuted; + set + { + if (@internal._Modifications.IsTextChatMuted == value) + return; + @internal._Modifications.IsTextChatMuted = value; + @internal._Modifications.IsDirtyFlag = true; + } + } + public bool IsVoiceChatMuted + { + get => @internal._Modifications.IsVoiceChatMuted; + set + { + if (@internal._Modifications.IsVoiceChatMuted == value) + return; + @internal._Modifications.IsVoiceChatMuted = value; + @internal._Modifications.IsDirtyFlag = true; + } + } + public float RespawnTime + { + get => @internal._Modifications.RespawnTime; + set + { + if (@internal._Modifications.RespawnTime == value) + return; + @internal._Modifications.RespawnTime = value; + @internal._Modifications.IsDirtyFlag = true; + } + } + public bool CanSuicide + { + get => @internal._Modifications.CanSuicide; + set + { + if (@internal._Modifications.CanSuicide == value) + return; + @internal._Modifications.CanSuicide = value; + @internal._Modifications.IsDirtyFlag = true; + } + } + public float MinimumDamageToStartBleeding + { + get => @internal._Modifications.MinDamageToStartBleeding; + set + { + if (@internal._Modifications.MinDamageToStartBleeding == value) + return; + @internal._Modifications.MinDamageToStartBleeding = value; + @internal._Modifications.IsDirtyFlag = true; + } + } + public float MinimumHpToStartBleeding + { + get => @internal._Modifications.MinHpToStartBleeding; + set + { + if (@internal._Modifications.MinHpToStartBleeding == value) + return; + @internal._Modifications.MinHpToStartBleeding = value; + @internal._Modifications.IsDirtyFlag = true; + } + } + public float HpPerBandage + { + get => @internal._Modifications.HPperBandage; + set + { + if (value >= 100f) + value = 100f; + else if (value < 0) + value = 0f; + + if (@internal._Modifications.HPperBandage == value) + return; + @internal._Modifications.HPperBandage = value; + @internal._Modifications.IsDirtyFlag = true; + } + } + public bool StaminaEnabled + { + get => @internal._Modifications.StaminaEnabled; + set + { + if (@internal._Modifications.StaminaEnabled == value) + return; + @internal._Modifications.StaminaEnabled = value; + @internal._Modifications.IsDirtyFlag = true; + } + } + public bool HitMarkersEnabled + { + get => @internal._Modifications.HitMarkersEnabled; + set + { + if (@internal._Modifications.HitMarkersEnabled == value) + return; + @internal._Modifications.HitMarkersEnabled = value; + @internal._Modifications.IsDirtyFlag = true; + } + } + public bool FriendlyHUDEnabled + { + get => @internal._Modifications.FriendlyHUDEnabled; + set + { + if (@internal._Modifications.FriendlyHUDEnabled == value) + return; + @internal._Modifications.FriendlyHUDEnabled = value; + @internal._Modifications.IsDirtyFlag = true; + } + } + public float CaptureFlagSpeedMultiplier + { + get => @internal._Modifications.CaptureFlagSpeedMultiplier; + set + { + if (@internal._Modifications.CaptureFlagSpeedMultiplier == value) + return; + @internal._Modifications.CaptureFlagSpeedMultiplier = value; + @internal._Modifications.IsDirtyFlag = true; + } + } + public bool PointLogHudEnabled + { + get => @internal._Modifications.PointLogHudEnabled; + set + { + if (@internal._Modifications.PointLogHudEnabled == value) + return; + @internal._Modifications.PointLogHudEnabled = value; + @internal._Modifications.IsDirtyFlag = true; + } + } + public bool KillFeed + { + get => @internal._Modifications.KillFeed; + set + { + if (@internal._Modifications.KillFeed == value) + return; + @internal._Modifications.KillFeed = value; + @internal._Modifications.IsDirtyFlag = true; + } + } + + public void DisableBleeding() + { + this.MinimumDamageToStartBleeding = 100f; + this.MinimumHpToStartBleeding = 0f; + } + public void EnableBleeding(float minimumHP = 40f, float minimumDamage = 10f) + { + this.MinimumDamageToStartBleeding = minimumDamage; + this.MinimumHpToStartBleeding = minimumHP; + } + + // ---- Classes ---- + public class mPlayerModifications + { + public float RunningSpeedMultiplier = 1f; + public float ReceiveDamageMultiplier = 1f; + public float GiveDamageMultiplier = 1f; + public float JumpHeightMultiplier = 1f; + public float FallDamageMultiplier = 1f; + public float ReloadSpeedMultiplier = 1f; + public bool CanUseNightVision = true; + public float DownTimeGiveUpTime = 60f; + public bool AirStrafe = true; + public bool CanDeploy = true; + public bool CanSpectate = true; + public bool IsTextChatMuted = false; + public bool IsVoiceChatMuted = false; + public float RespawnTime = 10f; + public bool CanSuicide = true; + public float MinDamageToStartBleeding = 10f; + public float MinHpToStartBleeding = 40f; + public float HPperBandage = 40f; + public bool StaminaEnabled = false; + public bool HitMarkersEnabled = true; + public bool FriendlyHUDEnabled = true; + public float CaptureFlagSpeedMultiplier = 1f; + public bool PointLogHudEnabled = true; + public bool KillFeed = false; + + public bool IsDirtyFlag = false; + public void Write(BattleBitAPI.Common.Serialization.Stream ser) + { + ser.Write(this.RunningSpeedMultiplier); + ser.Write(this.ReceiveDamageMultiplier); + ser.Write(this.GiveDamageMultiplier); + ser.Write(this.JumpHeightMultiplier); + ser.Write(this.FallDamageMultiplier); + ser.Write(this.ReloadSpeedMultiplier); + ser.Write(this.CanUseNightVision); + ser.Write(this.DownTimeGiveUpTime); + ser.Write(this.AirStrafe); + ser.Write(this.CanDeploy); + ser.Write(this.CanSpectate); + ser.Write(this.IsTextChatMuted); + ser.Write(this.IsVoiceChatMuted); + ser.Write(this.RespawnTime); + ser.Write(this.CanSuicide); + + ser.Write(this.MinDamageToStartBleeding); + ser.Write(this.MinHpToStartBleeding); + ser.Write(this.HPperBandage); + ser.Write(this.StaminaEnabled); + ser.Write(this.HitMarkersEnabled); + ser.Write(this.FriendlyHUDEnabled); + ser.Write(this.CaptureFlagSpeedMultiplier); + ser.Write(this.PointLogHudEnabled); + ser.Write(this.KillFeed); + } + public void Read(BattleBitAPI.Common.Serialization.Stream ser) + { + this.RunningSpeedMultiplier = ser.ReadFloat(); + if (this.RunningSpeedMultiplier <= 0f) + this.RunningSpeedMultiplier = 0.01f; + + this.ReceiveDamageMultiplier = ser.ReadFloat(); + this.GiveDamageMultiplier = ser.ReadFloat(); + this.JumpHeightMultiplier = ser.ReadFloat(); + this.FallDamageMultiplier = ser.ReadFloat(); + this.ReloadSpeedMultiplier = ser.ReadFloat(); + this.CanUseNightVision = ser.ReadBool(); + this.DownTimeGiveUpTime = ser.ReadFloat(); + this.AirStrafe = ser.ReadBool(); + this.CanDeploy = ser.ReadBool(); + this.CanSpectate = ser.ReadBool(); + this.IsTextChatMuted = ser.ReadBool(); + this.IsVoiceChatMuted = ser.ReadBool(); + this.RespawnTime = ser.ReadFloat(); + this.CanSuicide = ser.ReadBool(); + + this.MinDamageToStartBleeding = ser.ReadFloat(); + this.MinHpToStartBleeding = ser.ReadFloat(); + this.HPperBandage = ser.ReadFloat(); + this.StaminaEnabled = ser.ReadBool(); + this.HitMarkersEnabled = ser.ReadBool(); + this.FriendlyHUDEnabled = ser.ReadBool(); + this.CaptureFlagSpeedMultiplier = ser.ReadFloat(); + this.PointLogHudEnabled = ser.ReadBool(); + this.KillFeed = ser.ReadBool(); + } + public void Reset() + { + this.RunningSpeedMultiplier = 1f; + this.ReceiveDamageMultiplier = 1f; + this.GiveDamageMultiplier = 1f; + this.JumpHeightMultiplier = 1f; + this.FallDamageMultiplier = 1f; + this.ReloadSpeedMultiplier = 1f; + this.CanUseNightVision = true; + this.DownTimeGiveUpTime = 60f; + this.AirStrafe = true; + this.CanDeploy = true; + this.CanSpectate = true; + this.IsTextChatMuted = false; + this.IsVoiceChatMuted = false; + this.RespawnTime = 10f; + this.CanSuicide = true; + this.MinDamageToStartBleeding = 10f; + this.MinHpToStartBleeding = 40f; + this.HPperBandage = 40f; + this.StaminaEnabled = false; + this.HitMarkersEnabled = true; + this.FriendlyHUDEnabled = true; + this.CaptureFlagSpeedMultiplier = 1f; + this.PointLogHudEnabled = true; + this.KillFeed = false; + } + } } } diff --git a/BattleBitAPI/Server/Internal/RoundSettings.cs b/BattleBitAPI/Server/Internal/RoundSettings.cs index a25a203c..4653da88 100644 --- a/BattleBitAPI/Server/Internal/RoundSettings.cs +++ b/BattleBitAPI/Server/Internal/RoundSettings.cs @@ -1,16 +1,17 @@ using BattleBitAPI.Common; -using CommunityServerAPI.BattleBitAPI.Server; namespace BattleBitAPI.Server { public class RoundSettings where TPlayer : Player { + // ---- Construction ---- private GameServer.Internal mResources; public RoundSettings(GameServer.Internal resources) { mResources = resources; } + // ---- Variables ---- public GameState State { get => this.mResources._RoundSettings.State; @@ -61,9 +62,52 @@ public int SecondsLeft } } + // ---- Reset ---- public void Reset() { } + + // ---- Classes ---- + public class mRoundSettings + { + public const int Size = 1 + 8 + 8 + 8 + 4 + 4; + + public GameState State = GameState.WaitingForPlayers; + public double TeamATickets = 0; + public double TeamBTickets = 0; + public double MaxTickets = 1; + public int PlayersToStart = 16; + public int SecondsLeft = 60; + + public void Write(Common.Serialization.Stream ser) + { + ser.Write((byte)this.State); + ser.Write(this.TeamATickets); + ser.Write(this.TeamBTickets); + ser.Write(this.MaxTickets); + ser.Write(this.PlayersToStart); + ser.Write(this.SecondsLeft); + } + public void Read(Common.Serialization.Stream ser) + { + this.State = (GameState)ser.ReadInt8(); + this.TeamATickets = ser.ReadDouble(); + this.TeamBTickets = ser.ReadDouble(); + this.MaxTickets = ser.ReadDouble(); + this.PlayersToStart = ser.ReadInt32(); + this.SecondsLeft = ser.ReadInt32(); + } + + public void Reset() + { + this.State = GameState.WaitingForPlayers; + this.TeamATickets = 0; + this.TeamBTickets = 0; + this.MaxTickets = 1; + this.PlayersToStart = 16; + this.SecondsLeft = 60; + } + } } } diff --git a/BattleBitAPI/Server/Internal/ServerSettings.cs b/BattleBitAPI/Server/Internal/ServerSettings.cs index b84bdf82..64eee730 100644 --- a/BattleBitAPI/Server/Internal/ServerSettings.cs +++ b/BattleBitAPI/Server/Internal/ServerSettings.cs @@ -1,47 +1,33 @@ -using CommunityServerAPI.BattleBitAPI.Server; - -namespace BattleBitAPI.Server +namespace BattleBitAPI.Server { public class ServerSettings where TPlayer : Player { + // ---- Construction ---- private GameServer.Internal mResources; public ServerSettings(GameServer.Internal resources) { mResources = resources; } + // ---- Variables ---- public float DamageMultiplier { get => mResources._RoomSettings.DamageMultiplier; set { + if (mResources._RoomSettings.DamageMultiplier == value) + return; mResources._RoomSettings.DamageMultiplier = value; mResources.IsDirtyRoomSettings = true; } } - public bool BleedingEnabled - { - get => mResources._RoomSettings.BleedingEnabled; - set - { - mResources._RoomSettings.BleedingEnabled = value; - mResources.IsDirtyRoomSettings = true; - } - } - public bool StamineEnabled - { - get => mResources._RoomSettings.StaminaEnabled; - set - { - mResources._RoomSettings.StaminaEnabled = value; - mResources.IsDirtyRoomSettings = true; - } - } public bool FriendlyFireEnabled { get => mResources._RoomSettings.FriendlyFireEnabled; set { + if (mResources._RoomSettings.FriendlyFireEnabled == value) + return; mResources._RoomSettings.FriendlyFireEnabled = value; mResources.IsDirtyRoomSettings = true; } @@ -51,41 +37,82 @@ public bool OnlyWinnerTeamCanVote get => mResources._RoomSettings.OnlyWinnerTeamCanVote; set { + if (mResources._RoomSettings.OnlyWinnerTeamCanVote == value) + return; mResources._RoomSettings.OnlyWinnerTeamCanVote = value; mResources.IsDirtyRoomSettings = true; } } - public bool HitMarkersEnabled + public bool PlayerCollision { - get => mResources._RoomSettings.HitMarkersEnabled; + get => mResources._RoomSettings.PlayerCollision; set { - mResources._RoomSettings.HitMarkersEnabled = value; + if (mResources._RoomSettings.PlayerCollision == value) + return; + mResources._RoomSettings.PlayerCollision = value; mResources.IsDirtyRoomSettings = true; } } - public bool PointLogEnabled + + // ---- Reset ---- + public void Reset() { - get => mResources._RoomSettings.PointLogEnabled; - set - { - mResources._RoomSettings.PointLogEnabled = value; - mResources.IsDirtyRoomSettings = true; - } + } - public bool SpectatorEnabled + + // ---- Classes ---- + public class mRoomSettings { - get => mResources._RoomSettings.SpectatorEnabled; - set + public float DamageMultiplier = 1.0f; + public bool FriendlyFireEnabled = false; + 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 void Write(Common.Serialization.Stream ser) { - mResources._RoomSettings.SpectatorEnabled = value; - mResources.IsDirtyRoomSettings = true; + ser.Write(this.DamageMultiplier); + ser.Write(this.FriendlyFireEnabled); + ser.Write(this.HideMapVotes); + ser.Write(this.OnlyWinnerTeamCanVote); + ser.Write(this.PlayerCollision); + + ser.Write(this.MedicLimitPerSquad); + ser.Write(this.EngineerLimitPerSquad); + ser.Write(this.SupportLimitPerSquad); + ser.Write(this.ReconLimitPerSquad); } - } + public void Read(Common.Serialization.Stream ser) + { + this.DamageMultiplier = ser.ReadFloat(); + this.FriendlyFireEnabled = ser.ReadBool(); + this.HideMapVotes = ser.ReadBool(); + this.OnlyWinnerTeamCanVote = ser.ReadBool(); + this.PlayerCollision=ser.ReadBool(); - public void Reset() - { + this.MedicLimitPerSquad = ser.ReadInt8(); + this.EngineerLimitPerSquad = ser.ReadInt8(); + this.SupportLimitPerSquad = ser.ReadInt8(); + this.ReconLimitPerSquad = ser.ReadInt8(); + } + public void Reset() + { + this.DamageMultiplier = 1.0f; + this.FriendlyFireEnabled = false; + this.HideMapVotes = true; + this.OnlyWinnerTeamCanVote = false; + this.PlayerCollision = false; + this.MedicLimitPerSquad = 8; + this.EngineerLimitPerSquad = 8; + this.SupportLimitPerSquad = 8; + this.ReconLimitPerSquad = 8; + } } } } diff --git a/BattleBitAPI/Server/Player.cs b/BattleBitAPI/Server/Player.cs index c05f783e..d16c0b76 100644 --- a/BattleBitAPI/Server/Player.cs +++ b/BattleBitAPI/Server/Player.cs @@ -49,7 +49,23 @@ public Squads Squad public bool InSquad => mInternal.Squad != Squads.NoSquad; public int PingMs => mInternal.PingMs; - public float HP => mInternal.HP; + public float HP + { + get => mInternal.HP; + set + { + if (mInternal.HP > 0) + { + float v = value; + if (v <= 0) + v = 0.1f; + else if (v > 100f) + v = 100f; + + SetHP(v); + } + } + } public bool IsAlive => mInternal.HP >= 0f; public bool IsUp => mInternal.HP > 0f; public bool IsDown => mInternal.HP == 0f; @@ -193,26 +209,6 @@ public void Heal(float hp) { GameServer.Heal(this, hp); } - public void SetRunningSpeedMultiplier(float value) - { - GameServer.SetRunningSpeedMultiplier(this, value); - } - public void SetReceiveDamageMultiplier(float value) - { - GameServer.SetReceiveDamageMultiplier(this, value); - } - public void SetGiveDamageMultiplier(float value) - { - GameServer.SetGiveDamageMultiplier(this, value); - } - public void SetJumpMultiplier(float value) - { - GameServer.SetJumpMultiplier(this, value); - } - public void SetFallDamageMultiplier(float value) - { - GameServer.SetFallDamageMultiplier(this, value); - } public void SetPrimaryWeapon(WeaponItem item, int extraMagazines, bool clear = false) { GameServer.SetPrimaryWeapon(this, item, extraMagazines, clear); @@ -275,13 +271,13 @@ public class Internal public PlayerLoadout CurrentLoadout; public PlayerWearings CurrentWearings; - public mPlayerModifications _Modifications; + public PlayerModifications.mPlayerModifications _Modifications; public PlayerModifications Modifications; public Internal() { + this._Modifications = new PlayerModifications.mPlayerModifications(); this.Modifications = new PlayerModifications(this); - this._Modifications = new mPlayerModifications(); } public void OnDie() @@ -298,67 +294,5 @@ public void OnDie() CurrentWearings = new PlayerWearings(); } } - public class mPlayerModifications - { - public float RunningSpeedMultiplier = 1f; - public float ReceiveDamageMultiplier = 1f; - public float GiveDamageMultiplier = 1f; - public float JumpHeightMultiplier = 1f; - public float FallDamageMultiplier = 1f; - public float ReloadSpeedMultiplier = 1f; - public bool CanUseNightVision = true; - public bool HasCollision = false; - public float DownTimeGiveUpTime = 60f; - public bool AirStrafe = true; - public bool CanSpawn = true; - public bool CanSpectate = true; - public bool IsTextChatMuted = false; - public bool IsVoiceChatMuted = false; - public float RespawnTime = 10f; - public bool CanRespawn = true; - - public bool IsDirtyFlag = false; - public void Write(BattleBitAPI.Common.Serialization.Stream ser) - { - ser.Write(this.RunningSpeedMultiplier); - ser.Write(this.ReceiveDamageMultiplier); - ser.Write(this.GiveDamageMultiplier); - ser.Write(this.JumpHeightMultiplier); - ser.Write(this.FallDamageMultiplier); - ser.Write(this.ReloadSpeedMultiplier); - ser.Write(this.CanUseNightVision); - ser.Write(this.HasCollision); - ser.Write(this.DownTimeGiveUpTime); - ser.Write(this.AirStrafe); - ser.Write(this.CanSpawn); - ser.Write(this.CanSpectate); - ser.Write(this.IsTextChatMuted); - ser.Write(this.IsVoiceChatMuted); - ser.Write(this.RespawnTime); - ser.Write(this.CanRespawn); - } - public void Read(BattleBitAPI.Common.Serialization.Stream ser) - { - this.RunningSpeedMultiplier = ser.ReadFloat(); - if (this.RunningSpeedMultiplier <= 0f) - this.RunningSpeedMultiplier = 0.01f; - - this.ReceiveDamageMultiplier = ser.ReadFloat(); - this.GiveDamageMultiplier = ser.ReadFloat(); - this.JumpHeightMultiplier = ser.ReadFloat(); - this.FallDamageMultiplier = ser.ReadFloat(); - this.ReloadSpeedMultiplier = ser.ReadFloat(); - this.CanUseNightVision = ser.ReadBool(); - this.HasCollision = ser.ReadBool(); - this.DownTimeGiveUpTime = ser.ReadFloat(); - this.AirStrafe = ser.ReadBool(); - this.CanSpawn = ser.ReadBool(); - this.CanSpectate = ser.ReadBool(); - this.IsTextChatMuted = ser.ReadBool(); - this.IsVoiceChatMuted = ser.ReadBool(); - this.RespawnTime = ser.ReadFloat(); - this.CanRespawn = ser.ReadBool(); - } - } } } diff --git a/BattleBitAPI/Server/ServerListener.cs b/BattleBitAPI/Server/ServerListener.cs index 5a4d261b..4177d6c3 100644 --- a/BattleBitAPI/Server/ServerListener.cs +++ b/BattleBitAPI/Server/ServerListener.cs @@ -1,15 +1,10 @@ -using System.Diagnostics; -using System.Net; -using System.Net.Security; +using System.Net; using System.Net.Sockets; using System.Numerics; -using System.Xml; using BattleBitAPI.Common; using BattleBitAPI.Common.Extentions; -using BattleBitAPI.Common.Serialization; using BattleBitAPI.Networking; using CommunityServerAPI.BattleBitAPI; -using CommunityServerAPI.BattleBitAPI.Server; namespace BattleBitAPI.Server { @@ -35,6 +30,22 @@ public class ServerListener : IDisposable where TPlayer : /// public Func> OnGameServerConnecting { get; set; } + /// + /// Fired when server needs to validate token from incoming connection.
+ /// Default, any connection attempt will be accepted + ///
+ /// + /// + /// IPAddress: IP of incoming connection
+ /// ushort: Game Port of the connection
+ /// string: Token of connection
+ ///
+ /// + /// + /// Returns: true if allow connection, false if deny the connection. + /// + public Func> OnValidateGameServerToken { get; set; } + /// /// Fired when a game server connects. /// @@ -178,6 +189,24 @@ private async Task mInternalOnClientConnecting(TcpClient client) throw new Exception("Incoming package wasn't hail."); } + //Read the server name + string token; + { + readStream.Reset(); + if (!await networkStream.TryRead(readStream, 2, source.Token)) + throw new Exception("Unable to read the Token Size"); + + int stringSize = readStream.ReadUInt16(); + if (stringSize > Const.MaxTokenSize) + throw new Exception("Invalid token size"); + + readStream.Reset(); + if (!await networkStream.TryRead(readStream, stringSize, source.Token)) + throw new Exception("Unable to read the token"); + + token = readStream.ReadString(stringSize); + } + //Read port int gamePort; { @@ -187,6 +216,12 @@ private async Task mInternalOnClientConnecting(TcpClient client) gamePort = readStream.ReadUInt16(); } + if (OnValidateGameServerToken != null) + allow = await OnValidateGameServerToken(ip, (ushort)gamePort, token); + + if (!allow) + throw new Exception("Token was not valid!"); + //Read is server protected bool isPasswordProtected; { @@ -349,6 +384,7 @@ private async Task mInternalOnClientConnecting(TcpClient client) server = this.mInstanceDatabase.GetServerInstance(hash, out bool isNew, out resources); resources.Set( this.mExecutePackage, + this.mGetPlayerInternals, client, ip, gamePort, @@ -409,7 +445,7 @@ private async Task mInternalOnClientConnecting(TcpClient client) //Round Settings { readStream.Reset(); - if (!await networkStream.TryRead(readStream, GameServer.mRoundSettings.Size, source.Token)) + if (!await networkStream.TryRead(readStream, RoundSettings.mRoundSettings.Size, source.Token)) throw new Exception("Unable to read the round settings"); resources._RoundSettings.Read(readStream); } @@ -531,13 +567,26 @@ private async Task mInternalOnClientConnecting(TcpClient client) playerInternal.CurrentLoadout = loadout; playerInternal.CurrentWearings = wearings; + //Modifications + { + readStream.Reset(); + if (!await networkStream.TryRead(readStream, 4, source.Token)) + throw new Exception("Unable to read the Modifications Size"); + int modificationSize = (int)readStream.ReadUInt32(); + + readStream.Reset(); + if (!await networkStream.TryRead(readStream, modificationSize, source.Token)) + throw new Exception("Unable to read the Modifications"); + playerInternal._Modifications.Read(readStream); + } + + //Call new instance callback if needed. if (isNewClient) { if (this.OnCreatingPlayerInstance != null) this.OnCreatingPlayerInstance(player); } - resources.AddPlayer(player); } @@ -677,6 +726,9 @@ private async Task mExecutePackage(GameServer server, GameServer.mRoundSettings.Size)) + if (stream.CanRead(RoundSettings.mRoundSettings.Size)) { var oldState = resources._RoundSettings.State; resources._RoundSettings.Read(stream); @@ -1187,6 +1239,12 @@ async Task mHandle() } } + // --- Private --- + private Player.Internal mGetPlayerInternals(ulong steamID) + { + return mInstanceDatabase.GetPlayerInternals(steamID); + } + // --- Public --- public IEnumerable ConnectedGameServers { diff --git a/Program.cs b/Program.cs index 022a2b98..9c041c0a 100644 --- a/Program.cs +++ b/Program.cs @@ -1,6 +1,8 @@ using BattleBitAPI; using BattleBitAPI.Common; using BattleBitAPI.Server; +using System.Net; +using System.Numerics; using System.Threading.Channels; using System.Xml; @@ -9,16 +11,29 @@ class Program static void Main(string[] args) { var listener = new ServerListener(); + listener.OnGameServerConnecting += OnGameServerConnecting; + listener.OnValidateGameServerToken += OnValidateGameServerToken; listener.Start(29294); Thread.Sleep(-1); } + private static async Task OnValidateGameServerToken(IPAddress ip, ushort gameport, string sentToken) + { + await Console.Out.WriteLineAsync(ip + ":" + gameport + " sent " + sentToken); + return true; + } + + private static async Task OnGameServerConnecting(IPAddress arg) + { + await Console.Out.WriteLineAsync(arg.ToString() + " connecting"); + return true; + } } class MyPlayer : Player { - public override async Task OnConnected() + public override async Task OnSpawned() { } } @@ -27,14 +42,25 @@ class MyGameServer : GameServer public override async Task OnConnected() { ForceStartGame(); + ServerSettings.PlayerCollision = true; + } + public override async Task OnDisconnected() + { + await Console.Out.WriteLineAsync("Disconnected: "+ this.TerminationReason); + } - ServerSettings.PointLogEnabled = false; + public override async Task OnTick() + { + base.ServerSettings.PlayerCollision = true; + foreach (var item in AllPlayers) + item.Modifications.CanSuicide = true; } public override async Task OnPlayerConnected(MyPlayer player) { await Console.Out.WriteLineAsync("Connected: " + player); + } public override async Task OnPlayerSpawned(MyPlayer player) { From 1cc92edc8dc0311834b76c6bd0b7fc1d529c670c Mon Sep 17 00:00:00 2001 From: caesarakalaeii Date: Thu, 17 Aug 2023 19:03:39 +0200 Subject: [PATCH 6/6] got rid of some stuff --- MyProgram.cs | 405 --------------------------------------------------- 1 file changed, 405 deletions(-) delete mode 100644 MyProgram.cs diff --git a/MyProgram.cs b/MyProgram.cs deleted file mode 100644 index f79cbdff..00000000 --- a/MyProgram.cs +++ /dev/null @@ -1,405 +0,0 @@ -using System.Text.Json; -using BattleBitAPI; -using BattleBitAPI.Common; -using BattleBitAPI.Server; -using CommunityServerAPI; -using CommunityServerAPI.server_utilities; - -internal class MyProgram -{ - private static void Main(string[] args) - { - Console.WriteLine("Starting API"); - var listener = new ServerListener(); - listener.Start(55669); - Thread.Sleep(-1); - } -} - -public class GameMode : GameServer -{ - public string Name = string.Empty; - - public virtual void Reset() - { - } -} - -public class MyPlayer : Player -{ - public int Level; -} - -public class MyGameServer : GameServer -{ - private const string AdminJson = "./config/admins.json"; - private const string SteamIdJson = "./config/streamer_steamids.json"; - private readonly List mAdmins = new(); - - private readonly List mChatCommands = new() - { - new HealCommand(), - new KillCommand(), - new TeleportCommand(), - new GrenadeCommand(), - new ForceStartCommand(), - new SpeedCommand(), - new HelpCommand(), - new RevealCommand(), - new ChangeDamageCommand(), - new ChangeReceivedDamageCommand(), - new ChangeAmmoCommand(), - new SetStreamerCommand(), - new RemoveStreamerCommand(), - new OpCommand(), - new DeopCommand(), - new NextGameModeCommand(), - new SetGameModeCommand(), - new TogglePlaylistCommand() - }; - - private readonly List mGameModes = new() - { - new TeamGunGame(), - new LifeSteal(), - new Swap(), - new Hardcore(), - new MeleeOnly(), - new GunGame() - }; - - //public CommandQueue queue = new(); - private readonly List mListedStreamers = new(); - - private GameMode mCurrentGameMode = new GunGame(); - - private bool mCyclePlaylist; - private int mGameModeIndex; - - //modular GameModes: CHECK if new Gamemodes need more passthrough - - - public override Task OnAPlayerDownedAnotherPlayer(OnPlayerKillArguments args) - { - return mCurrentGameMode.OnAPlayerDownedAnotherPlayer(args); - } - - public override Task OnPlayerGivenUp(MyPlayer player) - { - return mCurrentGameMode.OnPlayerGivenUp(player); - } - - - public override Task OnPlayerSpawned(MyPlayer player) - { - return mCurrentGameMode.OnPlayerSpawned(player); - } - - public override Task OnPlayerSpawning(MyPlayer player, OnPlayerSpawnArguments request) - { - return mCurrentGameMode.OnPlayerSpawning(player, request); - } - - public override Task OnRoundEnded() - { - if (mCyclePlaylist) mGameModeIndex = (mGameModeIndex + 1) % mGameModes.Count; - return mCurrentGameMode.OnRoundEnded(); - } - - public override Task OnRoundStarted() - { - mCurrentGameMode = mGameModes[mGameModeIndex]; - return mCurrentGameMode.OnRoundStarted(); - } - - //basic Functionality - - public override Task OnDisconnected() - { - Console.WriteLine("Server disconnected"); - return base.OnDisconnected(); - } - - - public override Task OnPlayerDisconnected(MyPlayer player) - { - Console.WriteLine($"{player.Name} disconnected"); - return mCurrentGameMode.OnPlayerDisconnected(player); - } - - - public override Task OnPlayerJoiningToServer(ulong steamID, PlayerJoiningArguments args) - { - args.Stats.Progress.Rank = 200; - args.Stats.Progress.Prestige = 10; - - return mCurrentGameMode.OnPlayerJoiningToServer(steamID, args); - } - - - public override async Task OnPlayerTypedMessage(MyPlayer player, ChatChannel channel, string msg) - { - if (msg.StartsWith("!fetch")) - { - player.Message("Fetching Admins and Streamers", 2f); - FetchStreamers(); - FetchAdmins(); - } - - if (!mAdmins.Contains(player.SteamID)) return true; - var splits = msg.Split(" "); - foreach (var command in mChatCommands) - if (splits[0] == command.CommandPrefix) - { - var c = command.ChatCommand(player, channel, msg); - await HandleCommand(c); - return false; - } - - return await mCurrentGameMode.OnPlayerTypedMessage(player, channel, msg); - } - - - public void SaveStreamers() - { - try - { - var newJson = - JsonSerializer.Serialize(mListedStreamers, new JsonSerializerOptions { WriteIndented = true }); - - // Write the JSON to the file, overwriting its content - File.WriteAllText(SteamIdJson, newJson); - - Console.WriteLine("Steam IDs updated and saved to the file."); - } - catch (Exception ex) - { - Console.WriteLine("Steam IDs couldn't be updated and saved to the file." + ex); - } - } - - public void SaveAdmins() - { - try - { - var newJson = - JsonSerializer.Serialize(mAdmins, new JsonSerializerOptions { WriteIndented = true }); - - // Write the JSON to the file, overwriting its content - File.WriteAllText(AdminJson, newJson); - - Console.WriteLine("Admins updated and saved to the file."); - } - catch (Exception ex) - { - Console.WriteLine("Admins couldn't be updated and saved to the file." + ex); - } - } - - public override Task OnReconnected() - { - Console.Out.WriteLine($"Current GameMode: {mCurrentGameMode.Name}"); - return base.OnReconnected(); - } - - public void FetchStreamers() - { - Console.Out.WriteLine("Fetching configs"); - try - { - // Read the entire JSON file as a string - var jsonFilePath = SteamIdJson; - var jsonString = File.ReadAllText(jsonFilePath); - - // Parse the JSON array using System.Text.Json - var steamIds = JsonSerializer.Deserialize(jsonString); - foreach (var steamId in steamIds) mListedStreamers.Add(steamId); - Console.Out.WriteLine("Fetching streamers succeeded"); - } - catch (Exception ex) - { - Console.Out.WriteLine("Fetching streamers failed: " + ex); - } - } - - public void FetchAdmins() - { - try - { - // Read the entire JSON file as a string - var jsonFilePath = AdminJson; - var jsonString = File.ReadAllText(jsonFilePath); - - // Parse the JSON array using System.Text.Json - var steamIds = JsonSerializer.Deserialize(jsonString); - foreach (var steamId in steamIds) mAdmins.Add(steamId); - Console.Out.WriteLine("Fetching admins succeeded"); - } - catch (Exception ex) - { - Console.Out.WriteLine("Fetching admins failed: " + ex); - } - } - - public override async Task OnConnected() - { - mCurrentGameMode = mGameModes[mGameModeIndex]; - await Console.Out.WriteLineAsync(GameIP + " Connected"); - FetchStreamers(); - FetchAdmins(); - } - - - public override async Task OnPlayerConnected(MyPlayer player) - { - await Console.Out.WriteLineAsync(player.Name + " Connected"); - if (!mListedStreamers.Contains(player.SteamID)) return true; - player.Message($"Current GameMode is: {mCurrentGameMode.Name}", 4f); - return true; - } - - - public async Task HandleCommand(Command c) - { - // need testing if blocking - foreach (var player in AllPlayers) - { - if (!mListedStreamers.Contains(player.SteamID)) continue; - if (player.SteamID != c.StreamerId) continue; - switch (c.Action) - { - case ActionType.Heal: - { - player.Heal(c.Amount); - player.Message($"{c.ExecutorName} has healed you for {c.Amount}", 2f); - break; - } - case ActionType.Kill: - { - player.Kill(); - player.Message($"{c.ExecutorName} has killed you", 2f); - break; - } - case ActionType.Grenade: - { - //can't spawn stuff, also no playerPOS - player.Message($"{c.ExecutorName} has spawned a grenade on you", 2f); - break; - } - case ActionType.Teleport: - { - //relative teleport???? - player.Message($"{c.ExecutorName} has teleported you {c.Data}", 2f); - break; - } - case ActionType.Speed: - { - player.SetRunningSpeedMultiplier(c.Amount); - player.Message($"{c.ExecutorName} has set your speed to {c.Amount}x", 2f); - break; - } - case ActionType.Reveal: - { - //set marker on Map - player.Message($"{c.ExecutorName} has revealed your Position", 2f); - break; - } - case ActionType.ChangeAmmo: - { - player.Message($"{c.ExecutorName} has set your Ammo to {c.Amount}", 2f); - break; - } - case ActionType.Start: - { - player.Message("Forcing start", 2f); - ForceStartGame(); - break; - } - case ActionType.Help: - { - foreach (var command in mChatCommands) SayToChat($"{command.CommandPrefix} {command.Help}"); - break; - } - case ActionType.ChangeDamage: - { - player.SetGiveDamageMultiplier(c.Amount); - player.Message($"{c.ExecutorName} has set your Dmg Multiplier to {c.Amount}", 2f); - break; - } - case ActionType.ChangeReceivedDamage: - { - player.SetReceiveDamageMultiplier(c.Amount); - player.Message($"{c.ExecutorName} has set your recieve Dmg Multiplier to {c.Amount}", 2f); - break; - } - case ActionType.SetStreamer: - { - player.Message("You are now a streamer", 2f); - mListedStreamers.Add(player.SteamID); - SaveStreamers(); - break; - } - case ActionType.RemoveStreamer: - { - player.Message("You are no longer a streamer", 2f); - mListedStreamers.Remove(player.SteamID); - SaveStreamers(); - break; - } - case ActionType.GrantOP: - { - player.Message("You are now an admin", 2f); - mAdmins.Add(player.SteamID); - SaveAdmins(); - break; - } - case ActionType.RevokeOP: - { - player.Message("You are no longer an Admin", 2f); - mAdmins.Remove(player.SteamID); - SaveAdmins(); - break; - } - case ActionType.NextGameMode: - { - mCurrentGameMode.Reset(); - mGameModeIndex = (mGameModeIndex + 1) % mGameModes.Count; - mCurrentGameMode = mGameModes[mGameModeIndex]; - AnnounceShort($"GameMode is now {mCurrentGameMode.Name}"); - Console.WriteLine($"GameMode is now {mCurrentGameMode.Name}"); - mCurrentGameMode.Reset(); - break; - } - case ActionType.SetGameMode: - { - mCurrentGameMode.Reset(); - foreach (var gameMode in mGameModes) - if (gameMode.Name == c.ExecutorName) - { - mCurrentGameMode = gameMode; - mGameModeIndex = mGameModes.IndexOf(gameMode); - } - - AnnounceShort($"GameMode is now {mCurrentGameMode.Name}"); - mCurrentGameMode.Reset(); - break; - } - case ActionType.TogglePlaylist: - { - mCyclePlaylist = !mCyclePlaylist; - AnnounceShort($"GameModePlaylist is now {mCyclePlaylist}"); - break; - } - // Add more cases for other ActionType values as needed - } - } - } - -/* - set admin role - if (steamID == ID) - { - stats.Roles = Roles.Admin; - } - */ -} \ No newline at end of file