mirror of
https://github.com/roflmuffin/CounterStrikeSharp.git
synced 2025-12-05 23:58:24 -08:00
feat(config): add toml loading support (#804)
This commit is contained in:
@@ -1,6 +1,11 @@
|
||||
using System.Text.Json.Serialization;
|
||||
using CounterStrikeSharp.API.Core;
|
||||
using CounterStrikeSharp.API.Core.Attributes;
|
||||
using CounterStrikeSharp.API.Core.Attributes.Registration;
|
||||
using CounterStrikeSharp.API.Modules.Admin;
|
||||
using CounterStrikeSharp.API.Modules.Commands;
|
||||
using CounterStrikeSharp.API.Modules.Config;
|
||||
using CounterStrikeSharp.API.Modules.Extensions;
|
||||
|
||||
namespace WithConfig;
|
||||
|
||||
@@ -35,4 +40,21 @@ public class WithConfigPlugin : BasePlugin, IPluginConfig<SampleConfig>
|
||||
// Once we've validated the config, we can set it to the instance
|
||||
Config = config;
|
||||
}
|
||||
|
||||
[ConsoleCommand("css_reload_config", "Reloads the plugin config")]
|
||||
public void OnReloadConfig(CCSPlayerController? player, CommandInfo commandInfo)
|
||||
{
|
||||
commandInfo.ReplyToCommand("Chat Interval before reload: " + Config.ChatInterval);
|
||||
Config.Reload();
|
||||
commandInfo.ReplyToCommand("Chat Interval after reload: " + Config.ChatInterval);
|
||||
}
|
||||
|
||||
[ConsoleCommand("css_reset_config", "Resets the plugin config")]
|
||||
public void OnResetConfig(CCSPlayerController? player, CommandInfo commandInfo)
|
||||
{
|
||||
commandInfo.ReplyToCommand("Chat Interval before reset: " + Config.ChatInterval);
|
||||
Config.ChatInterval = 60;
|
||||
Config.Update();
|
||||
commandInfo.ReplyToCommand("Chat Interval after reset: " + Config.ChatInterval);
|
||||
}
|
||||
}
|
||||
File diff suppressed because it is too large
Load Diff
@@ -39,6 +39,7 @@
|
||||
<PackageReference Include="Serilog.Sinks.Console" Version="5.0.0"/>
|
||||
<PackageReference Include="Serilog.Sinks.File" Version="5.0.0"/>
|
||||
<PackageReference Include="System.Data.DataSetExtensions" Version="4.5.0"/>
|
||||
<PackageReference Include="Tomlyn" Version="0.19.0"/>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<Folder Include="Core\Schema\"/>
|
||||
|
||||
@@ -14,18 +14,21 @@
|
||||
* along with CounterStrikeSharp. If not, see <https://www.gnu.org/licenses/>. *
|
||||
*/
|
||||
|
||||
using System;
|
||||
using System.IO;
|
||||
using System.Reflection;
|
||||
using System.Text;
|
||||
using System.Text.Json;
|
||||
|
||||
using CounterStrikeSharp.API.Core;
|
||||
using CounterStrikeSharp.API.Core.Logging;
|
||||
using Microsoft.Extensions.Logging;
|
||||
using Tomlyn;
|
||||
|
||||
namespace CounterStrikeSharp.API.Modules.Config
|
||||
{
|
||||
enum ConfigType
|
||||
{
|
||||
Json,
|
||||
Toml
|
||||
}
|
||||
|
||||
public static class ConfigManager
|
||||
{
|
||||
private static readonly DirectoryInfo? _rootDir;
|
||||
@@ -33,47 +36,59 @@ namespace CounterStrikeSharp.API.Modules.Config
|
||||
private static readonly string _pluginConfigsFolderPath;
|
||||
private static ILogger _logger = CoreLogging.Factory.CreateLogger("ConfigManager");
|
||||
|
||||
internal static JsonSerializerOptions JsonSerializerOptions { get; } = new()
|
||||
{
|
||||
WriteIndented = true,
|
||||
ReadCommentHandling = JsonCommentHandling.Skip
|
||||
};
|
||||
|
||||
internal static TomlModelOptions TomlModelOptions { get; } = new()
|
||||
{
|
||||
ConvertPropertyName = name => name
|
||||
};
|
||||
|
||||
static ConfigManager()
|
||||
{
|
||||
_rootDir = new FileInfo(Assembly.GetExecutingAssembly().Location).Directory.Parent;
|
||||
_pluginConfigsFolderPath = Path.Combine(_rootDir.FullName, "configs", "plugins");
|
||||
}
|
||||
|
||||
public static T Load<T>(string pluginName) where T : IBasePluginConfig, new()
|
||||
public static T Load<T>(string pluginName) where T : class, IBasePluginConfig, new()
|
||||
{
|
||||
string directoryPath = Path.Combine(_pluginConfigsFolderPath, pluginName);
|
||||
string configPath = Path.Combine(directoryPath, $"{pluginName}.json");
|
||||
string exampleConfigPath = Path.Combine(directoryPath, $"{pluginName}.example.json");
|
||||
string configPath = Path.Combine(directoryPath, $"{pluginName}");
|
||||
string exampleConfigPath = Path.Combine(directoryPath, $"{pluginName}.example");
|
||||
|
||||
T config = (T)Activator.CreateInstance(typeof(T))!;
|
||||
string[] configFilePaths =
|
||||
[
|
||||
$"{configPath}.toml",
|
||||
$"{configPath}.json",
|
||||
];
|
||||
|
||||
if (!File.Exists(configPath) && !File.Exists(exampleConfigPath))
|
||||
foreach (var path in configFilePaths)
|
||||
{
|
||||
try
|
||||
if (File.Exists(path))
|
||||
{
|
||||
if (!Directory.Exists(directoryPath))
|
||||
{
|
||||
Directory.CreateDirectory(directoryPath);
|
||||
return Deserialize<T>(path);
|
||||
}
|
||||
}
|
||||
|
||||
StringBuilder builder = new StringBuilder();
|
||||
builder.Append(
|
||||
$"// This configuration was automatically generated by CounterStrikeSharp for plugin '{pluginName}', at {DateTimeOffset.Now:yyyy/MM/dd hh:mm:ss}\n");
|
||||
builder.Append(JsonSerializer.Serialize<T>(config,
|
||||
new JsonSerializerOptions { WriteIndented = true }));
|
||||
File.WriteAllText(configPath, builder.ToString());
|
||||
return config;
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
_logger.LogError(ex, "Failed to generate configuration file for {PluginName}", pluginName);
|
||||
}
|
||||
} else if (File.Exists(exampleConfigPath) && !File.Exists(configPath))
|
||||
string[] exampleFilePaths =
|
||||
[
|
||||
$"{exampleConfigPath}.toml",
|
||||
$"{exampleConfigPath}.json"
|
||||
];
|
||||
|
||||
foreach (var path in exampleFilePaths)
|
||||
{
|
||||
if (!File.Exists(path)) continue;
|
||||
|
||||
try
|
||||
{
|
||||
_logger.LogInformation("Copying example configuration file for {PluginName}", pluginName);
|
||||
File.Copy(exampleConfigPath, configPath);
|
||||
var destPath = Path.Combine(directoryPath, Path.GetFileName(path).Replace(".example", ""));
|
||||
File.Copy(path, destPath);
|
||||
return Deserialize<T>(destPath);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
@@ -83,14 +98,58 @@ namespace CounterStrikeSharp.API.Modules.Config
|
||||
|
||||
try
|
||||
{
|
||||
config = JsonSerializer.Deserialize<T>(File.ReadAllText(configPath), new JsonSerializerOptions() { ReadCommentHandling = JsonCommentHandling.Skip })!;
|
||||
}
|
||||
catch (Exception ex)
|
||||
if (!Directory.Exists(directoryPath))
|
||||
{
|
||||
_logger.LogError(ex, "Failed to parse configuration file for {PluginName}", pluginName);
|
||||
Directory.CreateDirectory(directoryPath);
|
||||
}
|
||||
|
||||
var config = new T();
|
||||
var output = Serialize(config, ConfigType.Json, pluginName);
|
||||
File.WriteAllText(Path.Combine(directoryPath, $"{pluginName}.json"), output);
|
||||
|
||||
return config;
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
_logger.LogError(ex, "Failed to generate configuration file for {PluginName}", pluginName);
|
||||
return new T();
|
||||
}
|
||||
}
|
||||
|
||||
private static T Deserialize<T>(string path) where T : class, IBasePluginConfig, new()
|
||||
{
|
||||
switch (Path.GetExtension(path))
|
||||
{
|
||||
case ".toml":
|
||||
return Toml.ToModel<T>(File.ReadAllText(path), options: TomlModelOptions);
|
||||
case ".json":
|
||||
return JsonSerializer.Deserialize<T>(File.ReadAllText(path), JsonSerializerOptions)!;
|
||||
}
|
||||
|
||||
throw new NotSupportedException("Unsupported configuration file format");
|
||||
}
|
||||
|
||||
private static string Serialize<T>(T config, ConfigType configType, string pluginName) where T : class, IBasePluginConfig, new()
|
||||
{
|
||||
StringBuilder builder = new StringBuilder();
|
||||
string comment =
|
||||
$"This configuration was automatically generated by CounterStrikeSharp for plugin '{pluginName}', at {DateTimeOffset.Now:yyyy/MM/dd hh:mm:ss}\n";
|
||||
|
||||
switch (configType)
|
||||
{
|
||||
case ConfigType.Json:
|
||||
builder.Append($"// {comment}");
|
||||
builder.Append(JsonSerializer.Serialize<T>(config, JsonSerializerOptions));
|
||||
break;
|
||||
case ConfigType.Toml:
|
||||
builder.Append($"# {comment}");
|
||||
builder.Append(Toml.FromModel(config, options: TomlModelOptions));
|
||||
break;
|
||||
default:
|
||||
throw new NotSupportedException("Unsupported configuration file format");
|
||||
}
|
||||
|
||||
return builder.ToString();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,17 +1,14 @@
|
||||
using System.Text.Json;
|
||||
using System.Reflection;
|
||||
using System.Runtime.Serialization;
|
||||
using CounterStrikeSharp.API.Modules.Config;
|
||||
using Tomlyn;
|
||||
|
||||
namespace CounterStrikeSharp.API.Modules.Extensions;
|
||||
|
||||
public static class PluginConfigExtensions
|
||||
{
|
||||
private static readonly JsonSerializerOptions _jsonSerializerOptions = new()
|
||||
{
|
||||
WriteIndented = true,
|
||||
ReadCommentHandling = JsonCommentHandling.Skip
|
||||
};
|
||||
|
||||
public static JsonSerializerOptions JsonSerializerOptions => _jsonSerializerOptions;
|
||||
public static JsonSerializerOptions JsonSerializerOptions => ConfigManager.JsonSerializerOptions;
|
||||
|
||||
/// <summary>
|
||||
/// Gets the configuration file path
|
||||
@@ -21,7 +18,24 @@ public static class PluginConfigExtensions
|
||||
public static string GetConfigPath<T>(this T _) where T : BasePluginConfig, new()
|
||||
{
|
||||
string assemblyName = typeof(T).Assembly.GetName().Name ?? string.Empty;
|
||||
return Path.Combine(Server.GameDirectory, "csgo", "addons", "counterstrikesharp", "configs", "plugins", assemblyName, $"{assemblyName}.json");
|
||||
|
||||
string[] configFilePaths =
|
||||
[
|
||||
Path.Combine(Server.GameDirectory, "csgo", "addons", "counterstrikesharp", "configs", "plugins", assemblyName,
|
||||
$"{assemblyName}.json"),
|
||||
Path.Combine(Server.GameDirectory, "csgo", "addons", "counterstrikesharp", "configs", "plugins", assemblyName,
|
||||
$"{assemblyName}.toml"),
|
||||
];
|
||||
|
||||
foreach (var path in configFilePaths)
|
||||
{
|
||||
if (File.Exists(path))
|
||||
{
|
||||
return path;
|
||||
}
|
||||
}
|
||||
|
||||
return configFilePaths[0];
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -37,7 +51,22 @@ public static class PluginConfigExtensions
|
||||
{
|
||||
using var stream = new FileStream(configPath, FileMode.Create, FileAccess.Write, FileShare.None);
|
||||
using var writer = new StreamWriter(stream);
|
||||
writer.Write(JsonSerializer.Serialize(config, JsonSerializerOptions));
|
||||
|
||||
switch (Path.GetExtension(configPath))
|
||||
{
|
||||
case ".json":
|
||||
{
|
||||
writer.Write(JsonSerializer.Serialize(config, ConfigManager.JsonSerializerOptions));
|
||||
break;
|
||||
}
|
||||
case ".toml":
|
||||
writer.Write(Toml.FromModel(config, ConfigManager.TomlModelOptions));
|
||||
break;
|
||||
default:
|
||||
throw new NotSupportedException($"Configuration file type '{Path.GetExtension(configPath)}' is not supported.");
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
@@ -63,8 +92,22 @@ public static class PluginConfigExtensions
|
||||
|
||||
var configContent = File.ReadAllText(configPath);
|
||||
|
||||
var newConfig = JsonSerializer.Deserialize<T>(configContent, JsonSerializerOptions)
|
||||
T? newConfig = null;
|
||||
switch (Path.GetExtension(configPath))
|
||||
{
|
||||
case ".json":
|
||||
newConfig = JsonSerializer.Deserialize<T>(configContent, ConfigManager.JsonSerializerOptions)
|
||||
?? throw new JsonException($"Deserialization failed for configuration file '{configPath}'.");
|
||||
break;
|
||||
case ".toml":
|
||||
newConfig = Toml.ToModel<T>(configContent, options: ConfigManager.TomlModelOptions);
|
||||
break;
|
||||
}
|
||||
|
||||
if (newConfig is null)
|
||||
{
|
||||
throw new SerializationException($"Deserialization failed for configuration file '{configPath}'.");
|
||||
}
|
||||
|
||||
foreach (var property in typeof(T).GetProperties(BindingFlags.Instance | BindingFlags.Public))
|
||||
{
|
||||
|
||||
Reference in New Issue
Block a user