mirror of
https://github.com/roflmuffin/CounterStrikeSharp.git
synced 2025-12-06 16:06:37 -08:00
Compare commits
44 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
84d4998a72 | ||
|
|
1b194318af | ||
|
|
22d0dd8200 | ||
|
|
7baf0a25e2 | ||
|
|
9fdbb9500b | ||
|
|
0ab3cf429a | ||
|
|
1f9630b92d | ||
|
|
02bf2483d3 | ||
|
|
cb181b6a49 | ||
|
|
cc21dca5a0 | ||
|
|
5721d060ea | ||
|
|
220521d571 | ||
|
|
5698b511e9 | ||
|
|
48c9d195ff | ||
|
|
603827d331 | ||
|
|
e557d54c32 | ||
|
|
48d3ade5cf | ||
|
|
77b05e912e | ||
|
|
1354b4972d | ||
|
|
8b5eb7e38d | ||
|
|
2dd62c44d3 | ||
|
|
f811338ce4 | ||
|
|
194c340ae7 | ||
|
|
6b0912d3cd | ||
|
|
2d3aa09aa4 | ||
|
|
911084e71e | ||
|
|
5b99206568 | ||
|
|
4bfdf28beb | ||
|
|
9bcd0f7e92 | ||
|
|
11c6486ec5 | ||
|
|
ee69560a66 | ||
|
|
d37e5e194a | ||
|
|
c4740d1cc9 | ||
|
|
7e92f178fd | ||
|
|
107ca08132 | ||
|
|
8cda8d9a50 | ||
|
|
3d59a05de8 | ||
|
|
77b7040d6c | ||
|
|
75de9732ef | ||
|
|
575c859ddb | ||
|
|
7c7f52a219 | ||
|
|
cd593fb238 | ||
|
|
c5cc65be48 | ||
|
|
59928bbcc5 |
58
.github/workflows/publish-docs.yml
vendored
58
.github/workflows/publish-docs.yml
vendored
@@ -1,42 +1,46 @@
|
||||
name: Deploy to GitHub Pages
|
||||
|
||||
on:
|
||||
# Trigger the workflow every time you push to the `main` branch
|
||||
# Using a different branch name? Replace `main` with your branch’s name
|
||||
push:
|
||||
paths:
|
||||
- 'docs/**'
|
||||
branches: [ main ]
|
||||
branches:
|
||||
- main
|
||||
|
||||
# Allows you to run this workflow manually from the Actions tab on GitHub.
|
||||
workflow_dispatch:
|
||||
|
||||
# Allow this job to clone the repo and create a page deployment
|
||||
permissions:
|
||||
contents: read
|
||||
pages: write
|
||||
id-token: write
|
||||
|
||||
jobs:
|
||||
build:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Checkout your repository using git
|
||||
uses: actions/checkout@v3
|
||||
- name: Install, build, and upload your site
|
||||
uses: withastro/action@v1
|
||||
with:
|
||||
path: ./docs # The root location of your Astro project inside the repository. (optional)
|
||||
node-version: 20 # The specific version of Node that should be used to build your site. Defaults to 18. (optional)
|
||||
package-manager: pnpm@latest # The Node package manager that should be used to install dependencies and build your site. Automatically detected based on your lockfile. (optional)
|
||||
concurrency:
|
||||
group: "pages"
|
||||
cancel-in-progress: false
|
||||
|
||||
deploy:
|
||||
needs: build
|
||||
runs-on: ubuntu-latest
|
||||
jobs:
|
||||
publish-docs:
|
||||
environment:
|
||||
name: github-pages
|
||||
url: ${{ steps.deployment.outputs.page_url }}
|
||||
|
||||
runs-on: ubuntu-latest
|
||||
|
||||
steps:
|
||||
- name: Checkout
|
||||
uses: actions/checkout@v3
|
||||
|
||||
- name: Dotnet Setup
|
||||
uses: actions/setup-dotnet@v3
|
||||
with:
|
||||
dotnet-version: 8.x
|
||||
|
||||
- run: dotnet tool update -g docfx
|
||||
|
||||
- run: docfx docfx/docfx.json
|
||||
|
||||
- name: Setup Pages
|
||||
uses: actions/configure-pages@v3
|
||||
|
||||
- name: Upload artifact
|
||||
uses: actions/upload-pages-artifact@v2
|
||||
with:
|
||||
path: "docfx/_site"
|
||||
|
||||
- name: Deploy to GitHub Pages
|
||||
id: deployment
|
||||
uses: actions/deploy-pages@v1
|
||||
uses: actions/deploy-pages@v2
|
||||
|
||||
9
.gitignore
vendored
9
.gitignore
vendored
@@ -1,6 +1,6 @@
|
||||
.ccls-cache/
|
||||
.cmake/
|
||||
cmake-build-debug/
|
||||
cmake-build-debug*/
|
||||
.kdev4/
|
||||
.vscode/
|
||||
generated/
|
||||
@@ -548,4 +548,9 @@ $RECYCLE.BIN/
|
||||
|
||||
_NCrunch*
|
||||
|
||||
.idea/
|
||||
.idea/
|
||||
|
||||
# docfx
|
||||
docfx/_site/
|
||||
docfx/api/
|
||||
docfx/_exported_templates/
|
||||
|
||||
@@ -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
|
||||
}
|
||||
7
docfx/404.md
Normal file
7
docfx/404.md
Normal file
@@ -0,0 +1,7 @@
|
||||
---
|
||||
_layout: landing
|
||||
---
|
||||
|
||||
# 404
|
||||
|
||||
We recently changed our docs. Your page may exist at a different location.
|
||||
45
docfx/docfx.json
Normal file
45
docfx/docfx.json
Normal file
@@ -0,0 +1,45 @@
|
||||
{
|
||||
"metadata": [
|
||||
{
|
||||
"src": [
|
||||
{
|
||||
"src": "../managed/CounterStrikeSharp.API",
|
||||
"files": ["**/*.csproj"],
|
||||
"exclude": ["**/bin/**", "**/obj/**"]
|
||||
}
|
||||
],
|
||||
"dest": "api",
|
||||
"namespaceLayout": "nested"
|
||||
}
|
||||
],
|
||||
"build": {
|
||||
"content": [
|
||||
{
|
||||
"files": ["**/*.{md,yml}"],
|
||||
"exclude": ["_site/**"]
|
||||
}
|
||||
],
|
||||
"resource": [
|
||||
{
|
||||
"files": ["images/**"]
|
||||
}
|
||||
],
|
||||
"output": "_site",
|
||||
"template": ["default", "modern", "layouts/cssharp"],
|
||||
"globalMetadata": {
|
||||
"_appFaviconPath": "images/cssharp.svg",
|
||||
"_appFooter": "<a href=\"https://docs.cssharp.dev\">docs.cssharp.dev</a>",
|
||||
"_appLogoPath": "images/cssharp.svg",
|
||||
"_appName": "CounterStrikeSharp",
|
||||
"_appTitle": "CounterStrikeSharp",
|
||||
"_disableNewTab": true,
|
||||
"_enableNewTab": true,
|
||||
"_enableSearch": true,
|
||||
"pdf": false
|
||||
},
|
||||
"sitemap": {
|
||||
"baseUrl": "https://docs.cssharp.dev",
|
||||
"changefreq": "hourly"
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -3,6 +3,10 @@ title: Admin Command Attributes
|
||||
description: A guide on using the Admin Command Attributes in plugins.
|
||||
---
|
||||
|
||||
# Admin Command Attributes
|
||||
|
||||
A guide on using the Admin Command Attributes in plugins.
|
||||
|
||||
## Assigning permissions to a Command
|
||||
|
||||
Assigning permissions to a Command is as easy as tagging the Command method (function callback) with either a `RequiresPermissions` or `RequiresPermissionsOr` attribute. The difference between the two attributes is that `RequiresPermissionsOr` needs only one permission to be present on the caller to be passed, while `RequiresPermissions` needs the caller to have all permissions listed. CounterStrikeSharp handles all of the permission checks behind the scenes for you.
|
||||
@@ -3,6 +3,10 @@ title: Defining Admin Groups
|
||||
description: A guide on how to define admin groups for CounterStrikeSharp.
|
||||
---
|
||||
|
||||
# Defining Admin Groups
|
||||
|
||||
A guide on how to define admin groups for CounterStrikeSharp.
|
||||
|
||||
## Adding Groups
|
||||
|
||||
Groups can be created to group a series of permissions together under one tag. They are defined in `configs/admin_groups.json`. The important things you need to declare is the name of the group and the permissions they have.
|
||||
@@ -34,9 +38,9 @@ You can add admins to groups using the `groups` array in `configs/admins.json`
|
||||
}
|
||||
```
|
||||
|
||||
:::note
|
||||
All group names MUST start with a hashtag # character, otherwise CounterStrikeSharp won't recognize the group.
|
||||
:::
|
||||
> [!NOTE]
|
||||
> All group names MUST start with a hashtag # character, otherwise CounterStrikeSharp won't recognize the group.
|
||||
|
||||
|
||||
Admins can be assigned to multiple groups and they will inherit their flags. You can manually assign groups to players in code with `AdminManager.AddPlayerToGroup` and `AdminManager.RemovePlayerFromGroup`.
|
||||
|
||||
@@ -3,6 +3,10 @@ title: Defining Admin Immunity
|
||||
description: A guide on how to define immunity for admins for CounterStrikeSharp.
|
||||
---
|
||||
|
||||
# Defining Admin Immunity
|
||||
|
||||
A guide on how to define immunity for admins for CounterStrikeSharp.
|
||||
|
||||
## Player Immunity
|
||||
|
||||
Admins can be assigned an immunity value, similar to SourceMod. If an admin or player with a lower immunity value targets another admin or player with a larger immunity value, then the command will fail. You can define an immunity value by adding the `immunity` key to each admin in `configs/admins.json`.
|
||||
@@ -31,6 +35,5 @@ You can even assign an immunity value to groups. If an admin has a lower immunit
|
||||
}
|
||||
```
|
||||
|
||||
:::note
|
||||
CounterStrikeSharp does not automatically handle immunity checking. It is up to individual plugins to handle immunity checks as they can implement different ways of targeting players. This can be done in code with `AdminManager.CanPlayerTarget`. You can also set a player's immunity in code with `AdminManager.SetPlayerImmunity`.
|
||||
:::
|
||||
> [!NOTE]
|
||||
> CounterStrikeSharp does not automatically handle immunity checking. It is up to individual plugins to handle immunity checks as they can implement different ways of targeting players. This can be done in code with `AdminManager.CanPlayerTarget`. You can also set a player's immunity in code with `AdminManager.SetPlayerImmunity`.
|
||||
@@ -3,6 +3,10 @@ title: Defining Admins
|
||||
description: A guide on how to define admins for CounterStrikeSharp.
|
||||
---
|
||||
|
||||
# Defining Admins
|
||||
|
||||
A guide on how to define admins for CounterStrikeSharp.
|
||||
|
||||
## Admin Framework
|
||||
|
||||
CounterStrikeSharp has a basic framework which allows plugin developers to assign permissions to commands. When CSS is initialized, a list of admins are loaded from `configs/admins.json`.
|
||||
@@ -26,9 +30,8 @@ Adding an Admin is as simple as creating a new entry in the `configs/admins.json
|
||||
|
||||
You can also manually assign permissions to players in code with `AdminManager.AddPlayerPermissions` and `AdminManager.RemovePlayerPermissions`. These changes are not saved to `configs/admins.json`.
|
||||
|
||||
:::note
|
||||
All user permissions MUST start with an at-symbol @ character, otherwise CounterStrikeSharp will not recognize the permission.
|
||||
:::
|
||||
> [!NOTE]
|
||||
> All user permissions MUST start with an at-symbol @ character, otherwise CounterStrikeSharp will not recognize the permission.
|
||||
|
||||
### Standard Permissions
|
||||
|
||||
@@ -55,7 +58,5 @@ However there is a somewhat standardized list of flags that it is advised you us
|
||||
@css/root # Magically enables all flags and ignores immunity values.
|
||||
```
|
||||
|
||||
:::note
|
||||
CounterStrikeSharp does not implement traditional admin command such as `!slay`, `!kick`, and `!ban`. It is up to individual plugins to implement these commands.
|
||||
:::
|
||||
|
||||
> [!NOTE]
|
||||
> CounterStrikeSharp does not implement traditional admin command such as `!slay`, `!kick`, and `!ban`. It is up to individual plugins to implement these commands.
|
||||
@@ -3,6 +3,10 @@ title: Defining Command Overrides
|
||||
description: A guide on how to define command overrides for CounterStrikeSharp.
|
||||
---
|
||||
|
||||
# Defining Command Overrides
|
||||
|
||||
A guide on how to define command overrides for CounterStrikeSharp.
|
||||
|
||||
## Defining Admin and Group specific overrides
|
||||
|
||||
Command permissions can be overriden so specific admins or groups can execute the command, regardless of any permissions they may or may not have. You can define command overrides by adding the `command_overrides` key to each admin in `configs/admins.json` or group in `configs/admin_groups.json`. Command overrides can either be set to `true`, meaning the admin/group can execute the command, or `false`, meaning the admin/group cannot execute the command at all.
|
||||
14
docfx/docs/admin-framework/toc.yml
Normal file
14
docfx/docs/admin-framework/toc.yml
Normal file
@@ -0,0 +1,14 @@
|
||||
- name: Admin Command Attributes
|
||||
href: admin-command-attributes.md
|
||||
|
||||
- name: Defining Admins
|
||||
href: defining-admins.md
|
||||
|
||||
- name: Defining Command Overrides
|
||||
href: defining-command-overrides.md
|
||||
|
||||
- name: Defining Admin Groups
|
||||
href: defining-admin-groups.md
|
||||
|
||||
- name: Defining Admin Immunity
|
||||
href: defining-admin-immunity.md
|
||||
@@ -3,6 +3,10 @@ title: Console Commands
|
||||
description: How to add a new console command
|
||||
---
|
||||
|
||||
# Console Commands
|
||||
|
||||
How to add a new console command
|
||||
|
||||
## Adding a Console Command
|
||||
|
||||
### Automatic registration
|
||||
@@ -3,6 +3,10 @@ title: Console Variables
|
||||
description: How to read & write console variables (ConVars).
|
||||
---
|
||||
|
||||
# Console Variables
|
||||
|
||||
How to read & write console variables (ConVars).
|
||||
|
||||
## Finding a ConVar
|
||||
|
||||
Use the `ConVar.Find` static method to find a reference to an existing ConVar (or `null`).
|
||||
@@ -3,15 +3,18 @@ title: Game Events
|
||||
description: How to listen to Source 1 style game events.
|
||||
---
|
||||
|
||||
# Game Events
|
||||
|
||||
How to listen to Source 1 style game events.
|
||||
|
||||
## Adding an Event Listener
|
||||
|
||||
### Automatic registration
|
||||
|
||||
CounterStrikeSharp will automatically register event listeners marked with a `GameEventHandler` attribute on the `BasePlugin` class. These listeners are automatically registered/deregistered for you on hot reload.
|
||||
|
||||
:::note
|
||||
The first parameter type must be a subclass of the `GameEvent` class. The names are automatically generated from the [game event list](https://cs2.poggu.me/dumped-data/game-events).
|
||||
:::
|
||||
> [!NOTE]
|
||||
> The first parameter type must be a subclass of the `GameEvent` class. The names are automatically generated from the [game event list](https://cs2.poggu.me/dumped-data/game-events).
|
||||
|
||||
```csharp
|
||||
[GameEventHandler]
|
||||
@@ -3,6 +3,10 @@ title: Global Listeners
|
||||
description: How to subscribe to CounterStrikeSharp global listeners.
|
||||
---
|
||||
|
||||
# Global Listeners
|
||||
|
||||
How to subscribe to CounterStrikeSharp global listeners.
|
||||
|
||||
## Adding a Listener
|
||||
|
||||
Global listeners come in a variety of shapes so there is no automatic registration for these, they must be registered in the `OnLoad` of your plugin (or anywhere you have access to the plugin instance). You can find the full list of event listeners in the `Listeners` class as seen below.
|
||||
11
docfx/docs/features/toc.yml
Normal file
11
docfx/docs/features/toc.yml
Normal file
@@ -0,0 +1,11 @@
|
||||
- name: Console Commands
|
||||
href: console-commands.md
|
||||
|
||||
- name: Console Variables
|
||||
href: console-variables.md
|
||||
|
||||
- name: Game Events
|
||||
href: game-events.md
|
||||
|
||||
- name: Global Listeners
|
||||
href: global-listeners.md
|
||||
@@ -1,10 +1,12 @@
|
||||
---
|
||||
title: Dependency Injection
|
||||
description: How to make use of dependency injection in CounterStrikeSharp
|
||||
sidebar:
|
||||
order: 1
|
||||
---
|
||||
|
||||
# Dependency Injection
|
||||
|
||||
How to make use of dependency injection in CounterStrikeSharp
|
||||
|
||||
`CounterStrikeSharp` uses a standard <a href="https://learn.microsoft.com/en-us/aspnet/core/fundamentals/dependency-injection?view=aspnetcore-8.0" target="_blank">`IServiceCollection`</a> to allow for dependency injection in plugins.
|
||||
|
||||
There are a handful of standard services that are predefined for you (`ILogger` for logging for instance), with more to come in the future. To add your own scoped & singleton services to the container, you can create a new class that implements the `IPluginServiceCollection<T>` interface for your plugin.
|
||||
@@ -1,26 +1,25 @@
|
||||
---
|
||||
title: Getting Started
|
||||
description: How to get started installing & using CounterStrikeSharp.
|
||||
sidebar:
|
||||
order: 0
|
||||
---
|
||||
|
||||
# Installation
|
||||
# Getting Started
|
||||
|
||||
### Installing Metamod
|
||||
How to get started installing & using CounterStrikeSharp.
|
||||
|
||||
## Installing Metamod
|
||||
|
||||
`CounterStrikeSharp` uses `Metamod:Source` as its main way of communicating with the game server. To install it, you can follow the detailed instructions found <a href="https://cs2.poggu.me/metamod/installation/" target="_blank">here</a>.
|
||||
|
||||
### Installing CounterStrikeSharp
|
||||
## Installing CounterStrikeSharp
|
||||
|
||||
Download the latest release of CounterStrikeSharp from <a href="https://github.com/roflmuffin/CounterStrikeSharp/actions/workflows/cmake-single-platform.yml" target="_blank">GitHub actions build pages</a> (just choose the latest development snapshot). **You may need to be logged into GitHub to gain access to the downloads**.
|
||||
|
||||
:::caution[.NET Runtime]
|
||||
If this is your first time installing, you will need to download the `with-runtime` version. This includes a copy of the .NET runtime, which is required to run the plugin.
|
||||
Depending on the os you might also either need to install `libicu` / `icu-libs` / `libicu-dev` using your package manager for .NET to run or setting `DOTNET_SYSTEM_GLOBALIZATION_INVARIANT=true` in your servers environment variables. You can find more infos about that <a href="https://github.com/dotnet/runtime/blob/main/docs/design/features/globalization-invariant-mode.md#enabling-the-invariant-mode" target="_blank">here</a>
|
||||
|
||||
Subsequent upgrades will not require the runtime, unless a version bump of the .NET runtime is required (i.e. from 7.0.x to 8.0.x). We will inform you when this occurs.
|
||||
:::
|
||||
> [!CAUTION]
|
||||
> If this is your first time installing, you will need to download the `with-runtime` version. This includes a copy of the .NET runtime, which is required to run the plugin.
|
||||
> Depending on the os you might also either need to install `libicu` / `icu-libs` / `libicu-dev` using your package manager for .NET to run or setting `DOTNET_SYSTEM_GLOBALIZATION_INVARIANT=true` in your servers environment variables. You can find more infos about that <a href="https://github.com/dotnet/runtime/blob/main/docs/design/features/globalization-invariant-mode.md#enabling-the-invariant-mode" target="_blank">here</a>
|
||||
>
|
||||
> Subsequent upgrades will not require the runtime, unless a version bump of the .NET runtime is required (i.e. from 7.0.x to 8.0.x). We will inform you when this occurs.
|
||||
|
||||
Extract the `addons` folder to the `/csgo/` directory of the dedicated server. The contents of your addons folder should contain both the `counterstrikesharp` folder and the `metamod` folder as seen below.
|
||||
|
||||
@@ -28,22 +27,22 @@ Extract the `addons` folder to the `/csgo/` directory of the dedicated server. T
|
||||
<server_path>/game/csgo/addons > tree -L 2
|
||||
addons
|
||||
├── counterstrikesharp
|
||||
│ ├── api
|
||||
│ ├── bin
|
||||
│ ├── dotnet
|
||||
│ ├── plugins
|
||||
│ ├── api
|
||||
│ ├── bin
|
||||
│ ├── dotnet
|
||||
│ ├── plugins
|
||||
│ └── gamedata
|
||||
│
|
||||
├── metamod
|
||||
│ ├── bin
|
||||
│ ├── counterstrikesharp.vdf
|
||||
│ ├── metaplugins.ini
|
||||
│ └── README.txt
|
||||
│ ├── bin
|
||||
│ ├── counterstrikesharp.vdf
|
||||
│ ├── metaplugins.ini
|
||||
│ └── README.txt
|
||||
├── metamod.vdf
|
||||
└── metamod_x64.vdf
|
||||
```
|
||||
|
||||
### Start the Server
|
||||
## Start the Server
|
||||
|
||||
Launch your CS2 dedicated server as normal. If everything is working correctly, you should see a message in the console that says `CSSharp: CounterStrikeSharp.API Loaded Successfully.`.
|
||||
|
||||
@@ -53,4 +52,4 @@ Running the command `meta list` in the console should show 1 plugin loaded 🎉
|
||||
meta list
|
||||
Listing 1 plugin:
|
||||
[01] CounterStrikeSharp (0.1.0) by Roflmuffin
|
||||
```
|
||||
```
|
||||
@@ -1,10 +1,12 @@
|
||||
---
|
||||
title: Hello World Plugin
|
||||
description: How to write your first plugin for CounterStrikeSharp
|
||||
sidebar:
|
||||
order: 0
|
||||
---
|
||||
|
||||
# Hello World Plugin
|
||||
|
||||
How to write your first plugin for CounterStrikeSharp
|
||||
|
||||
## Creating a New Project
|
||||
|
||||
First, ensure you have the relevant .NET 7.0 SDK for your platform installed on your machine. You can find the links to the latest downloads on the <a href="https://dotnet.microsoft.com/en-us/download/dotnet/7.0" target="_blank"> official Microsoft download page</a>.
|
||||
@@ -36,12 +38,11 @@ Use your IDE (Visual Studio/Rider) to add a reference to the `CounterStrikeSharp
|
||||
</Project>
|
||||
```
|
||||
|
||||
:::tip
|
||||
Instead of manually adding a reference to `CounterStrikeSharp.Api.dll`, you can install the NuGet package `CounterStrikeSharp.Api` using the following:
|
||||
```shell
|
||||
dotnet add package CounterStrikeSharp.API
|
||||
```
|
||||
:::
|
||||
> [!TIP]
|
||||
> Instead of manually adding a reference to `CounterStrikeSharp.Api.dll`, you can > install the NuGet package `CounterStrikeSharp.Api` using the following:
|
||||
> ```shell
|
||||
> dotnet add package CounterStrikeSharp.API
|
||||
> ```
|
||||
|
||||
### Creating a Plugin File
|
||||
|
||||
@@ -68,29 +69,27 @@ 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
|
||||
```
|
||||
|
||||
:::note
|
||||
Note that some of these dependencies may change depending on the version of CounterStrikeSharp being used.
|
||||
:::
|
||||
> [!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.
|
||||
|
||||
### Start the Server
|
||||
|
||||
Now start your CS2 dedicated server. Just before the `CounterStrikeSharp.API Loaded Successfully.` message you should see your `Hello World!` console write that we called from the load function, neat!
|
||||
|
||||
:::note[Hot Reloading!]
|
||||
By default, CounterStrikeSharp will automatically hot reload your plugin if you replace the .dll file in your plugin folder. When it does so, it will call the `Unload` and `Load` functions respectively, with the `hotReload` flag set to true.
|
||||
|
||||
It is worth noting that the framework will automatically deregister any event handlers or listeners for you automatically, so you can safely reregister these on load without checking this flag. However you may want to do some specific actions on a hot reload, which you can do in your `Load()` call by checking the flag!
|
||||
:::
|
||||
> [!NOTE]
|
||||
> By default, CounterStrikeSharp will automatically hot reload your plugin if you replace the .dll file in your plugin folder. When it does so, it will call the `Unload` and `Load` functions respectively, with the `hotReload` flag set to true.
|
||||
>
|
||||
> It is worth noting that the framework will automatically deregister any event handlers or listeners for you automatically, so you can safely reregister these on load without checking this flag. However you may want to do some specific actions on a hot reload, which you can do in your `Load()` call by checking the flag!
|
||||
8
docfx/docs/guides/toc.yml
Normal file
8
docfx/docs/guides/toc.yml
Normal file
@@ -0,0 +1,8 @@
|
||||
- name: Getting Started
|
||||
href: getting-started.md
|
||||
|
||||
- name: Hello World Plugin
|
||||
href: hello-world-plugin.md
|
||||
|
||||
- name: Dependency Injection
|
||||
href: dependency-injection.md
|
||||
@@ -3,6 +3,10 @@ title: Core Configuration
|
||||
description: Summary for core configuration values
|
||||
---
|
||||
|
||||
# Core Configuration
|
||||
|
||||
Summary for core configuration values
|
||||
|
||||
## PublicChatTrigger
|
||||
|
||||
List of characters to use for public chat triggers.
|
||||
@@ -21,6 +25,10 @@ Enabling this option will block plugins from using functionality that is known t
|
||||
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.
|
||||
:::
|
||||
> [!NOTE]
|
||||
> Disable this option at your own risk.
|
||||
|
||||
|
||||
## PluginHotReloadEnabled
|
||||
|
||||
When enabled, plugins are automatically reloaded when their .dll file is updated.
|
||||
@@ -3,6 +3,10 @@ title: Referencing Players
|
||||
description: Difference between player slots, indexes, userids, controllers & pawns.
|
||||
---
|
||||
|
||||
# Referencing Players
|
||||
|
||||
Difference between player slots, indexes, userids, controllers & pawns.
|
||||
|
||||
## Controllers & Pawns
|
||||
|
||||
All players in CS2 are split between a player controller & a player pawn. The player controller represents the player on the server, and the player pawn represents the players physical character in the game world. This means to edit a players health for example, you would need to edit their `PlayerPawn`'s health; but to check for a player's SteamID, you would check the `PlayerController`.
|
||||
@@ -44,13 +48,12 @@ var player = Utilities.GetPlayerFromIndex(index);
|
||||
var player = Utilities.GetPlayerFromSlot(slot);
|
||||
```
|
||||
|
||||
:::note[Entity Safety]
|
||||
Wherever possible, you should check the validity of any handle you are accessing before assuming it is safe to use.
|
||||
```csharp
|
||||
RegisterEventHandler<EventPlayerSpawn>((@event, info) =>
|
||||
{
|
||||
if (!@event.Userid.IsValid) return 0; // Checks that the PlayerController is valid
|
||||
if (!@event.Userid.PlayerPawn.IsValid) return 0; // Checks that the value of the CHandle is pointing to a valid PlayerPawn.
|
||||
}
|
||||
```
|
||||
:::
|
||||
> [!NOTE]
|
||||
> Wherever possible, you should check the validity of any handle you are accessing before assuming it is safe to use.
|
||||
> ```csharp
|
||||
> RegisterEventHandler<EventPlayerSpawn>((@event, info) =>
|
||||
> {
|
||||
> if (!@event.Userid.IsValid) return 0; // Checks that the PlayerController is valid
|
||||
> if (!@event.Userid.PlayerPawn.IsValid) return 0; // Checks that the value of the CHandle is pointing to a valid PlayerPawn.
|
||||
> }
|
||||
> ```
|
||||
5
docfx/docs/reference/toc.yml
Normal file
5
docfx/docs/reference/toc.yml
Normal file
@@ -0,0 +1,5 @@
|
||||
- name: Core Configuration
|
||||
href: core-configuration.md
|
||||
|
||||
- name: Referencing Players
|
||||
href: referencing-players.md
|
||||
16
docfx/docs/toc.yml
Normal file
16
docfx/docs/toc.yml
Normal file
@@ -0,0 +1,16 @@
|
||||
items:
|
||||
- name: Guides
|
||||
href: guides/toc.yml
|
||||
expanded: true
|
||||
|
||||
- name: Features
|
||||
href: features/toc.yml
|
||||
expanded: true
|
||||
|
||||
- name: Admin Framework
|
||||
href: admin-framework/toc.yml
|
||||
expanded: true
|
||||
|
||||
- name: Reference
|
||||
href: reference/toc.yml
|
||||
expanded: true
|
||||
5
docfx/examples/HelloWorld.md
Normal file
5
docfx/examples/HelloWorld.md
Normal file
@@ -0,0 +1,5 @@
|
||||
[!INCLUDE [HelloWorld](../../examples/HelloWorld/README.md)]
|
||||
|
||||
<a href="https://github.com/roflmuffin/CounterStrikeSharp/tree/main/examples/HelloWorld" class="btn btn-secondary">View project on Github <i class="bi bi-github"></i></a>
|
||||
|
||||
[!code-csharp[](../../examples/HelloWorld/HelloWorldPlugin.cs)]
|
||||
13
docfx/examples/WarcraftPlugin.md
Normal file
13
docfx/examples/WarcraftPlugin.md
Normal file
@@ -0,0 +1,13 @@
|
||||
# Warcraft Plugin
|
||||
|
||||
This Warcraft plugin is migrated from the previous VSP.NET project to give you an idea of the kind of power this scripting runtime is capable of.
|
||||
|
||||
<a href="https://github.com/roflmuffin/CounterStrikeSharp/tree/main/examples/WarcraftPlugin" class="btn btn-secondary">View project on Github <i class="bi bi-github"></i></a>
|
||||
|
||||
## Demonstrated
|
||||
- Hook events
|
||||
- Create commands
|
||||
- Use third party libraries
|
||||
- SQLite
|
||||
- Entity manipulation
|
||||
|
||||
5
docfx/examples/WithCommands.md
Normal file
5
docfx/examples/WithCommands.md
Normal file
@@ -0,0 +1,5 @@
|
||||
[!INCLUDE [WithCommands](../../examples/WithCommands/README.md)]
|
||||
|
||||
<a href="https://github.com/roflmuffin/CounterStrikeSharp/tree/main/examples/WithCommands" class="btn btn-secondary">View project on Github <i class="bi bi-github"></i></a>
|
||||
|
||||
[!code-csharp[](../../examples/WithCommands/WithCommandsPlugin.cs)]
|
||||
5
docfx/examples/WithConfig.md
Normal file
5
docfx/examples/WithConfig.md
Normal file
@@ -0,0 +1,5 @@
|
||||
[!INCLUDE [WithConfig](../../examples/WithConfig/README.md)]
|
||||
|
||||
<a href="https://github.com/roflmuffin/CounterStrikeSharp/tree/main/examples/WithConfig" class="btn btn-secondary">View project on Github <i class="bi bi-github"></i></a>
|
||||
|
||||
[!code-csharp[](../../examples/WithConfig/WithConfigPlugin.cs)]
|
||||
5
docfx/examples/WithDatabase.md
Normal file
5
docfx/examples/WithDatabase.md
Normal file
@@ -0,0 +1,5 @@
|
||||
[!INCLUDE [Database](../../examples/WithDatabaseDapper/README.md)]
|
||||
|
||||
<a href="https://github.com/roflmuffin/CounterStrikeSharp/tree/main/examples/WithDatabaseDapper" class="btn btn-secondary">View project on Github <i class="bi bi-github"></i></a>
|
||||
|
||||
[!code-csharp[](../../examples/WithDatabaseDapper/WithDatabaseDapperPlugin.cs)]
|
||||
5
docfx/examples/WithDependencyInjection.md
Normal file
5
docfx/examples/WithDependencyInjection.md
Normal file
@@ -0,0 +1,5 @@
|
||||
[!INCLUDE [WithDependencyInjection](../../examples/WithDependencyInjection/README.md)]
|
||||
|
||||
<a href="https://github.com/roflmuffin/CounterStrikeSharp/tree/main/examples/WithDependencyInjection" class="btn btn-secondary">View project on Github <i class="bi bi-github"></i></a>
|
||||
|
||||
[!code-csharp[](../../examples/WithDependencyInjection/WithDependencyInjectionPlugin.cs)]
|
||||
5
docfx/examples/WithGameEventHandlers.md
Normal file
5
docfx/examples/WithGameEventHandlers.md
Normal file
@@ -0,0 +1,5 @@
|
||||
[!INCLUDE [WithGameEventHandlers](../../examples/WithGameEventHandlers/README.md)]
|
||||
|
||||
<a href="https://github.com/roflmuffin/CounterStrikeSharp/tree/main/examples/WithGameEventHandlers" class="btn btn-secondary">View project on Github <i class="bi bi-github"></i></a>
|
||||
|
||||
[!code-csharp[](../../examples/WithGameEventHandlers/WithGameEventHandlersPlugin.cs)]
|
||||
15
docfx/examples/toc.yml
Normal file
15
docfx/examples/toc.yml
Normal file
@@ -0,0 +1,15 @@
|
||||
items:
|
||||
- name: Hello World
|
||||
href: HelloWorld.md
|
||||
- name: Commands
|
||||
href: WithCommands.md
|
||||
- name: Config
|
||||
href: WithConfig.md
|
||||
- name: Dependency Injection
|
||||
href: WithDependencyInjection.md
|
||||
- name: Game Event Handlers
|
||||
href: WithGameEventHandlers.md
|
||||
- name: Database (Dapper)
|
||||
href: WithDatabase.md
|
||||
- name: Warcraft Plugin
|
||||
href: WarcraftPlugin.md
|
||||
1
docfx/images/cssharp.svg
Normal file
1
docfx/images/cssharp.svg
Normal file
@@ -0,0 +1 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" xml:space="preserve" width="50" height="50" viewBox="0 0 13.229 13.229"><path d="M9.91 0 4.881.039c-.545.004-1.073.02-1.577.057A6.957 6.957 0 0 0 .403.934c-.233.124-.403.338-.403.6a.652.652 0 0 0 .98.563l.004-.002a5.434 5.434 0 0 1 2.098-.66c2.123-.227 3.599.534 4.595 1.428 1.095.982 2.108 2.982 1.74 5.175-.22 1.313-.826 2.42-1.77 3.28l-.002.002c-.171.156-.312.337-.312.568a.674.674 0 0 0 1.1.52c.027-.02.058-.049.073-.063a7.327 7.327 0 0 0 1.76-2.566l2.679-6.357c.126-.287.232-.583.265-.871.142-1.26-.531-1.985-1.383-2.32-.436-.172-1.05-.224-1.72-.23L9.91 0Zm.725.802c.476.02.94.363.88.99-.073.758-.83 1.287-1.16 1.785h1.16c.07.102.07.433 0 .535-.583-.057-1.233-.047-1.874-.045-.274-1.001 1.42-1.674 1.249-2.498-.081-.389-.636-.4-.536.179h-.669c-.012-.663.475-.966.95-.946Z" style="display:inline;opacity:1;fill:#ff6000;fill-opacity:1;stroke-width:.0470931" transform="translate(0 .334)"/><g style="display:inline"><path fill="#a179dc" d="M7.52 5.702a.743.743 0 0 0-.09-.374.715.715 0 0 0-.272-.264C6.16 4.489 5.163 3.916 4.167 3.34a.734.734 0 0 0-.796.008C2.974 3.583.987 4.72.395 5.064a.692.692 0 0 0-.363.638V9.17c0 .139.03.26.088.367.06.109.15.2.275.27.592.344 2.579 1.482 2.976 1.717a.735.735 0 0 0 .796.007c.996-.575 1.995-1.148 2.992-1.723a.713.713 0 0 0 .275-.271.747.747 0 0 0 .087-.367V5.702"/><path fill="#280068" d="M3.788 7.424.12 9.538c.06.109.15.2.275.27.592.344 2.579 1.482 2.976 1.717a.735.735 0 0 0 .796.007c.996-.575 1.995-1.148 2.992-1.723a.713.713 0 0 0 .275-.271L3.788 7.424"/><path fill="#390091" d="M7.52 5.702a.743.743 0 0 0-.09-.374L3.787 7.425l3.646 2.112a.748.748 0 0 0 .087-.367V5.702"/><path fill="#fff" d="M5.948 6.635v.395h.395v-.395h.197v.395h.395v.197H6.54v.395h.395v.198H6.54v.394h-.197V7.82h-.395v.394H5.75V7.82h-.395v-.198h.395v-.395h-.395V7.03h.395v-.395Zm.395.592h-.395v.395h.395z"/><path fill="#fff" d="M3.796 4.652c1.03 0 1.93.56 2.41 1.39l-.004-.007-1.212.698a1.385 1.385 0 0 0-1.178-.683h-.016a1.386 1.386 0 1 0 1.208 2.066l-.006.01 1.21.7a2.783 2.783 0 0 1-2.38 1.394h-.032a2.784 2.784 0 1 1 0-5.568z"/></g></svg>
|
||||
|
After Width: | Height: | Size: 2.1 KiB |
23
docfx/index.md
Normal file
23
docfx/index.md
Normal file
@@ -0,0 +1,23 @@
|
||||
---
|
||||
_layout: landing
|
||||
uid: home
|
||||
title: CounterStrikeSharp
|
||||
_appTitle: ''
|
||||
description: Write Counter-Strike 2 server plugins in C#.
|
||||
---
|
||||
|
||||
<div class="row justify-content-md-center">
|
||||
<div class="col-12 col-lg-10 col-xl-8 col-xxl-6">
|
||||
<div class="text-center">
|
||||
<img src="images/cssharp.svg" height="128" width="128">
|
||||
<h1 class="h1">CounterStrikeSharp</h1>
|
||||
<span>CounterStrikeSharp is a simpler way to write CS2 server plugins.</span>
|
||||
<div>
|
||||
<a href="docs/guides/getting-started.md" class="btn btn-primary btn-lg fw-bold my-5">Get Started <i class="bi bi-arrow-right"></a>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
[!code-csharp[](../examples/HelloWorld/HelloWorldPlugin.cs)]
|
||||
|
||||
</div>
|
||||
</div>
|
||||
149
docfx/layouts/cssharp/layout/_master.tmpl
Normal file
149
docfx/layouts/cssharp/layout/_master.tmpl
Normal file
@@ -0,0 +1,149 @@
|
||||
{{!Licensed to the .NET Foundation under one or more agreements. The .NET Foundation licenses this file to you under the MIT license.}}
|
||||
{{!include(/^public/.*/)}}
|
||||
{{!include(favicon.ico)}}
|
||||
{{!include(logo.svg)}}
|
||||
<!DOCTYPE html>
|
||||
<html {{#_lang}}lang="{{_lang}}"{{/_lang}}>
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
{{#redirect_url}}
|
||||
<meta http-equiv="refresh" content="0;URL='{{redirect_url}}'">
|
||||
{{/redirect_url}}
|
||||
{{^redirect_url}}
|
||||
<title>{{#title}}{{title}}{{/title}}{{^title}}{{>partials/title}}{{/title}} {{#_appTitle}}| {{_appTitle}} {{/_appTitle}}</title>
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<meta name="title" content="{{#title}}{{title}}{{/title}}{{^title}}{{>partials/title}}{{/title}} {{#_appTitle}}| {{_appTitle}} {{/_appTitle}}">
|
||||
{{#_description}}<meta name="description" content="{{_description}}">{{/_description}}
|
||||
<link rel="icon" href="{{_rel}}{{{_appFaviconPath}}}{{^_appFaviconPath}}favicon.ico{{/_appFaviconPath}}">
|
||||
<link rel="stylesheet" href="{{_rel}}public/docfx.min.css">
|
||||
<link rel="stylesheet" href="{{_rel}}public/main.css">
|
||||
<meta name="docfx:navrel" content="{{_navRel}}">
|
||||
<meta name="docfx:tocrel" content="{{_tocRel}}">
|
||||
{{#_noindex}}<meta name="searchOption" content="noindex">{{/_noindex}}
|
||||
{{#_enableSearch}}<meta name="docfx:rel" content="{{_rel}}">{{/_enableSearch}}
|
||||
{{#_disableNewTab}}<meta name="docfx:disablenewtab" content="true">{{/_disableNewTab}}
|
||||
{{#_disableTocFilter}}<meta name="docfx:disabletocfilter" content="true">{{/_disableTocFilter}}
|
||||
{{#docurl}}<meta name="docfx:docurl" content="{{docurl}}">{{/docurl}}
|
||||
<meta name="loc:inThisArticle" content="{{__global.inThisArticle}}">
|
||||
<meta name="loc:searchResultsCount" content="{{__global.searchResultsCount}}">
|
||||
<meta name="loc:searchNoResults" content="{{__global.searchNoResults}}">
|
||||
<meta name="loc:tocFilter" content="{{__global.tocFilter}}">
|
||||
<meta name="loc:nextArticle" content="{{__global.nextArticle}}">
|
||||
<meta name="loc:prevArticle" content="{{__global.prevArticle}}">
|
||||
<meta name="loc:themeLight" content="{{__global.themeLight}}">
|
||||
<meta name="loc:themeDark" content="{{__global.themeDark}}">
|
||||
<meta name="loc:themeAuto" content="{{__global.themeAuto}}">
|
||||
<meta name="loc:changeTheme" content="{{__global.changeTheme}}">
|
||||
<meta name="loc:copy" content="{{__global.copy}}">
|
||||
<meta name="loc:downloadPdf" content="{{__global.downloadPdf}}">
|
||||
{{/redirect_url}}
|
||||
<script data-goatcounter="https://cssharp.goatcounter.com/count" async src="//gc.zgo.at/count.js"></script>
|
||||
</head>
|
||||
|
||||
{{^redirect_url}}
|
||||
<script type="module" src="./{{_rel}}public/docfx.min.js"></script>
|
||||
|
||||
<script>
|
||||
const theme = localStorage.getItem('theme') || 'auto'
|
||||
document.documentElement.setAttribute('data-bs-theme', theme === 'auto' ? (window.matchMedia('(prefers-color-scheme: dark)').matches ? 'dark' : 'light') : theme)
|
||||
</script>
|
||||
|
||||
{{#_googleAnalyticsTagId}}
|
||||
<script async src="https://www.googletagmanager.com/gtag/js?id={{_googleAnalyticsTagId}}"></script>
|
||||
<script>
|
||||
window.dataLayer = window.dataLayer || [];
|
||||
function gtag() { dataLayer.push(arguments); }
|
||||
gtag('js', new Date());
|
||||
gtag('config', '{{_googleAnalyticsTagId}}');
|
||||
</script>
|
||||
{{/_googleAnalyticsTagId}}
|
||||
|
||||
<body class="tex2jax_ignore" data-layout="{{_layout}}{{layout}}" data-yaml-mime="{{yamlmime}}">
|
||||
<header class="bg-body border-bottom">
|
||||
<nav id="autocollapse" class="navbar navbar-expand-md" role="navigation">
|
||||
<div class="container-xxl flex-nowrap">
|
||||
<a class="navbar-brand" href="{{_appLogoUrl}}{{^_appLogoUrl}}{{_rel}}index.html{{/_appLogoUrl}}">
|
||||
<img id="logo" class="svg" src="{{_rel}}{{{_appLogoPath}}}{{^_appLogoPath}}logo.svg{{/_appLogoPath}}" alt="{{_appName}}" >
|
||||
{{_appName}}
|
||||
</a>
|
||||
<button class="btn btn-lg d-md-none border-0" type="button" data-bs-toggle="collapse" data-bs-target="#navpanel" aria-controls="navpanel" aria-expanded="false" aria-label="Toggle navigation">
|
||||
<i class="bi bi-three-dots"></i>
|
||||
</button>
|
||||
<div class="collapse navbar-collapse" id="navpanel">
|
||||
<div id="navbar">
|
||||
{{#_enableSearch}}
|
||||
<form class="search" role="search" id="search">
|
||||
<i class="bi bi-search"></i>
|
||||
<input class="form-control" id="search-query" type="search" disabled placeholder="{{__global.search}}" autocomplete="off" aria-label="Search">
|
||||
</form>
|
||||
{{/_enableSearch}}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</nav>
|
||||
</header>
|
||||
|
||||
<main class="container-xxl">
|
||||
<div class="toc-offcanvas">
|
||||
<div class="offcanvas-md offcanvas-start" tabindex="-1" id="tocOffcanvas" aria-labelledby="tocOffcanvasLabel">
|
||||
<div class="offcanvas-header">
|
||||
<h5 class="offcanvas-title" id="tocOffcanvasLabel">Table of Contents</h5>
|
||||
<button type="button" class="btn-close" data-bs-dismiss="offcanvas" data-bs-target="#tocOffcanvas" aria-label="Close"></button>
|
||||
</div>
|
||||
<div class="offcanvas-body">
|
||||
<nav class="toc" id="toc"></nav>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="content">
|
||||
<div class="actionbar">
|
||||
<button class="btn btn-lg border-0 d-md-none" style="margin-top: -.65em; margin-left: -.8em"
|
||||
type="button" data-bs-toggle="offcanvas" data-bs-target="#tocOffcanvas"
|
||||
aria-controls="tocOffcanvas" aria-expanded="false" aria-label="Show table of contents">
|
||||
<i class="bi bi-list"></i>
|
||||
</button>
|
||||
|
||||
<nav id="breadcrumb"></nav>
|
||||
</div>
|
||||
|
||||
<article data-uid="{{uid}}">
|
||||
{{!body}}
|
||||
</article>
|
||||
|
||||
{{^_disableContribution}}
|
||||
<div class="contribution d-print-none">
|
||||
{{#sourceurl}}
|
||||
<a href="{{sourceurl}}" class="edit-link">{{__global.improveThisDoc}}</a>
|
||||
{{/sourceurl}}
|
||||
{{^sourceurl}}{{#docurl}}
|
||||
<a href="{{docurl}}" class="edit-link">{{__global.improveThisDoc}}</a>
|
||||
{{/docurl}}{{/sourceurl}}
|
||||
</div>
|
||||
{{/_disableContribution}}
|
||||
|
||||
{{^_disableNextArticle}}
|
||||
<div class="next-article d-print-none border-top" id="nextArticle"></div>
|
||||
{{/_disableNextArticle}}
|
||||
|
||||
</div>
|
||||
|
||||
<div class="affix">
|
||||
<nav id="affix"></nav>
|
||||
</div>
|
||||
</main>
|
||||
|
||||
{{#_enableSearch}}
|
||||
<div class="container-xxl search-results" id="search-results"></div>
|
||||
{{/_enableSearch}}
|
||||
|
||||
<footer class="border-top text-secondary">
|
||||
<div class="container-xxl">
|
||||
<div class="flex-fill">
|
||||
{{{_appFooter}}}{{^_appFooter}}<span>Made with <a href="https://dotnet.github.io/docfx">docfx</a></span>{{/_appFooter}}
|
||||
</div>
|
||||
</div>
|
||||
</footer>
|
||||
</body>
|
||||
{{/redirect_url}}
|
||||
</html>
|
||||
14
docfx/layouts/cssharp/public/main.js
Normal file
14
docfx/layouts/cssharp/public/main.js
Normal file
@@ -0,0 +1,14 @@
|
||||
export default {
|
||||
iconLinks: [
|
||||
{
|
||||
icon: "github",
|
||||
href: "https://github.com/roflmuffin/CounterStrikeSharp",
|
||||
title: "GitHub",
|
||||
},
|
||||
{
|
||||
icon: "discord",
|
||||
href: "https://discord.gg/X7r3PmuYKq",
|
||||
title: "Discord",
|
||||
},
|
||||
],
|
||||
};
|
||||
6
docfx/toc.yml
Normal file
6
docfx/toc.yml
Normal file
@@ -0,0 +1,6 @@
|
||||
- name: Docs
|
||||
href: docs/
|
||||
- name: Examples
|
||||
href: examples/
|
||||
- name: API
|
||||
href: api/
|
||||
21
docs/.gitignore
vendored
21
docs/.gitignore
vendored
@@ -1,21 +0,0 @@
|
||||
# build output
|
||||
dist/
|
||||
# generated types
|
||||
.astro/
|
||||
|
||||
# dependencies
|
||||
node_modules/
|
||||
|
||||
# logs
|
||||
npm-debug.log*
|
||||
yarn-debug.log*
|
||||
yarn-error.log*
|
||||
pnpm-debug.log*
|
||||
|
||||
|
||||
# environment variables
|
||||
.env
|
||||
.env.production
|
||||
|
||||
# macOS-specific files
|
||||
.DS_Store
|
||||
@@ -1,6 +0,0 @@
|
||||
{
|
||||
"trailingComma": "es5",
|
||||
"tabWidth": 2,
|
||||
"semi": true,
|
||||
"singleQuote": true
|
||||
}
|
||||
@@ -1,61 +0,0 @@
|
||||
import { defineConfig } from 'astro/config';
|
||||
import starlight from '@astrojs/starlight';
|
||||
|
||||
// https://astro.build/config
|
||||
export default defineConfig({
|
||||
integrations: [
|
||||
starlight({
|
||||
title: 'CounterStrikeSharp Docs',
|
||||
customCss: [
|
||||
'@fontsource/dm-sans/400.css',
|
||||
'@fontsource/dm-sans/500.css',
|
||||
'@fontsource/dm-sans/700.css',
|
||||
'@fontsource/jetbrains-mono/400.css',
|
||||
'@fontsource/jetbrains-mono/600.css',
|
||||
'./src/styles/custom.css',
|
||||
],
|
||||
head: [
|
||||
{
|
||||
tag: 'script',
|
||||
attrs: {
|
||||
src: 'https://gc.zgo.at/count.js',
|
||||
'data-goatcounter': 'https://cssharp.goatcounter.com/count',
|
||||
async: true,
|
||||
},
|
||||
},
|
||||
],
|
||||
social: {
|
||||
github: 'https://github.com/roflmuffin/CounterStrikeSharp',
|
||||
},
|
||||
sidebar: [
|
||||
{
|
||||
label: 'Guides',
|
||||
autogenerate: { directory: 'guides' },
|
||||
},
|
||||
{
|
||||
label: 'Features',
|
||||
autogenerate: { directory: 'features' },
|
||||
},
|
||||
{
|
||||
label: 'Admin Framework',
|
||||
autogenerate: { directory: 'admin-framework' },
|
||||
},
|
||||
{
|
||||
label: 'Reference',
|
||||
autogenerate: { directory: 'reference' },
|
||||
},
|
||||
],
|
||||
editLink: {
|
||||
baseUrl:
|
||||
'https://github.com/roflmuffin/CounterStrikeSharp/edit/main/docs/',
|
||||
},
|
||||
}),
|
||||
],
|
||||
base: '/',
|
||||
site: 'https://docs.cssharp.dev',
|
||||
markdown: {
|
||||
shikiConfig: {
|
||||
wrap: false,
|
||||
},
|
||||
},
|
||||
});
|
||||
@@ -1,22 +0,0 @@
|
||||
{
|
||||
"name": "",
|
||||
"type": "module",
|
||||
"version": "0.0.1",
|
||||
"scripts": {
|
||||
"dev": "astro dev",
|
||||
"start": "astro dev",
|
||||
"build": "astro build",
|
||||
"preview": "astro preview",
|
||||
"astro": "astro"
|
||||
},
|
||||
"dependencies": {
|
||||
"@astrojs/starlight": "^0.11.1",
|
||||
"@fontsource/dm-sans": "^5.0.15",
|
||||
"@fontsource/jetbrains-mono": "^5.0.15",
|
||||
"astro": "^3.2.3",
|
||||
"sharp": "^0.32.5"
|
||||
},
|
||||
"devDependencies": {
|
||||
"prettier": "^3.0.3"
|
||||
}
|
||||
}
|
||||
4118
docs/pnpm-lock.yaml
generated
4118
docs/pnpm-lock.yaml
generated
File diff suppressed because it is too large
Load Diff
@@ -1,7 +0,0 @@
|
||||
import { defineCollection } from 'astro:content';
|
||||
import { docsSchema, i18nSchema } from '@astrojs/starlight/schema';
|
||||
|
||||
export const collections = {
|
||||
docs: defineCollection({ schema: docsSchema() }),
|
||||
i18n: defineCollection({ type: 'data', schema: i18nSchema() }),
|
||||
};
|
||||
@@ -1,48 +0,0 @@
|
||||
---
|
||||
title: CounterStrikeSharp
|
||||
description: Write Counter-Strike 2 server plugins in C#.
|
||||
template: splash
|
||||
hero:
|
||||
tagline: <code class="csharp">CounterStrikeSharp</code> is a simpler way to write CS2 server plugins.
|
||||
actions:
|
||||
- text: Get started
|
||||
link: ./guides/getting-started/
|
||||
icon: right-arrow
|
||||
variant: primary
|
||||
- text: Browse source
|
||||
link: https://github.com/roflmuffin/CounterStrikeSharp/
|
||||
icon: github
|
||||
---
|
||||
|
||||
```csharp
|
||||
using CounterStrikeSharp.API.Core;
|
||||
|
||||
namespace HelloWorldPlugin;
|
||||
|
||||
public class HelloWorldPlugin : BasePlugin
|
||||
{
|
||||
public override string ModuleName => "Hello World Plugin";
|
||||
|
||||
public override string ModuleVersion => "0.0.1";
|
||||
|
||||
public override void Load(bool hotReload)
|
||||
{
|
||||
Logger.LogInformation("Plugin loaded successfully!");
|
||||
}
|
||||
|
||||
[GameEventHandler]
|
||||
public HookResult OnPlayerConnect(EventPlayerConnect @event, GameEventInfo info)
|
||||
{
|
||||
// Userid will give you a reference to a CCSPlayerController class
|
||||
Logger.LogInformation("Player {Name} has connected!", @event.Userid.PlayerName);
|
||||
|
||||
return HookResult.Continue;
|
||||
}
|
||||
|
||||
[ConsoleCommand("issue_warning", "Issue warning to player")]
|
||||
public void OnCommand(CCSPlayerController? player, CommandInfo command)
|
||||
{
|
||||
Logger.LogWarning("Player shouldn't be doing that");
|
||||
}
|
||||
}
|
||||
```
|
||||
2
docs/src/env.d.ts
vendored
2
docs/src/env.d.ts
vendored
@@ -1,2 +0,0 @@
|
||||
/// <reference path="../.astro/types.d.ts" />
|
||||
/// <reference types="astro/client" />
|
||||
@@ -1,19 +0,0 @@
|
||||
:root {
|
||||
--sl-font: 'DM Sans', serif;
|
||||
--sl-font-mono: 'Jetbrains Mono', monospace;
|
||||
}
|
||||
|
||||
.hero {
|
||||
grid-template-columns: 1fr;
|
||||
}
|
||||
|
||||
.hero .copy {
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
.hero .actions {
|
||||
justify-content: center;
|
||||
}
|
||||
|
||||
.hero {
|
||||
}
|
||||
@@ -1,3 +0,0 @@
|
||||
{
|
||||
"extends": "astro/tsconfigs/strict"
|
||||
}
|
||||
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.
|
||||
@@ -73,7 +73,7 @@ namespace WarcraftPlugin
|
||||
var victim = @event.Userid;
|
||||
var headshot = @event.Headshot;
|
||||
|
||||
if (attacker.IsValid && victim.IsValid && (attacker.EntityIndex.Value.Value != victim.EntityIndex.Value.Value) && !attacker.IsBot)
|
||||
if (attacker.IsValid && victim.IsValid && (attacker != victim) && !attacker.IsBot)
|
||||
{
|
||||
var weaponName = attacker.PlayerPawn.Value.WeaponServices.ActiveWeapon.Value.DesignerName;
|
||||
|
||||
|
||||
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/WithDatabaseDapper/README.md
Normal file
2
examples/WithDatabaseDapper/README.md
Normal file
@@ -0,0 +1,2 @@
|
||||
# With Database (Dapper)
|
||||
Simple SQLite database example using Dapper library to track kills.
|
||||
16
examples/WithDatabaseDapper/WithDatabaseDapper.csproj
Normal file
16
examples/WithDatabaseDapper/WithDatabaseDapper.csproj
Normal file
@@ -0,0 +1,16 @@
|
||||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
<PropertyGroup>
|
||||
<TargetFramework>net7.0</TargetFramework>
|
||||
<ImplicitUsings>enable</ImplicitUsings>
|
||||
<Nullable>enable</Nullable>
|
||||
<GenerateAssemblyInfo>false</GenerateAssemblyInfo>
|
||||
<CopyLocalLockFileAssemblies>true</CopyLocalLockFileAssemblies>
|
||||
</PropertyGroup>
|
||||
<ItemGroup>
|
||||
<ProjectReference Include="..\..\managed\CounterStrikeSharp.API\CounterStrikeSharp.API.csproj" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<PackageReference Include="Dapper" Version="2.1.24" />
|
||||
<PackageReference Include="Microsoft.Data.Sqlite" Version="7.0.14" />
|
||||
</ItemGroup>
|
||||
</Project>
|
||||
89
examples/WithDatabaseDapper/WithDatabaseDapperPlugin.cs
Normal file
89
examples/WithDatabaseDapper/WithDatabaseDapperPlugin.cs
Normal file
@@ -0,0 +1,89 @@
|
||||
using CounterStrikeSharp.API;
|
||||
using CounterStrikeSharp.API.Core;
|
||||
using CounterStrikeSharp.API.Core.Attributes;
|
||||
using CounterStrikeSharp.API.Core.Attributes.Registration;
|
||||
using CounterStrikeSharp.API.Modules.Commands;
|
||||
using Dapper;
|
||||
using Microsoft.Data.Sqlite;
|
||||
using Microsoft.Extensions.Logging;
|
||||
|
||||
namespace WithDatabaseDapper;
|
||||
|
||||
[MinimumApiVersion(80)]
|
||||
public class WithDatabaseDapperPlugin : BasePlugin
|
||||
{
|
||||
public override string ModuleName => "Example: With Database (Dapper)";
|
||||
public override string ModuleVersion => "1.0.0";
|
||||
public override string ModuleAuthor => "CounterStrikeSharp & Contributors";
|
||||
public override string ModuleDescription => "A plugin that reads and writes from the database.";
|
||||
|
||||
private SqliteConnection _connection = null!;
|
||||
|
||||
public override void Load(bool hotReload)
|
||||
{
|
||||
Logger.LogInformation("Loading database from {Path}", Path.Join(ModuleDirectory, "database.db"));
|
||||
_connection = new SqliteConnection($"Data Source={Path.Join(ModuleDirectory, "database.db")}");
|
||||
_connection.Open();
|
||||
|
||||
// Create the table if it doesn't exist
|
||||
// Run in a separate thread to avoid blocking the main thread
|
||||
Task.Run(async () =>
|
||||
{
|
||||
await _connection.ExecuteAsync(@"
|
||||
CREATE TABLE IF NOT EXISTS `players` (
|
||||
`steamid` UNSIGNED BIG INT NOT NULL,
|
||||
`kills` INT NOT NULL DEFAULT 0,
|
||||
PRIMARY KEY (`steamid`));");
|
||||
});
|
||||
}
|
||||
|
||||
[GameEventHandler]
|
||||
public HookResult OnPlayerKilled(EventPlayerDeath @event, GameEventInfo info)
|
||||
{
|
||||
// Don't count suicides.
|
||||
if (@event.Attacker == @event.Userid) return HookResult.Continue;
|
||||
|
||||
// Capture the steamid of the player as `@event` will not be available outside of this function.
|
||||
var steamId = @event.Attacker.AuthorizedSteamID?.SteamId64;
|
||||
|
||||
if (steamId == null) return HookResult.Continue;
|
||||
|
||||
// Run in a separate thread to avoid blocking the main thread
|
||||
Task.Run(async () =>
|
||||
{
|
||||
// insert or update the player's kills
|
||||
await _connection.ExecuteAsync(@"
|
||||
INSERT INTO `players` (`steamid`, `kills`) VALUES (@SteamId, 1)
|
||||
ON CONFLICT(`steamid`) DO UPDATE SET `kills` = `kills` + 1;",
|
||||
new
|
||||
{
|
||||
SteamId = steamId
|
||||
});
|
||||
});
|
||||
|
||||
return HookResult.Continue;
|
||||
}
|
||||
|
||||
[ConsoleCommand("css_kills", "Get count of kills for a player")]
|
||||
public void OnKillsCommand(CCSPlayerController? player, CommandInfo commandInfo)
|
||||
{
|
||||
if (player == null) return;
|
||||
|
||||
// Capture the SteamID of the player as `@event` will not be available outside of this function.
|
||||
var steamId = player.AuthorizedSteamID.SteamId64;
|
||||
|
||||
// Run in a separate thread to avoid blocking the main thread
|
||||
Task.Run(async () =>
|
||||
{
|
||||
var result = await _connection.QueryFirstOrDefaultAsync(@"SELECT `kills` FROM `players` WHERE `steamid` = @SteamId;",
|
||||
new
|
||||
{
|
||||
SteamId = steamId
|
||||
});
|
||||
|
||||
// Print the result to the player's chat. Note that this needs to be run on the game thread.
|
||||
// So we use `Server.NextFrame` to run it on the next game tick.
|
||||
Server.NextFrame(() => { player.PrintToChat($"Kills: {result?.kills ?? 0}"); });
|
||||
});
|
||||
}
|
||||
}
|
||||
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;
|
||||
}
|
||||
}
|
||||
Submodule libraries/hl2sdk-cs2 updated: 1d394d3365...d7ed476064
@@ -30,5 +30,19 @@ namespace CounterStrikeSharp.API
|
||||
{
|
||||
Handle = pointer;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Returns a new instance of the specified type using the pointer from the passed in object.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// Useful for creating a new instance of a class that inherits from NativeObject.
|
||||
/// e.g. <code>var weaponServices = playerWeaponServices.As<CCSPlayer_WeaponServices>();</code>
|
||||
/// </remarks>
|
||||
/// <typeparam name="T"></typeparam>
|
||||
/// <returns></returns>
|
||||
public T As<T>() where T : NativeObject
|
||||
{
|
||||
return (T)Activator.CreateInstance(typeof(T), this.Handle);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -157,6 +157,30 @@ namespace CounterStrikeSharp.API.Core
|
||||
}
|
||||
}
|
||||
|
||||
public static string GetClientConvarValue(int clientindex, string convarname){
|
||||
lock (ScriptContext.GlobalScriptContext.Lock) {
|
||||
ScriptContext.GlobalScriptContext.Reset();
|
||||
ScriptContext.GlobalScriptContext.Push(clientindex);
|
||||
ScriptContext.GlobalScriptContext.Push(convarname);
|
||||
ScriptContext.GlobalScriptContext.SetIdentifier(0xAE4B1B79);
|
||||
ScriptContext.GlobalScriptContext.Invoke();
|
||||
ScriptContext.GlobalScriptContext.CheckErrors();
|
||||
return (string)ScriptContext.GlobalScriptContext.GetResult(typeof(string));
|
||||
}
|
||||
}
|
||||
|
||||
public static void SetFakeClientConvarValue(int clientindex, string convarname, string convarvalue){
|
||||
lock (ScriptContext.GlobalScriptContext.Lock) {
|
||||
ScriptContext.GlobalScriptContext.Reset();
|
||||
ScriptContext.GlobalScriptContext.Push(clientindex);
|
||||
ScriptContext.GlobalScriptContext.Push(convarname);
|
||||
ScriptContext.GlobalScriptContext.Push(convarvalue);
|
||||
ScriptContext.GlobalScriptContext.SetIdentifier(0x4C61E8BB);
|
||||
ScriptContext.GlobalScriptContext.Invoke();
|
||||
ScriptContext.GlobalScriptContext.CheckErrors();
|
||||
}
|
||||
}
|
||||
|
||||
public static T DynamicHookGetReturn<T>(IntPtr hook, int datatype){
|
||||
lock (ScriptContext.GlobalScriptContext.Lock) {
|
||||
ScriptContext.GlobalScriptContext.Reset();
|
||||
@@ -455,6 +479,16 @@ namespace CounterStrikeSharp.API.Core
|
||||
}
|
||||
}
|
||||
|
||||
public static void QueueTaskForNextWorldUpdate(IntPtr callback){
|
||||
lock (ScriptContext.GlobalScriptContext.Lock) {
|
||||
ScriptContext.GlobalScriptContext.Reset();
|
||||
ScriptContext.GlobalScriptContext.Push(callback);
|
||||
ScriptContext.GlobalScriptContext.SetIdentifier(0xAD51A0C9);
|
||||
ScriptContext.GlobalScriptContext.Invoke();
|
||||
ScriptContext.GlobalScriptContext.CheckErrors();
|
||||
}
|
||||
}
|
||||
|
||||
public static IntPtr GetValveInterface(int interfacetype, string interfacename){
|
||||
lock (ScriptContext.GlobalScriptContext.Lock) {
|
||||
ScriptContext.GlobalScriptContext.Reset();
|
||||
@@ -534,6 +568,49 @@ namespace CounterStrikeSharp.API.Core
|
||||
}
|
||||
}
|
||||
|
||||
public static uint GetRefFromEntityPointer(IntPtr entitypointer){
|
||||
lock (ScriptContext.GlobalScriptContext.Lock) {
|
||||
ScriptContext.GlobalScriptContext.Reset();
|
||||
ScriptContext.GlobalScriptContext.Push(entitypointer);
|
||||
ScriptContext.GlobalScriptContext.SetIdentifier(0xAF13DA94);
|
||||
ScriptContext.GlobalScriptContext.Invoke();
|
||||
ScriptContext.GlobalScriptContext.CheckErrors();
|
||||
return (uint)ScriptContext.GlobalScriptContext.GetResult(typeof(uint));
|
||||
}
|
||||
}
|
||||
|
||||
public static IntPtr GetEntityPointerFromRef(uint entityref){
|
||||
lock (ScriptContext.GlobalScriptContext.Lock) {
|
||||
ScriptContext.GlobalScriptContext.Reset();
|
||||
ScriptContext.GlobalScriptContext.Push(entityref);
|
||||
ScriptContext.GlobalScriptContext.SetIdentifier(0xDBC17174);
|
||||
ScriptContext.GlobalScriptContext.Invoke();
|
||||
ScriptContext.GlobalScriptContext.CheckErrors();
|
||||
return (IntPtr)ScriptContext.GlobalScriptContext.GetResult(typeof(IntPtr));
|
||||
}
|
||||
}
|
||||
|
||||
public static IntPtr GetConcreteEntityListPointer(){
|
||||
lock (ScriptContext.GlobalScriptContext.Lock) {
|
||||
ScriptContext.GlobalScriptContext.Reset();
|
||||
ScriptContext.GlobalScriptContext.SetIdentifier(0x5756DB36);
|
||||
ScriptContext.GlobalScriptContext.Invoke();
|
||||
ScriptContext.GlobalScriptContext.CheckErrors();
|
||||
return (IntPtr)ScriptContext.GlobalScriptContext.GetResult(typeof(IntPtr));
|
||||
}
|
||||
}
|
||||
|
||||
public static bool IsRefValidEntity(uint entityref){
|
||||
lock (ScriptContext.GlobalScriptContext.Lock) {
|
||||
ScriptContext.GlobalScriptContext.Reset();
|
||||
ScriptContext.GlobalScriptContext.Push(entityref);
|
||||
ScriptContext.GlobalScriptContext.SetIdentifier(0x6E38A1FC);
|
||||
ScriptContext.GlobalScriptContext.Invoke();
|
||||
ScriptContext.GlobalScriptContext.CheckErrors();
|
||||
return (bool)ScriptContext.GlobalScriptContext.GetResult(typeof(bool));
|
||||
}
|
||||
}
|
||||
|
||||
public static void PrintToConsole(int index, string message){
|
||||
lock (ScriptContext.GlobalScriptContext.Lock) {
|
||||
ScriptContext.GlobalScriptContext.Reset();
|
||||
@@ -555,6 +632,28 @@ namespace CounterStrikeSharp.API.Core
|
||||
}
|
||||
}
|
||||
|
||||
public static ulong GetPlayerAuthorizedSteamid(int slot){
|
||||
lock (ScriptContext.GlobalScriptContext.Lock) {
|
||||
ScriptContext.GlobalScriptContext.Reset();
|
||||
ScriptContext.GlobalScriptContext.Push(slot);
|
||||
ScriptContext.GlobalScriptContext.SetIdentifier(0xD1F30B3B);
|
||||
ScriptContext.GlobalScriptContext.Invoke();
|
||||
ScriptContext.GlobalScriptContext.CheckErrors();
|
||||
return (ulong)ScriptContext.GlobalScriptContext.GetResult(typeof(ulong));
|
||||
}
|
||||
}
|
||||
|
||||
public static string GetPlayerIpAddress(int slot){
|
||||
lock (ScriptContext.GlobalScriptContext.Lock) {
|
||||
ScriptContext.GlobalScriptContext.Reset();
|
||||
ScriptContext.GlobalScriptContext.Push(slot);
|
||||
ScriptContext.GlobalScriptContext.SetIdentifier(0x46A45CB0);
|
||||
ScriptContext.GlobalScriptContext.Invoke();
|
||||
ScriptContext.GlobalScriptContext.CheckErrors();
|
||||
return (string)ScriptContext.GlobalScriptContext.GetResult(typeof(string));
|
||||
}
|
||||
}
|
||||
|
||||
public static void HookEvent(string name, InputArgument callback, bool ispost){
|
||||
lock (ScriptContext.GlobalScriptContext.Lock) {
|
||||
ScriptContext.GlobalScriptContext.Reset();
|
||||
@@ -967,6 +1066,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();
|
||||
@@ -977,6 +1087,16 @@ namespace CounterStrikeSharp.API.Core
|
||||
}
|
||||
}
|
||||
|
||||
public static bool IsServerPaused(){
|
||||
lock (ScriptContext.GlobalScriptContext.Lock) {
|
||||
ScriptContext.GlobalScriptContext.Reset();
|
||||
ScriptContext.GlobalScriptContext.SetIdentifier(0xB216AAAC);
|
||||
ScriptContext.GlobalScriptContext.Invoke();
|
||||
ScriptContext.GlobalScriptContext.CheckErrors();
|
||||
return (bool)ScriptContext.GlobalScriptContext.GetResult(typeof(bool));
|
||||
}
|
||||
}
|
||||
|
||||
public static IntPtr CreateTimer(float interval, InputArgument callback, int flags){
|
||||
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)
|
||||
|
||||
@@ -126,5 +126,26 @@ namespace CounterStrikeSharp.API.Core
|
||||
/// <param name="hostname">New hostname of the server</param>
|
||||
[ListenerName("OnHostNameChanged")]
|
||||
public delegate void OnHostNameChanged(string hostname);
|
||||
|
||||
/// <summary>
|
||||
/// Called before the server enters fatal shutdown.
|
||||
/// </summary>
|
||||
[ListenerName("OnPreFatalShutdown")]
|
||||
public delegate void OnServerPreFatalShutdown();
|
||||
|
||||
/// <summary>
|
||||
/// Called when the server is in a loading stage.
|
||||
/// </summary>
|
||||
/// <param name="frameTime"></param>
|
||||
[ListenerName("OnUpdateWhenNotInGame")]
|
||||
public delegate void OnUpdateWhenNotInGame(float frameTime);
|
||||
|
||||
/// <summary>
|
||||
/// Called before the world updates.
|
||||
/// This seems to be called even when the server is hibernating.
|
||||
/// </summary>
|
||||
/// <param name="simulating"><see langword="true"/> if simulating, <see langword="false"/> otherwise</param>
|
||||
[ListenerName("OnServerPreWorldUpdate")]
|
||||
public delegate void OnServerPreWorldUpdate(bool simulating);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,4 +1,7 @@
|
||||
using System;
|
||||
|
||||
using CounterStrikeSharp.API.Modules.Cvars;
|
||||
using CounterStrikeSharp.API.Modules.Entities;
|
||||
using CounterStrikeSharp.API.Modules.Entities.Constants;
|
||||
using CounterStrikeSharp.API.Modules.Memory;
|
||||
using CounterStrikeSharp.API.Modules.Utils;
|
||||
@@ -11,8 +14,7 @@ public partial class CCSPlayerController
|
||||
{
|
||||
get
|
||||
{
|
||||
if (EntityIndex == null) return null;
|
||||
return NativeAPI.GetUseridFromIndex((int)this.EntityIndex.Value.Value);
|
||||
return NativeAPI.GetUseridFromIndex((int)this.Index);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -38,7 +40,7 @@ public partial class CCSPlayerController
|
||||
|
||||
public void PrintToConsole(string message)
|
||||
{
|
||||
NativeAPI.PrintToConsole((int)EntityIndex.Value.Value, $"{message}\n\0");
|
||||
NativeAPI.PrintToConsole((int)Index, $"{message}\n\0");
|
||||
}
|
||||
|
||||
public void PrintToChat(string message)
|
||||
@@ -50,13 +52,15 @@ public partial class CCSPlayerController
|
||||
{
|
||||
VirtualFunctions.ClientPrint(this.Handle, HudDestination.Center, message, 0, 0, 0, 0);
|
||||
}
|
||||
|
||||
public void PrintToCenterHtml(string message) => PrintToCenterHtml(message, 5);
|
||||
|
||||
public void PrintToCenterHtml(string message)
|
||||
public void PrintToCenterHtml(string message, int duration)
|
||||
{
|
||||
var @event = new EventShowSurvivalRespawnStatus(true)
|
||||
{
|
||||
LocToken = message,
|
||||
Duration = 5,
|
||||
Duration = duration,
|
||||
Userid = this
|
||||
};
|
||||
@event.FireEventToClient(this);
|
||||
@@ -140,8 +144,94 @@ public partial class CCSPlayerController
|
||||
team);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Get a ConVar value for given player
|
||||
/// </summary>
|
||||
/// <param name="conVar">Name of the convar to retrieve</param>
|
||||
/// <returns>ConVar string value</returns>
|
||||
public string GetConVarValue(string conVar)
|
||||
{
|
||||
return NativeAPI.GetClientConvarValue(this.Slot, conVar);
|
||||
}
|
||||
|
||||
public string GetConVarValue(ConVar? conVar)
|
||||
{
|
||||
if (conVar == null)
|
||||
{
|
||||
throw new Exception("Invalid convar passed to 'GetConVarValue'");
|
||||
}
|
||||
|
||||
return GetConVarValue(conVar.Name);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Sets a ConVar value on a fake client (bot).
|
||||
/// </summary>
|
||||
/// <param name="conVar">Console variable name</param>
|
||||
/// <param name="value">String value to set</param>
|
||||
/// <exception cref="InvalidOperationException">Player is not a bot</exception>
|
||||
public void SetFakeClientConVar(string conVar, string value)
|
||||
{
|
||||
if (!IsBot)
|
||||
{
|
||||
throw new InvalidOperationException("'SetFakeClientConVar' can only be called for fake clients (bots)");
|
||||
}
|
||||
|
||||
NativeAPI.SetFakeClientConvarValue(this.Slot, conVar, value);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// <inheritdoc cref="SetFakeClientConVar(string,string)"/>
|
||||
/// </summary>
|
||||
/// <exception cref="ArgumentException"><paramref name="conVar"/> is <see langword="null"/></exception>
|
||||
/// <inheritdoc cref="SetFakeClientConVar(string,string)" select="exception"/>
|
||||
public void SetFakeClientConVar(ConVar conVar, string value)
|
||||
{
|
||||
if (conVar == null)
|
||||
{
|
||||
throw new ArgumentException("Invalid convar passed to 'SetFakeClientConVar'");
|
||||
}
|
||||
|
||||
SetFakeClientConVar(conVar.Name, value);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the active pawns button state. Will work even if the player is dead or observing.
|
||||
/// </summary>
|
||||
public PlayerButtons Buttons => (PlayerButtons)Pawn.Value.MovementServices!.Buttons.ButtonStates[0];
|
||||
|
||||
public void ExecuteClientCommand(string command) => NativeAPI.IssueClientCommand(Slot, command);
|
||||
|
||||
public int Slot => (int)Index - 1;
|
||||
|
||||
/// <summary>
|
||||
/// Returns the authorized SteamID of this user which has been validated with the SteamAPI.
|
||||
/// </summary>
|
||||
public SteamID? AuthorizedSteamID
|
||||
{
|
||||
get
|
||||
{
|
||||
if (!this.IsValid) return null;
|
||||
var authorizedSteamId = NativeAPI.GetPlayerAuthorizedSteamid(this.Slot);
|
||||
if ((long)authorizedSteamId == -1) return null;
|
||||
|
||||
return (SteamID)authorizedSteamId;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Returns the IP address (and possibly port) of this player.
|
||||
/// <remarks>Returns 127.0.0.1 if the player is a bot.</remarks>
|
||||
/// </summary>
|
||||
public string? IpAddress
|
||||
{
|
||||
get
|
||||
{
|
||||
if (!this.IsValid) return null;
|
||||
var ipAddress = NativeAPI.GetPlayerIpAddress(this.Slot);
|
||||
if (string.IsNullOrWhiteSpace(ipAddress)) return null;
|
||||
|
||||
return ipAddress;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -12,23 +12,36 @@ namespace CounterStrikeSharp.API.Core;
|
||||
|
||||
public partial class CEntityInstance : IEquatable<CEntityInstance>
|
||||
{
|
||||
public bool IsValid => Handle != IntPtr.Zero;
|
||||
public CEntityInstance(IntPtr pointer) : base(pointer)
|
||||
{
|
||||
}
|
||||
|
||||
public CEntityIndex? EntityIndex => IsValid ? Entity?.EntityHandle.Index : null;
|
||||
public CEntityInstance(uint rawHandle) : base(rawHandle)
|
||||
{
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Checks that the entity handle is valid and the handle points to a valid entity
|
||||
/// </summary>
|
||||
public bool IsValid => EntityHandle.IsValid && Handle != IntPtr.Zero;
|
||||
|
||||
[Obsolete("Use Index instead", true)]
|
||||
public CEntityIndex? EntityIndex => new CEntityIndex(EntityHandle.Index);
|
||||
|
||||
public uint Index => EntityHandle.Index;
|
||||
|
||||
public string DesignerName => IsValid ? Entity?.DesignerName : null;
|
||||
|
||||
public void Remove() => VirtualFunctions.UTIL_Remove(this.Handle);
|
||||
|
||||
|
||||
|
||||
public bool Equals(CEntityInstance? other)
|
||||
{
|
||||
return this.Handle == other?.Handle;
|
||||
return this.EntityHandle.Equals(other?.EntityHandle);
|
||||
}
|
||||
|
||||
public override bool Equals(object? obj)
|
||||
{
|
||||
return ReferenceEquals(this, obj) || obj is CEntityInstance other && Equals(other);
|
||||
return obj is CEntityInstance other && Equals(other);
|
||||
}
|
||||
|
||||
public override int GetHashCode()
|
||||
@@ -50,5 +63,5 @@ public partial class CEntityInstance : IEquatable<CEntityInstance>
|
||||
public partial class CEntityIdentity
|
||||
{
|
||||
public unsafe CEntityInstance EntityInstance => new(Unsafe.Read<IntPtr>((void*)Handle));
|
||||
public unsafe CHandle<CEntityInstance> EntityHandle => new(Handle + 0x10);
|
||||
public unsafe CHandle<CEntityInstance> EntityHandle => new(this.Handle + 0x10);
|
||||
}
|
||||
@@ -9420,10 +9420,8 @@ public partial class CEntityIdentity : NativeObject
|
||||
|
||||
}
|
||||
|
||||
public partial class CEntityInstance : NativeObject
|
||||
public partial class CEntityInstance : NativeEntity
|
||||
{
|
||||
public CEntityInstance (IntPtr pointer) : base(pointer) {}
|
||||
|
||||
// m_iszPrivateVScripts
|
||||
public string PrivateVScripts
|
||||
{
|
||||
|
||||
@@ -64,32 +64,41 @@ 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) =>
|
||||
{
|
||||
Server.NextWorldUpdate(() =>
|
||||
{
|
||||
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)
|
||||
{
|
||||
_logger.LogInformation("Reloading plugin {Name}", Plugin.ModuleName);
|
||||
Loader = eventargs.Loader;
|
||||
Unload(hotReload: true);
|
||||
Load(hotReload: true);
|
||||
|
||||
Server.NextWorldUpdate(() =>
|
||||
{
|
||||
_logger.LogInformation("Reloading plugin {Name}", Plugin.ModuleName);
|
||||
Loader = eventargs.Loader;
|
||||
Unload(hotReload: true);
|
||||
Load(hotReload: true);
|
||||
});
|
||||
|
||||
return Task.CompletedTask;
|
||||
}
|
||||
|
||||
|
||||
@@ -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)
|
||||
{
|
||||
|
||||
@@ -94,7 +94,7 @@ namespace CounterStrikeSharp.API.Modules.Admin
|
||||
// The server console should have access to all commands, regardless of groups.
|
||||
if (player == null) return true;
|
||||
if (!player.IsValid || player.Connected != PlayerConnectedState.PlayerConnected || player.IsBot) { return false; }
|
||||
var playerData = GetPlayerAdminData((SteamID)player.SteamID);
|
||||
var playerData = GetPlayerAdminData((SteamID)player.AuthorizedSteamID);
|
||||
return playerData?.Groups.IsSupersetOf(groups) ?? false;
|
||||
}
|
||||
|
||||
@@ -119,7 +119,7 @@ namespace CounterStrikeSharp.API.Modules.Admin
|
||||
{
|
||||
if (player == null) return;
|
||||
if (!player.IsValid || player.Connected != PlayerConnectedState.PlayerConnected || player.IsBot) { return; }
|
||||
AddPlayerToGroup((SteamID)player.SteamID, groups);
|
||||
AddPlayerToGroup((SteamID)player.AuthorizedSteamID, groups);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -161,7 +161,7 @@ namespace CounterStrikeSharp.API.Modules.Admin
|
||||
{
|
||||
if (player == null) return;
|
||||
if (!player.IsValid || player.Connected != PlayerConnectedState.PlayerConnected || player.IsBot) { return; }
|
||||
RemovePlayerFromGroup((SteamID)player.SteamID, true, groups);
|
||||
RemovePlayerFromGroup((SteamID)player.AuthorizedSteamID, true, groups);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
|
||||
@@ -102,7 +102,7 @@ namespace CounterStrikeSharp.API.Modules.Admin
|
||||
// The server console should have access to all commands, regardless of permissions.
|
||||
if (player == null) return true;
|
||||
if (!player.IsValid || player.Connected != PlayerConnectedState.PlayerConnected || player.IsBot) { return false; }
|
||||
var playerData = GetPlayerAdminData((SteamID)player.SteamID);
|
||||
var playerData = GetPlayerAdminData(player.AuthorizedSteamID);
|
||||
return playerData?.Flags.IsSupersetOf(flags) ?? false;
|
||||
}
|
||||
|
||||
@@ -136,7 +136,7 @@ namespace CounterStrikeSharp.API.Modules.Admin
|
||||
// The server console should have access to all commands, regardless of permissions.
|
||||
if (player == null) return true;
|
||||
if (!player.IsValid || player.Connected != PlayerConnectedState.PlayerConnected || player.IsBot) { return false; }
|
||||
var playerData = GetPlayerAdminData((SteamID)player.SteamID);
|
||||
var playerData = GetPlayerAdminData((SteamID)player.AuthorizedSteamID);
|
||||
return playerData?.CommandOverrides.ContainsKey(command) ?? false;
|
||||
}
|
||||
|
||||
@@ -165,7 +165,7 @@ namespace CounterStrikeSharp.API.Modules.Admin
|
||||
// The server console should have access to all commands, regardless of permissions.
|
||||
if (player == null) return true;
|
||||
if (!player.IsValid || player.Connected != PlayerConnectedState.PlayerConnected || player.IsBot) { return false; }
|
||||
var playerData = GetPlayerAdminData((SteamID)player.SteamID);
|
||||
var playerData = GetPlayerAdminData((SteamID)player.AuthorizedSteamID);
|
||||
return playerData?.CommandOverrides.GetValueOrDefault(command) ?? false;
|
||||
}
|
||||
|
||||
@@ -193,7 +193,7 @@ namespace CounterStrikeSharp.API.Modules.Admin
|
||||
// The server console should have access to all commands, regardless of permissions.
|
||||
if (player == null) return;
|
||||
if (!player.IsValid || player.Connected != PlayerConnectedState.PlayerConnected || player.IsBot) { return; }
|
||||
SetPlayerCommandOverride((SteamID)player.SteamID, command, state);
|
||||
SetPlayerCommandOverride((SteamID)player.AuthorizedSteamID, command, state);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -235,7 +235,7 @@ namespace CounterStrikeSharp.API.Modules.Admin
|
||||
{
|
||||
if (player == null) return;
|
||||
if (!player.IsValid || player.Connected != PlayerConnectedState.PlayerConnected || player.IsBot) return;
|
||||
AddPlayerPermissions((SteamID)player.SteamID, flags);
|
||||
AddPlayerPermissions((SteamID)player.AuthorizedSteamID, flags);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -278,7 +278,7 @@ namespace CounterStrikeSharp.API.Modules.Admin
|
||||
if (player == null) return;
|
||||
if (!player.IsValid || player.Connected != PlayerConnectedState.PlayerConnected || player.IsBot) return;
|
||||
|
||||
RemovePlayerPermissions((SteamID)player.SteamID, flags);
|
||||
RemovePlayerPermissions((SteamID)player.AuthorizedSteamID, flags);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -306,7 +306,7 @@ namespace CounterStrikeSharp.API.Modules.Admin
|
||||
if (player == null) return;
|
||||
if (!player.IsValid || player.Connected != PlayerConnectedState.PlayerConnected || player.IsBot) return;
|
||||
|
||||
ClearPlayerPermissions((SteamID)player.SteamID);
|
||||
ClearPlayerPermissions((SteamID)player.AuthorizedSteamID);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -335,7 +335,7 @@ namespace CounterStrikeSharp.API.Modules.Admin
|
||||
if (player == null) return;
|
||||
if (!player.IsValid || player.Connected != PlayerConnectedState.PlayerConnected || player.IsBot) return;
|
||||
|
||||
SetPlayerImmunity((SteamID)player.SteamID, value);
|
||||
SetPlayerImmunity((SteamID)player.AuthorizedSteamID, value);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -366,10 +366,10 @@ namespace CounterStrikeSharp.API.Modules.Admin
|
||||
if (target == null) return false;
|
||||
if (!target.IsValid || target.Connected != PlayerConnectedState.PlayerConnected) return false;
|
||||
|
||||
var callerData = GetPlayerAdminData((SteamID)caller.SteamID);
|
||||
var callerData = GetPlayerAdminData((SteamID)caller.AuthorizedSteamID);
|
||||
if (callerData == null) return false;
|
||||
|
||||
var targetData = GetPlayerAdminData((SteamID)target.SteamID);
|
||||
var targetData = GetPlayerAdminData((SteamID)target.AuthorizedSteamID);
|
||||
if (targetData == null) return true;
|
||||
|
||||
return callerData.Immunity >= targetData.Immunity;
|
||||
|
||||
@@ -31,7 +31,8 @@ namespace CounterStrikeSharp.API.Modules.Admin
|
||||
{
|
||||
// If we have a command in the "command_overrides" section in "configs/admins.json",
|
||||
// we skip the checks below and just return the defined value.
|
||||
var adminData = AdminManager.GetPlayerAdminData((SteamID)caller.SteamID);
|
||||
if (caller?.AuthorizedSteamID == null) return false;
|
||||
var adminData = AdminManager.GetPlayerAdminData(caller.AuthorizedSteamID);
|
||||
if (adminData == null) return false;
|
||||
if (adminData.CommandOverrides.ContainsKey(Command))
|
||||
{
|
||||
|
||||
@@ -23,7 +23,7 @@ namespace CounterStrikeSharp.API.Modules.Admin
|
||||
var groupPermissions = Permissions.Where(perm => perm.StartsWith(PermissionCharacters.GroupPermissionChar));
|
||||
var userPermissions = Permissions.Where(perm => perm.StartsWith(PermissionCharacters.UserPermissionChar));
|
||||
|
||||
var adminData = AdminManager.GetPlayerAdminData((SteamID)caller.SteamID);
|
||||
var adminData = AdminManager.GetPlayerAdminData(caller.AuthorizedSteamID);
|
||||
if (adminData == null) return false;
|
||||
return (groupPermissions.Intersect(adminData.Groups).Count() + userPermissions.Intersect(adminData.Flags).Count()) > 0;
|
||||
}
|
||||
|
||||
@@ -0,0 +1,32 @@
|
||||
namespace CounterStrikeSharp.API.Modules.Entities.Constants;
|
||||
|
||||
/// <summary>
|
||||
/// Represents the instance types for a Steam account.
|
||||
/// </summary>
|
||||
public enum SteamAccountInstance
|
||||
{
|
||||
/// <summary>
|
||||
/// Invalid instance.
|
||||
/// </summary>
|
||||
Invalid = -1,
|
||||
|
||||
/// <summary>
|
||||
/// All instances.
|
||||
/// </summary>
|
||||
All = 0,
|
||||
|
||||
/// <summary>
|
||||
/// Desktop instance.
|
||||
/// </summary>
|
||||
Desktop = 1,
|
||||
|
||||
/// <summary>
|
||||
/// Console instance.
|
||||
/// </summary>
|
||||
Console = 2,
|
||||
|
||||
/// <summary>
|
||||
/// Web instance.
|
||||
/// </summary>
|
||||
Web = 4
|
||||
}
|
||||
@@ -0,0 +1,70 @@
|
||||
using System.Runtime.Serialization;
|
||||
|
||||
namespace CounterStrikeSharp.API.Modules.Entities.Constants;
|
||||
|
||||
/// <summary>
|
||||
/// Represents the types of Steam accounts.
|
||||
/// </summary>
|
||||
public enum SteamAccountType
|
||||
{
|
||||
/// <summary>
|
||||
/// Invalid account type.
|
||||
/// </summary>
|
||||
[EnumMember(Value = "I")]
|
||||
Invalid = 0,
|
||||
/// <summary>
|
||||
/// Individual account type.
|
||||
/// </summary>
|
||||
[EnumMember(Value = "U")]
|
||||
Individual,
|
||||
/// <summary>
|
||||
/// MultiSeat account type.
|
||||
/// </summary>
|
||||
[EnumMember(Value = "M")]
|
||||
MultiSeat,
|
||||
/// <summary>
|
||||
/// Game Server account type.
|
||||
/// </summary>
|
||||
[EnumMember(Value = "G")]
|
||||
GameServer,
|
||||
/// <summary>
|
||||
/// Anonymous Game Server account type.
|
||||
/// </summary>
|
||||
[EnumMember(Value = "A")]
|
||||
AnonGameServer,
|
||||
/// <summary>
|
||||
/// Pending account type.
|
||||
/// </summary>
|
||||
[EnumMember(Value = "P")]
|
||||
Pending,
|
||||
/// <summary>
|
||||
/// Content Server account type.
|
||||
/// </summary>
|
||||
[EnumMember(Value = "C")]
|
||||
ContentServer,
|
||||
/// <summary>
|
||||
/// Clan account type.
|
||||
/// </summary>
|
||||
[EnumMember(Value = "g")]
|
||||
Clan,
|
||||
/// <summary>
|
||||
/// Chat account type.
|
||||
/// </summary>
|
||||
[EnumMember(Value = "T")]
|
||||
Chat,
|
||||
/// <summary>
|
||||
/// Console user account type.
|
||||
/// </summary>
|
||||
[EnumMember(Value = "c")]
|
||||
ConsoleUser,
|
||||
/// <summary>
|
||||
/// P2P Super Seeder account type.
|
||||
/// </summary>
|
||||
[EnumMember(Value = " ")]
|
||||
P2PSuperSeeder,
|
||||
/// <summary>
|
||||
/// Anonymous user account type.
|
||||
/// </summary>
|
||||
[EnumMember(Value = "a")]
|
||||
AnonUser,
|
||||
}
|
||||
@@ -0,0 +1,32 @@
|
||||
namespace CounterStrikeSharp.API.Modules.Entities.Constants;
|
||||
|
||||
/// <summary>
|
||||
/// Represents the universe of a Steam account.
|
||||
/// </summary>
|
||||
public enum SteamAccountUniverse
|
||||
{
|
||||
/// <summary>
|
||||
/// Individual / unspecified universe.
|
||||
/// </summary>
|
||||
Unspecified = 0,
|
||||
|
||||
/// <summary>
|
||||
/// Public universe.
|
||||
/// </summary>
|
||||
Public = 1,
|
||||
|
||||
/// <summary>
|
||||
/// Beta universe.
|
||||
/// </summary>
|
||||
Beta = 2,
|
||||
|
||||
/// <summary>
|
||||
/// Internal universe.
|
||||
/// </summary>
|
||||
Internal = 3,
|
||||
|
||||
/// <summary>
|
||||
/// Development universe.
|
||||
/// </summary>
|
||||
Dev = 4,
|
||||
}
|
||||
@@ -0,0 +1,78 @@
|
||||
using System.Runtime.CompilerServices;
|
||||
using System.Runtime.InteropServices;
|
||||
using CounterStrikeSharp.API.Modules.Memory;
|
||||
using CounterStrikeSharp.API.Modules.Utils;
|
||||
|
||||
namespace CounterStrikeSharp.API.Modules.Entities;
|
||||
|
||||
public static class EntitySystem
|
||||
{
|
||||
private static Lazy<IntPtr> ConcreteEntityListPointer = new(NativeAPI.GetConcreteEntityListPointer);
|
||||
|
||||
private const int MaxEntities = 32768;
|
||||
private const int MaxEntitiesPerChunk = 512;
|
||||
private const int MaxChunks = MaxEntities / MaxEntitiesPerChunk;
|
||||
private const int SizeOfEntityIdentity = 0x78;
|
||||
private const int HandleOffset = 0x10;
|
||||
private const uint InvalidEHandleIndex = 0xFFFFFFFF;
|
||||
|
||||
static unsafe Span<IntPtr> IdentityChunks => new((void*)ConcreteEntityListPointer.Value, MaxChunks);
|
||||
public static IntPtr FirstActiveEntity => Marshal.ReadIntPtr(ConcreteEntityListPointer.Value, MaxEntitiesPerChunk);
|
||||
|
||||
public static IntPtr? GetEntityByHandle(uint raw)
|
||||
{
|
||||
return GetEntityByHandle(new CHandle<CEntityInstance>(raw));
|
||||
}
|
||||
|
||||
public static IntPtr? GetEntityByHandle<T>(CHandle<T> handle) where T : NativeEntity
|
||||
{
|
||||
if (!handle.IsValid)
|
||||
return null;
|
||||
|
||||
IntPtr pChunkToUse = IdentityChunks[(int)(handle.Index / MaxEntitiesPerChunk)];
|
||||
if (pChunkToUse == IntPtr.Zero)
|
||||
return null;
|
||||
|
||||
IntPtr pIdentityPtr = IntPtr.Add(pChunkToUse, SizeOfEntityIdentity * (int)(handle.Index % MaxEntitiesPerChunk));
|
||||
|
||||
if (pIdentityPtr == IntPtr.Zero)
|
||||
return null;
|
||||
|
||||
var foundHandle = new CEntityHandle(pIdentityPtr + HandleOffset);
|
||||
|
||||
if (foundHandle.Raw != handle.Raw)
|
||||
return null;
|
||||
|
||||
return Marshal.ReadIntPtr(pIdentityPtr);
|
||||
}
|
||||
|
||||
public static IntPtr? GetEntityByIndex(uint index)
|
||||
{
|
||||
if ((int)index <= -1 || index >= MaxEntities - 1) return null;
|
||||
|
||||
IntPtr pChunkToUse = IdentityChunks[(int)(index / MaxEntitiesPerChunk)];
|
||||
if (pChunkToUse == IntPtr.Zero)
|
||||
return null;
|
||||
|
||||
IntPtr pIdentityPtr = IntPtr.Add(pChunkToUse, SizeOfEntityIdentity * (int)(index % MaxEntitiesPerChunk));
|
||||
|
||||
if (pIdentityPtr == IntPtr.Zero)
|
||||
return null;
|
||||
|
||||
var foundHandle = new CEntityHandle(pIdentityPtr + HandleOffset);
|
||||
|
||||
if (foundHandle.Index != index)
|
||||
return null;
|
||||
|
||||
return Marshal.ReadIntPtr(pIdentityPtr);
|
||||
}
|
||||
|
||||
public static uint GetRawHandleFromEntityPointer(IntPtr pointer)
|
||||
{
|
||||
if (pointer == IntPtr.Zero)
|
||||
return InvalidEHandleIndex;
|
||||
|
||||
return Schema.GetPointer<CEntityIdentity?>(pointer, "CEntityInstance", "m_pEntity")?.EntityHandle.Raw ??
|
||||
InvalidEHandleIndex;
|
||||
}
|
||||
}
|
||||
@@ -1,4 +1,5 @@
|
||||
using System;
|
||||
using CounterStrikeSharp.API.Modules.Entities.Constants;
|
||||
using CounterStrikeSharp.API.Modules.Utils;
|
||||
|
||||
namespace CounterStrikeSharp.API.Modules.Entities
|
||||
{
|
||||
@@ -12,6 +13,7 @@ namespace CounterStrikeSharp.API.Modules.Entities
|
||||
|
||||
public static explicit operator SteamID(ulong u) => new(u);
|
||||
public static explicit operator SteamID(string s) => new(s);
|
||||
|
||||
ulong ParseId(string id)
|
||||
{
|
||||
var parts = id.Split(':');
|
||||
@@ -34,7 +36,7 @@ namespace CounterStrikeSharp.API.Modules.Entities
|
||||
|
||||
public string SteamId3
|
||||
{
|
||||
get => $"[U:1:{SteamId64 - Base}]";
|
||||
get => $"[{EnumUtils.GetEnumMemberAttributeValue(AccountType)}:{(int)AccountUniverse}:{SteamId64 - Base}]";
|
||||
set => SteamId64 = ParseId3(value);
|
||||
}
|
||||
|
||||
@@ -44,20 +46,54 @@ namespace CounterStrikeSharp.API.Modules.Entities
|
||||
set => SteamId64 = (ulong)value + Base;
|
||||
}
|
||||
|
||||
public int AccountId => (int)((SteamId64 >> 0) & 0xFFFFFFFF);
|
||||
|
||||
public SteamAccountInstance AccountInstance =>
|
||||
(SteamAccountInstance)((SteamId64 >> 32) & 0xFFFFF);
|
||||
|
||||
public SteamAccountType AccountType =>
|
||||
(SteamAccountType)((SteamId64 >> 52) & 0xF);
|
||||
|
||||
public SteamAccountUniverse AccountUniverse =>
|
||||
(SteamAccountUniverse)((SteamId64 >> 56) & 0xF);
|
||||
|
||||
public bool IsValid()
|
||||
{
|
||||
if (AccountUniverse == SteamAccountUniverse.Unspecified
|
||||
|| AccountType == SteamAccountType.Invalid
|
||||
|| AccountInstance == SteamAccountInstance.Invalid)
|
||||
return false;
|
||||
if (AccountType == SteamAccountType.Individual
|
||||
&& (AccountId == 0 || AccountInstance != SteamAccountInstance.Desktop))
|
||||
return false;
|
||||
if (AccountType == SteamAccountType.Clan
|
||||
&& (AccountId == 0 || AccountInstance != SteamAccountInstance.All))
|
||||
return false;
|
||||
if (AccountType == SteamAccountType.GameServer && AccountId == 0)
|
||||
return false;
|
||||
return true;
|
||||
}
|
||||
|
||||
public override string ToString() => $"[SteamID {SteamId64}, {SteamId2}, {SteamId3}]";
|
||||
|
||||
public Uri ToCommunityUrl()
|
||||
{
|
||||
string url = string.Empty;
|
||||
if (AccountType == SteamAccountType.Individual)
|
||||
url = "https://steamcommunity.com/profiles/" + SteamId64;
|
||||
if (AccountType == SteamAccountType.Clan)
|
||||
url = "https://steamcommunity.com/gid/" + SteamId64;
|
||||
return new Uri(url);
|
||||
}
|
||||
|
||||
public bool Equals(SteamID? other)
|
||||
{
|
||||
if (ReferenceEquals(null, other)) return false;
|
||||
if (ReferenceEquals(this, other)) return true;
|
||||
return SteamId64 == other.SteamId64;
|
||||
return other != null && SteamId64 == other.SteamId64;
|
||||
}
|
||||
|
||||
public override bool Equals(object? obj)
|
||||
{
|
||||
if (ReferenceEquals(null, obj)) return false;
|
||||
if (ReferenceEquals(this, obj)) return true;
|
||||
if (obj.GetType() != this.GetType()) return false;
|
||||
if (obj?.GetType() != this.GetType()) return false;
|
||||
return Equals((SteamID)obj);
|
||||
}
|
||||
|
||||
|
||||
@@ -77,7 +77,7 @@ namespace CounterStrikeSharp.API.Modules.Events
|
||||
break;
|
||||
case var _ when value is CCSPlayerController player:
|
||||
// When I was testing this, the code seems to expect a slot, even though it is called index
|
||||
SetEntityIndex(name, (int)player.EntityIndex.Value.Value - 1);
|
||||
SetEntityIndex(name, (int)player.Index - 1);
|
||||
break;
|
||||
case var _ when value is string s:
|
||||
SetString(name, s);
|
||||
@@ -124,6 +124,6 @@ namespace CounterStrikeSharp.API.Modules.Events
|
||||
|
||||
public void FireEvent(bool dontBroadcast) => NativeAPI.FireEvent(Handle, dontBroadcast);
|
||||
|
||||
public void FireEventToClient(CCSPlayerController player) => NativeAPI.FireEventToClient(Handle, (int)player.EntityIndex.Value.Value);
|
||||
public void FireEventToClient(CCSPlayerController player) => NativeAPI.FireEventToClient(Handle, (int)player.Index);
|
||||
}
|
||||
}
|
||||
@@ -28,11 +28,35 @@ public abstract class BaseMemoryFunction : NativeObject
|
||||
return function;
|
||||
}
|
||||
|
||||
private static IntPtr CreateValveFunctionBySignature(string signature, string binarypath, DataType returnType,
|
||||
DataType[] argumentTypes)
|
||||
{
|
||||
if (!_createdFunctions.TryGetValue(signature, out var function))
|
||||
{
|
||||
try
|
||||
{
|
||||
function = NativeAPI.CreateVirtualFunctionBySignature(IntPtr.Zero, binarypath, signature,
|
||||
argumentTypes.Length, (int)returnType, argumentTypes.Cast<object>().ToArray());
|
||||
_createdFunctions[signature] = function;
|
||||
}
|
||||
catch (Exception)
|
||||
{
|
||||
}
|
||||
}
|
||||
|
||||
return function;
|
||||
}
|
||||
|
||||
public BaseMemoryFunction(string signature, DataType returnType, DataType[] parameters) : base(
|
||||
CreateValveFunctionBySignature(signature, returnType, parameters))
|
||||
{
|
||||
}
|
||||
|
||||
public BaseMemoryFunction(string signature, string binarypath, DataType returnType, DataType[] parameters) : base(
|
||||
CreateValveFunctionBySignature(signature, binarypath, returnType, parameters))
|
||||
{
|
||||
}
|
||||
|
||||
public void Hook(Func<DynamicHook, HookResult> handler, HookMode mode)
|
||||
{
|
||||
NativeAPI.HookFunction(Handle, handler, mode == HookMode.Post);
|
||||
|
||||
@@ -8,6 +8,10 @@ public class MemoryFunctionVoid : BaseMemoryFunction
|
||||
{
|
||||
}
|
||||
|
||||
public MemoryFunctionVoid(string signature, string binarypath) : base(signature, binarypath, DataType.DATA_TYPE_VOID, Array.Empty<DataType>())
|
||||
{
|
||||
}
|
||||
|
||||
public void Invoke()
|
||||
{
|
||||
InvokeInternalVoid();
|
||||
@@ -21,6 +25,11 @@ public class MemoryFunctionVoid<T1> : BaseMemoryFunction
|
||||
{
|
||||
}
|
||||
|
||||
public MemoryFunctionVoid(string signature, string binarypath) : base(signature, binarypath, DataType.DATA_TYPE_VOID,
|
||||
new[] { typeof(T1).ToValidDataType() })
|
||||
{
|
||||
}
|
||||
|
||||
public void Invoke(T1 arg1)
|
||||
{
|
||||
InvokeInternalVoid(arg1);
|
||||
@@ -34,6 +43,11 @@ public class MemoryFunctionVoid<T1, T2> : BaseMemoryFunction
|
||||
{
|
||||
}
|
||||
|
||||
public MemoryFunctionVoid(string signature, string binarypath) : base(signature, binarypath, DataType.DATA_TYPE_VOID,
|
||||
new[] { typeof(T1).ToValidDataType(), typeof(T2).ToValidDataType() })
|
||||
{
|
||||
}
|
||||
|
||||
public void Invoke(T1 arg1, T2 arg2)
|
||||
{
|
||||
InvokeInternalVoid(arg1, arg2);
|
||||
@@ -47,6 +61,11 @@ public class MemoryFunctionVoid<T1, T2, T3> : BaseMemoryFunction
|
||||
{
|
||||
}
|
||||
|
||||
public MemoryFunctionVoid(string signature, string binarypath) : base(signature, binarypath, DataType.DATA_TYPE_VOID,
|
||||
new[] { typeof(T1).ToValidDataType(), typeof(T2).ToValidDataType(), typeof(T3).ToValidDataType() })
|
||||
{
|
||||
}
|
||||
|
||||
public void Invoke(T1 arg1, T2 arg2, T3 arg3)
|
||||
{
|
||||
InvokeInternalVoid(arg1, arg2, arg3);
|
||||
@@ -64,6 +83,15 @@ public class MemoryFunctionVoid<T1, T2, T3, T4> : BaseMemoryFunction
|
||||
{
|
||||
}
|
||||
|
||||
public MemoryFunctionVoid(string signature, string binarypath) : base(signature, binarypath, DataType.DATA_TYPE_VOID,
|
||||
new[]
|
||||
{
|
||||
typeof(T1).ToValidDataType(), typeof(T2).ToValidDataType(),
|
||||
typeof(T3).ToValidDataType(), typeof(T4).ToValidDataType()
|
||||
})
|
||||
{
|
||||
}
|
||||
|
||||
public void Invoke(T1 arg1, T2 arg2, T3 arg3, T4 arg4)
|
||||
{
|
||||
InvokeInternalVoid(arg1, arg2, arg3, arg4);
|
||||
@@ -82,6 +110,16 @@ public class MemoryFunctionVoid<T1, T2, T3, T4, T5> : BaseMemoryFunction
|
||||
{
|
||||
}
|
||||
|
||||
public MemoryFunctionVoid(string signature, string binarypath) : base(signature, binarypath, DataType.DATA_TYPE_VOID,
|
||||
new[]
|
||||
{
|
||||
typeof(T1).ToValidDataType(), typeof(T2).ToValidDataType(),
|
||||
typeof(T3).ToValidDataType(), typeof(T4).ToValidDataType(),
|
||||
typeof(T5).ToValidDataType()
|
||||
})
|
||||
{
|
||||
}
|
||||
|
||||
public void Invoke(T1 arg1, T2 arg2, T3 arg3, T4 arg4, T5 arg5)
|
||||
{
|
||||
InvokeInternalVoid(arg1, arg2, arg3, arg4, arg5);
|
||||
@@ -100,6 +138,16 @@ public class MemoryFunctionVoid<T1, T2, T3, T4, T5, T6> : BaseMemoryFunction
|
||||
{
|
||||
}
|
||||
|
||||
public MemoryFunctionVoid(string signature, string binarypath) : base(signature, binarypath, DataType.DATA_TYPE_VOID,
|
||||
new[]
|
||||
{
|
||||
typeof(T1).ToValidDataType(), typeof(T2).ToValidDataType(),
|
||||
typeof(T3).ToValidDataType(), typeof(T4).ToValidDataType(),
|
||||
typeof(T5).ToValidDataType(), typeof(T6).ToValidDataType()
|
||||
})
|
||||
{
|
||||
}
|
||||
|
||||
public void Invoke(T1 arg1, T2 arg2, T3 arg3, T4 arg4, T5 arg5, T6 arg6)
|
||||
{
|
||||
InvokeInternalVoid(arg1, arg2, arg3, arg4, arg5, arg6);
|
||||
@@ -119,6 +167,17 @@ public class MemoryFunctionVoid<T1, T2, T3, T4, T5, T6, T7> : BaseMemoryFunction
|
||||
{
|
||||
}
|
||||
|
||||
public MemoryFunctionVoid(string signature, string binarypath) : base(signature, binarypath, DataType.DATA_TYPE_VOID,
|
||||
new[]
|
||||
{
|
||||
typeof(T1).ToValidDataType(), typeof(T2).ToValidDataType(),
|
||||
typeof(T3).ToValidDataType(), typeof(T4).ToValidDataType(),
|
||||
typeof(T5).ToValidDataType(), typeof(T6).ToValidDataType(),
|
||||
typeof(T7).ToValidDataType()
|
||||
})
|
||||
{
|
||||
}
|
||||
|
||||
public void Invoke(T1 arg1, T2 arg2, T3 arg3, T4 arg4, T5 arg5, T6 arg6, T7 arg7)
|
||||
{
|
||||
InvokeInternalVoid(arg1, arg2, arg3, arg4, arg5, arg6, arg7);
|
||||
@@ -138,6 +197,17 @@ public class MemoryFunctionVoid<T1, T2, T3, T4, T5, T6, T7, T8> : BaseMemoryFunc
|
||||
{
|
||||
}
|
||||
|
||||
public MemoryFunctionVoid(string signature, string binarypath) : base(signature, binarypath, DataType.DATA_TYPE_VOID,
|
||||
new[]
|
||||
{
|
||||
typeof(T1).ToValidDataType(), typeof(T2).ToValidDataType(),
|
||||
typeof(T3).ToValidDataType(), typeof(T4).ToValidDataType(),
|
||||
typeof(T5).ToValidDataType(), typeof(T6).ToValidDataType(),
|
||||
typeof(T7).ToValidDataType(), typeof(T8).ToValidDataType()
|
||||
})
|
||||
{
|
||||
}
|
||||
|
||||
public void Invoke(T1 arg1, T2 arg2, T3 arg3, T4 arg4, T5 arg5, T6 arg6, T7 arg7, T8 arg8)
|
||||
{
|
||||
InvokeInternalVoid(arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8);
|
||||
@@ -158,6 +228,18 @@ public class MemoryFunctionVoid<T1, T2, T3, T4, T5, T6, T7, T8, T9> : BaseMemory
|
||||
{
|
||||
}
|
||||
|
||||
public MemoryFunctionVoid(string signature, string binarypath) : base(signature, binarypath, DataType.DATA_TYPE_VOID,
|
||||
new[]
|
||||
{
|
||||
typeof(T1).ToValidDataType(), typeof(T2).ToValidDataType(),
|
||||
typeof(T3).ToValidDataType(), typeof(T4).ToValidDataType(),
|
||||
typeof(T5).ToValidDataType(), typeof(T6).ToValidDataType(),
|
||||
typeof(T7).ToValidDataType(), typeof(T8).ToValidDataType(),
|
||||
typeof(T9).ToValidDataType()
|
||||
})
|
||||
{
|
||||
}
|
||||
|
||||
public void Invoke(T1 arg1, T2 arg2, T3 arg3, T4 arg4, T5 arg5, T6 arg6, T7 arg7, T8 arg8, T9 arg9)
|
||||
{
|
||||
InvokeInternalVoid(arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8, arg9);
|
||||
@@ -178,6 +260,18 @@ public class MemoryFunctionVoid<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10> : BaseM
|
||||
{
|
||||
}
|
||||
|
||||
public MemoryFunctionVoid(string signature, string binarypath) : base(signature, binarypath, DataType.DATA_TYPE_VOID,
|
||||
new[]
|
||||
{
|
||||
typeof(T1).ToValidDataType(), typeof(T2).ToValidDataType(),
|
||||
typeof(T3).ToValidDataType(), typeof(T4).ToValidDataType(),
|
||||
typeof(T5).ToValidDataType(), typeof(T6).ToValidDataType(),
|
||||
typeof(T7).ToValidDataType(), typeof(T8).ToValidDataType(),
|
||||
typeof(T9).ToValidDataType(), typeof(T10).ToValidDataType()
|
||||
})
|
||||
{
|
||||
}
|
||||
|
||||
public void Invoke(T1 arg1, T2 arg2, T3 arg3, T4 arg4, T5 arg5, T6 arg6, T7 arg7, T8 arg8, T9 arg9, T10 arg10)
|
||||
{
|
||||
InvokeInternalVoid(arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8, arg9, arg10);
|
||||
|
||||
@@ -9,6 +9,11 @@ public class MemoryFunctionWithReturn<TResult> : BaseMemoryFunction
|
||||
{
|
||||
}
|
||||
|
||||
public MemoryFunctionWithReturn(string signature, string binarypath) : base(signature, binarypath, typeof(TResult).ToValidDataType(),
|
||||
Array.Empty<DataType>())
|
||||
{
|
||||
}
|
||||
|
||||
public TResult Invoke()
|
||||
{
|
||||
return InvokeInternal<TResult>();
|
||||
@@ -22,6 +27,11 @@ public class MemoryFunctionWithReturn<T1, TResult> : BaseMemoryFunction
|
||||
{
|
||||
}
|
||||
|
||||
public MemoryFunctionWithReturn(string signature, string binarypath) : base(signature, binarypath, typeof(TResult).ToValidDataType(),
|
||||
new[] { typeof(T1).ToValidDataType() })
|
||||
{
|
||||
}
|
||||
|
||||
public TResult Invoke(T1 arg1)
|
||||
{
|
||||
return InvokeInternal<TResult>(arg1);
|
||||
@@ -35,6 +45,11 @@ public class MemoryFunctionWithReturn<T1, T2, TResult> : BaseMemoryFunction
|
||||
{
|
||||
}
|
||||
|
||||
public MemoryFunctionWithReturn(string signature, string binarypath) : base(signature, binarypath, typeof(TResult).ToValidDataType(),
|
||||
new[] { typeof(T1).ToValidDataType(), typeof(T2).ToValidDataType() })
|
||||
{
|
||||
}
|
||||
|
||||
public TResult Invoke(T1 arg1, T2 arg2)
|
||||
{
|
||||
return InvokeInternal<TResult>(arg1, arg2);
|
||||
@@ -48,6 +63,11 @@ public class MemoryFunctionWithReturn<T1, T2, T3, TResult> : BaseMemoryFunction
|
||||
{
|
||||
}
|
||||
|
||||
public MemoryFunctionWithReturn(string signature, string binarypath) : base(signature, binarypath, typeof(TResult).ToValidDataType(),
|
||||
new[] { typeof(T1).ToValidDataType(), typeof(T2).ToValidDataType(), typeof(T3).ToValidDataType() })
|
||||
{
|
||||
}
|
||||
|
||||
public TResult Invoke(T1 arg1, T2 arg2, T3 arg3)
|
||||
{
|
||||
return InvokeInternal<TResult>(arg1, arg2, arg3);
|
||||
@@ -65,6 +85,15 @@ public class MemoryFunctionWithReturn<T1, T2, T3, T4, TResult> : BaseMemoryFunct
|
||||
{
|
||||
}
|
||||
|
||||
public MemoryFunctionWithReturn(string signature, string binarypath) : base(signature, binarypath, typeof(TResult).ToValidDataType(),
|
||||
new[]
|
||||
{
|
||||
typeof(T1).ToValidDataType(), typeof(T2).ToValidDataType(), typeof(T3).ToValidDataType(),
|
||||
typeof(T4).ToValidDataType()
|
||||
})
|
||||
{
|
||||
}
|
||||
|
||||
public TResult Invoke(T1 arg1, T2 arg2, T3 arg3, T4 arg4)
|
||||
{
|
||||
return InvokeInternal<TResult>(arg1, arg2, arg3, arg4);
|
||||
@@ -82,6 +111,15 @@ public class MemoryFunctionWithReturn<T1, T2, T3, T4, T5, TResult> : BaseMemoryF
|
||||
{
|
||||
}
|
||||
|
||||
public MemoryFunctionWithReturn(string signature, string binarypath) : base(signature, binarypath, typeof(TResult).ToValidDataType(),
|
||||
new[]
|
||||
{
|
||||
typeof(T1).ToValidDataType(), typeof(T2).ToValidDataType(), typeof(T3).ToValidDataType(),
|
||||
typeof(T4).ToValidDataType(), typeof(T5).ToValidDataType()
|
||||
})
|
||||
{
|
||||
}
|
||||
|
||||
public TResult Invoke(T1 arg1, T2 arg2, T3 arg3, T4 arg4, T5 arg5)
|
||||
{
|
||||
return InvokeInternal<TResult>(arg1, arg2, arg3, arg4, arg5);
|
||||
@@ -99,6 +137,15 @@ public class MemoryFunctionWithReturn<T1, T2, T3, T4, T5, T6, TResult> : BaseMem
|
||||
{
|
||||
}
|
||||
|
||||
public MemoryFunctionWithReturn(string signature, string binarypath) : base(signature, binarypath, typeof(TResult).ToValidDataType(),
|
||||
new[]
|
||||
{
|
||||
typeof(T1).ToValidDataType(), typeof(T2).ToValidDataType(), typeof(T3).ToValidDataType(),
|
||||
typeof(T4).ToValidDataType(), typeof(T5).ToValidDataType(), typeof(T6).ToValidDataType()
|
||||
})
|
||||
{
|
||||
}
|
||||
|
||||
public TResult Invoke(T1 arg1, T2 arg2, T3 arg3, T4 arg4, T5 arg5, T6 arg6)
|
||||
{
|
||||
return InvokeInternal<TResult>(arg1, arg2, arg3, arg4, arg5, arg6);
|
||||
@@ -117,6 +164,16 @@ public class MemoryFunctionWithReturn<T1, T2, T3, T4, T5, T6, T7, TResult> : Bas
|
||||
{
|
||||
}
|
||||
|
||||
public MemoryFunctionWithReturn(string signature, string binarypath) : base(signature, binarypath, typeof(TResult).ToValidDataType(),
|
||||
new[]
|
||||
{
|
||||
typeof(T1).ToValidDataType(), typeof(T2).ToValidDataType(), typeof(T3).ToValidDataType(),
|
||||
typeof(T4).ToValidDataType(), typeof(T5).ToValidDataType(), typeof(T6).ToValidDataType(),
|
||||
typeof(T7).ToValidDataType()
|
||||
})
|
||||
{
|
||||
}
|
||||
|
||||
public TResult Invoke(T1 arg1, T2 arg2, T3 arg3, T4 arg4, T5 arg5, T6 arg6, T7 arg7)
|
||||
{
|
||||
return InvokeInternal<TResult>(arg1, arg2, arg3, arg4, arg5, arg6, arg7);
|
||||
@@ -135,6 +192,16 @@ public class MemoryFunctionWithReturn<T1, T2, T3, T4, T5, T6, T7, T8, TResult> :
|
||||
{
|
||||
}
|
||||
|
||||
public MemoryFunctionWithReturn(string signature, string binarypath) : base(signature, binarypath, typeof(TResult).ToValidDataType(),
|
||||
new[]
|
||||
{
|
||||
typeof(T1).ToValidDataType(), typeof(T2).ToValidDataType(), typeof(T3).ToValidDataType(),
|
||||
typeof(T4).ToValidDataType(), typeof(T5).ToValidDataType(), typeof(T6).ToValidDataType(),
|
||||
typeof(T7).ToValidDataType(), typeof(T8).ToValidDataType()
|
||||
})
|
||||
{
|
||||
}
|
||||
|
||||
public TResult Invoke(T1 arg1, T2 arg2, T3 arg3, T4 arg4, T5 arg5, T6 arg6, T7 arg7, T8 arg8)
|
||||
{
|
||||
return InvokeInternal<TResult>(arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8);
|
||||
@@ -153,6 +220,16 @@ public class MemoryFunctionWithReturn<T1, T2, T3, T4, T5, T6, T7, T8, T9, TResul
|
||||
{
|
||||
}
|
||||
|
||||
public MemoryFunctionWithReturn(string signature, string binarypath) : base(signature, binarypath, typeof(TResult).ToValidDataType(),
|
||||
new[]
|
||||
{
|
||||
typeof(T1).ToValidDataType(), typeof(T2).ToValidDataType(), typeof(T3).ToValidDataType(),
|
||||
typeof(T4).ToValidDataType(), typeof(T5).ToValidDataType(), typeof(T6).ToValidDataType(),
|
||||
typeof(T7).ToValidDataType(), typeof(T8).ToValidDataType(), typeof(T9).ToValidDataType()
|
||||
})
|
||||
{
|
||||
}
|
||||
|
||||
public TResult Invoke(T1 arg1, T2 arg2, T3 arg3, T4 arg4, T5 arg5, T6 arg6, T7 arg7, T8 arg8, T9 arg9)
|
||||
{
|
||||
return InvokeInternal<TResult>(arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8, arg9);
|
||||
@@ -172,6 +249,17 @@ public class MemoryFunctionWithReturn<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T
|
||||
{
|
||||
}
|
||||
|
||||
public MemoryFunctionWithReturn(string signature, string binarypath) : base(signature, binarypath, typeof(TResult).ToValidDataType(),
|
||||
new[]
|
||||
{
|
||||
typeof(T1).ToValidDataType(), typeof(T2).ToValidDataType(), typeof(T3).ToValidDataType(),
|
||||
typeof(T4).ToValidDataType(), typeof(T5).ToValidDataType(), typeof(T6).ToValidDataType(),
|
||||
typeof(T7).ToValidDataType(), typeof(T8).ToValidDataType(), typeof(T9).ToValidDataType(),
|
||||
typeof(T10).ToValidDataType()
|
||||
})
|
||||
{
|
||||
}
|
||||
|
||||
public TResult Invoke(T1 arg1, T2 arg2, T3 arg3, T4 arg4, T5 arg5, T6 arg6, T7 arg7, T8 arg8, T9 arg9, T10 arg10)
|
||||
{
|
||||
return InvokeInternal<TResult>(arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8, arg9, arg10);
|
||||
|
||||
@@ -2,6 +2,7 @@ using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Drawing;
|
||||
using System.Runtime.CompilerServices;
|
||||
using System.Runtime.InteropServices;
|
||||
using CounterStrikeSharp.API.Core;
|
||||
|
||||
namespace CounterStrikeSharp.API.Modules.Memory;
|
||||
@@ -49,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)
|
||||
{
|
||||
@@ -92,9 +95,9 @@ public class Schema
|
||||
return ref Unsafe.AsRef<T>((void*)(pointer + GetSchemaOffset(className, memberName)));
|
||||
}
|
||||
|
||||
public static unsafe T GetPointer<T>(IntPtr pointer)
|
||||
public static T GetPointer<T>(IntPtr pointer)
|
||||
{
|
||||
var pointerTo = Unsafe.Read<IntPtr>((void*)pointer);
|
||||
var pointerTo = Marshal.ReadIntPtr(pointer);
|
||||
if (pointerTo == IntPtr.Zero)
|
||||
{
|
||||
return default;
|
||||
@@ -103,9 +106,9 @@ public class Schema
|
||||
return (T)Activator.CreateInstance(typeof(T), pointerTo);
|
||||
}
|
||||
|
||||
public static unsafe T GetPointer<T>(IntPtr pointer, string className, string memberName)
|
||||
public static T GetPointer<T>(IntPtr pointer, string className, string memberName)
|
||||
{
|
||||
var pointerTo = Unsafe.Read<IntPtr>((void*)(pointer + GetSchemaOffset(className, memberName)));
|
||||
var pointerTo = Marshal.ReadIntPtr(pointer + GetSchemaOffset(className, memberName));
|
||||
if (pointerTo == IntPtr.Zero)
|
||||
{
|
||||
return default;
|
||||
|
||||
@@ -45,6 +45,26 @@ public partial class VirtualFunction
|
||||
return function;
|
||||
}
|
||||
|
||||
private static IntPtr CreateVirtualFunctionBySignature(string signature, string binarypath, IEnumerable<DataType> argumentTypes,
|
||||
DataType returnType,
|
||||
object[] arguments)
|
||||
{
|
||||
if (!_createdFunctions.TryGetValue(signature, out var function))
|
||||
{
|
||||
try
|
||||
{
|
||||
function = NativeAPI.CreateVirtualFunctionBySignature(IntPtr.Zero, binarypath, signature,
|
||||
argumentTypes.Count(), (int)returnType, arguments);
|
||||
_createdFunctions[signature] = function;
|
||||
}
|
||||
catch (Exception)
|
||||
{
|
||||
}
|
||||
}
|
||||
|
||||
return function;
|
||||
}
|
||||
|
||||
#region Funcs
|
||||
public static Func<TResult> Create<TResult>(string signature)
|
||||
{
|
||||
@@ -306,7 +326,270 @@ public partial class VirtualFunction
|
||||
NativeAPI.ExecuteVirtualFunction<TResult>(virtualFunctionPointer,
|
||||
new object[] { arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8, arg9, arg10 });
|
||||
}
|
||||
|
||||
|
||||
#endregion
|
||||
|
||||
#region FuncsBinary
|
||||
public static Func<TResult> Create<TResult>(string signature, string binarypath)
|
||||
{
|
||||
var arguments = Enumerable.Empty<DataType>().ToArray();
|
||||
|
||||
if (typeof(TResult).ToDataType() == null)
|
||||
{
|
||||
throw new Exception($"Invalid argument type(s) supplied to Virtual Function");
|
||||
}
|
||||
|
||||
var virtualFunctionPointer = CreateVirtualFunctionBySignature(signature, binarypath, arguments,
|
||||
(DataType)typeof(TResult).ToDataType()!, arguments.Cast<object>().ToArray());
|
||||
|
||||
return () => NativeAPI.ExecuteVirtualFunction<TResult>(virtualFunctionPointer, new object[] { });
|
||||
}
|
||||
|
||||
public static Func<TArg1, TResult> Create<TArg1, TResult>(string signature, string binarypath)
|
||||
{
|
||||
var arguments = new[]
|
||||
{
|
||||
typeof(TArg1).ToDataType()
|
||||
};
|
||||
|
||||
if (arguments.Any(x => x == null))
|
||||
{
|
||||
throw new Exception($"Invalid argument type(s) supplied to Virtual Function");
|
||||
}
|
||||
|
||||
var virtualFunctionPointer = CreateVirtualFunctionBySignature(signature, binarypath, arguments.Cast<DataType>(),
|
||||
(DataType)typeof(TResult).ToDataType()!, arguments.Cast<object>().ToArray());
|
||||
|
||||
return (arg1) => NativeAPI.ExecuteVirtualFunction<TResult>(virtualFunctionPointer, new object[] { arg1 });
|
||||
}
|
||||
|
||||
public static Func<TArg1, TArg2, TResult> Create<TArg1, TArg2, TResult>(string signature, string binarypath)
|
||||
{
|
||||
var arguments = new[]
|
||||
{
|
||||
typeof(TArg1).ToDataType(),
|
||||
typeof(TArg2).ToDataType()
|
||||
};
|
||||
|
||||
if (arguments.Any(x => x == null))
|
||||
{
|
||||
throw new Exception($"Invalid argument type(s) supplied to Virtual Function");
|
||||
}
|
||||
|
||||
var virtualFunctionPointer = CreateVirtualFunctionBySignature(signature, binarypath, arguments.Cast<DataType>(),
|
||||
(DataType)typeof(TResult).ToDataType()!, arguments.Cast<object>().ToArray());
|
||||
|
||||
return (arg1, arg2) =>
|
||||
NativeAPI.ExecuteVirtualFunction<TResult>(virtualFunctionPointer, new object[] { arg1, arg2 });
|
||||
}
|
||||
|
||||
public static Func<TArg1, TArg2, TArg3, TResult> Create<TArg1, TArg2, TArg3, TResult>(string signature, string binarypath)
|
||||
{
|
||||
var arguments = new[]
|
||||
{
|
||||
typeof(TArg1).ToDataType(),
|
||||
typeof(TArg2).ToDataType(),
|
||||
typeof(TArg3).ToDataType()
|
||||
};
|
||||
|
||||
if (arguments.Any(x => x == null))
|
||||
{
|
||||
throw new Exception($"Invalid argument type(s) supplied to Virtual Function");
|
||||
}
|
||||
|
||||
var virtualFunctionPointer = CreateVirtualFunctionBySignature(signature, binarypath, arguments.Cast<DataType>(),
|
||||
(DataType)typeof(TResult).ToDataType()!, arguments.Cast<object>().ToArray());
|
||||
|
||||
return (arg1, arg2, arg3) =>
|
||||
NativeAPI.ExecuteVirtualFunction<TResult>(virtualFunctionPointer, new object[] { arg1, arg2, arg3 });
|
||||
}
|
||||
|
||||
public static Func<TArg1, TArg2, TArg3, TArg4, TResult> Create<TArg1, TArg2, TArg3, TArg4, TResult>(
|
||||
string signature, string binarypath)
|
||||
{
|
||||
var arguments = new[]
|
||||
{
|
||||
typeof(TArg1).ToDataType(),
|
||||
typeof(TArg2).ToDataType(),
|
||||
typeof(TArg3).ToDataType(),
|
||||
typeof(TArg4).ToDataType()
|
||||
};
|
||||
|
||||
if (arguments.Any(x => x == null))
|
||||
{
|
||||
throw new Exception($"Invalid argument type(s) supplied to Virtual Function");
|
||||
}
|
||||
|
||||
var virtualFunctionPointer = CreateVirtualFunctionBySignature(signature, binarypath, arguments.Cast<DataType>(),
|
||||
(DataType)typeof(TResult).ToDataType()!, arguments.Cast<object>().ToArray());
|
||||
|
||||
return (arg1, arg2, arg3, arg4) =>
|
||||
NativeAPI.ExecuteVirtualFunction<TResult>(virtualFunctionPointer, new object[] { arg1, arg2, arg3, arg4 });
|
||||
}
|
||||
|
||||
public static Func<TArg1, TArg2, TArg3, TArg4, TArg5, TResult> Create<TArg1, TArg2, TArg3, TArg4, TArg5, TResult>(
|
||||
string signature, string binarypath)
|
||||
{
|
||||
var arguments = new[]
|
||||
{
|
||||
typeof(TArg1).ToDataType(),
|
||||
typeof(TArg2).ToDataType(),
|
||||
typeof(TArg3).ToDataType(),
|
||||
typeof(TArg4).ToDataType(),
|
||||
typeof(TArg5).ToDataType()
|
||||
};
|
||||
|
||||
if (arguments.Any(x => x == null))
|
||||
{
|
||||
throw new Exception($"Invalid argument type(s) supplied to Virtual Function");
|
||||
}
|
||||
|
||||
var virtualFunctionPointer = CreateVirtualFunctionBySignature(signature, binarypath, arguments.Cast<DataType>(),
|
||||
(DataType)typeof(TResult).ToDataType()!, arguments.Cast<object>().ToArray());
|
||||
|
||||
return (arg1, arg2, arg3, arg4, arg5) =>
|
||||
NativeAPI.ExecuteVirtualFunction<TResult>(virtualFunctionPointer,
|
||||
new object[] { arg1, arg2, arg3, arg4, arg5 });
|
||||
}
|
||||
|
||||
public static Func<TArg1, TArg2, TArg3, TArg4, TArg5, TArg6, TResult> Create<TArg1, TArg2, TArg3, TArg4, TArg5,
|
||||
TArg6, TResult>(string signature, string binarypath)
|
||||
{
|
||||
var arguments = new[]
|
||||
{
|
||||
typeof(TArg1).ToDataType(),
|
||||
typeof(TArg2).ToDataType(),
|
||||
typeof(TArg3).ToDataType(),
|
||||
typeof(TArg4).ToDataType(),
|
||||
typeof(TArg5).ToDataType(),
|
||||
typeof(TArg6).ToDataType()
|
||||
};
|
||||
|
||||
if (arguments.Any(x => x == null))
|
||||
{
|
||||
throw new Exception($"Invalid argument type(s) supplied to Virtual Function");
|
||||
}
|
||||
|
||||
var virtualFunctionPointer = CreateVirtualFunctionBySignature(signature, binarypath, arguments.Cast<DataType>(),
|
||||
(DataType)typeof(TResult).ToDataType()!, arguments.Cast<object>().ToArray());
|
||||
|
||||
return (arg1, arg2, arg3, arg4, arg5, arg6) => NativeAPI.ExecuteVirtualFunction<TResult>(virtualFunctionPointer,
|
||||
new object[] { arg1, arg2, arg3, arg4, arg5, arg6 });
|
||||
}
|
||||
|
||||
public static Func<TArg1, TArg2, TArg3, TArg4, TArg5, TArg6, TArg7, TResult> Create<TArg1, TArg2, TArg3, TArg4,
|
||||
TArg5, TArg6, TArg7, TResult>(string signature, string binarypath)
|
||||
{
|
||||
var arguments = new[]
|
||||
{
|
||||
typeof(TArg1).ToDataType(),
|
||||
typeof(TArg2).ToDataType(),
|
||||
typeof(TArg3).ToDataType(),
|
||||
typeof(TArg4).ToDataType(),
|
||||
typeof(TArg5).ToDataType(),
|
||||
typeof(TArg6).ToDataType(),
|
||||
typeof(TArg7).ToDataType()
|
||||
};
|
||||
|
||||
if (arguments.Any(x => x == null))
|
||||
{
|
||||
throw new Exception($"Invalid argument type(s) supplied to Virtual Function");
|
||||
}
|
||||
|
||||
var virtualFunctionPointer = CreateVirtualFunctionBySignature(signature, binarypath, arguments.Cast<DataType>(),
|
||||
(DataType)typeof(TResult).ToDataType()!, arguments.Cast<object>().ToArray());
|
||||
|
||||
return (arg1, arg2, arg3, arg4, arg5, arg6, arg7) =>
|
||||
NativeAPI.ExecuteVirtualFunction<TResult>(virtualFunctionPointer,
|
||||
new object[] { arg1, arg2, arg3, arg4, arg5, arg6, arg7 });
|
||||
}
|
||||
|
||||
public static Func<TArg1, TArg2, TArg3, TArg4, TArg5, TArg6, TArg7, TArg8, TResult> Create<TArg1, TArg2, TArg3,
|
||||
TArg4, TArg5, TArg6, TArg7, TArg8, TResult>(string signature, string binarypath)
|
||||
{
|
||||
var arguments = new[]
|
||||
{
|
||||
typeof(TArg1).ToDataType(),
|
||||
typeof(TArg2).ToDataType(),
|
||||
typeof(TArg3).ToDataType(),
|
||||
typeof(TArg4).ToDataType(),
|
||||
typeof(TArg5).ToDataType(),
|
||||
typeof(TArg6).ToDataType(),
|
||||
typeof(TArg7).ToDataType(),
|
||||
typeof(TArg8).ToDataType()
|
||||
};
|
||||
|
||||
if (arguments.Any(x => x == null))
|
||||
{
|
||||
throw new Exception($"Invalid argument type(s) supplied to Virtual Function");
|
||||
}
|
||||
|
||||
var virtualFunctionPointer = CreateVirtualFunctionBySignature(signature, binarypath, arguments.Cast<DataType>(),
|
||||
(DataType)typeof(TResult).ToDataType()!, arguments.Cast<object>().ToArray());
|
||||
|
||||
return (arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8) =>
|
||||
NativeAPI.ExecuteVirtualFunction<TResult>(virtualFunctionPointer,
|
||||
new object[] { arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8 });
|
||||
}
|
||||
|
||||
public static Func<TArg1, TArg2, TArg3, TArg4, TArg5, TArg6, TArg7, TArg8, TArg9, TResult> Create<TArg1, TArg2,
|
||||
TArg3, TArg4, TArg5, TArg6, TArg7, TArg8, TArg9, TResult>(string signature, string binarypath)
|
||||
{
|
||||
var arguments = new[]
|
||||
{
|
||||
typeof(TArg1).ToDataType(),
|
||||
typeof(TArg2).ToDataType(),
|
||||
typeof(TArg3).ToDataType(),
|
||||
typeof(TArg4).ToDataType(),
|
||||
typeof(TArg5).ToDataType(),
|
||||
typeof(TArg6).ToDataType(),
|
||||
typeof(TArg7).ToDataType(),
|
||||
typeof(TArg8).ToDataType(),
|
||||
typeof(TArg9).ToDataType()
|
||||
};
|
||||
|
||||
if (arguments.Any(x => x == null))
|
||||
{
|
||||
throw new Exception($"Invalid argument type(s) supplied to Virtual Function");
|
||||
}
|
||||
|
||||
var virtualFunctionPointer = CreateVirtualFunctionBySignature(signature, binarypath, arguments.Cast<DataType>(),
|
||||
(DataType)typeof(TResult).ToDataType()!, arguments.Cast<object>().ToArray());
|
||||
|
||||
return (arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8, arg9) =>
|
||||
NativeAPI.ExecuteVirtualFunction<TResult>(virtualFunctionPointer,
|
||||
new object[] { arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8, arg9 });
|
||||
}
|
||||
|
||||
public static Func<TArg1, TArg2, TArg3, TArg4, TArg5, TArg6, TArg7, TArg8, TArg9, TArg10, TResult> Create<TArg1,
|
||||
TArg2, TArg3, TArg4, TArg5, TArg6, TArg7, TArg8, TArg9, TArg10, TResult>(string signature, string binarypath)
|
||||
{
|
||||
var arguments = new[]
|
||||
{
|
||||
typeof(TArg1).ToDataType(),
|
||||
typeof(TArg2).ToDataType(),
|
||||
typeof(TArg3).ToDataType(),
|
||||
typeof(TArg4).ToDataType(),
|
||||
typeof(TArg5).ToDataType(),
|
||||
typeof(TArg6).ToDataType(),
|
||||
typeof(TArg7).ToDataType(),
|
||||
typeof(TArg8).ToDataType(),
|
||||
typeof(TArg9).ToDataType(),
|
||||
typeof(TArg10).ToDataType()
|
||||
};
|
||||
|
||||
if (arguments.Any(x => x == null))
|
||||
{
|
||||
throw new Exception($"Invalid argument type(s) supplied to Virtual Function");
|
||||
}
|
||||
|
||||
var virtualFunctionPointer = CreateVirtualFunctionBySignature(signature, binarypath, arguments.Cast<DataType>(),
|
||||
(DataType)typeof(TResult).ToDataType()!, arguments.Cast<object>().ToArray());
|
||||
|
||||
return (arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8, arg9, arg10) =>
|
||||
NativeAPI.ExecuteVirtualFunction<TResult>(virtualFunctionPointer,
|
||||
new object[] { arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8, arg9, arg10 });
|
||||
}
|
||||
#endregion
|
||||
|
||||
#region Void Actions
|
||||
@@ -587,4 +870,281 @@ public partial class VirtualFunction
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Void Actions Binary
|
||||
public static Action CreateVoid(string signature, string binarypath)
|
||||
{
|
||||
var arguments = Enumerable.Empty<DataType>().ToArray();
|
||||
|
||||
var virtualFunctionPointer = CreateVirtualFunctionBySignature(signature, binarypath, arguments,
|
||||
DataType.DATA_TYPE_VOID, arguments.Cast<object>().ToArray());
|
||||
|
||||
return () => { NativeAPI.ExecuteVirtualFunction<object>(virtualFunctionPointer, new object[] { }); };
|
||||
}
|
||||
|
||||
public static Action<TArg1> CreateVoid<TArg1>(string signature, string binarypath)
|
||||
{
|
||||
var arguments = new[]
|
||||
{
|
||||
typeof(TArg1).ToDataType()
|
||||
};
|
||||
|
||||
if (arguments.Any(x => x == null))
|
||||
{
|
||||
throw new Exception($"Invalid argument type(s) supplied to Virtual Function");
|
||||
}
|
||||
|
||||
var virtualFunctionPointer = CreateVirtualFunctionBySignature(signature, binarypath, arguments.Cast<DataType>(),
|
||||
DataType.DATA_TYPE_VOID, arguments.Cast<object>().ToArray());
|
||||
|
||||
return (arg1) => { NativeAPI.ExecuteVirtualFunction<object>(virtualFunctionPointer, new object[] { arg1 }); };
|
||||
}
|
||||
|
||||
public static Action<TArg1, TArg2> CreateVoid<TArg1, TArg2>(string signature, string binarypath)
|
||||
{
|
||||
var arguments = new[]
|
||||
{
|
||||
typeof(TArg1).ToDataType(),
|
||||
typeof(TArg2).ToDataType()
|
||||
};
|
||||
|
||||
if (arguments.Any(x => x == null))
|
||||
{
|
||||
throw new Exception($"Invalid argument type(s) supplied to Virtual Function");
|
||||
}
|
||||
|
||||
var virtualFunctionPointer = CreateVirtualFunctionBySignature(signature, binarypath, arguments.Cast<DataType>(),
|
||||
DataType.DATA_TYPE_VOID, arguments.Cast<object>().ToArray());
|
||||
|
||||
return (arg1, arg2) =>
|
||||
{
|
||||
NativeAPI.ExecuteVirtualFunction<object>(virtualFunctionPointer, new object[] { arg1, arg2 });
|
||||
};
|
||||
}
|
||||
|
||||
public static Action<TArg1, TArg2, TArg3> CreateVoid<TArg1, TArg2, TArg3>(string signature, string binarypath)
|
||||
{
|
||||
var arguments = new[]
|
||||
{
|
||||
typeof(TArg1).ToDataType(),
|
||||
typeof(TArg2).ToDataType(),
|
||||
typeof(TArg3).ToDataType()
|
||||
};
|
||||
|
||||
if (arguments.Any(x => x == null))
|
||||
{
|
||||
throw new Exception($"Invalid argument type(s) supplied to Virtual Function");
|
||||
}
|
||||
|
||||
var virtualFunctionPointer = CreateVirtualFunctionBySignature(signature, binarypath, arguments.Cast<DataType>(),
|
||||
DataType.DATA_TYPE_VOID, arguments.Cast<object>().ToArray());
|
||||
|
||||
return (arg1, arg2, arg3) =>
|
||||
{
|
||||
NativeAPI.ExecuteVirtualFunction<object>(virtualFunctionPointer, new object[] { arg1, arg2, arg3 });
|
||||
};
|
||||
}
|
||||
|
||||
public static Action<TArg1, TArg2, TArg3, TArg4> CreateVoid<TArg1, TArg2, TArg3, TArg4>(string signature, string binarypath)
|
||||
{
|
||||
var arguments = new[]
|
||||
{
|
||||
typeof(TArg1).ToDataType(),
|
||||
typeof(TArg2).ToDataType(),
|
||||
typeof(TArg3).ToDataType(),
|
||||
typeof(TArg4).ToDataType()
|
||||
};
|
||||
|
||||
if (arguments.Any(x => x == null))
|
||||
{
|
||||
throw new Exception($"Invalid argument type(s) supplied to Virtual Function");
|
||||
}
|
||||
|
||||
var virtualFunctionPointer = CreateVirtualFunctionBySignature(signature, binarypath, arguments.Cast<DataType>(),
|
||||
DataType.DATA_TYPE_VOID, arguments.Cast<object>().ToArray());
|
||||
|
||||
return (arg1, arg2, arg3, arg4) =>
|
||||
{
|
||||
NativeAPI.ExecuteVirtualFunction<object>(virtualFunctionPointer,
|
||||
new object[] { arg1, arg2, arg3, arg4 });
|
||||
};
|
||||
}
|
||||
|
||||
public static Action<TArg1, TArg2, TArg3, TArg4, TArg5> CreateVoid<TArg1, TArg2, TArg3, TArg4, TArg5>(
|
||||
string signature, string binarypath)
|
||||
{
|
||||
var arguments = new[]
|
||||
{
|
||||
typeof(TArg1).ToDataType(),
|
||||
typeof(TArg2).ToDataType(),
|
||||
typeof(TArg3).ToDataType(),
|
||||
typeof(TArg4).ToDataType(),
|
||||
typeof(TArg5).ToDataType()
|
||||
};
|
||||
|
||||
if (arguments.Any(x => x == null))
|
||||
{
|
||||
throw new Exception($"Invalid argument type(s) supplied to Virtual Function");
|
||||
}
|
||||
|
||||
var virtualFunctionPointer = CreateVirtualFunctionBySignature(signature, binarypath, arguments.Cast<DataType>(),
|
||||
DataType.DATA_TYPE_VOID, arguments.Cast<object>().ToArray());
|
||||
|
||||
return (arg1, arg2, arg3, arg4, arg5) =>
|
||||
{
|
||||
NativeAPI.ExecuteVirtualFunction<object>(virtualFunctionPointer,
|
||||
new object[] { arg1, arg2, arg3, arg4, arg5 });
|
||||
};
|
||||
}
|
||||
|
||||
public static Action<TArg1, TArg2, TArg3, TArg4, TArg5, TArg6> CreateVoid<TArg1, TArg2, TArg3, TArg4, TArg5, TArg6>(
|
||||
string signature, string binarypath)
|
||||
{
|
||||
var arguments = new[]
|
||||
{
|
||||
typeof(TArg1).ToDataType(),
|
||||
typeof(TArg2).ToDataType(),
|
||||
typeof(TArg3).ToDataType(),
|
||||
typeof(TArg4).ToDataType(),
|
||||
typeof(TArg5).ToDataType(),
|
||||
typeof(TArg6).ToDataType()
|
||||
};
|
||||
|
||||
if (arguments.Any(x => x == null))
|
||||
{
|
||||
throw new Exception($"Invalid argument type(s) supplied to Virtual Function");
|
||||
}
|
||||
|
||||
var virtualFunctionPointer = CreateVirtualFunctionBySignature(signature, binarypath, arguments.Cast<DataType>(),
|
||||
DataType.DATA_TYPE_VOID, arguments.Cast<object>().ToArray());
|
||||
|
||||
return (arg1, arg2, arg3, arg4, arg5, arg6) =>
|
||||
{
|
||||
NativeAPI.ExecuteVirtualFunction<object>(virtualFunctionPointer,
|
||||
new object[] { arg1, arg2, arg3, arg4, arg5, arg6 });
|
||||
};
|
||||
}
|
||||
|
||||
public static Action<TArg1, TArg2, TArg3, TArg4, TArg5, TArg6, TArg7> CreateVoid<TArg1, TArg2, TArg3, TArg4, TArg5,
|
||||
TArg6, TArg7>(string signature, string binarypath)
|
||||
{
|
||||
var arguments = new[]
|
||||
{
|
||||
typeof(TArg1).ToDataType(),
|
||||
typeof(TArg2).ToDataType(),
|
||||
typeof(TArg3).ToDataType(),
|
||||
typeof(TArg4).ToDataType(),
|
||||
typeof(TArg5).ToDataType(),
|
||||
typeof(TArg6).ToDataType(),
|
||||
typeof(TArg7).ToDataType()
|
||||
};
|
||||
|
||||
if (arguments.Any(x => x == null))
|
||||
{
|
||||
throw new Exception($"Invalid argument type(s) supplied to Virtual Function");
|
||||
}
|
||||
|
||||
var virtualFunctionPointer = CreateVirtualFunctionBySignature(signature, binarypath, arguments.Cast<DataType>(),
|
||||
DataType.DATA_TYPE_VOID, arguments.Cast<object>().ToArray());
|
||||
|
||||
return (arg1, arg2, arg3, arg4, arg5, arg6, arg7) =>
|
||||
{
|
||||
NativeAPI.ExecuteVirtualFunction<object>(virtualFunctionPointer,
|
||||
new object[] { arg1, arg2, arg3, arg4, arg5, arg6, arg7 });
|
||||
};
|
||||
}
|
||||
|
||||
public static Action<TArg1, TArg2, TArg3, TArg4, TArg5, TArg6, TArg7, TArg8> CreateVoid<TArg1, TArg2, TArg3, TArg4,
|
||||
TArg5, TArg6, TArg7, TArg8>(string signature, string binarypath)
|
||||
{
|
||||
var arguments = new[]
|
||||
{
|
||||
typeof(TArg1).ToDataType(),
|
||||
typeof(TArg2).ToDataType(),
|
||||
typeof(TArg3).ToDataType(),
|
||||
typeof(TArg4).ToDataType(),
|
||||
typeof(TArg5).ToDataType(),
|
||||
typeof(TArg6).ToDataType(),
|
||||
typeof(TArg7).ToDataType(),
|
||||
typeof(TArg8).ToDataType()
|
||||
};
|
||||
|
||||
if (arguments.Any(x => x == null))
|
||||
{
|
||||
throw new Exception($"Invalid argument type(s) supplied to Virtual Function");
|
||||
}
|
||||
|
||||
var virtualFunctionPointer = CreateVirtualFunctionBySignature(signature, binarypath, arguments.Cast<DataType>(),
|
||||
DataType.DATA_TYPE_VOID, arguments.Cast<object>().ToArray());
|
||||
|
||||
return (arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8) =>
|
||||
{
|
||||
NativeAPI.ExecuteVirtualFunction<object>(virtualFunctionPointer,
|
||||
new object[] { arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8 });
|
||||
};
|
||||
}
|
||||
|
||||
public static Action<TArg1, TArg2, TArg3, TArg4, TArg5, TArg6, TArg7, TArg8, TArg9> CreateVoid<TArg1, TArg2, TArg3,
|
||||
TArg4, TArg5, TArg6, TArg7, TArg8, TArg9>(string signature, string binarypath)
|
||||
{
|
||||
var arguments = new[]
|
||||
{
|
||||
typeof(TArg1).ToDataType(),
|
||||
typeof(TArg2).ToDataType(),
|
||||
typeof(TArg3).ToDataType(),
|
||||
typeof(TArg4).ToDataType(),
|
||||
typeof(TArg5).ToDataType(),
|
||||
typeof(TArg6).ToDataType(),
|
||||
typeof(TArg7).ToDataType(),
|
||||
typeof(TArg8).ToDataType(),
|
||||
typeof(TArg9).ToDataType()
|
||||
};
|
||||
|
||||
if (arguments.Any(x => x == null))
|
||||
{
|
||||
throw new Exception($"Invalid argument type(s) supplied to Virtual Function");
|
||||
}
|
||||
|
||||
var virtualFunctionPointer = CreateVirtualFunctionBySignature(signature, binarypath, arguments.Cast<DataType>(),
|
||||
DataType.DATA_TYPE_VOID, arguments.Cast<object>().ToArray());
|
||||
|
||||
return (arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8, arg9) =>
|
||||
{
|
||||
NativeAPI.ExecuteVirtualFunction<object>(virtualFunctionPointer,
|
||||
new object[] { arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8, arg9 });
|
||||
};
|
||||
}
|
||||
|
||||
public static Action<TArg1, TArg2, TArg3, TArg4, TArg5, TArg6, TArg7, TArg8, TArg9, TArg10> CreateVoid<TArg1, TArg2,
|
||||
TArg3, TArg4, TArg5, TArg6, TArg7, TArg8, TArg9, TArg10>(string signature, string binarypath)
|
||||
{
|
||||
var arguments = new[]
|
||||
{
|
||||
typeof(TArg1).ToDataType(),
|
||||
typeof(TArg2).ToDataType(),
|
||||
typeof(TArg3).ToDataType(),
|
||||
typeof(TArg4).ToDataType(),
|
||||
typeof(TArg5).ToDataType(),
|
||||
typeof(TArg6).ToDataType(),
|
||||
typeof(TArg7).ToDataType(),
|
||||
typeof(TArg8).ToDataType(),
|
||||
typeof(TArg9).ToDataType(),
|
||||
typeof(TArg10).ToDataType()
|
||||
};
|
||||
|
||||
if (arguments.Any(x => x == null))
|
||||
{
|
||||
throw new Exception($"Invalid argument type(s) supplied to Virtual Function");
|
||||
}
|
||||
|
||||
var virtualFunctionPointer = CreateVirtualFunctionBySignature(signature, binarypath, arguments.Cast<DataType>(),
|
||||
DataType.DATA_TYPE_VOID, arguments.Cast<object>().ToArray());
|
||||
|
||||
return (arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8, arg9, arg10) =>
|
||||
{
|
||||
NativeAPI.ExecuteVirtualFunction<object>(virtualFunctionPointer,
|
||||
new object[] { arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8, arg9, arg10 });
|
||||
};
|
||||
}
|
||||
#endregion
|
||||
}
|
||||
@@ -0,0 +1,287 @@
|
||||
/*
|
||||
* 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.Modules.Memory;
|
||||
|
||||
public partial class VirtualFunctionVoid
|
||||
{
|
||||
private Action Function;
|
||||
|
||||
public VirtualFunctionVoid(string signature)
|
||||
{
|
||||
this.Function = VirtualFunction.CreateVoid(signature);
|
||||
}
|
||||
|
||||
public VirtualFunctionVoid(string signature, string binarypath)
|
||||
{
|
||||
this.Function = VirtualFunction.CreateVoid(signature, binarypath);
|
||||
}
|
||||
|
||||
public void Invoke()
|
||||
{
|
||||
this.Function();
|
||||
}
|
||||
}
|
||||
|
||||
public partial class VirtualFunctionVoid<TArg1>
|
||||
{
|
||||
private Action<TArg1> Function;
|
||||
|
||||
public VirtualFunctionVoid(string signature)
|
||||
{
|
||||
this.Function = VirtualFunction.CreateVoid<TArg1>(signature);
|
||||
}
|
||||
|
||||
public VirtualFunctionVoid(string signature, string binarypath)
|
||||
{
|
||||
this.Function = VirtualFunction.CreateVoid<TArg1>(signature, binarypath);
|
||||
}
|
||||
|
||||
public VirtualFunctionVoid(IntPtr objectPtr, int offset)
|
||||
{
|
||||
this.Function = VirtualFunction.CreateVoid<TArg1>(objectPtr, offset);
|
||||
}
|
||||
|
||||
public void Invoke(TArg1 arg1)
|
||||
{
|
||||
this.Function(arg1);
|
||||
}
|
||||
}
|
||||
|
||||
public partial class VirtualFunctionVoid<TArg1, TArg2>
|
||||
{
|
||||
private Action<TArg1, TArg2> Function;
|
||||
|
||||
public VirtualFunctionVoid(string signature)
|
||||
{
|
||||
this.Function = VirtualFunction.CreateVoid<TArg1, TArg2>(signature);
|
||||
}
|
||||
|
||||
public VirtualFunctionVoid(string signature, string binarypath)
|
||||
{
|
||||
this.Function = VirtualFunction.CreateVoid<TArg1, TArg2>(signature, binarypath);
|
||||
}
|
||||
|
||||
public VirtualFunctionVoid(IntPtr objectPtr, int offset)
|
||||
{
|
||||
this.Function = VirtualFunction.CreateVoid<TArg1, TArg2>(objectPtr, offset);
|
||||
}
|
||||
|
||||
public void Invoke(TArg1 arg1, TArg2 arg2)
|
||||
{
|
||||
this.Function(arg1, arg2);
|
||||
}
|
||||
}
|
||||
|
||||
public partial class VirtualFunctionVoid<TArg1, TArg2, TArg3>
|
||||
{
|
||||
private Action<TArg1, TArg2, TArg3> Function;
|
||||
|
||||
public VirtualFunctionVoid(string signature)
|
||||
{
|
||||
this.Function = VirtualFunction.CreateVoid<TArg1, TArg2, TArg3>(signature);
|
||||
}
|
||||
|
||||
public VirtualFunctionVoid(string signature, string binarypath)
|
||||
{
|
||||
this.Function = VirtualFunction.CreateVoid<TArg1, TArg2, TArg3>(signature, binarypath);
|
||||
}
|
||||
|
||||
public VirtualFunctionVoid(IntPtr objectPtr, int offset)
|
||||
{
|
||||
this.Function = VirtualFunction.CreateVoid<TArg1, TArg2, TArg3>(objectPtr, offset);
|
||||
}
|
||||
|
||||
public void Invoke(TArg1 arg1, TArg2 arg2, TArg3 arg3)
|
||||
{
|
||||
this.Function(arg1, arg2, arg3);
|
||||
}
|
||||
}
|
||||
|
||||
public partial class VirtualFunctionVoid<TArg1, TArg2, TArg3, TArg4>
|
||||
{
|
||||
private Action<TArg1, TArg2, TArg3, TArg4> Function;
|
||||
|
||||
public VirtualFunctionVoid(string signature)
|
||||
{
|
||||
this.Function = VirtualFunction.CreateVoid<TArg1, TArg2, TArg3, TArg4>(signature);
|
||||
}
|
||||
|
||||
public VirtualFunctionVoid(string signature, string binarypath)
|
||||
{
|
||||
this.Function = VirtualFunction.CreateVoid<TArg1, TArg2, TArg3, TArg4>(signature, binarypath);
|
||||
}
|
||||
|
||||
public VirtualFunctionVoid(IntPtr objectPtr, int offset)
|
||||
{
|
||||
this.Function = VirtualFunction.CreateVoid<TArg1, TArg2, TArg3, TArg4>(objectPtr, offset);
|
||||
}
|
||||
|
||||
public void Invoke(TArg1 arg1, TArg2 arg2, TArg3 arg3, TArg4 arg4)
|
||||
{
|
||||
this.Function(arg1, arg2, arg3, arg4);
|
||||
}
|
||||
}
|
||||
|
||||
public partial class VirtualFunctionVoid<TArg1, TArg2, TArg3, TArg4, TArg5>
|
||||
{
|
||||
private Action<TArg1, TArg2, TArg3, TArg4, TArg5> Function;
|
||||
|
||||
public VirtualFunctionVoid(string signature)
|
||||
{
|
||||
this.Function = VirtualFunction.CreateVoid<TArg1, TArg2, TArg3, TArg4, TArg5>(signature);
|
||||
}
|
||||
|
||||
public VirtualFunctionVoid(string signature, string binarypath)
|
||||
{
|
||||
this.Function = VirtualFunction.CreateVoid<TArg1, TArg2, TArg3, TArg4, TArg5>(signature, binarypath);
|
||||
}
|
||||
|
||||
public VirtualFunctionVoid(IntPtr objectPtr, int offset)
|
||||
{
|
||||
this.Function = VirtualFunction.CreateVoid<TArg1, TArg2, TArg3, TArg4, TArg5>(objectPtr, offset);
|
||||
}
|
||||
|
||||
public void Invoke(TArg1 arg1, TArg2 arg2, TArg3 arg3, TArg4 arg4, TArg5 arg5)
|
||||
{
|
||||
this.Function(arg1, arg2, arg3, arg4, arg5);
|
||||
}
|
||||
}
|
||||
|
||||
public partial class VirtualFunctionVoid<TArg1, TArg2, TArg3, TArg4, TArg5, TArg6>
|
||||
{
|
||||
private Action<TArg1, TArg2, TArg3, TArg4, TArg5, TArg6> Function;
|
||||
|
||||
public VirtualFunctionVoid(string signature)
|
||||
{
|
||||
this.Function = VirtualFunction.CreateVoid<TArg1, TArg2, TArg3, TArg4, TArg5, TArg6>(signature);
|
||||
}
|
||||
|
||||
public VirtualFunctionVoid(string signature, string binarypath)
|
||||
{
|
||||
this.Function = VirtualFunction.CreateVoid<TArg1, TArg2, TArg3, TArg4, TArg5, TArg6>(signature, binarypath);
|
||||
}
|
||||
|
||||
public VirtualFunctionVoid(IntPtr objectPtr, int offset)
|
||||
{
|
||||
this.Function = VirtualFunction.CreateVoid<TArg1, TArg2, TArg3, TArg4, TArg5, TArg6>(objectPtr, offset);
|
||||
}
|
||||
|
||||
public void Invoke(TArg1 arg1, TArg2 arg2, TArg3 arg3, TArg4 arg4, TArg5 arg5, TArg6 arg6)
|
||||
{
|
||||
this.Function(arg1, arg2, arg3, arg4, arg5, arg6);
|
||||
}
|
||||
}
|
||||
|
||||
public partial class VirtualFunctionVoid<TArg1, TArg2, TArg3, TArg4, TArg5, TArg6, TArg7>
|
||||
{
|
||||
private Action<TArg1, TArg2, TArg3, TArg4, TArg5, TArg6, TArg7> Function;
|
||||
|
||||
public VirtualFunctionVoid(string signature)
|
||||
{
|
||||
this.Function = VirtualFunction.CreateVoid<TArg1, TArg2, TArg3, TArg4, TArg5, TArg6, TArg7>(signature);
|
||||
}
|
||||
|
||||
public VirtualFunctionVoid(string signature, string binarypath)
|
||||
{
|
||||
this.Function = VirtualFunction.CreateVoid<TArg1, TArg2, TArg3, TArg4, TArg5, TArg6, TArg7>(signature, binarypath);
|
||||
}
|
||||
|
||||
public VirtualFunctionVoid(IntPtr objectPtr, int offset)
|
||||
{
|
||||
this.Function = VirtualFunction.CreateVoid<TArg1, TArg2, TArg3, TArg4, TArg5, TArg6, TArg7>(objectPtr, offset);
|
||||
}
|
||||
|
||||
public void Invoke(TArg1 arg1, TArg2 arg2, TArg3 arg3, TArg4 arg4, TArg5 arg5, TArg6 arg6, TArg7 arg7)
|
||||
{
|
||||
this.Function(arg1, arg2, arg3, arg4, arg5, arg6, arg7);
|
||||
}
|
||||
}
|
||||
|
||||
public partial class VirtualFunctionVoid<TArg1, TArg2, TArg3, TArg4, TArg5, TArg6, TArg7, TArg8>
|
||||
{
|
||||
private Action<TArg1, TArg2, TArg3, TArg4, TArg5, TArg6, TArg7, TArg8> Function;
|
||||
|
||||
public VirtualFunctionVoid(string signature)
|
||||
{
|
||||
this.Function = VirtualFunction.CreateVoid<TArg1, TArg2, TArg3, TArg4, TArg5, TArg6, TArg7, TArg8>(signature);
|
||||
}
|
||||
|
||||
public VirtualFunctionVoid(string signature, string binarypath)
|
||||
{
|
||||
this.Function = VirtualFunction.CreateVoid<TArg1, TArg2, TArg3, TArg4, TArg5, TArg6, TArg7, TArg8>(signature, binarypath);
|
||||
}
|
||||
|
||||
public VirtualFunctionVoid(IntPtr objectPtr, int offset)
|
||||
{
|
||||
this.Function = VirtualFunction.CreateVoid<TArg1, TArg2, TArg3, TArg4, TArg5, TArg6, TArg7, TArg8>(objectPtr, offset);
|
||||
}
|
||||
|
||||
public void Invoke(TArg1 arg1, TArg2 arg2, TArg3 arg3, TArg4 arg4, TArg5 arg5, TArg6 arg6, TArg7 arg7, TArg8 arg8)
|
||||
{
|
||||
this.Function(arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8);
|
||||
}
|
||||
}
|
||||
|
||||
public partial class VirtualFunctionVoid<TArg1, TArg2, TArg3, TArg4, TArg5, TArg6, TArg7, TArg8, TArg9>
|
||||
{
|
||||
private Action<TArg1, TArg2, TArg3, TArg4, TArg5, TArg6, TArg7, TArg8, TArg9> Function;
|
||||
|
||||
public VirtualFunctionVoid(string signature)
|
||||
{
|
||||
this.Function = VirtualFunction.CreateVoid<TArg1, TArg2, TArg3, TArg4, TArg5, TArg6, TArg7, TArg8, TArg9>(signature);
|
||||
}
|
||||
|
||||
public VirtualFunctionVoid(string signature, string binarypath)
|
||||
{
|
||||
this.Function = VirtualFunction.CreateVoid<TArg1, TArg2, TArg3, TArg4, TArg5, TArg6, TArg7, TArg8, TArg9>(signature, binarypath);
|
||||
}
|
||||
|
||||
public VirtualFunctionVoid(IntPtr objectPtr, int offset)
|
||||
{
|
||||
this.Function = VirtualFunction.CreateVoid<TArg1, TArg2, TArg3, TArg4, TArg5, TArg6, TArg7, TArg8, TArg9>(objectPtr, offset);
|
||||
}
|
||||
|
||||
public void Invoke(TArg1 arg1, TArg2 arg2, TArg3 arg3, TArg4 arg4, TArg5 arg5, TArg6 arg6, TArg7 arg7, TArg8 arg8, TArg9 arg9)
|
||||
{
|
||||
this.Function(arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8, arg9);
|
||||
}
|
||||
}
|
||||
|
||||
public partial class VirtualFunctionVoid<TArg1, TArg2, TArg3, TArg4, TArg5, TArg6, TArg7, TArg8, TArg9, TArg10>
|
||||
{
|
||||
private Action<TArg1, TArg2, TArg3, TArg4, TArg5, TArg6, TArg7, TArg8, TArg9, TArg10> Function;
|
||||
|
||||
public VirtualFunctionVoid(string signature)
|
||||
{
|
||||
this.Function = VirtualFunction.CreateVoid<TArg1, TArg2, TArg3, TArg4, TArg5, TArg6, TArg7, TArg8, TArg9, TArg10>(signature);
|
||||
}
|
||||
|
||||
public VirtualFunctionVoid(string signature, string binarypath)
|
||||
{
|
||||
this.Function = VirtualFunction.CreateVoid<TArg1, TArg2, TArg3, TArg4, TArg5, TArg6, TArg7, TArg8, TArg9, TArg10>(signature, binarypath);
|
||||
}
|
||||
|
||||
public VirtualFunctionVoid(IntPtr objectPtr, int offset)
|
||||
{
|
||||
this.Function = VirtualFunction.CreateVoid<TArg1, TArg2, TArg3, TArg4, TArg5, TArg6, TArg7, TArg8, TArg9, TArg10>(objectPtr, offset);
|
||||
}
|
||||
|
||||
public void Invoke(TArg1 arg1, TArg2 arg2, TArg3 arg3, TArg4 arg4, TArg5 arg5, TArg6 arg6, TArg7 arg7, TArg8 arg8, TArg9 arg9, TArg10 arg10)
|
||||
{
|
||||
this.Function(arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8, arg9, arg10);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,292 @@
|
||||
/*
|
||||
* 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.Modules.Memory;
|
||||
|
||||
public partial class VirtualFunctionWithReturn<TResult>
|
||||
{
|
||||
private Func<TResult> Function;
|
||||
|
||||
public VirtualFunctionWithReturn(string signature)
|
||||
{
|
||||
this.Function = VirtualFunction.Create<TResult>(signature);
|
||||
}
|
||||
|
||||
public VirtualFunctionWithReturn(string signature, string binarypath)
|
||||
{
|
||||
this.Function = VirtualFunction.Create<TResult>(signature, binarypath);
|
||||
}
|
||||
|
||||
public VirtualFunctionWithReturn(IntPtr objectPtr, int offset)
|
||||
{
|
||||
this.Function = VirtualFunction.Create<TResult>(objectPtr, offset);
|
||||
}
|
||||
|
||||
public TResult Invoke()
|
||||
{
|
||||
return this.Function();
|
||||
}
|
||||
}
|
||||
|
||||
public partial class VirtualFunctionWithReturn<TArg1, TResult>
|
||||
{
|
||||
private Func<TArg1, TResult> Function;
|
||||
|
||||
public VirtualFunctionWithReturn(string signature)
|
||||
{
|
||||
this.Function = VirtualFunction.Create<TArg1, TResult>(signature);
|
||||
}
|
||||
|
||||
public VirtualFunctionWithReturn(string signature, string binarypath)
|
||||
{
|
||||
this.Function = VirtualFunction.Create<TArg1, TResult>(signature, binarypath);
|
||||
}
|
||||
|
||||
public VirtualFunctionWithReturn(IntPtr objectPtr, int offset)
|
||||
{
|
||||
this.Function = VirtualFunction.Create<TArg1, TResult>(objectPtr, offset);
|
||||
}
|
||||
|
||||
public TResult Invoke(TArg1 arg1)
|
||||
{
|
||||
return this.Function(arg1);
|
||||
}
|
||||
}
|
||||
|
||||
public partial class VirtualFunctionWithReturn<TArg1, TArg2, TResult>
|
||||
{
|
||||
private Func<TArg1, TArg2, TResult> Function;
|
||||
|
||||
public VirtualFunctionWithReturn(string signature)
|
||||
{
|
||||
this.Function = VirtualFunction.Create<TArg1, TArg2, TResult>(signature);
|
||||
}
|
||||
|
||||
public VirtualFunctionWithReturn(string signature, string binarypath)
|
||||
{
|
||||
this.Function = VirtualFunction.Create<TArg1, TArg2, TResult>(signature, binarypath);
|
||||
}
|
||||
|
||||
public VirtualFunctionWithReturn(IntPtr objectPtr, int offset)
|
||||
{
|
||||
this.Function = VirtualFunction.Create<TArg1, TArg2, TResult>(objectPtr, offset);
|
||||
}
|
||||
|
||||
public TResult Invoke(TArg1 arg1, TArg2 arg2)
|
||||
{
|
||||
return this.Function(arg1, arg2);
|
||||
}
|
||||
}
|
||||
|
||||
public partial class VirtualFunctionWithReturn<TArg1, TArg2, TArg3, TResult>
|
||||
{
|
||||
private Func<TArg1, TArg2, TArg3, TResult> Function;
|
||||
|
||||
public VirtualFunctionWithReturn(string signature)
|
||||
{
|
||||
this.Function = VirtualFunction.Create<TArg1, TArg2, TArg3, TResult>(signature);
|
||||
}
|
||||
|
||||
public VirtualFunctionWithReturn(string signature, string binarypath)
|
||||
{
|
||||
this.Function = VirtualFunction.Create<TArg1, TArg2, TArg3, TResult>(signature, binarypath);
|
||||
}
|
||||
|
||||
public VirtualFunctionWithReturn(IntPtr objectPtr, int offset)
|
||||
{
|
||||
this.Function = VirtualFunction.Create<TArg1, TArg2, TArg3, TResult>(objectPtr, offset);
|
||||
}
|
||||
|
||||
public TResult Invoke(TArg1 arg1, TArg2 arg2, TArg3 arg3)
|
||||
{
|
||||
return this.Function(arg1, arg2, arg3);
|
||||
}
|
||||
}
|
||||
|
||||
public partial class VirtualFunctionWithReturn<TArg1, TArg2, TArg3, TArg4, TResult>
|
||||
{
|
||||
private Func<TArg1, TArg2, TArg3, TArg4, TResult> Function;
|
||||
|
||||
public VirtualFunctionWithReturn(string signature)
|
||||
{
|
||||
this.Function = VirtualFunction.Create<TArg1, TArg2, TArg3, TArg4, TResult>(signature);
|
||||
}
|
||||
|
||||
public VirtualFunctionWithReturn(string signature, string binarypath)
|
||||
{
|
||||
this.Function = VirtualFunction.Create<TArg1, TArg2, TArg3, TArg4, TResult>(signature, binarypath);
|
||||
}
|
||||
|
||||
public VirtualFunctionWithReturn(IntPtr objectPtr, int offset)
|
||||
{
|
||||
this.Function = VirtualFunction.Create<TArg1, TArg2, TArg3, TArg4, TResult>(objectPtr, offset);
|
||||
}
|
||||
|
||||
public TResult Invoke(TArg1 arg1, TArg2 arg2, TArg3 arg3, TArg4 arg4)
|
||||
{
|
||||
return this.Function(arg1, arg2, arg3, arg4);
|
||||
}
|
||||
}
|
||||
|
||||
public partial class VirtualFunctionWithReturn<TArg1, TArg2, TArg3, TArg4, TArg5, TResult>
|
||||
{
|
||||
private Func<TArg1, TArg2, TArg3, TArg4, TArg5, TResult> Function;
|
||||
|
||||
public VirtualFunctionWithReturn(string signature)
|
||||
{
|
||||
this.Function = VirtualFunction.Create<TArg1, TArg2, TArg3, TArg4, TArg5, TResult>(signature);
|
||||
}
|
||||
|
||||
public VirtualFunctionWithReturn(string signature, string binarypath)
|
||||
{
|
||||
this.Function = VirtualFunction.Create<TArg1, TArg2, TArg3, TArg4, TArg5, TResult>(signature, binarypath);
|
||||
}
|
||||
|
||||
public VirtualFunctionWithReturn(IntPtr objectPtr, int offset)
|
||||
{
|
||||
this.Function = VirtualFunction.Create<TArg1, TArg2, TArg3, TArg4, TArg5, TResult>(objectPtr, offset);
|
||||
}
|
||||
|
||||
public TResult Invoke(TArg1 arg1, TArg2 arg2, TArg3 arg3, TArg4 arg4, TArg5 arg5)
|
||||
{
|
||||
return this.Function(arg1, arg2, arg3, arg4, arg5);
|
||||
}
|
||||
}
|
||||
|
||||
public partial class VirtualFunctionWithReturn<TArg1, TArg2, TArg3, TArg4, TArg5, TArg6, TResult>
|
||||
{
|
||||
private Func<TArg1, TArg2, TArg3, TArg4, TArg5, TArg6, TResult> Function;
|
||||
|
||||
public VirtualFunctionWithReturn(string signature)
|
||||
{
|
||||
this.Function = VirtualFunction.Create<TArg1, TArg2, TArg3, TArg4, TArg5, TArg6, TResult>(signature);
|
||||
}
|
||||
|
||||
public VirtualFunctionWithReturn(string signature, string binarypath)
|
||||
{
|
||||
this.Function = VirtualFunction.Create<TArg1, TArg2, TArg3, TArg4, TArg5, TArg6, TResult>(signature, binarypath);
|
||||
}
|
||||
|
||||
public VirtualFunctionWithReturn(IntPtr objectPtr, int offset)
|
||||
{
|
||||
this.Function = VirtualFunction.Create<TArg1, TArg2, TArg3, TArg4, TArg5, TArg6, TResult>(objectPtr, offset);
|
||||
}
|
||||
|
||||
public TResult Invoke(TArg1 arg1, TArg2 arg2, TArg3 arg3, TArg4 arg4, TArg5 arg5, TArg6 arg6)
|
||||
{
|
||||
return this.Function(arg1, arg2, arg3, arg4, arg5, arg6);
|
||||
}
|
||||
}
|
||||
|
||||
public partial class VirtualFunctionWithReturn<TArg1, TArg2, TArg3, TArg4, TArg5, TArg6, TArg7, TResult>
|
||||
{
|
||||
private Func<TArg1, TArg2, TArg3, TArg4, TArg5, TArg6, TArg7, TResult> Function;
|
||||
|
||||
public VirtualFunctionWithReturn(string signature)
|
||||
{
|
||||
this.Function = VirtualFunction.Create<TArg1, TArg2, TArg3, TArg4, TArg5, TArg6, TArg7, TResult>(signature);
|
||||
}
|
||||
|
||||
public VirtualFunctionWithReturn(string signature, string binarypath)
|
||||
{
|
||||
this.Function = VirtualFunction.Create<TArg1, TArg2, TArg3, TArg4, TArg5, TArg6, TArg7, TResult>(signature, binarypath);
|
||||
}
|
||||
|
||||
public VirtualFunctionWithReturn(IntPtr objectPtr, int offset)
|
||||
{
|
||||
this.Function = VirtualFunction.Create<TArg1, TArg2, TArg3, TArg4, TArg5, TArg6, TArg7, TResult>(objectPtr, offset);
|
||||
}
|
||||
|
||||
public TResult Invoke(TArg1 arg1, TArg2 arg2, TArg3 arg3, TArg4 arg4, TArg5 arg5, TArg6 arg6, TArg7 arg7)
|
||||
{
|
||||
return this.Function(arg1, arg2, arg3, arg4, arg5, arg6, arg7);
|
||||
}
|
||||
}
|
||||
|
||||
public partial class VirtualFunctionWithReturn<TArg1, TArg2, TArg3, TArg4, TArg5, TArg6, TArg7, TArg8, TResult>
|
||||
{
|
||||
private Func<TArg1, TArg2, TArg3, TArg4, TArg5, TArg6, TArg7, TArg8, TResult> Function;
|
||||
|
||||
public VirtualFunctionWithReturn(string signature)
|
||||
{
|
||||
this.Function = VirtualFunction.Create<TArg1, TArg2, TArg3, TArg4, TArg5, TArg6, TArg7, TArg8, TResult>(signature);
|
||||
}
|
||||
|
||||
public VirtualFunctionWithReturn(string signature, string binarypath)
|
||||
{
|
||||
this.Function = VirtualFunction.Create<TArg1, TArg2, TArg3, TArg4, TArg5, TArg6, TArg7, TArg8, TResult>(signature, binarypath);
|
||||
}
|
||||
|
||||
public VirtualFunctionWithReturn(IntPtr objectPtr, int offset)
|
||||
{
|
||||
this.Function = VirtualFunction.Create<TArg1, TArg2, TArg3, TArg4, TArg5, TArg6, TArg7, TArg8, TResult>(objectPtr, offset);
|
||||
}
|
||||
|
||||
public TResult Invoke(TArg1 arg1, TArg2 arg2, TArg3 arg3, TArg4 arg4, TArg5 arg5, TArg6 arg6, TArg7 arg7, TArg8 arg8)
|
||||
{
|
||||
return this.Function(arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8);
|
||||
}
|
||||
}
|
||||
|
||||
public partial class VirtualFunctionWithReturn<TArg1, TArg2, TArg3, TArg4, TArg5, TArg6, TArg7, TArg8, TArg9, TResult>
|
||||
{
|
||||
private Func<TArg1, TArg2, TArg3, TArg4, TArg5, TArg6, TArg7, TArg8, TArg9, TResult> Function;
|
||||
|
||||
public VirtualFunctionWithReturn(string signature)
|
||||
{
|
||||
this.Function = VirtualFunction.Create<TArg1, TArg2, TArg3, TArg4, TArg5, TArg6, TArg7, TArg8, TArg9, TResult>(signature);
|
||||
}
|
||||
|
||||
public VirtualFunctionWithReturn(string signature, string binarypath)
|
||||
{
|
||||
this.Function = VirtualFunction.Create<TArg1, TArg2, TArg3, TArg4, TArg5, TArg6, TArg7, TArg8, TArg9, TResult>(signature, binarypath);
|
||||
}
|
||||
|
||||
public VirtualFunctionWithReturn(IntPtr objectPtr, int offset)
|
||||
{
|
||||
this.Function = VirtualFunction.Create<TArg1, TArg2, TArg3, TArg4, TArg5, TArg6, TArg7, TArg8, TArg9, TResult>(objectPtr, offset);
|
||||
}
|
||||
|
||||
public TResult Invoke(TArg1 arg1, TArg2 arg2, TArg3 arg3, TArg4 arg4, TArg5 arg5, TArg6 arg6, TArg7 arg7, TArg8 arg8, TArg9 arg9)
|
||||
{
|
||||
return this.Function(arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8, arg9);
|
||||
}
|
||||
}
|
||||
|
||||
public partial class VirtualFunctionWithReturn<TArg1, TArg2, TArg3, TArg4, TArg5, TArg6, TArg7, TArg8, TArg9, TArg10, TResult>
|
||||
{
|
||||
private Func<TArg1, TArg2, TArg3, TArg4, TArg5, TArg6, TArg7, TArg8, TArg9, TArg10, TResult> Function;
|
||||
|
||||
public VirtualFunctionWithReturn(string signature)
|
||||
{
|
||||
this.Function = VirtualFunction.Create<TArg1, TArg2, TArg3, TArg4, TArg5, TArg6, TArg7, TArg8, TArg9, TArg10, TResult>(signature);
|
||||
}
|
||||
|
||||
public VirtualFunctionWithReturn(string signature, string binarypath)
|
||||
{
|
||||
this.Function = VirtualFunction.Create<TArg1, TArg2, TArg3, TArg4, TArg5, TArg6, TArg7, TArg8, TArg9, TArg10, TResult>(signature, binarypath);
|
||||
}
|
||||
|
||||
public VirtualFunctionWithReturn(IntPtr objectPtr, int offset)
|
||||
{
|
||||
this.Function = VirtualFunction.Create<TArg1, TArg2, TArg3, TArg4, TArg5, TArg6, TArg7, TArg8, TArg9, TArg10, TResult>(objectPtr, offset);
|
||||
}
|
||||
|
||||
public TResult Invoke(TArg1 arg1, TArg2 arg2, TArg3 arg3, TArg4 arg4, TArg5 arg5, TArg6 arg6, TArg7 arg7, TArg8 arg8, TArg9 arg9, TArg10 arg10)
|
||||
{
|
||||
return this.Function(arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8, arg9, arg10);
|
||||
}
|
||||
}
|
||||
@@ -1,6 +1,8 @@
|
||||
using System;
|
||||
using System.Runtime.CompilerServices;
|
||||
using System.Runtime.InteropServices;
|
||||
using CounterStrikeSharp.API.Core;
|
||||
using CounterStrikeSharp.API.Modules.Entities;
|
||||
|
||||
namespace CounterStrikeSharp.API.Modules.Utils;
|
||||
|
||||
@@ -9,22 +11,80 @@ public readonly record struct CEntityIndex(uint Value)
|
||||
public override string ToString() => $"Entity Index {Value}";
|
||||
}
|
||||
|
||||
public class CHandle<T> : NativeObject
|
||||
public class CHandle<T> : IEquatable<CHandle<T>> where T : NativeEntity
|
||||
{
|
||||
public CHandle(IntPtr pointer) : base(pointer)
|
||||
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 T Value => (T)Activator.CreateInstance(typeof(T), NativeAPI.GetEntityPointerFromHandle(Handle));
|
||||
public CHandle(uint raw)
|
||||
{
|
||||
Raw = raw;
|
||||
}
|
||||
|
||||
public unsafe ref ulong Raw => ref Unsafe.AsRef<ulong>((void*)Handle);
|
||||
public CHandle(IntPtr raw)
|
||||
{
|
||||
_pointer = raw;
|
||||
}
|
||||
|
||||
public override string ToString() => IsValid ? $"Index = {Index.Value}, Serial = {SerialNum}" : "<invalid>";
|
||||
public T? Value => (T)Activator.CreateInstance(typeof(T), EntitySystem.GetEntityByHandle(this));
|
||||
|
||||
public bool IsValid => Index.Value != (Utilities.MaxEdicts - 1);
|
||||
public override string ToString() => IsValid ? $"Index = {Index}, Serial = {SerialNum}" : "<invalid>";
|
||||
|
||||
public CEntityIndex Index => new((uint)(Raw & (Utilities.MaxEdicts - 1)));
|
||||
public uint SerialNum => (uint)(Raw >> Utilities.MaxEdictBits);
|
||||
public bool IsValid => Index != (Utilities.MaxEdicts - 1);
|
||||
|
||||
public uint Index => (uint)(Raw & (Utilities.MaxEdicts - 1));
|
||||
public uint SerialNum => Raw >> Utilities.MaxEdictBits;
|
||||
|
||||
public static implicit operator uint(CHandle<T> handle) => handle.Raw;
|
||||
|
||||
public bool Equals(CHandle<T>? other)
|
||||
{
|
||||
return other != null && Raw == other.Raw;
|
||||
}
|
||||
|
||||
public override bool Equals(object? obj)
|
||||
{
|
||||
return Equals(obj as CHandle<T>);
|
||||
}
|
||||
|
||||
public override int GetHashCode()
|
||||
{
|
||||
return (int)Raw;
|
||||
}
|
||||
}
|
||||
|
||||
public class CEntityHandle : CHandle<CEntityInstance>
|
||||
{
|
||||
public CEntityHandle(uint raw) : base(raw)
|
||||
{
|
||||
}
|
||||
|
||||
public CEntityHandle(IntPtr raw) : base (raw)
|
||||
{
|
||||
}
|
||||
}
|
||||
|
||||
public class PointerTo<T> : NativeObject where T : NativeObject
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
using System;
|
||||
using System.Linq;
|
||||
using System.Reflection;
|
||||
using System.Runtime.Serialization;
|
||||
|
||||
|
||||
@@ -7,30 +8,57 @@ namespace CounterStrikeSharp.API.Modules.Utils
|
||||
{
|
||||
public static class EnumUtils
|
||||
{
|
||||
public static string? GetEnumMemberAttributeValue<T>(T enumValue)
|
||||
/// <summary>
|
||||
/// Brute force search using Enum.GetNames as enum members pointing to other enum members do not have the correct attributes.
|
||||
/// </summary>
|
||||
public static T? GetEnumMemberAttribute<T>(this Enum enumValue) where T : Attribute
|
||||
{
|
||||
var type = enumValue.GetType();
|
||||
foreach (var name in Enum.GetNames(type))
|
||||
{
|
||||
var field = type.GetField(name);
|
||||
if (field == null) continue;
|
||||
|
||||
var fieldValue = field.GetValue(null)!;
|
||||
if (fieldValue.Equals(enumValue))
|
||||
{
|
||||
var attribute = field.GetCustomAttribute<T>();
|
||||
if (attribute != null)
|
||||
{
|
||||
return attribute;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
public static string? GetEnumMemberAttributeValue<T>(T? enumValue) where T : Enum
|
||||
{
|
||||
var enumType = typeof(T);
|
||||
|
||||
if(!enumType.IsEnum || enumValue == null)
|
||||
if (!enumType.IsEnum || enumValue == null)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
var enumString = enumValue.ToString();
|
||||
|
||||
if(string.IsNullOrWhiteSpace(enumString))
|
||||
if (string.IsNullOrWhiteSpace(enumString))
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
var memberInfo = enumType.GetMember(enumString);
|
||||
var enumMemberAttribute = memberInfo.FirstOrDefault()?.GetCustomAttributes(false).OfType<EnumMemberAttribute>().FirstOrDefault();
|
||||
var enumMemberAttribute = memberInfo.FirstOrDefault()?.GetCustomAttributes(false)
|
||||
.OfType<EnumMemberAttribute>().FirstOrDefault();
|
||||
if (enumMemberAttribute != null)
|
||||
{
|
||||
return enumMemberAttribute.Value;
|
||||
}
|
||||
|
||||
return null;
|
||||
// Brute force search by name if we still can't find it.
|
||||
return enumValue.GetEnumMemberAttribute<EnumMemberAttribute>()?.Value;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
21
managed/CounterStrikeSharp.API/NativeEntity.cs
Normal file
21
managed/CounterStrikeSharp.API/NativeEntity.cs
Normal file
@@ -0,0 +1,21 @@
|
||||
using System.Runtime.InteropServices;
|
||||
using CounterStrikeSharp.API.Modules.Entities;
|
||||
using CounterStrikeSharp.API.Modules.Utils;
|
||||
|
||||
namespace CounterStrikeSharp.API;
|
||||
|
||||
public abstract class NativeEntity : NativeObject
|
||||
{
|
||||
public new IntPtr Handle => EntitySystem.GetEntityByHandle(EntityHandle) ?? IntPtr.Zero;
|
||||
public CEntityHandle EntityHandle { get; }
|
||||
|
||||
public NativeEntity(IntPtr pointer) : base(pointer)
|
||||
{
|
||||
EntityHandle = new(EntitySystem.GetRawHandleFromEntityPointer(pointer));
|
||||
}
|
||||
|
||||
public NativeEntity(uint rawHandle) : base(EntitySystem.GetEntityByHandle(rawHandle) ?? IntPtr.Zero)
|
||||
{
|
||||
EntityHandle = new(rawHandle);
|
||||
}
|
||||
}
|
||||
@@ -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)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user