From 18e9e37a98def699b97d6b5f1fca40b23cad0571 Mon Sep 17 00:00:00 2001 From: Nexd Date: Sun, 12 Nov 2023 03:19:57 +0100 Subject: [PATCH] `CoreConfig` implementation on the managed side (#62) Co-authored-by: Michael Wilson --- .../counterstrikesharp/configs/core.json | 5 + .../docs/reference/core-configuration.md | 26 ++++ .../CounterStrikeSharp.API/Core/CoreConfig.cs | 118 ++++++++++++++++++ .../Core/GlobalContext.cs | 3 + .../Modules/Memory/Schema.cs | 50 ++++++++ 5 files changed, 202 insertions(+) create mode 100644 configs/addons/counterstrikesharp/configs/core.json create mode 100644 docs/src/content/docs/reference/core-configuration.md create mode 100644 managed/CounterStrikeSharp.API/Core/CoreConfig.cs diff --git a/configs/addons/counterstrikesharp/configs/core.json b/configs/addons/counterstrikesharp/configs/core.json new file mode 100644 index 000000000..3f97851a1 --- /dev/null +++ b/configs/addons/counterstrikesharp/configs/core.json @@ -0,0 +1,5 @@ +{ + "PublicChatTrigger": "!", + "SilentChatTrigger": "/", + "FollowCS2ServerGuidelines": true +} \ No newline at end of file diff --git a/docs/src/content/docs/reference/core-configuration.md b/docs/src/content/docs/reference/core-configuration.md new file mode 100644 index 000000000..6e1e740cb --- /dev/null +++ b/docs/src/content/docs/reference/core-configuration.md @@ -0,0 +1,26 @@ +--- +title: Core Configuration +description: Summary for core configuration values +--- + +## PublicChatTrigger + +List of characters to use for public chat triggers. + +## SilentChatTrigger + +List of characters to use for silent chat triggers. + +## FollowCS2ServerGuidelines + +Per [CS2 Server Guidelines](https://blog.counter-strike.net/index.php/server_guidelines/), certain plugin +functionality will trigger all of the game server owner's Game Server Login Tokens +(GSLTs) to get banned when executed on a Counter-Strike 2 game server. + +Enabling this option will block plugins from using functionality that is known to cause this. +This option only has any effect on CS2. Note that this does NOT guarantee that you cannot +receive a ban. + +:::note +Disable this option at your own risk. +::: \ No newline at end of file diff --git a/managed/CounterStrikeSharp.API/Core/CoreConfig.cs b/managed/CounterStrikeSharp.API/Core/CoreConfig.cs new file mode 100644 index 000000000..921cff7c5 --- /dev/null +++ b/managed/CounterStrikeSharp.API/Core/CoreConfig.cs @@ -0,0 +1,118 @@ +/* + * This file is part of CounterStrikeSharp. + * CounterStrikeSharp is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * CounterStrikeSharp is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with CounterStrikeSharp. If not, see . * + */ + +using System; +using System.IO; +using System.Reflection; +using System.Text.Json; +using System.Text.Json.Serialization; + +using CounterStrikeSharp.API.Modules.Utils; +using CounterStrikeSharp.API.Modules.Admin; +using CounterStrikeSharp.API.Modules.Commands; + +namespace CounterStrikeSharp.API.Core +{ + /// + /// Serializable instance of the CoreConfig + /// + internal sealed partial class CoreConfigData + { + [JsonPropertyName("PublicChatTrigger")] public string PublicChatTrigger { get; internal set; } = "!"; + + [JsonPropertyName("SilentChatTrigger")] public string SilentChatTrigger { get; internal set; } = "/"; + + [JsonPropertyName("FollowCS2ServerGuidelines")] public bool FollowCS2ServerGuidelines { get; internal set; } = true; + } + + /// + /// Configuration related to the Core API. + /// + public static partial class CoreConfig + { + /// + /// List of characters to use for public chat triggers. + /// + public static string PublicChatTrigger => _coreConfig.PublicChatTrigger; + + /// + /// List of characters to use for silent chat triggers. + /// + public static string SilentChatTrigger => _coreConfig.SilentChatTrigger; + + /// + /// + /// Per , certain plugin + /// functionality will trigger all of the game server owner's Game Server Login Tokens + /// (GSLTs) to get banned when executed on a Counter-Strike 2 game server. + /// + /// + /// + /// Enabling this option will block plugins from using functionality that is known to cause this. + /// Note that this does NOT guarantee that you cannot + /// receive a ban. + /// + /// + /// + /// Disable this option at your own risk. + /// + /// + public static bool FollowCS2ServerGuidelines => _coreConfig.FollowCS2ServerGuidelines; + } + + public static partial class CoreConfig + { + private static CoreConfigData _coreConfig = new CoreConfigData(); + + static CoreConfig() + { + CommandUtils.AddStandaloneCommand("css_core_reload", "Reloads the core configuration file.", ReloadCoreConfigCommand); + } + + [RequiresPermissions("@css/config")] + [CommandHelper(whoCanExecute: CommandUsage.CLIENT_AND_SERVER)] + private static void ReloadCoreConfigCommand(CCSPlayerController? player, CommandInfo command) + { + var rootDir = new FileInfo(Assembly.GetExecutingAssembly().Location).Directory.Parent; + Load(Path.Combine(rootDir.FullName, "configs", "core.json")); + } + + public static void Load(string coreConfigPath) + { + if (!File.Exists(coreConfigPath)) + { + Console.WriteLine($"Core configuration could not be found at path '{coreConfigPath}', fallback values will be used."); + return; + } + + try + { + var data = JsonSerializer.Deserialize(File.ReadAllText(coreConfigPath), new JsonSerializerOptions() { ReadCommentHandling = JsonCommentHandling.Skip }); + + if (data != null) + { + _coreConfig = data; + } + + Console.WriteLine($"Loaded core configuration"); + } + catch (Exception ex) + { + Console.WriteLine($"Failed to load core configuration: {ex}, fallback values will be used."); + } + } + } +} diff --git a/managed/CounterStrikeSharp.API/Core/GlobalContext.cs b/managed/CounterStrikeSharp.API/Core/GlobalContext.cs index 9868bde34..f75dc261e 100644 --- a/managed/CounterStrikeSharp.API/Core/GlobalContext.cs +++ b/managed/CounterStrikeSharp.API/Core/GlobalContext.cs @@ -59,6 +59,9 @@ public void OnNativeUnload() } public void InitGlobalContext() { + Console.WriteLine("Loading CoreConfig from \"configs/core.json\""); + CoreConfig.Load(Path.Combine(rootDir.FullName, "configs", "core.json")); + Console.WriteLine("Loading GameData from \"gamedata/gamedata.json\""); GameData.Load(Path.Combine(rootDir.FullName, "gamedata", "gamedata.json")); diff --git a/managed/CounterStrikeSharp.API/Modules/Memory/Schema.cs b/managed/CounterStrikeSharp.API/Modules/Memory/Schema.cs index 2b5cb9c46..20569c825 100644 --- a/managed/CounterStrikeSharp.API/Modules/Memory/Schema.cs +++ b/managed/CounterStrikeSharp.API/Modules/Memory/Schema.cs @@ -10,8 +10,53 @@ public class Schema { private static Dictionary, short> _schemaOffsets = new(); + private static HashSet _cs2BadList = new HashSet() + { + "m_bIsValveDS", + "m_bIsQuestEligible", + // "m_iItemDefinitionIndex", // as of 2023.11.11 this is currently not blocked + "m_iEntityLevel", + "m_iItemIDHigh", + "m_iItemIDLow", + "m_iAccountID", + "m_iEntityQuality", + + "m_bInitialized", + "m_szCustomName", + "m_iAttributeDefinitionIndex", + "m_iRawValue32", + "m_iRawInitialValue32", + "m_flValue", // MNetworkAlias "m_iRawValue32" + "m_flInitialValue", // MNetworkAlias "m_iRawInitialValue32" + "m_bSetBonus", + "m_nRefundableCurrency", + + "m_OriginalOwnerXuidLow", + "m_OriginalOwnerXuidHigh", + + "m_nFallbackPaintKit", + "m_nFallbackSeed", + "m_flFallbackWear", + "m_nFallbackStatTrak", + + "m_iCompetitiveWins", + "m_iCompetitiveRanking", + "m_iCompetitiveRankType", + "m_iCompetitiveRankingPredicted_Win", + "m_iCompetitiveRankingPredicted_Loss", + "m_iCompetitiveRankingPredicted_Tie", + + "m_nActiveCoinRank", + "m_nMusicID", + }; + public static short GetSchemaOffset(string className, string propertyName) { + if (CoreConfig.FollowCS2ServerGuidelines && _cs2BadList.Contains(propertyName)) + { + throw new Exception($"Cannot set or get '{className}::{propertyName}' with \"FollowCS2ServerGuidelines\" option enabled."); + } + var key = new Tuple(className, propertyName); if (!_schemaOffsets.TryGetValue(key, out var offset)) { @@ -29,6 +74,11 @@ public static T GetSchemaValue(IntPtr handle, string className, string proper public static void SetSchemaValue(IntPtr handle, string className, string propertyName, T value) { + if (CoreConfig.FollowCS2ServerGuidelines && _cs2BadList.Contains(propertyName)) + { + throw new Exception($"Cannot set or get '{className}::{propertyName}' with \"FollowCS2ServerGuidelines\" option enabled."); + } + NativeAPI.SetSchemaValueByName(handle, (int)typeof(T).ToDataType(), className, propertyName, value); }