mirror of
https://github.com/roflmuffin/CounterStrikeSharp.git
synced 2025-12-06 16:06:37 -08:00
Compare commits
24 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
77b05e912e | ||
|
|
1354b4972d | ||
|
|
8b5eb7e38d | ||
|
|
2dd62c44d3 | ||
|
|
f811338ce4 | ||
|
|
194c340ae7 | ||
|
|
6b0912d3cd | ||
|
|
2d3aa09aa4 | ||
|
|
911084e71e | ||
|
|
5b99206568 | ||
|
|
4bfdf28beb | ||
|
|
11c6486ec5 | ||
|
|
ee69560a66 | ||
|
|
d37e5e194a | ||
|
|
c4740d1cc9 | ||
|
|
7e92f178fd | ||
|
|
107ca08132 | ||
|
|
3d59a05de8 | ||
|
|
77b7040d6c | ||
|
|
75de9732ef | ||
|
|
7c7f52a219 | ||
|
|
cd593fb238 | ||
|
|
c5cc65be48 | ||
|
|
59928bbcc5 |
@@ -63,6 +63,10 @@ public class HelloWorldPlugin : BasePlugin
|
||||
|
||||
public override string ModuleVersion => "0.0.1";
|
||||
|
||||
public override string ModuleAuthor => "roflmuffin";
|
||||
|
||||
public override string ModuleDescription => "Simple hello world plugin";
|
||||
|
||||
public override void Load(bool hotReload)
|
||||
{
|
||||
Logger.LogInformation("Plugin loaded successfully!");
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
{
|
||||
"PublicChatTrigger": [ "!" ],
|
||||
"SilentChatTrigger": [ "/" ],
|
||||
"FollowCS2ServerGuidelines": true
|
||||
"FollowCS2ServerGuidelines": true,
|
||||
"PluginHotReloadEnabled": true
|
||||
}
|
||||
@@ -68,19 +68,20 @@ Now build your project using your ide or the `dotnet build` command. You should
|
||||
|
||||
### Installing your Plugin
|
||||
|
||||
Locate the `plugins` folder in your CS2 dedicated server (`/game/csgo/addons/counterstrikesharp/plugins`) and create a new folder with the exact same name as your output .dll file. In this example it would be `HelloWorldPlugin.dll`, so I will make a new folder called `HelloWorldPlugin`. Inside of this folder, copy and paste all of the `.dll` files _except_ the `CounterStrikeSharp.API.dll` file. Once completed, the folder should look as follows:
|
||||
Locate the `plugins` folder in your CS2 dedicated server (`/game/csgo/addons/counterstrikesharp/plugins`) and create a new folder with the exact same name as your output .dll file. In this example it would be `HelloWorldPlugin.dll`, so I will make a new folder called `HelloWorldPlugin`. Inside of this folder, copy and paste the: `HelloWorldPlugin.deps.json`, `HelloWorldPlugin.dll`, and `HelloWorldPlugin.pdb` files. Once completed, the folder should look as follows:
|
||||
|
||||
```shell
|
||||
.
|
||||
└── SamplePlugin
|
||||
├── McMaster.NETCore.Plugins.dll
|
||||
├── Microsoft.DotNet.PlatformAbstractions.dll
|
||||
├── Microsoft.Extensions.DependencyModel.dll
|
||||
├── SamplePlugin.deps.json
|
||||
├── SamplePlugin.dll
|
||||
└── SamplePlugin.pdb
|
||||
└── HelloWorldPlugin
|
||||
├── HelloWorldPlugin.deps.json
|
||||
├── HelloWorldPlugin.dll
|
||||
└── HelloWorldPlugin.pdb
|
||||
```
|
||||
|
||||
:::caution
|
||||
If you have installed external nuget packages for your plugin, you may need to include their respective `.dll`s. For example, if you utilize the `Stateless` C# library, include `stateless.dll` in your `HelloWorld` plugin directory.
|
||||
:::
|
||||
|
||||
:::note
|
||||
Note that some of these dependencies may change depending on the version of CounterStrikeSharp being used.
|
||||
:::
|
||||
|
||||
@@ -25,6 +25,10 @@ public class HelloWorldPlugin : BasePlugin
|
||||
|
||||
public override string ModuleVersion => "0.0.1";
|
||||
|
||||
public override string ModuleAuthor => "roflmuffin";
|
||||
|
||||
public override string ModuleDescription => "Simple hello world plugin";
|
||||
|
||||
public override void Load(bool hotReload)
|
||||
{
|
||||
Logger.LogInformation("Plugin loaded successfully!");
|
||||
|
||||
@@ -23,4 +23,8 @@ receive a ban.
|
||||
|
||||
:::note
|
||||
Disable this option at your own risk.
|
||||
:::
|
||||
:::
|
||||
|
||||
## PluginHotReloadEnabled
|
||||
|
||||
When enabled, plugins are automatically reloaded when their .dll file is updated.
|
||||
|
||||
12
examples/HelloWorld/HelloWorld.csproj
Normal file
12
examples/HelloWorld/HelloWorld.csproj
Normal file
@@ -0,0 +1,12 @@
|
||||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
<PropertyGroup>
|
||||
<TargetFramework>net7.0</TargetFramework>
|
||||
<ImplicitUsings>enable</ImplicitUsings>
|
||||
<Nullable>enable</Nullable>
|
||||
<GenerateAssemblyInfo>false</GenerateAssemblyInfo>
|
||||
<CopyLocalLockFileAssemblies>false</CopyLocalLockFileAssemblies>
|
||||
</PropertyGroup>
|
||||
<ItemGroup>
|
||||
<ProjectReference Include="..\..\managed\CounterStrikeSharp.API\CounterStrikeSharp.API.csproj" />
|
||||
</ItemGroup>
|
||||
</Project>
|
||||
24
examples/HelloWorld/HelloWorldPlugin.cs
Normal file
24
examples/HelloWorld/HelloWorldPlugin.cs
Normal file
@@ -0,0 +1,24 @@
|
||||
using CounterStrikeSharp.API.Core;
|
||||
using CounterStrikeSharp.API.Core.Attributes;
|
||||
using Microsoft.Extensions.Logging;
|
||||
|
||||
namespace HelloWorld;
|
||||
|
||||
[MinimumApiVersion(80)]
|
||||
public class HelloWorldPlugin : BasePlugin
|
||||
{
|
||||
public override string ModuleName => "Example: Hello World";
|
||||
public override string ModuleVersion => "1.0.0";
|
||||
public override string ModuleAuthor => "CounterStrikeSharp & Contributors";
|
||||
public override string ModuleDescription => "A simple plugin that says hello world!";
|
||||
|
||||
public override void Load(bool hotReload)
|
||||
{
|
||||
Logger.LogInformation("Hello World! We are loading!");
|
||||
}
|
||||
|
||||
public override void Unload(bool hotReload)
|
||||
{
|
||||
Logger.LogInformation("Hello World! We are unloading!");
|
||||
}
|
||||
}
|
||||
2
examples/HelloWorld/README.md
Normal file
2
examples/HelloWorld/README.md
Normal file
@@ -0,0 +1,2 @@
|
||||
# Hello World
|
||||
This is a minimal "Hello World" example that executes code on load & unload.
|
||||
4
examples/WithCommands/README.md
Normal file
4
examples/WithCommands/README.md
Normal file
@@ -0,0 +1,4 @@
|
||||
# With Commands
|
||||
This is an example that shows how to register chat & console commands.
|
||||
|
||||
All commands that are prefixed with "css_" will automatically be registered as a chat command without the prefix. i.e. `css_ping` can be called with `!ping` or `/ping`.
|
||||
12
examples/WithCommands/WithCommands.csproj
Normal file
12
examples/WithCommands/WithCommands.csproj
Normal file
@@ -0,0 +1,12 @@
|
||||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
<PropertyGroup>
|
||||
<TargetFramework>net7.0</TargetFramework>
|
||||
<ImplicitUsings>enable</ImplicitUsings>
|
||||
<Nullable>enable</Nullable>
|
||||
<GenerateAssemblyInfo>false</GenerateAssemblyInfo>
|
||||
<CopyLocalLockFileAssemblies>false</CopyLocalLockFileAssemblies>
|
||||
</PropertyGroup>
|
||||
<ItemGroup>
|
||||
<ProjectReference Include="..\..\managed\CounterStrikeSharp.API\CounterStrikeSharp.API.csproj" />
|
||||
</ItemGroup>
|
||||
</Project>
|
||||
63
examples/WithCommands/WithCommandsPlugin.cs
Normal file
63
examples/WithCommands/WithCommandsPlugin.cs
Normal file
@@ -0,0 +1,63 @@
|
||||
using CounterStrikeSharp.API;
|
||||
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;
|
||||
|
||||
namespace WithCommands;
|
||||
|
||||
[MinimumApiVersion(80)]
|
||||
public class WithCommandsPlugin : BasePlugin
|
||||
{
|
||||
public override string ModuleName => "Example: With Commands";
|
||||
public override string ModuleVersion => "1.0.0";
|
||||
public override string ModuleAuthor => "CounterStrikeSharp & Contributors";
|
||||
public override string ModuleDescription => "A simple plugin that registers some commands";
|
||||
|
||||
public override void Load(bool hotReload)
|
||||
{
|
||||
// All commands that are prefixed with "css_" will automatically be registered as a chat command without the prefix.
|
||||
// i.e. `css_ping` can be called with `!ping` or `/ping`.
|
||||
// Commands can be registered using the instance `AddCommand` method.
|
||||
AddCommand("css_ping", "Responds to the caller with \"pong\"", (player, commandInfo) =>
|
||||
{
|
||||
// The player is null, then the command has been called by the server console.
|
||||
if (player == null)
|
||||
{
|
||||
commandInfo.ReplyToCommand("pong server");
|
||||
return;
|
||||
}
|
||||
|
||||
commandInfo.ReplyToCommand("pong");
|
||||
});
|
||||
}
|
||||
|
||||
// Commands can also be registered using the `Command` attribute.
|
||||
[ConsoleCommand("css_hello", "Responds to the caller with \"pong\"")]
|
||||
// The `CommandHelper` attribute can be used to provide additional information about the command.
|
||||
[CommandHelper(minArgs: 1, usage: "[name]", whoCanExecute: CommandUsage.CLIENT_AND_SERVER)]
|
||||
[RequiresPermissions("@css/cvar")]
|
||||
public void OnHelloCommand(CCSPlayerController? player, CommandInfo commandInfo)
|
||||
{
|
||||
// The first argument is the command name, in this case "css_hello".
|
||||
commandInfo.GetArg(0); // css_hello
|
||||
|
||||
// The second argument is the first argument passed to the command, in this case "name".
|
||||
// The `minArgs` helper parameter is used to ensure that the second argument is present.
|
||||
var name = commandInfo.GetArg(1);
|
||||
|
||||
commandInfo.ReplyToCommand($"Hello {name}");
|
||||
}
|
||||
|
||||
// Permissions can be added to commands using the `RequiresPermissions` attribute.
|
||||
// See the admin documentation for more information on permissions.
|
||||
[RequiresPermissions("@css/kick")]
|
||||
[CommandHelper(minArgs: 1, usage: "[id]", whoCanExecute: CommandUsage.CLIENT_AND_SERVER)]
|
||||
public void OnSpecialCommand(CCSPlayerController? player, CommandInfo commandInfo)
|
||||
{
|
||||
var id = commandInfo.GetArg(1);
|
||||
|
||||
Server.ExecuteCommand($"kick {id}");
|
||||
}
|
||||
}
|
||||
2
examples/WithConfig/README.md
Normal file
2
examples/WithConfig/README.md
Normal file
@@ -0,0 +1,2 @@
|
||||
# WithConfig
|
||||
This example shows how you can implement the `IPluginConfig` interface to allow for semi-automatic config parsing & loading.
|
||||
12
examples/WithConfig/WithConfig.csproj
Normal file
12
examples/WithConfig/WithConfig.csproj
Normal file
@@ -0,0 +1,12 @@
|
||||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
<PropertyGroup>
|
||||
<TargetFramework>net7.0</TargetFramework>
|
||||
<ImplicitUsings>enable</ImplicitUsings>
|
||||
<Nullable>enable</Nullable>
|
||||
<GenerateAssemblyInfo>false</GenerateAssemblyInfo>
|
||||
<CopyLocalLockFileAssemblies>false</CopyLocalLockFileAssemblies>
|
||||
</PropertyGroup>
|
||||
<ItemGroup>
|
||||
<ProjectReference Include="..\..\managed\CounterStrikeSharp.API\CounterStrikeSharp.API.csproj" />
|
||||
</ItemGroup>
|
||||
</Project>
|
||||
38
examples/WithConfig/WithConfigPlugin.cs
Normal file
38
examples/WithConfig/WithConfigPlugin.cs
Normal file
@@ -0,0 +1,38 @@
|
||||
using System.Text.Json.Serialization;
|
||||
using CounterStrikeSharp.API.Core;
|
||||
using CounterStrikeSharp.API.Core.Attributes;
|
||||
|
||||
namespace WithConfig;
|
||||
|
||||
public class SampleConfig : BasePluginConfig
|
||||
{
|
||||
[JsonPropertyName("ChatPrefix")] public string ChatPrefix { get; set; } = "My Cool Plugin";
|
||||
|
||||
[JsonPropertyName("ChatInterval")] public float ChatInterval { get; set; } = 60;
|
||||
}
|
||||
|
||||
[MinimumApiVersion(80)]
|
||||
public class WithConfigPlugin : BasePlugin, IPluginConfig<SampleConfig>
|
||||
{
|
||||
public override string ModuleName => "Example: With Config";
|
||||
public override string ModuleVersion => "1.0.0";
|
||||
|
||||
public SampleConfig Config { get; set; }
|
||||
|
||||
public void OnConfigParsed(SampleConfig config)
|
||||
{
|
||||
// Do manual verification of the config and override any invalid values
|
||||
if (config.ChatInterval > 60)
|
||||
{
|
||||
config.ChatInterval = 60;
|
||||
}
|
||||
|
||||
if (config.ChatPrefix.Length > 25)
|
||||
{
|
||||
throw new Exception($"Invalid value has been set to config value 'ChatPrefix': {config.ChatPrefix}");
|
||||
}
|
||||
|
||||
// Once we've validated the config, we can set it to the instance
|
||||
Config = config;
|
||||
}
|
||||
}
|
||||
2
examples/WithDependencyInjection/README.md
Normal file
2
examples/WithDependencyInjection/README.md
Normal file
@@ -0,0 +1,2 @@
|
||||
# With Dependency Injection
|
||||
This example shows how can you implement the `IPluginServiceCollection` interface to register your services in a provided DI container.
|
||||
@@ -0,0 +1,12 @@
|
||||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
<PropertyGroup>
|
||||
<TargetFramework>net7.0</TargetFramework>
|
||||
<ImplicitUsings>enable</ImplicitUsings>
|
||||
<Nullable>enable</Nullable>
|
||||
<GenerateAssemblyInfo>false</GenerateAssemblyInfo>
|
||||
<CopyLocalLockFileAssemblies>false</CopyLocalLockFileAssemblies>
|
||||
</PropertyGroup>
|
||||
<ItemGroup>
|
||||
<ProjectReference Include="..\..\managed\CounterStrikeSharp.API\CounterStrikeSharp.API.csproj" />
|
||||
</ItemGroup>
|
||||
</Project>
|
||||
@@ -0,0 +1,50 @@
|
||||
using CounterStrikeSharp.API.Core;
|
||||
using CounterStrikeSharp.API.Core.Attributes;
|
||||
using Microsoft.Extensions.DependencyInjection;
|
||||
using Microsoft.Extensions.Logging;
|
||||
|
||||
namespace WithDependencyInjection;
|
||||
|
||||
[MinimumApiVersion(80)]
|
||||
public class WithDependencyInjectionPlugin : BasePlugin
|
||||
{
|
||||
public override string ModuleName => "Example: Dependency Injection";
|
||||
public override string ModuleVersion => "1.0.0";
|
||||
public override string ModuleAuthor => "CounterStrikeSharp & Contributors";
|
||||
public override string ModuleDescription => "An example plugin that uses dependency injection.";
|
||||
|
||||
private readonly TestInjectedClass _testInjectedClass;
|
||||
|
||||
public WithDependencyInjectionPlugin(TestInjectedClass testInjectedClass)
|
||||
{
|
||||
_testInjectedClass = testInjectedClass;
|
||||
}
|
||||
|
||||
public override void Load(bool hotReload)
|
||||
{
|
||||
_testInjectedClass.SayHello();
|
||||
}
|
||||
}
|
||||
|
||||
public class WithDependencyInjectionPluginServiceCollection : IPluginServiceCollection<WithDependencyInjectionPlugin>
|
||||
{
|
||||
public void ConfigureServices(IServiceCollection serviceCollection)
|
||||
{
|
||||
serviceCollection.AddSingleton<TestInjectedClass>();
|
||||
}
|
||||
}
|
||||
|
||||
public class TestInjectedClass
|
||||
{
|
||||
private readonly ILogger<TestInjectedClass> _logger;
|
||||
|
||||
public TestInjectedClass(ILogger<TestInjectedClass> logger)
|
||||
{
|
||||
_logger = logger;
|
||||
}
|
||||
|
||||
public void SayHello()
|
||||
{
|
||||
_logger.LogInformation("Hello World from Test Injected Class");
|
||||
}
|
||||
}
|
||||
2
examples/WithGameEventHandlers/README.md
Normal file
2
examples/WithGameEventHandlers/README.md
Normal file
@@ -0,0 +1,2 @@
|
||||
# With Game Event Handlers
|
||||
This is example shows how you can subscribe to legacy Source 1 game events.
|
||||
12
examples/WithGameEventHandlers/WithGameEventHandlers.csproj
Normal file
12
examples/WithGameEventHandlers/WithGameEventHandlers.csproj
Normal file
@@ -0,0 +1,12 @@
|
||||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
<PropertyGroup>
|
||||
<TargetFramework>net7.0</TargetFramework>
|
||||
<ImplicitUsings>enable</ImplicitUsings>
|
||||
<Nullable>enable</Nullable>
|
||||
<GenerateAssemblyInfo>false</GenerateAssemblyInfo>
|
||||
<CopyLocalLockFileAssemblies>false</CopyLocalLockFileAssemblies>
|
||||
</PropertyGroup>
|
||||
<ItemGroup>
|
||||
<ProjectReference Include="..\..\managed\CounterStrikeSharp.API\CounterStrikeSharp.API.csproj" />
|
||||
</ItemGroup>
|
||||
</Project>
|
||||
@@ -0,0 +1,54 @@
|
||||
using CounterStrikeSharp.API.Core;
|
||||
using CounterStrikeSharp.API.Core.Attributes;
|
||||
using CounterStrikeSharp.API.Core.Attributes.Registration;
|
||||
using Microsoft.Extensions.Logging;
|
||||
|
||||
namespace WithGameEventHandlers;
|
||||
|
||||
[MinimumApiVersion(80)]
|
||||
public class WithGameEventHandlersPlugin : BasePlugin
|
||||
{
|
||||
public override string ModuleName => "Example: With Game Event Handlers";
|
||||
public override string ModuleVersion => "1.0.0";
|
||||
public override string ModuleAuthor => "CounterStrikeSharp & Contributors";
|
||||
public override string ModuleDescription => "A simple plugin that subscribes to game events";
|
||||
|
||||
public override void Load(bool hotReload)
|
||||
{
|
||||
// Subscriptions can be added via the instance method
|
||||
RegisterEventHandler<EventPlayerDeath>((@event, info) =>
|
||||
{
|
||||
// You can use `info.DontBroadcast` to set the dont broadcast flag on the event (in pre handlers)
|
||||
// This will prevent the event from being broadcast to other clients.
|
||||
// In this example we prevent kill-feed messages from being broadcast if it was not a headshot.
|
||||
if (!@event.Headshot)
|
||||
{
|
||||
@event.Attacker.PrintToChat($"Skipping player_death broadcast");
|
||||
info.DontBroadcast = true;
|
||||
}
|
||||
|
||||
return HookResult.Continue;
|
||||
}, HookMode.Pre);
|
||||
}
|
||||
|
||||
// Subscriptions can be added via an attribute
|
||||
[GameEventHandler]
|
||||
public HookResult OnPlayerBlind(EventPlayerBlind @event, GameEventInfo info)
|
||||
{
|
||||
Logger.LogInformation("Player was just blinded for {Duration}", @event.BlindDuration);
|
||||
|
||||
return HookResult.Continue;
|
||||
}
|
||||
|
||||
// The event name is inferred from the event type you pass to the first argument.
|
||||
// e.g. EventRoundStart becomes "round_start"
|
||||
// Note: You can use the `HookMode` enum to specify the hook mode
|
||||
// If you do not specify a hook mode, it will default to `HookMode.Post`
|
||||
[GameEventHandler(HookMode.Pre)]
|
||||
public HookResult OnEventRoundStartPre(EventRoundStart @event, GameEventInfo info)
|
||||
{
|
||||
Logger.LogInformation("Round has started with Timelimit: {Timelimit}", @event.Timelimit);
|
||||
|
||||
return HookResult.Continue;
|
||||
}
|
||||
}
|
||||
@@ -1010,6 +1010,17 @@ namespace CounterStrikeSharp.API.Core
|
||||
}
|
||||
}
|
||||
|
||||
public static int GetSchemaClassSize(string classname){
|
||||
lock (ScriptContext.GlobalScriptContext.Lock) {
|
||||
ScriptContext.GlobalScriptContext.Reset();
|
||||
ScriptContext.GlobalScriptContext.Push(classname);
|
||||
ScriptContext.GlobalScriptContext.SetIdentifier(0x9CE4FC56);
|
||||
ScriptContext.GlobalScriptContext.Invoke();
|
||||
ScriptContext.GlobalScriptContext.CheckErrors();
|
||||
return (int)ScriptContext.GlobalScriptContext.GetResult(typeof(int));
|
||||
}
|
||||
}
|
||||
|
||||
public static IntPtr GetEconItemSystem(){
|
||||
lock (ScriptContext.GlobalScriptContext.Lock) {
|
||||
ScriptContext.GlobalScriptContext.Reset();
|
||||
|
||||
@@ -43,6 +43,9 @@ namespace CounterStrikeSharp.API.Core
|
||||
|
||||
[JsonPropertyName("FollowCS2ServerGuidelines")]
|
||||
public bool FollowCS2ServerGuidelines { get; set; } = true;
|
||||
|
||||
[JsonPropertyName("PluginHotReloadEnabled")]
|
||||
public bool PluginHotReloadEnabled { get; set; } = true;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -80,6 +83,11 @@ namespace CounterStrikeSharp.API.Core
|
||||
/// </para>
|
||||
/// </summary>
|
||||
public static bool FollowCS2ServerGuidelines => _coreConfig.FollowCS2ServerGuidelines;
|
||||
|
||||
/// <summary>
|
||||
/// When enabled, plugins are automatically reloaded when their .dll file is updated.
|
||||
/// </summary>
|
||||
public static bool PluginHotReloadEnabled => _coreConfig.PluginHotReloadEnabled;
|
||||
}
|
||||
|
||||
public partial class CoreConfig : IStartupService
|
||||
|
||||
@@ -23,6 +23,10 @@ namespace CounterStrikeSharp.API.Core
|
||||
{
|
||||
T Config { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Called when the `ConfigManager` has parsed the configuration file for this plugin
|
||||
/// </summary>
|
||||
/// <param name="config">Parsed config instance</param>
|
||||
public void OnConfigParsed(T config);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -125,6 +125,18 @@ namespace CounterStrikeSharp.API.Core
|
||||
{
|
||||
return new InputArgument(value);
|
||||
}
|
||||
|
||||
[SecurityCritical]
|
||||
public static implicit operator InputArgument(NativeObject value)
|
||||
{
|
||||
return new InputArgument(value.Handle);
|
||||
}
|
||||
|
||||
[SecurityCritical]
|
||||
public static implicit operator InputArgument(NativeEntity value)
|
||||
{
|
||||
return new InputArgument(value.Handle);
|
||||
}
|
||||
|
||||
[SecurityCritical]
|
||||
public static unsafe implicit operator InputArgument(void* value)
|
||||
|
||||
@@ -64,23 +64,26 @@ namespace CounterStrikeSharp.API.Core.Plugin
|
||||
config.IsUnloadable = true;
|
||||
});
|
||||
|
||||
_fileWatcher = new FileSystemWatcher
|
||||
if (CoreConfig.PluginHotReloadEnabled)
|
||||
{
|
||||
Path = Path.GetDirectoryName(path)
|
||||
};
|
||||
|
||||
_fileWatcher.Deleted += async (s, e) =>
|
||||
{
|
||||
if (e.FullPath == path)
|
||||
_fileWatcher = new FileSystemWatcher
|
||||
{
|
||||
_logger.LogInformation("Plugin {Name} has been deleted, unloading...", Plugin.ModuleName);
|
||||
Unload(true);
|
||||
}
|
||||
};
|
||||
Path = Path.GetDirectoryName(path)
|
||||
};
|
||||
|
||||
_fileWatcher.Filter = "*.dll";
|
||||
_fileWatcher.EnableRaisingEvents = true;
|
||||
Loader.Reloaded += async (s, e) => await OnReloadedAsync(s, e);
|
||||
_fileWatcher.Deleted += async (s, e) =>
|
||||
{
|
||||
if (e.FullPath == path)
|
||||
{
|
||||
_logger.LogInformation("Plugin {Name} has been deleted, unloading...", Plugin.ModuleName);
|
||||
Unload(true);
|
||||
}
|
||||
};
|
||||
|
||||
_fileWatcher.Filter = "*.dll";
|
||||
_fileWatcher.EnableRaisingEvents = true;
|
||||
Loader.Reloaded += async (s, e) => await OnReloadedAsync(s, e);
|
||||
}
|
||||
}
|
||||
|
||||
private Task OnReloadedAsync(object sender, PluginReloadedEventArgs eventargs)
|
||||
|
||||
@@ -205,6 +205,16 @@ namespace CounterStrikeSharp.API.Core
|
||||
|
||||
return;
|
||||
}
|
||||
else if (arg is NativeObject nativeObject)
|
||||
{
|
||||
Push(context, (InputArgument)nativeObject);
|
||||
return;
|
||||
}
|
||||
else if (arg is NativeEntity nativeValue)
|
||||
{
|
||||
Push(context, (InputArgument)nativeValue);
|
||||
return;
|
||||
}
|
||||
|
||||
if (Marshal.SizeOf(arg.GetType()) <= 8)
|
||||
{
|
||||
|
||||
@@ -50,6 +50,8 @@ public class Schema
|
||||
"m_nActiveCoinRank",
|
||||
"m_nMusicID",
|
||||
};
|
||||
|
||||
public static int GetClassSize(string className) => NativeAPI.GetSchemaClassSize(className);
|
||||
|
||||
public static short GetSchemaOffset(string className, string propertyName)
|
||||
{
|
||||
|
||||
@@ -13,18 +13,42 @@ public readonly record struct CEntityIndex(uint Value)
|
||||
|
||||
public class CHandle<T> : IEquatable<CHandle<T>> where T : NativeEntity
|
||||
{
|
||||
public uint Raw;
|
||||
|
||||
private uint _raw;
|
||||
private IntPtr? _pointer;
|
||||
|
||||
public uint Raw
|
||||
{
|
||||
get
|
||||
{
|
||||
if (_pointer != null)
|
||||
{
|
||||
return (uint)Marshal.ReadInt32(_pointer.Value);
|
||||
}
|
||||
|
||||
return _raw;
|
||||
}
|
||||
set
|
||||
{
|
||||
if (_pointer != null)
|
||||
{
|
||||
Marshal.WriteInt32(_pointer.Value, (int)value);
|
||||
return;
|
||||
}
|
||||
|
||||
_raw = value;
|
||||
}
|
||||
}
|
||||
|
||||
public CHandle(uint raw)
|
||||
{
|
||||
Raw = raw;
|
||||
}
|
||||
|
||||
|
||||
public CHandle(IntPtr raw)
|
||||
{
|
||||
Raw = (uint)Marshal.ReadInt32(raw);
|
||||
_pointer = raw;
|
||||
}
|
||||
|
||||
|
||||
public T? Value => (T)Activator.CreateInstance(typeof(T), EntitySystem.GetEntityByHandle(this));
|
||||
|
||||
public override string ToString() => IsValid ? $"Index = {Index}, Serial = {SerialNum}" : "<invalid>";
|
||||
|
||||
@@ -35,14 +35,14 @@ namespace CounterStrikeSharp.API
|
||||
Reload = (1 << 13),
|
||||
Alt1 = (1 << 14),
|
||||
Alt2 = (1 << 15),
|
||||
Speed = (1 << 16), /**< Player is holding the speed key */
|
||||
Walk = (1 << 17), /**< Player holding walk key */
|
||||
Zoom = (1 << 18), /**< Zoom key for HUD zoom */
|
||||
Weapon1 = (1 << 19), /**< weapon defines these bits */
|
||||
Weapon2 = (1 << 20), /**< weapon defines these bits */
|
||||
Speed = (1 << 16), /** Player is holding the speed key */
|
||||
Walk = (1 << 17), /** Player holding walk key */
|
||||
Zoom = (1 << 18), /** Zoom key for HUD zoom */
|
||||
Weapon1 = (1 << 19), /** weapon defines these bits */
|
||||
Weapon2 = (1 << 20), /** weapon defines these bits */
|
||||
Bullrush = (1 << 21),
|
||||
Grenade1 = (1 << 22), /**< grenade 1 */
|
||||
Grenade2 = (1 << 23), /**< grenade 2 */
|
||||
Grenade1 = (1 << 22), /** grenade 1 */
|
||||
Grenade2 = (1 << 23), /** grenade 2 */
|
||||
Attack3 = (1 << 24)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -78,12 +78,10 @@ namespace CounterStrikeSharp.API
|
||||
public static IEnumerable<T> FindAllEntitiesByDesignerName<T>(string designerName) where T : CEntityInstance
|
||||
{
|
||||
var pEntity = new CEntityIdentity(EntitySystem.FirstActiveEntity);
|
||||
for (; pEntity != null && pEntity.EntityHandle.IsValid; pEntity = pEntity.Next)
|
||||
for (; pEntity != null && pEntity.Handle != IntPtr.Zero; pEntity = pEntity.Next)
|
||||
{
|
||||
var value = pEntity.EntityInstance.EntityHandle.Value;
|
||||
if (value == null) continue;
|
||||
|
||||
yield return value.As<T>();
|
||||
if (!pEntity.DesignerName.Contains(designerName)) continue;
|
||||
yield return new PointerTo<T>(pEntity.Handle).Value;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -92,10 +90,7 @@ namespace CounterStrikeSharp.API
|
||||
var pEntity = new CEntityIdentity(EntitySystem.FirstActiveEntity);
|
||||
for (; pEntity != null && pEntity.Handle != IntPtr.Zero; pEntity = pEntity.Next)
|
||||
{
|
||||
var value = pEntity.EntityInstance.EntityHandle.Value;
|
||||
if (value == null) continue;
|
||||
|
||||
yield return value;
|
||||
yield return new PointerTo<CEntityInstance>(pEntity.Handle).Value;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -12,6 +12,16 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "WarcraftPlugin", "..\exampl
|
||||
EndProject
|
||||
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Examples", "Examples", "{7DF99C35-881D-4FF2-B1C9-246BD3DECB9A}"
|
||||
EndProject
|
||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "WithConfig", "..\examples\WithConfig\WithConfig.csproj", "{2846604A-5B9F-4D80-9476-657C09CFDD5C}"
|
||||
EndProject
|
||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "HelloWorld", "..\examples\HelloWorld\HelloWorld.csproj", "{DDA4F93A-7D4A-4698-8C2A-5DAE7FBCDC72}"
|
||||
EndProject
|
||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "WithDependencyInjection", "..\examples\WithDependencyInjection\WithDependencyInjection.csproj", "{E497E40C-A7B4-41A7-A1C6-2EC6698FF3BF}"
|
||||
EndProject
|
||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "WithCommands", "..\examples\WithCommands\WithCommands.csproj", "{EA2F596E-2236-4999-B476-B1FDA287674A}"
|
||||
EndProject
|
||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "WithGameEventHandlers", "..\examples\WithGameEventHandlers\WithGameEventHandlers.csproj", "{3032F3FA-E20A-4581-9A08-2FB5FF1524F4}"
|
||||
EndProject
|
||||
Global
|
||||
GlobalSection(SolutionConfigurationPlatforms) = preSolution
|
||||
Debug|Any CPU = Debug|Any CPU
|
||||
@@ -38,9 +48,34 @@ Global
|
||||
{DAE388A8-94A4-4C24-9450-E34677EEA2CF}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{DAE388A8-94A4-4C24-9450-E34677EEA2CF}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{DAE388A8-94A4-4C24-9450-E34677EEA2CF}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
{2846604A-5B9F-4D80-9476-657C09CFDD5C}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{2846604A-5B9F-4D80-9476-657C09CFDD5C}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{2846604A-5B9F-4D80-9476-657C09CFDD5C}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{2846604A-5B9F-4D80-9476-657C09CFDD5C}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
{DDA4F93A-7D4A-4698-8C2A-5DAE7FBCDC72}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{DDA4F93A-7D4A-4698-8C2A-5DAE7FBCDC72}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{DDA4F93A-7D4A-4698-8C2A-5DAE7FBCDC72}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{DDA4F93A-7D4A-4698-8C2A-5DAE7FBCDC72}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
{E497E40C-A7B4-41A7-A1C6-2EC6698FF3BF}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{E497E40C-A7B4-41A7-A1C6-2EC6698FF3BF}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{E497E40C-A7B4-41A7-A1C6-2EC6698FF3BF}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{E497E40C-A7B4-41A7-A1C6-2EC6698FF3BF}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
{EA2F596E-2236-4999-B476-B1FDA287674A}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{EA2F596E-2236-4999-B476-B1FDA287674A}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{EA2F596E-2236-4999-B476-B1FDA287674A}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{EA2F596E-2236-4999-B476-B1FDA287674A}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
{3032F3FA-E20A-4581-9A08-2FB5FF1524F4}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{3032F3FA-E20A-4581-9A08-2FB5FF1524F4}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{3032F3FA-E20A-4581-9A08-2FB5FF1524F4}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{3032F3FA-E20A-4581-9A08-2FB5FF1524F4}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
EndGlobalSection
|
||||
GlobalSection(NestedProjects) = preSolution
|
||||
{57E64289-5D69-4AA1-BEF0-D0D96A55EE8F} = {7DF99C35-881D-4FF2-B1C9-246BD3DECB9A}
|
||||
{DAE388A8-94A4-4C24-9450-E34677EEA2CF} = {7DF99C35-881D-4FF2-B1C9-246BD3DECB9A}
|
||||
{2846604A-5B9F-4D80-9476-657C09CFDD5C} = {7DF99C35-881D-4FF2-B1C9-246BD3DECB9A}
|
||||
{DDA4F93A-7D4A-4698-8C2A-5DAE7FBCDC72} = {7DF99C35-881D-4FF2-B1C9-246BD3DECB9A}
|
||||
{E497E40C-A7B4-41A7-A1C6-2EC6698FF3BF} = {7DF99C35-881D-4FF2-B1C9-246BD3DECB9A}
|
||||
{EA2F596E-2236-4999-B476-B1FDA287674A} = {7DF99C35-881D-4FF2-B1C9-246BD3DECB9A}
|
||||
{3032F3FA-E20A-4581-9A08-2FB5FF1524F4} = {7DF99C35-881D-4FF2-B1C9-246BD3DECB9A}
|
||||
EndGlobalSection
|
||||
EndGlobal
|
||||
|
||||
@@ -47,9 +47,10 @@ bool CCoreConfig::Init(char* conf_error, int conf_error_size)
|
||||
m_json = json::parse(ifs);
|
||||
|
||||
try {
|
||||
PublicChatTrigger = m_json["PublicChatTrigger"];
|
||||
SilentChatTrigger = m_json["SilentChatTrigger"];
|
||||
FollowCS2ServerGuidelines = m_json["FollowCS2ServerGuidelines"];
|
||||
PublicChatTrigger = m_json.value("PublicChatTrigger", PublicChatTrigger);
|
||||
SilentChatTrigger = m_json.value("SilentChatTrigger", SilentChatTrigger);
|
||||
FollowCS2ServerGuidelines = m_json.value("FollowCS2ServerGuidelines", FollowCS2ServerGuidelines);
|
||||
PluginHotReloadEnabled = m_json.value("PluginHotReloadEnabled", PluginHotReloadEnabled);
|
||||
} catch (const std::exception& ex) {
|
||||
V_snprintf(conf_error, conf_error_size, "Failed to parse CoreConfig file: %s", ex.what());
|
||||
return false;
|
||||
|
||||
@@ -28,6 +28,7 @@ class CCoreConfig
|
||||
std::vector<std::string> PublicChatTrigger = { std::string("!") };
|
||||
std::vector<std::string> SilentChatTrigger = { std::string("/") };
|
||||
bool FollowCS2ServerGuidelines = true;
|
||||
bool PluginHotReloadEnabled = true;
|
||||
|
||||
using json = nlohmann::json;
|
||||
CCoreConfig(const std::string& path);
|
||||
|
||||
@@ -24,6 +24,9 @@
|
||||
#include "schema.h"
|
||||
#include "core/function.h"
|
||||
#include "core/coreconfig.h"
|
||||
#include "interfaces/cschemasystem.h"
|
||||
#include "core/cs2_sdk/interfaces/cschemasystem.h"
|
||||
#include "interfaces/cs2_interfaces.h"
|
||||
|
||||
namespace counterstrikesharp {
|
||||
|
||||
@@ -39,6 +42,20 @@ int16 GetSchemaOffset(ScriptContext& script_context)
|
||||
return m_key.offset;
|
||||
}
|
||||
|
||||
int GetSchemaClassSize(ScriptContext& script_context)
|
||||
{
|
||||
auto className = script_context.GetArgument<const char*>(0);
|
||||
|
||||
CSchemaSystemTypeScope* pType =
|
||||
interfaces::pSchemaSystem->FindTypeScopeForModule(MODULE_PREFIX "server" MODULE_EXT);
|
||||
|
||||
SchemaClassInfoData_t* pClassInfo = pType->FindDeclaredClass(className);
|
||||
if (!pClassInfo)
|
||||
return -1;
|
||||
|
||||
return pClassInfo->m_size;
|
||||
}
|
||||
|
||||
void GetSchemaValueByName(ScriptContext& script_context)
|
||||
{
|
||||
auto instancePointer = script_context.GetArgument<void*>(0);
|
||||
@@ -224,5 +241,6 @@ REGISTER_NATIVES(schema, {
|
||||
ScriptEngine::RegisterNativeHandler("GET_SCHEMA_OFFSET", GetSchemaOffset);
|
||||
ScriptEngine::RegisterNativeHandler("GET_SCHEMA_VALUE_BY_NAME", GetSchemaValueByName);
|
||||
ScriptEngine::RegisterNativeHandler("SET_SCHEMA_VALUE_BY_NAME", SetSchemaValueByName);
|
||||
ScriptEngine::RegisterNativeHandler("GET_SCHEMA_CLASS_SIZE", GetSchemaClassSize);
|
||||
})
|
||||
} // namespace counterstrikesharp
|
||||
@@ -1,3 +1,4 @@
|
||||
GET_SCHEMA_OFFSET: className:string, propName:string -> short
|
||||
GET_SCHEMA_VALUE_BY_NAME: instance:pointer, returnType:int, className:string, propName:string -> any
|
||||
SET_SCHEMA_VALUE_BY_NAME: instance:pointer, returnType:int, className:string, propName:string, value:any -> void
|
||||
SET_SCHEMA_VALUE_BY_NAME: instance:pointer, returnType:int, className:string, propName:string, value:any -> void
|
||||
GET_SCHEMA_CLASS_SIZE: className:string -> int
|
||||
Reference in New Issue
Block a user