Compare commits

...

3 Commits
v32 ... v1.0.43

Author SHA1 Message Date
Nexd
12c54cd4fc hotfix: deserializer couldn't call setter (#70) 2023-11-12 22:39:15 +10:00
Michael Wilson
e155a70873 Cross platform builds (#69) 2023-11-12 15:43:51 +10:00
Nexd
69d9b5d2c8 feat: Provide configuration standard for plugins (#67) 2023-11-12 14:25:06 +10:00
10 changed files with 353 additions and 126 deletions

View File

@@ -4,95 +4,185 @@ on:
push:
paths-ignore:
- 'docs/**'
branches: [ "main" ]
branches: [ "main", "feature/cross-platform-builds" ]
env:
BUILD_TYPE: Release
jobs:
build:
permissions:
contents: write
packages: write
runs-on: ubuntu-latest
container:
image: registry.gitlab.steamos.cloud/steamrt/sniper/sdk:latest
build_windows:
runs-on: windows-latest
steps:
- name: Prepare env
shell: bash
run: echo "GITHUB_SHA_SHORT=${GITHUB_SHA::7}" >> $GITHUB_ENV
- name: Setup protobuf
shell: bash
run: sudo apt-get update && sudo apt install -y protobuf-compiler
- name: Visual Studio environment
shell: cmd
run: |
:: See https://github.com/microsoft/vswhere/wiki/Find-VC
for /f "usebackq delims=*" %%i in (`vswhere -latest -property installationPath`) do (
call "%%i"\Common7\Tools\vsdevcmd.bat -arch=x64 -host_arch=x64
)
:: Loop over all environment variables and make them global.
for /f "delims== tokens=1,2" %%a in ('set') do (
echo>>"%GITHUB_ENV%" %%a=%%b
)
- uses: actions/checkout@v3
with:
submodules: 'recursive'
- name: Generate build number
id: buildnumber
uses: onyxmueller/build-tag-number@v1
with:
token: ${{secrets.github_token}}
- uses: actions/setup-dotnet@v3
with:
dotnet-version: '7.0.x'
- run: |
dotnet publish -c Release /p:Version=1.0.${{ env.BUILD_NUMBER }} managed/CounterStrikeSharp.API
dotnet pack -c Release /p:Version=1.0.${{ env.BUILD_NUMBER }} managed/CounterStrikeSharp.API
- name: Configure CMake
run: cmake -B build -DCMAKE_BUILD_TYPE=${{env.BUILD_TYPE}}
- name: Build
# Build your program with the given configuration
run: cmake --build build --config ${{env.BUILD_TYPE}}
run: |
mkdir -p build
cd build
cmake -DCMAKE_BUILD_TYPE=${{env.BUILD_TYPE}} ..
cmake --build . --config ${{env.BUILD_TYPE}} -- /m:16
- name: Clean build directory
run: |
mkdir -p build/addons/counterstrikesharp/bin/win64
mv build/${{env.BUILD_TYPE}}/*.dll build/addons/counterstrikesharp/bin/win64
mkdir build/output/
mv build/addons build/output
- uses: actions/upload-artifact@v3
with:
name: counterstrikesharp-build-windows-${{ env.GITHUB_SHA_SHORT }}
path: build/output/
build_linux:
runs-on: ubuntu-latest
# Could not figure out how to run in a container only on some matrix paths, so I've split it out into its own build.
container:
image: registry.gitlab.steamos.cloud/steamrt/sniper/sdk:latest
steps:
- name: Prepare env
shell: bash
run: echo "GITHUB_SHA_SHORT=${GITHUB_SHA::7}" >> $GITHUB_ENV
- uses: actions/checkout@v3
with:
submodules: 'recursive'
- name: Build
run: |
mkdir -p build
cd build
cmake -DCMAKE_BUILD_TYPE=${{env.BUILD_TYPE}} ..
cmake --build . --config ${{env.BUILD_TYPE}} -- -j16
- name: Clean build directory
run: |
mkdir build/output/
mv build/addons build/output
- name: Add API to Artifacts
run: |
mkdir -p build/output/addons/counterstrikesharp/api
cp -r managed/CounterStrikeSharp.API/bin/Release/net7.0/publish/* build/output/addons/counterstrikesharp/api
- uses: actions/upload-artifact@v3
with:
name: counterstrikesharp-build-linux-${{ env.GITHUB_SHA_SHORT }}
path: build/output/
build_managed:
permissions:
contents: write
runs-on: ubuntu-latest
outputs:
buildnumber: ${{ steps.buildnumber.outputs.build_number }}
steps:
- name: Prepare env
shell: bash
run: echo "GITHUB_SHA_SHORT=${GITHUB_SHA::7}" >> $GITHUB_ENV
# We don't need expensive submodules for the managed side.
- uses: actions/checkout@v3
- name: Generate build number
id: buildnumber
uses: onyxmueller/build-tag-number@v1
with:
token: ${{secrets.github_token}}
- name: Build runtime v${{ env.BUILD_NUMBER }}
uses: actions/setup-dotnet@v3
with:
dotnet-version: '7.0.x'
- run: |
dotnet publish -c Release /p:Version=1.0.${{ env.BUILD_NUMBER }} managed/CounterStrikeSharp.API
dotnet pack -c Release /p:Version=1.0.${{ env.BUILD_NUMBER }} managed/CounterStrikeSharp.API
- uses: actions/upload-artifact@v3
with:
name: counterstrikesharp-build-${{ env.BUILD_NUMBER }}-${{ env.GITHUB_SHA_SHORT }}
path: build/output/
name: counterstrikesharp-build-api-${{ env.GITHUB_SHA_SHORT }}
path: managed/CounterStrikeSharp.API/bin/Release
- name: Zip CounterStrikeSharp Build
run: (cd build/output && zip -qq -r ../../counterstrikesharp-build-${{ env.BUILD_NUMBER }}-${{ env.GITHUB_SHA_SHORT }}.zip *)
publish:
permissions:
contents: write
needs: [ "build_linux", "build_windows", "build_managed" ]
runs-on: ubuntu-latest
steps:
- name: Prepare env
shell: bash
run: echo "GITHUB_SHA_SHORT=${GITHUB_SHA::7}" >> $GITHUB_ENV
- uses: actions/download-artifact@v3
with:
name: counterstrikesharp-build-windows-${{ env.GITHUB_SHA_SHORT }}
path: build/windows
- uses: actions/download-artifact@v3
with:
name: counterstrikesharp-build-linux-${{ env.GITHUB_SHA_SHORT }}
path: build/linux
- uses: actions/download-artifact@v3
with:
name: counterstrikesharp-build-api-${{ env.GITHUB_SHA_SHORT }}
path: build/api
# TODO: This stuff should really be in a matrix
- name: Add API to Artifacts
run: |
mkdir -p build/linux/addons/counterstrikesharp/api
mkdir -p build/windows/addons/counterstrikesharp/api
cp -r build/api/net7.0/publish/* build/linux/addons/counterstrikesharp/api
cp -r build/api/net7.0/publish/* build/windows/addons/counterstrikesharp/api
- name: Zip Builds
run: |
(cd build/linux && zip -qq -r ../../counterstrikesharp-build-${{ needs.build_managed.outputs.buildnumber }}-linux-${{ env.GITHUB_SHA_SHORT }}.zip *)
(cd build/windows && zip -qq -r ../../counterstrikesharp-build-${{ needs.build_managed.outputs.buildnumber }}-windows-${{ env.GITHUB_SHA_SHORT }}.zip *)
- name: Add dotnet runtime
run: |
mkdir -p build/output/addons/counterstrikesharp/dotnet
mkdir -p build/linux/addons/counterstrikesharp/dotnet
curl -s -L https://download.visualstudio.microsoft.com/download/pr/dc2c0a53-85a8-4fda-a283-fa28adb5fbe2/8ccade5bc400a5bb40cd9240f003b45c/aspnetcore-runtime-7.0.11-linux-x64.tar.gz \
| tar xvz -C build/output/addons/counterstrikesharp/dotnet
mv build/output/addons/counterstrikesharp/dotnet/shared/Microsoft.NETCore.App/7.0.11/* build/output/addons/counterstrikesharp/dotnet/shared/Microsoft.NETCore.App/
| tar xvz -C build/linux/addons/counterstrikesharp/dotnet
mv build/linux/addons/counterstrikesharp/dotnet/shared/Microsoft.NETCore.App/7.0.11/* build/linux/addons/counterstrikesharp/dotnet/shared/Microsoft.NETCore.App/
mkdir -p build/windows/addons/counterstrikesharp/dotnet
curl -s -L https://download.visualstudio.microsoft.com/download/pr/a99861c8-2e00-4587-aaef-60366ca77307/a44ceec2c5d34165ae881600f52edc43/aspnetcore-runtime-7.0.11-win-x64.zip -o dotnet.zip
unzip -qq dotnet.zip -d build/windows/addons/counterstrikesharp/dotnet
- name: Zip CounterStrikeSharp Runtime Build
run: (cd build/output && zip -qq -r ../../counterstrikesharp-with-runtime-build-${{ env.BUILD_NUMBER }}-${{ env.GITHUB_SHA_SHORT }}.zip *)
- uses: actions/upload-artifact@v3
with:
name: counterstrikesharp-with-runtime-build-${{ env.BUILD_NUMBER }}-${{ env.GITHUB_SHA_SHORT }}
path: build/output/
- name: Zip Builds
run: |
(cd build/linux && zip -qq -r ../../counterstrikesharp-with-runtime-build-${{ needs.build_managed.outputs.buildnumber }}-linux-${{ env.GITHUB_SHA_SHORT }}.zip *)
(cd build/windows && zip -qq -r ../../counterstrikesharp-with-runtime-build-${{ needs.build_managed.outputs.buildnumber }}-windows-${{ env.GITHUB_SHA_SHORT }}.zip *)
- name: Release
uses: softprops/action-gh-release@v1
with:
tag_name: v${{ env.BUILD_NUMBER }}
tag_name: v${{ needs.build_managed.outputs.buildnumber }}
files: |
counterstrikesharp-build-${{ env.BUILD_NUMBER }}-${{ env.GITHUB_SHA_SHORT }}.zip
counterstrikesharp-with-runtime-build-${{ env.BUILD_NUMBER }}-${{ env.GITHUB_SHA_SHORT }}.zip
counterstrikesharp-build-${{ needs.build_managed.outputs.buildnumber }}-windows-${{ env.GITHUB_SHA_SHORT }}.zip
counterstrikesharp-with-runtime-build-${{ needs.build_managed.outputs.buildnumber }}-windows-${{ env.GITHUB_SHA_SHORT }}.zip
counterstrikesharp-build-${{ needs.build_managed.outputs.buildnumber }}-linux-${{ env.GITHUB_SHA_SHORT }}.zip
counterstrikesharp-with-runtime-build-${{ needs.build_managed.outputs.buildnumber }}-linux-${{ env.GITHUB_SHA_SHORT }}.zip
- name: Publish NuGet package
run: |
dotnet nuget push managed/CounterStrikeSharp.API/bin/Release/CounterStrikeSharp.API.1.0.${{ env.BUILD_NUMBER }}.nupkg --api-key ${{ secrets.NUGET_API_KEY }} --source https://api.nuget.org/v3/index.json --skip-duplicate
dotnet nuget push managed/CounterStrikeSharp.API/bin/Release/CounterStrikeSharp.API.1.0.${{ env.BUILD_NUMBER }}.snupkg --api-key ${{ secrets.NUGET_API_KEY }} --source https://api.nuget.org/v3/index.json --skip-duplicate
dotnet nuget push build/api/CounterStrikeSharp.API.1.0.${{ needs.build_managed.outputs.buildnumber }}.nupkg --api-key ${{ secrets.NUGET_API_KEY }} --source https://api.nuget.org/v3/index.json --skip-duplicate
dotnet nuget push build/api/CounterStrikeSharp.API.1.0.${{ needs.build_managed.outputs.buildnumber }}.snupkg --api-key ${{ secrets.NUGET_API_KEY }} --source https://api.nuget.org/v3/index.json --skip-duplicate

View File

@@ -1,64 +0,0 @@
name: Build
on:
push:
paths-ignore:
- 'docs/**'
branches: [ "win32" ]
env:
BUILD_TYPE: Release
jobs:
matrix:
runs-on: ${{ matrix.os }}
strategy:
matrix:
os: [ubuntu-latest, windows-latest]
steps:
- name: Prepare env
shell: bash
run: echo "GITHUB_SHA_SHORT=${GITHUB_SHA::7}" >> $GITHUB_ENV
- name: Visual Studio environment
if: runner.os == 'Windows'
shell: cmd
run: |
:: See https://github.com/microsoft/vswhere/wiki/Find-VC
for /f "usebackq delims=*" %%i in (`vswhere -latest -property installationPath`) do (
call "%%i"\Common7\Tools\vsdevcmd.bat -arch=x64 -host_arch=x64
)
:: Loop over all environment variables and make them global.
for /f "delims== tokens=1,2" %%a in ('set') do (
echo>>"%GITHUB_ENV%" %%a=%%b
)
- uses: actions/checkout@v3
with:
submodules: 'recursive'
- uses: actions/setup-dotnet@v3
with:
dotnet-version: '7.0.x'
- name: Install Protoc
uses: arduino/setup-protoc@v2
- name: Build Linux
if: runner.os == 'Linux'
run: |
cd ${{github.workspace}}
mkdir -p build
cd build
cmake -DCMAKE_BUILD_TYPE=${{env.BUILD_TYPE}} ..
cmake --build . --config ${{env.BUILD_TYPE}} -- -j16
- name: Build Windows
if: runner.os == 'Windows'
run: |
cd ${{github.workspace}}
mkdir -p build
cd build
cmake -DCMAKE_BUILD_TYPE=${{env.BUILD_TYPE}} ..
cmake --build . --config ${{env.BUILD_TYPE}} -- /m:16

View File

@@ -0,0 +1,4 @@
Place your plugin configurations here.
TestPlugin/TestPlugin.json
AnotherPlugin/AnotherPlugin.json

View File

@@ -30,6 +30,8 @@ using CounterStrikeSharp.API.Modules.Events;
using CounterStrikeSharp.API.Modules.Entities;
using CounterStrikeSharp.API.Modules.Listeners;
using CounterStrikeSharp.API.Modules.Timers;
using McMaster.NETCore.Plugins;
using CounterStrikeSharp.API.Modules.Config;
namespace CounterStrikeSharp.API.Core
{
@@ -333,6 +335,31 @@ namespace CounterStrikeSharp.API.Core
this.RegisterConsoleCommandAttributeHandlers(instance);
}
public void InitializeConfig(object instance, Type pluginType)
{
Type[] interfaces = pluginType.GetInterfaces();
Func<Type, bool> predicate = (i => i.IsGenericType && i.GetGenericTypeDefinition() == typeof(IPluginConfig<>));
// if the plugin has set a configuration type (implements IPluginConfig<>)
if (interfaces.Any(predicate))
{
// IPluginConfig<>
Type @interface = interfaces.Where(predicate).FirstOrDefault()!;
// custom config type passed as generic
Type genericType = @interface!.GetGenericArguments().First();
var config = typeof(ConfigManager)
.GetMethod("Load")!
.MakeGenericMethod(genericType)
.Invoke(null, new object[] { Path.GetFileName(ModuleDirectory) }) as IBasePluginConfig;
// we KNOW that we can do this "safely"
pluginType.GetRuntimeMethod("OnConfigParsed", new Type[] { genericType })
.Invoke(instance, new object[] { config });
}
}
/// <summary>
/// Registers all game event handlers that are decorated with the `[GameEventHandler]` attribute.
/// </summary>

View File

@@ -0,0 +1,32 @@
/*
* 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 <https://www.gnu.org/licenses/>. *
*/
using System.Text.Json.Serialization;
namespace CounterStrikeSharp.API.Core
{
public interface IBasePluginConfig
{
[JsonPropertyName("ConfigVersion")]
int Version { get; set; }
}
public class BasePluginConfig : IBasePluginConfig
{
[JsonPropertyName("ConfigVersion")]
public virtual int Version { get; set; } = 1;
}
}

View File

@@ -31,11 +31,11 @@ namespace CounterStrikeSharp.API.Core
/// </summary>
internal sealed partial class CoreConfigData
{
[JsonPropertyName("PublicChatTrigger")] public string PublicChatTrigger { get; internal set; } = "!";
[JsonPropertyName("SilentChatTrigger")] public string SilentChatTrigger { get; internal set; } = "/";
[JsonPropertyName("PublicChatTrigger")] public string PublicChatTrigger { get; set; } = "!";
[JsonPropertyName("FollowCS2ServerGuidelines")] public bool FollowCS2ServerGuidelines { get; internal set; } = true;
[JsonPropertyName("SilentChatTrigger")] public string SilentChatTrigger { get; set; } = "/";
[JsonPropertyName("FollowCS2ServerGuidelines")] public bool FollowCS2ServerGuidelines { get; set; } = true;
}
/// <summary>
@@ -62,7 +62,9 @@ namespace CounterStrikeSharp.API.Core
///
/// <para>
/// 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.
/// </para>
///
@@ -101,12 +103,12 @@ namespace CounterStrikeSharp.API.Core
try
{
var data = JsonSerializer.Deserialize<CoreConfigData>(File.ReadAllText(coreConfigPath), new JsonSerializerOptions() { ReadCommentHandling = JsonCommentHandling.Skip });
if (data != null)
{
_coreConfig = data;
}
Console.WriteLine($"Loaded core configuration");
}
catch (Exception ex)

View File

@@ -0,0 +1,28 @@
/*
* 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 <https://www.gnu.org/licenses/>. *
*/
namespace CounterStrikeSharp.API.Core
{
/// <summary>
/// An interface that describes a plugin configuration.
/// </summary>
public interface IPluginConfig<T> where T: IBasePluginConfig, new()
{
T Config { get; set; }
public void OnConfigParsed(T config);
}
}

View File

@@ -20,6 +20,7 @@ using System.Linq;
using System.Reflection;
using System.Threading.Tasks;
using CounterStrikeSharp.API.Core.Attributes;
using CounterStrikeSharp.API.Modules.Config;
using CounterStrikeSharp.API.Modules.Events;
using McMaster.NETCore.Plugins;
@@ -103,6 +104,7 @@ namespace CounterStrikeSharp.API.Core
_plugin = (BasePlugin)Activator.CreateInstance(pluginType)!;
_plugin.ModulePath = _path;
_plugin.RegisterAllAttributes(_plugin);
_plugin.InitializeConfig(_plugin, pluginType);
_plugin.Load(hotReload);
Console.WriteLine($"Finished loading plugin: {Name}");

View File

@@ -0,0 +1,79 @@
/*
* 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 <https://www.gnu.org/licenses/>. *
*/
using System;
using System.IO;
using System.Reflection;
using System.Text;
using System.Text.Json;
using CounterStrikeSharp.API.Core;
namespace CounterStrikeSharp.API.Modules.Config
{
public static class ConfigManager
{
private static readonly DirectoryInfo? _rootDir;
private static readonly string _pluginConfigsFolderPath;
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()
{
string directoryPath = Path.Combine(_pluginConfigsFolderPath, pluginName);
string configPath = Path.Combine(directoryPath, $"{pluginName}.json");
T config = (T)Activator.CreateInstance(typeof(T))!;
if (!File.Exists(configPath))
{
try
{
if (!Directory.Exists(directoryPath))
{
Directory.CreateDirectory(directoryPath);
}
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)
{
Console.WriteLine($"Failed to generate configuration file for {pluginName}: {ex}");
}
}
try
{
config = JsonSerializer.Deserialize<T>(File.ReadAllText(configPath), new JsonSerializerOptions() { ReadCommentHandling = JsonCommentHandling.Skip })!;
}
catch (Exception ex)
{
Console.WriteLine($"Failed to parse configuration '{pluginName}': {ex}");
}
return config;
}
}
}

View File

@@ -18,6 +18,8 @@ using System;
using System.Drawing;
using System.IO;
using System.Linq;
using System.Text.Json.Serialization;
using CounterStrikeSharp.API;
using CounterStrikeSharp.API.Core;
using CounterStrikeSharp.API.Core.Attributes;
@@ -32,8 +34,17 @@ using CounterStrikeSharp.API.Modules.Utils;
namespace TestPlugin
{
[MinimumApiVersion(1)]
public class SamplePlugin : BasePlugin
public class SampleConfig : BasePluginConfig
{
[JsonPropertyName("IsPluginEnabled")]
public bool IsPluginEnabled { get; set; } = true;
[JsonPropertyName("LogPrefix")]
public string LogPrefix { get; set; } = "CSSharp";
}
[MinimumApiVersion(33)]
public class SamplePlugin : BasePlugin, IPluginConfig<SampleConfig>
{
public override string ModuleName => "Sample Plugin";
public override string ModuleVersion => "v1.0.0";
@@ -42,8 +53,24 @@ namespace TestPlugin
public override string ModuleDescription => "A playground of features used for testing";
public SampleConfig Config { get; set; }
// This method is called right before `Load` is called
public void OnConfigParsed(SampleConfig config)
{
// Save config instance
Config = config;
}
public override void Load(bool hotReload)
{
// Basic usage of the configuration system
if (!Config.IsPluginEnabled)
{
Console.WriteLine($"{Config.LogPrefix} {ModuleName} is disabled");
return;
}
Console.WriteLine(
$"Test Plugin has been loaded, and the hot reload flag was {hotReload}, path is {ModulePath}");