mirror of
https://github.com/roflmuffin/CounterStrikeSharp.git
synced 2025-12-06 08:03:12 -08:00
Compare commits
22 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
98b2b01992 | ||
|
|
a537be89e4 | ||
|
|
c07d5d2aa9 | ||
|
|
1cc95555fe | ||
|
|
378c28dfd0 | ||
|
|
c7343c3b7a | ||
|
|
62f6b09f50 | ||
|
|
2a15a8de71 | ||
|
|
1d6bee02cd | ||
|
|
72e1f22e14 | ||
|
|
a8a238bdee | ||
|
|
cec8ef3d30 | ||
|
|
c7384df396 | ||
|
|
84d4998a72 | ||
|
|
1b194318af | ||
|
|
22d0dd8200 | ||
|
|
7baf0a25e2 | ||
|
|
9fdbb9500b | ||
|
|
0ab3cf429a | ||
|
|
1f9630b92d | ||
|
|
02bf2483d3 | ||
|
|
cb181b6a49 |
18
.github/workflows/cmake-single-platform.yml
vendored
18
.github/workflows/cmake-single-platform.yml
vendored
@@ -3,7 +3,7 @@ name: Build & Publish
|
||||
on:
|
||||
push:
|
||||
paths-ignore:
|
||||
- 'docs/**'
|
||||
- 'docfx/**'
|
||||
branches: [ "main" ]
|
||||
pull_request:
|
||||
branches: [ "main" ]
|
||||
@@ -117,7 +117,21 @@ jobs:
|
||||
with:
|
||||
dotnet-version: '7.0.x'
|
||||
|
||||
- run: |
|
||||
- name: Install dependencies
|
||||
run: dotnet restore managed/CounterStrikeSharp.sln
|
||||
|
||||
- name: Run tests
|
||||
run: dotnet test --logger trx --results-directory "TestResults-${{ env.GITHUB_SHA_SHORT }}" managed/CounterStrikeSharp.API.Tests/CounterStrikeSharp.API.Tests.csproj
|
||||
|
||||
- name: Upload dotnet test results
|
||||
uses: actions/upload-artifact@v3
|
||||
with:
|
||||
name: test-results-${{ env.GITHUB_SHA_SHORT }}
|
||||
path: TestResults-${{ env.GITHUB_SHA_SHORT }}
|
||||
if: ${{ always() }}
|
||||
|
||||
- name: Publish artifacts
|
||||
run: |
|
||||
dotnet publish -c Release /p:Version=1.0.${{ env.BUILD_NUMBER }} managed/CounterStrikeSharp.API
|
||||
dotnet pack -c Release /p:Version=1.0.${{ env.BUILD_NUMBER }} managed/CounterStrikeSharp.API
|
||||
|
||||
|
||||
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/
|
||||
|
||||
@@ -83,7 +83,7 @@ SET(SOURCE_FILES
|
||||
src/core/managers/server_manager.h
|
||||
src/scripting/natives/natives_server.cpp
|
||||
libraries/nlohmann/json.hpp
|
||||
src/scripting/natives/natives_dynamichooks.cpp
|
||||
src/scripting/natives/natives_dynamichooks.cpp
|
||||
)
|
||||
|
||||
|
||||
|
||||
@@ -164,5 +164,12 @@
|
||||
"windows": 91,
|
||||
"linux": 91
|
||||
}
|
||||
},
|
||||
"CEntityIOOutput_FireOutputInternal": {
|
||||
"signatures": {
|
||||
"library": "server",
|
||||
"windows": "\\x48\\x8B\\xC4\\x4C\\x89\\x48\\x20\\x55\\x57\\x41\\x54\\x41\\x56",
|
||||
"linux": "\\x55\\x48\\x89\\xE5\\x41\\x57\\x41\\x56\\x41\\x55\\x41\\x54\\x53\\x48\\x83\\xEC\\x58\\x4C\\x8B\\x6F\\x08"
|
||||
}
|
||||
}
|
||||
}
|
||||
3
docfx/404.md
Normal file
3
docfx/404.md
Normal file
@@ -0,0 +1,3 @@
|
||||
# 404
|
||||
|
||||
We recently changed our docs. Your page may exist at a different location.
|
||||
46
docfx/docfx.json
Normal file
46
docfx/docfx.json
Normal file
@@ -0,0 +1,46 @@
|
||||
{
|
||||
"metadata": [
|
||||
{
|
||||
"src": [
|
||||
{
|
||||
"src": "../managed/CounterStrikeSharp.API",
|
||||
"files": ["**/*.csproj"],
|
||||
"exclude": ["**/bin/**", "**/obj/**"]
|
||||
}
|
||||
],
|
||||
"filter": "filterConfig.yml",
|
||||
"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.
|
||||
63
docfx/docs/guides/getting-started.md
Normal file
63
docfx/docs/guides/getting-started.md
Normal file
@@ -0,0 +1,63 @@
|
||||
---
|
||||
title: Getting Started
|
||||
description: How to get started installing & using CounterStrikeSharp.
|
||||
---
|
||||
|
||||
# Getting Started
|
||||
|
||||
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
|
||||
|
||||
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]
|
||||
> 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]
|
||||
> For Windows users, you must ensure that you have installed **Visual Studio Redistributables**.
|
||||
> If not, you can download it here: <a href="https://aka.ms/vs/17/release/vc_redist.x64.exe" target="_blank">Download</a>
|
||||
> > This link will download VC Redistributable directly.
|
||||
>
|
||||
> You must install it before starting the server, otherwise CSS will not work!
|
||||
|
||||
|
||||
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.
|
||||
|
||||
```shell
|
||||
<server_path>/game/csgo/addons > tree -L 2
|
||||
addons
|
||||
├── counterstrikesharp
|
||||
│ ├── api
|
||||
│ ├── bin
|
||||
│ ├── dotnet
|
||||
│ ├── plugins
|
||||
│ └── gamedata
|
||||
│
|
||||
├── metamod
|
||||
│ ├── bin
|
||||
│ ├── counterstrikesharp.vdf
|
||||
│ ├── metaplugins.ini
|
||||
│ └── README.txt
|
||||
├── metamod.vdf
|
||||
└── metamod_x64.vdf
|
||||
```
|
||||
|
||||
## 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.`.
|
||||
|
||||
Running the command `meta list` in the console should show 1 plugin loaded 🎉
|
||||
|
||||
```shell
|
||||
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
|
||||
|
||||
@@ -78,20 +79,17 @@ Locate the `plugins` folder in your CS2 dedicated server (`/game/csgo/addons/cou
|
||||
└── HelloWorldPlugin.pdb
|
||||
```
|
||||
|
||||
:::caution
|
||||
If you have installed external nuget packages for your plugin, you may need to include their respective `.dll`s. For example, if you utilize the `Stateless` C# library, include `stateless.dll` in your `HelloWorld` plugin directory.
|
||||
:::
|
||||
> [!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.
|
||||
:::
|
||||
> [!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,9 +25,9 @@ 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
|
||||
|
||||
@@ -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/WithEntityOutputHooks.md
Normal file
5
docfx/examples/WithEntityOutputHooks.md
Normal file
@@ -0,0 +1,5 @@
|
||||
[!INCLUDE [WithEntityOutputHooks](../../examples/WithEntityOutputHooks/README.md)]
|
||||
|
||||
<a href="https://github.com/roflmuffin/CounterStrikeSharp/tree/main/examples/WithEntityOutputHooks" class="btn btn-secondary">View project on Github <i class="bi bi-github"></i></a>
|
||||
|
||||
[!code-csharp[](../../examples/WithEntityOutputHooks/WithEntityOutputHooksPlugin.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)]
|
||||
17
docfx/examples/toc.yml
Normal file
17
docfx/examples/toc.yml
Normal file
@@ -0,0 +1,17 @@
|
||||
items:
|
||||
- name: Hello World
|
||||
href: HelloWorld.md
|
||||
- name: Commands
|
||||
href: WithCommands.md
|
||||
- name: Config
|
||||
href: WithConfig.md
|
||||
- name: Dependency Injection
|
||||
href: WithDependencyInjection.md
|
||||
- name: Entity Output Hooks
|
||||
href: WithEntityOutputHooks.md
|
||||
- name: Game Event Handlers
|
||||
href: WithGameEventHandlers.md
|
||||
- name: Database (Dapper)
|
||||
href: WithDatabase.md
|
||||
- name: Warcraft Plugin
|
||||
href: WarcraftPlugin.md
|
||||
4
docfx/filterConfig.yml
Normal file
4
docfx/filterConfig.yml
Normal file
@@ -0,0 +1,4 @@
|
||||
apiRules:
|
||||
- exclude:
|
||||
uidRegex: ^System\.Object
|
||||
type: Type
|
||||
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" width="50" height="50" fill="none"><path fill="#F89A0F" d="m37.456 1.262-19.008.148a91.03 91.03 0 0 0-5.96.215A26.294 26.294 0 0 0 1.523 4.793C.643 5.26 0 6.07 0 7.06a2.464 2.464 0 0 0 3.704 2.128l.015-.007a20.538 20.538 0 0 1 7.93-2.495c8.024-.858 13.602 2.018 17.367 5.397 4.138 3.712 7.967 11.271 6.576 19.56-.831 4.962-3.122 9.146-6.69 12.397l-.007.007c-.646.59-1.18 1.274-1.18 2.147a2.547 2.547 0 0 0 4.158 1.965c.102-.075.22-.185.276-.238a27.692 27.692 0 0 0 6.652-9.698l10.126-24.027c.476-1.085.877-2.203 1.001-3.292.537-4.762-2.007-7.502-5.227-8.769-1.648-.65-3.968-.846-6.5-.869l-.745-.004Zm2.74 3.032c1.799.075 3.553 1.372 3.326 3.741-.276 2.865-3.137 4.865-4.384 6.747h4.384c.264.385.264 1.637 0 2.022-2.204-.215-4.66-.178-7.083-.17-1.036-3.783 5.367-6.327 4.72-9.441-.306-1.47-2.403-1.512-2.025.676h-2.529c-.045-2.506 1.796-3.651 3.59-3.575Z"/><path fill="#A079DF" d="M28.422 21.551a2.807 2.807 0 0 0-.34-1.413 2.7 2.7 0 0 0-1.028-.998c-3.772-2.174-7.54-4.34-11.304-6.516a2.774 2.774 0 0 0-3.01.03c-1.5.888-9.01 5.186-11.247 6.486A2.616 2.616 0 0 0 .12 21.55V34.66c0 .525.113.982.333 1.387a2.6 2.6 0 0 0 1.039 1.02c2.237 1.3 9.748 5.602 11.248 6.49a2.778 2.778 0 0 0 3.008.026c3.765-2.173 7.54-4.339 11.309-6.512.434-.24.794-.594 1.04-1.024.226-.427.339-.904.328-1.387l-.004-13.108Z"/><path fill="#270068" d="M14.317 28.06.454 36.05a2.6 2.6 0 0 0 1.039 1.02c2.237 1.3 9.748 5.601 11.248 6.49a2.778 2.778 0 0 0 3.008.026c3.765-2.173 7.54-4.339 11.309-6.512.434-.24.794-.594 1.04-1.024l-13.781-7.99Z"/><path fill="#390091" d="M28.422 21.551a2.807 2.807 0 0 0-.34-1.413l-13.769 7.925 13.78 7.983c.227-.427.34-.904.33-1.387V21.55Z"/><path fill="#fff" d="M22.48 25.078v1.492h1.494v-1.492h.744v1.492h1.493v.745h-1.493v1.493h1.493v.748h-1.493v1.49h-.744v-1.49H22.48v1.49h-.748v-1.49H20.24v-.748h1.493v-1.493H20.24v-.745h1.493v-1.492h.748Zm1.494 2.237H22.48v1.493h1.493v-1.493Z"/><path fill="#fff" d="M14.347 17.583c3.893 0 7.295 2.116 9.109 5.253l-.015-.026-4.58 2.638a5.236 5.236 0 0 0-4.453-2.582h-.06a5.238 5.238 0 1 0 4.565 7.809l-.023.038 4.574 2.645a10.519 10.519 0 0 1-8.996 5.27h-.12a10.522 10.522 0 1 1 0-21.045Z"/></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>
|
||||
152
docfx/layouts/cssharp/layout/_master.tmpl
Normal file
152
docfx/layouts/cssharp/layout/_master.tmpl
Normal file
@@ -0,0 +1,152 @@
|
||||
{{!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>
|
||||
<link rel="preconnect" href="https://fonts.googleapis.com">
|
||||
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
|
||||
<link href="https://fonts.googleapis.com/css2?family=DM+Sans:ital,opsz,wght@0,9..40,100;0,9..40,200;0,9..40,300;0,9..40,400;0,9..40,500;0,9..40,600;0,9..40,700;0,9..40,800;0,9..40,900;0,9..40,1000;1,9..40,100;1,9..40,200;1,9..40,300;1,9..40,400;1,9..40,500;1,9..40,600;1,9..40,700;1,9..40,800;1,9..40,900;1,9..40,1000&family=JetBrains+Mono:ital,wght@0,100;0,200;0,300;0,400;0,500;0,600;0,700;0,800;1,100;1,200;1,300;1,400;1,500;1,600;1,700;1,800&display=swap" rel="stylesheet">
|
||||
</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>
|
||||
4
docfx/layouts/cssharp/public/main.css
Normal file
4
docfx/layouts/cssharp/public/main.css
Normal file
@@ -0,0 +1,4 @@
|
||||
:root {
|
||||
--bs-font-sans-serif: "DM Sans", system-ui, -apple-system, "Segoe UI", Roboto, "Helvetica Neue", "Noto Sans", "Liberation Sans", Arial, sans-serif, "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol", "Noto Color Emoji";
|
||||
--bs-font-monospace: "Jetbrains Mono", SFMono-Regular, Menlo, Monaco, Consolas, "Liberation Mono", "Courier New", monospace;
|
||||
}
|
||||
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,56 +0,0 @@
|
||||
---
|
||||
title: Getting Started
|
||||
description: How to get started installing & using CounterStrikeSharp.
|
||||
sidebar:
|
||||
order: 0
|
||||
---
|
||||
|
||||
# Installation
|
||||
|
||||
### 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
|
||||
|
||||
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.
|
||||
:::
|
||||
|
||||
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.
|
||||
|
||||
```shell
|
||||
<server_path>/game/csgo/addons > tree -L 2
|
||||
addons
|
||||
├── counterstrikesharp
|
||||
│ ├── api
|
||||
│ ├── bin
|
||||
│ ├── dotnet
|
||||
│ ├── plugins
|
||||
│ └── gamedata
|
||||
│
|
||||
├── metamod
|
||||
│ ├── bin
|
||||
│ ├── counterstrikesharp.vdf
|
||||
│ ├── metaplugins.ini
|
||||
│ └── README.txt
|
||||
├── metamod.vdf
|
||||
└── metamod_x64.vdf
|
||||
```
|
||||
|
||||
### 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.`.
|
||||
|
||||
Running the command `meta list` in the console should show 1 plugin loaded 🎉
|
||||
|
||||
```shell
|
||||
meta list
|
||||
Listing 1 plugin:
|
||||
[01] CounterStrikeSharp (0.1.0) by Roflmuffin
|
||||
```
|
||||
@@ -1,52 +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 string ModuleAuthor => "roflmuffin";
|
||||
|
||||
public override string ModuleDescription => "Simple hello world plugin";
|
||||
|
||||
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"
|
||||
}
|
||||
@@ -1,2 +1,2 @@
|
||||
# WithConfig
|
||||
# With Config
|
||||
This example shows how you can implement the `IPluginConfig` interface to allow for semi-automatic config parsing & loading.
|
||||
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/WithEntityOutputHooks/README.md
Normal file
2
examples/WithEntityOutputHooks/README.md
Normal file
@@ -0,0 +1,2 @@
|
||||
# With Entity Output Hooks
|
||||
This example shows how to implement hooks for entity output, such as StartTouch, OnPickup etc.
|
||||
12
examples/WithEntityOutputHooks/WithEntityOutputHooks.csproj
Normal file
12
examples/WithEntityOutputHooks/WithEntityOutputHooks.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,43 @@
|
||||
using CounterStrikeSharp.API.Core;
|
||||
using CounterStrikeSharp.API.Core.Attributes;
|
||||
using CounterStrikeSharp.API.Core.Attributes.Registration;
|
||||
using Microsoft.Extensions.Logging;
|
||||
|
||||
namespace WithEntityOutputHooks;
|
||||
|
||||
[MinimumApiVersion(80)]
|
||||
public class WithEntityOutputHooksPlugin : BasePlugin
|
||||
{
|
||||
public override string ModuleName => "Example: With Entity Output Hooks";
|
||||
public override string ModuleVersion => "1.0.0";
|
||||
public override string ModuleAuthor => "CounterStrikeSharp & Contributors";
|
||||
public override string ModuleDescription => "A simple plugin that showcases entity output hooks";
|
||||
|
||||
public override void Load(bool hotReload)
|
||||
{
|
||||
HookEntityOutput("weapon_knife", "OnPlayerPickup", (CEntityIOOutput output, string name, CEntityInstance activator, CEntityInstance caller, CVariant value, float delay) =>
|
||||
{
|
||||
Logger.LogInformation("weapon_knife called OnPlayerPickup ({name}, {activator}, {caller}, {delay})", name, activator.DesignerName, caller.DesignerName, delay);
|
||||
|
||||
return HookResult.Continue;
|
||||
});
|
||||
}
|
||||
|
||||
// Output hooks can use wildcards to match multiple entities
|
||||
[EntityOutputHook("*", "OnPlayerPickup")]
|
||||
public HookResult OnPickup(CEntityIOOutput output, string name, CEntityInstance activator, CEntityInstance caller, CVariant value, float delay)
|
||||
{
|
||||
Logger.LogInformation("[EntityOutputHook Attribute] Called OnPlayerPickup ({name}, {activator}, {caller}, {delay})", name, activator.DesignerName, caller.DesignerName, delay);
|
||||
|
||||
return HookResult.Continue;
|
||||
}
|
||||
|
||||
// Output hooks can use wildcards to match multiple output names
|
||||
[EntityOutputHook("func_buyzone", "*")]
|
||||
public HookResult OnTouchStart(CEntityIOOutput output, string name, CEntityInstance activator, CEntityInstance caller, CVariant value, float delay)
|
||||
{
|
||||
Logger.LogInformation("[EntityOutputHook Attribute] Buyzone called output ({name}, {activator}, {caller}, {delay})", name, activator.DesignerName, caller.DesignerName, delay);
|
||||
|
||||
return HookResult.Continue;
|
||||
}
|
||||
}
|
||||
Submodule libraries/hl2sdk-cs2 updated: 1d394d3365...9363452257
@@ -0,0 +1,28 @@
|
||||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
|
||||
<PropertyGroup>
|
||||
<TargetFramework>net7.0</TargetFramework>
|
||||
<ImplicitUsings>enable</ImplicitUsings>
|
||||
<Nullable>enable</Nullable>
|
||||
|
||||
<IsPackable>false</IsPackable>
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="17.3.2"/>
|
||||
<PackageReference Include="xunit" Version="2.4.2"/>
|
||||
<PackageReference Include="xunit.runner.visualstudio" Version="2.4.5">
|
||||
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
|
||||
<PrivateAssets>all</PrivateAssets>
|
||||
</PackageReference>
|
||||
<PackageReference Include="coverlet.collector" Version="3.1.2">
|
||||
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
|
||||
<PrivateAssets>all</PrivateAssets>
|
||||
</PackageReference>
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<ProjectReference Include="..\CounterStrikeSharp.API\CounterStrikeSharp.API.csproj" />
|
||||
</ItemGroup>
|
||||
|
||||
</Project>
|
||||
52
managed/CounterStrikeSharp.API.Tests/SteamIDTests.cs
Normal file
52
managed/CounterStrikeSharp.API.Tests/SteamIDTests.cs
Normal file
@@ -0,0 +1,52 @@
|
||||
using CounterStrikeSharp.API.Modules.Entities;
|
||||
using CounterStrikeSharp.API.Modules.Entities.Constants;
|
||||
|
||||
namespace CounterStrikeSharp.API.Tests;
|
||||
|
||||
public class SteamIdTests
|
||||
{
|
||||
[Theory]
|
||||
[InlineData(76561197960524373ul, 76561197960524373ul, "STEAM_0:1:129322", "[U:1:258645]", 258645, SteamAccountType.Individual, SteamAccountInstance.Desktop, SteamAccountUniverse.Public, true)]
|
||||
[InlineData(258645, 76561197960524373ul, "STEAM_0:1:129322", "[U:1:258645]", 258645, SteamAccountType.Individual, SteamAccountInstance.Desktop, SteamAccountUniverse.Public, true)]
|
||||
[InlineData(76561197960265728ul, 76561197960265728ul, "STEAM_0:0:0", "[U:1:0]", 0, SteamAccountType.Individual, SteamAccountInstance.Desktop, SteamAccountUniverse.Public, false)]
|
||||
[InlineData(103582791429521412ul, 103582791429521412ul, "STEAM_0:0:13510796734627842", "[g:1:27021593469255684]", 4, SteamAccountType.Clan, SteamAccountInstance.All, SteamAccountUniverse.Public, true)]
|
||||
public void ValidateSteamId(ulong parseValue, ulong steamId64, string steamId2, string steamId3, int steamId32, SteamAccountType accountType, SteamAccountInstance accountInstance, SteamAccountUniverse accountUniverse, bool valid)
|
||||
{
|
||||
var steamId = new SteamID(parseValue);
|
||||
|
||||
Assert.Equal(steamId64, steamId.SteamId64);
|
||||
Assert.Equal(steamId2, steamId.SteamId2);
|
||||
Assert.Equal(steamId3, steamId.SteamId3);
|
||||
Assert.Equal(steamId32, steamId.SteamId32);
|
||||
Assert.Equal(accountType, steamId.AccountType);
|
||||
Assert.Equal(accountInstance, steamId.AccountInstance);
|
||||
Assert.Equal(accountUniverse, steamId.AccountUniverse);
|
||||
Assert.Equal(valid, steamId.IsValid());
|
||||
}
|
||||
|
||||
[Theory]
|
||||
[InlineData(76561197960524373ul, 76561197960524373ul)]
|
||||
[InlineData("STEAM_0:1:129322", 76561197960524373ul)]
|
||||
[InlineData("[U:1:258645]", 76561197960524373ul)]
|
||||
public void CanCastLongToString(dynamic parseable, ulong longValue)
|
||||
{
|
||||
Assert.Equal(longValue, ((SteamID)parseable).SteamId64);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void CanUseValueEquality()
|
||||
{
|
||||
var steamId1 = new SteamID(76561197960524373ul);
|
||||
var steamId2 = new SteamID(76561197960524373ul);
|
||||
var steamId3 = new SteamID(76561197960265728ul);
|
||||
|
||||
Assert.True(steamId1 == steamId2);
|
||||
Assert.True(steamId1 != steamId3);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void ThrowsOutOfRangeException()
|
||||
{
|
||||
Assert.Throws<ArgumentOutOfRangeException>(() => new SteamID(0));
|
||||
}
|
||||
}
|
||||
1
managed/CounterStrikeSharp.API.Tests/Usings.cs
Normal file
1
managed/CounterStrikeSharp.API.Tests/Usings.cs
Normal file
@@ -0,0 +1 @@
|
||||
global using Xunit;
|
||||
@@ -479,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();
|
||||
@@ -644,6 +654,32 @@ namespace CounterStrikeSharp.API.Core
|
||||
}
|
||||
}
|
||||
|
||||
public static void HookEntityOutput(string classname, string outputname, InputArgument callback, HookMode mode){
|
||||
lock (ScriptContext.GlobalScriptContext.Lock) {
|
||||
ScriptContext.GlobalScriptContext.Reset();
|
||||
ScriptContext.GlobalScriptContext.Push(classname);
|
||||
ScriptContext.GlobalScriptContext.Push(outputname);
|
||||
ScriptContext.GlobalScriptContext.Push((InputArgument)callback);
|
||||
ScriptContext.GlobalScriptContext.Push(mode);
|
||||
ScriptContext.GlobalScriptContext.SetIdentifier(0x15245242);
|
||||
ScriptContext.GlobalScriptContext.Invoke();
|
||||
ScriptContext.GlobalScriptContext.CheckErrors();
|
||||
}
|
||||
}
|
||||
|
||||
public static void UnhookEntityOutput(string classname, string outputname, InputArgument callback, HookMode mode){
|
||||
lock (ScriptContext.GlobalScriptContext.Lock) {
|
||||
ScriptContext.GlobalScriptContext.Reset();
|
||||
ScriptContext.GlobalScriptContext.Push(classname);
|
||||
ScriptContext.GlobalScriptContext.Push(outputname);
|
||||
ScriptContext.GlobalScriptContext.Push((InputArgument)callback);
|
||||
ScriptContext.GlobalScriptContext.Push(mode);
|
||||
ScriptContext.GlobalScriptContext.SetIdentifier(0x87DBD139);
|
||||
ScriptContext.GlobalScriptContext.Invoke();
|
||||
ScriptContext.GlobalScriptContext.CheckErrors();
|
||||
}
|
||||
}
|
||||
|
||||
public static void HookEvent(string name, InputArgument callback, bool ispost){
|
||||
lock (ScriptContext.GlobalScriptContext.Lock) {
|
||||
ScriptContext.GlobalScriptContext.Reset();
|
||||
|
||||
@@ -0,0 +1,16 @@
|
||||
using System;
|
||||
|
||||
namespace CounterStrikeSharp.API.Core.Attributes.Registration;
|
||||
|
||||
[AttributeUsage(AttributeTargets.Method, AllowMultiple = true)]
|
||||
public class EntityOutputHookAttribute : Attribute
|
||||
{
|
||||
public string Classname { get; }
|
||||
public string OutputName { get; }
|
||||
|
||||
public EntityOutputHookAttribute(string classname, string outputName)
|
||||
{
|
||||
Classname = classname;
|
||||
OutputName = outputName;
|
||||
}
|
||||
}
|
||||
@@ -26,6 +26,7 @@ using CounterStrikeSharp.API.Modules.Commands;
|
||||
using CounterStrikeSharp.API.Modules.Events;
|
||||
using CounterStrikeSharp.API.Modules.Timers;
|
||||
using CounterStrikeSharp.API.Modules.Config;
|
||||
using CounterStrikeSharp.API.Modules.Entities;
|
||||
using Microsoft.Extensions.Logging;
|
||||
|
||||
namespace CounterStrikeSharp.API.Core
|
||||
@@ -36,6 +37,13 @@ namespace CounterStrikeSharp.API.Core
|
||||
|
||||
public BasePlugin()
|
||||
{
|
||||
RegisterListener<Listeners.OnMapEnd>(() =>
|
||||
{
|
||||
foreach (KeyValuePair<Delegate, EntityIO.EntityOutputCallback> callback in EntitySingleOutputHooks)
|
||||
{
|
||||
UnhookSingleEntityOutputInternal(callback.Value.Classname, callback.Value.Output, callback.Value.Handler);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
public abstract string ModuleName { get; }
|
||||
@@ -108,6 +116,12 @@ namespace CounterStrikeSharp.API.Core
|
||||
public readonly Dictionary<Delegate, CallbackSubscriber> Listeners =
|
||||
new Dictionary<Delegate, CallbackSubscriber>();
|
||||
|
||||
public readonly Dictionary<Delegate, CallbackSubscriber> EntityOutputHooks =
|
||||
new Dictionary<Delegate, CallbackSubscriber>();
|
||||
|
||||
internal readonly Dictionary<Delegate, EntityIO.EntityOutputCallback> EntitySingleOutputHooks =
|
||||
new Dictionary<Delegate, EntityIO.EntityOutputCallback>();
|
||||
|
||||
public readonly List<Timer> Timers = new List<Timer>();
|
||||
|
||||
public delegate HookResult GameEventHandler<T>(T @event, GameEventInfo info) where T : GameEvent;
|
||||
@@ -354,6 +368,7 @@ namespace CounterStrikeSharp.API.Core
|
||||
{
|
||||
this.RegisterAttributeHandlers(instance);
|
||||
this.RegisterConsoleCommandAttributeHandlers(instance);
|
||||
this.RegisterEntityOutputAttributeHandlers(instance);
|
||||
}
|
||||
|
||||
public void InitializeConfig(object instance, Type pluginType)
|
||||
@@ -430,6 +445,77 @@ namespace CounterStrikeSharp.API.Core
|
||||
}
|
||||
}
|
||||
|
||||
public void RegisterEntityOutputAttributeHandlers(object instance)
|
||||
{
|
||||
var handlers = instance.GetType()
|
||||
.GetMethods()
|
||||
.Where(method => method.GetCustomAttributes<EntityOutputHookAttribute>().Any())
|
||||
.ToArray();
|
||||
|
||||
foreach (var handler in handlers)
|
||||
{
|
||||
var attributes = handler.GetCustomAttributes<EntityOutputHookAttribute>();
|
||||
foreach (var outputInfo in attributes)
|
||||
{
|
||||
HookEntityOutput(outputInfo.Classname, outputInfo.OutputName, handler.CreateDelegate<EntityIO.EntityOutputHandler>(instance));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void HookEntityOutput(string classname, string outputName, EntityIO.EntityOutputHandler handler, HookMode mode = HookMode.Pre)
|
||||
{
|
||||
var subscriber = new CallbackSubscriber(handler, handler,
|
||||
() => UnhookEntityOutput(classname, outputName, handler));
|
||||
|
||||
NativeAPI.HookEntityOutput(classname, outputName, subscriber.GetInputArgument(), mode);
|
||||
EntityOutputHooks[handler] = subscriber;
|
||||
}
|
||||
|
||||
public void UnhookEntityOutput(string classname, string outputName, EntityIO.EntityOutputHandler handler, HookMode mode = HookMode.Pre)
|
||||
{
|
||||
if (!EntityOutputHooks.TryGetValue(handler, out var subscriber)) return;
|
||||
|
||||
NativeAPI.UnhookEntityOutput(classname, outputName, subscriber.GetInputArgument(), mode);
|
||||
FunctionReference.Remove(subscriber.GetReferenceIdentifier());
|
||||
EntityOutputHooks.Remove(handler);
|
||||
}
|
||||
|
||||
public void HookSingleEntityOutput(CEntityInstance entityInstance, string outputName, EntityIO.EntityOutputHandler handler)
|
||||
{
|
||||
// since we wrap around the plugin handler we need to do this to ensure that the plugin callback is only called
|
||||
// if the entity instance is the same.
|
||||
EntityIO.EntityOutputHandler internalHandler = (output, name, activator, caller, value, delay) =>
|
||||
{
|
||||
if (caller == entityInstance)
|
||||
{
|
||||
return handler(output, name, activator, caller, value, delay);
|
||||
}
|
||||
|
||||
return HookResult.Continue;
|
||||
};
|
||||
|
||||
HookEntityOutput(entityInstance.DesignerName, outputName, internalHandler);
|
||||
|
||||
// because of ^ we would not be able to unhook since we passed the 'internalHandler' and that's what is being stored, not the original handler
|
||||
// but the plugin could only pass the original handler for unhooking.
|
||||
// (this dictionary does not needed to be cleared on dispose as it has no unmanaged reference and those are already being disposed, but on map end)
|
||||
// (the internal class is needed to be able to remove them on map start)
|
||||
EntitySingleOutputHooks[handler] = new EntityIO.EntityOutputCallback(entityInstance.DesignerName, outputName, internalHandler);
|
||||
}
|
||||
|
||||
public void UnhookSingleEntityOutput(CEntityInstance entityInstance, string outputName, EntityIO.EntityOutputHandler handler)
|
||||
{
|
||||
UnhookSingleEntityOutputInternal(entityInstance.DesignerName, outputName, handler);
|
||||
}
|
||||
|
||||
private void UnhookSingleEntityOutputInternal(string classname, string outputName, EntityIO.EntityOutputHandler handler)
|
||||
{
|
||||
if (!EntitySingleOutputHooks.TryGetValue(handler, out var internalHandler)) return;
|
||||
|
||||
UnhookEntityOutput(classname, outputName, internalHandler.Handler);
|
||||
EntitySingleOutputHooks.Remove(handler);
|
||||
}
|
||||
|
||||
public void Dispose()
|
||||
{
|
||||
Dispose(true);
|
||||
@@ -464,6 +550,11 @@ namespace CounterStrikeSharp.API.Core
|
||||
subscriber.Dispose();
|
||||
}
|
||||
|
||||
foreach (var subscriber in EntityOutputHooks.Values)
|
||||
{
|
||||
subscriber.Dispose();
|
||||
}
|
||||
|
||||
foreach (var timer in Timers)
|
||||
{
|
||||
timer.Kill();
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
using System;
|
||||
using System.Runtime.InteropServices;
|
||||
using CounterStrikeSharp.API.Modules.Memory;
|
||||
using CounterStrikeSharp.API.Modules.Utils;
|
||||
|
||||
@@ -26,4 +26,6 @@ public partial class CBaseEntity
|
||||
/// Shorthand for accessing an entity's CBodyComponent?.SceneNode?.AbsRotation;
|
||||
/// </summary>
|
||||
public QAngle? AbsRotation => CBodyComponent?.SceneNode?.AbsRotation;
|
||||
|
||||
public T? GetVData<T>() where T : CEntitySubclassVDataBase => (T)Activator.CreateInstance(typeof(T), Marshal.ReadIntPtr(SubclassID.Handle + 8));
|
||||
}
|
||||
@@ -0,0 +1,6 @@
|
||||
namespace CounterStrikeSharp.API.Core;
|
||||
|
||||
public partial class CBasePlayerWeapon
|
||||
{
|
||||
public CBasePlayerWeaponVData? VData => GetVData<CBasePlayerWeaponVData>();
|
||||
}
|
||||
@@ -0,0 +1,6 @@
|
||||
namespace CounterStrikeSharp.API.Core;
|
||||
|
||||
public partial class CCSWeaponBase
|
||||
{
|
||||
public new CCSWeaponBaseVData? VData => GetVData<CCSWeaponBaseVData>();
|
||||
}
|
||||
49
managed/CounterStrikeSharp.API/Core/Model/CEntityIOOutput.cs
Normal file
49
managed/CounterStrikeSharp.API/Core/Model/CEntityIOOutput.cs
Normal file
@@ -0,0 +1,49 @@
|
||||
using System.Runtime.CompilerServices;
|
||||
using System.Runtime.InteropServices;
|
||||
using CounterStrikeSharp.API.Modules.Utils;
|
||||
|
||||
namespace CounterStrikeSharp.API.Core;
|
||||
|
||||
public partial class CEntityIOOutput
|
||||
{
|
||||
public EntityIOConnection_t? Connections => Utilities.GetPointer<EntityIOConnection_t>(Handle + 8);
|
||||
|
||||
public EntityIOOutputDesc_t Description => new(Marshal.ReadIntPtr(Handle + 16));
|
||||
}
|
||||
|
||||
public class EntityIOOutputDesc_t : NativeObject
|
||||
{
|
||||
public EntityIOOutputDesc_t(IntPtr pointer) : base(pointer)
|
||||
{
|
||||
}
|
||||
|
||||
public string Name => Utilities.ReadStringUtf8(Handle + 0);
|
||||
public unsafe ref uint Flags => ref Unsafe.AsRef<uint>((void*)(Handle + 8));
|
||||
public unsafe ref uint OutputOffset => ref Unsafe.AsRef<uint>((void*)(Handle + 16));
|
||||
}
|
||||
|
||||
public class EntityIOConnection_t : EntityIOConnectionDesc_t
|
||||
{
|
||||
public EntityIOConnection_t(IntPtr pointer) : base(pointer)
|
||||
{
|
||||
}
|
||||
|
||||
public unsafe ref bool MarkedForRemoval => ref Unsafe.AsRef<bool>((void*)(Handle + 40));
|
||||
|
||||
public EntityIOConnection_t? Next => Utilities.GetPointer<EntityIOConnection_t>(Handle + 48);
|
||||
}
|
||||
|
||||
public class EntityIOConnectionDesc_t : NativeObject
|
||||
{
|
||||
public EntityIOConnectionDesc_t(IntPtr pointer) : base(pointer)
|
||||
{
|
||||
}
|
||||
|
||||
public string TargetDesc => Utilities.ReadStringUtf8(Handle + 0);
|
||||
public string TargetInput => Utilities.ReadStringUtf8(Handle + 8);
|
||||
public string ValueOverride => Utilities.ReadStringUtf8(Handle + 16);
|
||||
public CEntityHandle Target => new(Handle + 24);
|
||||
public unsafe ref EntityIOTargetType_t TargetType => ref Unsafe.AsRef<EntityIOTargetType_t>((void*)(Handle + 28));
|
||||
public unsafe ref int TimesToFire => ref Unsafe.AsRef<int>((void*)(Handle + 32));
|
||||
public unsafe ref float Delay => ref Unsafe.AsRef<float>((void*)(Handle + 36));
|
||||
}
|
||||
13
managed/CounterStrikeSharp.API/Core/Model/CVariant.cs
Normal file
13
managed/CounterStrikeSharp.API/Core/Model/CVariant.cs
Normal file
@@ -0,0 +1,13 @@
|
||||
namespace CounterStrikeSharp.API.Core;
|
||||
|
||||
/// <summary>
|
||||
/// Placeholder for CVariant
|
||||
/// <see href="https://github.com/alliedmodders/hl2sdk/blob/cs2/public/variant.h"/>
|
||||
/// <remarks>A lot of entity outputs do not use this value</remarks>
|
||||
/// </summary>
|
||||
public class CVariant : NativeObject
|
||||
{
|
||||
public CVariant(IntPtr pointer) : base(pointer)
|
||||
{
|
||||
}
|
||||
}
|
||||
@@ -4827,6 +4827,51 @@ public partial class CBasePlayerPawn : CBaseCombatCharacter
|
||||
|
||||
}
|
||||
|
||||
public partial class CBasePlayerVData : CEntitySubclassVDataBase
|
||||
{
|
||||
public CBasePlayerVData (IntPtr pointer) : base(pointer) {}
|
||||
|
||||
// m_flHeadDamageMultiplier
|
||||
public CSkillFloat HeadDamageMultiplier => Schema.GetDeclaredClass<CSkillFloat>(this.Handle, "CBasePlayerVData", "m_flHeadDamageMultiplier");
|
||||
|
||||
// m_flChestDamageMultiplier
|
||||
public CSkillFloat ChestDamageMultiplier => Schema.GetDeclaredClass<CSkillFloat>(this.Handle, "CBasePlayerVData", "m_flChestDamageMultiplier");
|
||||
|
||||
// m_flStomachDamageMultiplier
|
||||
public CSkillFloat StomachDamageMultiplier => Schema.GetDeclaredClass<CSkillFloat>(this.Handle, "CBasePlayerVData", "m_flStomachDamageMultiplier");
|
||||
|
||||
// m_flArmDamageMultiplier
|
||||
public CSkillFloat ArmDamageMultiplier => Schema.GetDeclaredClass<CSkillFloat>(this.Handle, "CBasePlayerVData", "m_flArmDamageMultiplier");
|
||||
|
||||
// m_flLegDamageMultiplier
|
||||
public CSkillFloat LegDamageMultiplier => Schema.GetDeclaredClass<CSkillFloat>(this.Handle, "CBasePlayerVData", "m_flLegDamageMultiplier");
|
||||
|
||||
// m_flHoldBreathTime
|
||||
public ref float HoldBreathTime => ref Schema.GetRef<float>(this.Handle, "CBasePlayerVData", "m_flHoldBreathTime");
|
||||
|
||||
// m_flDrowningDamageInterval
|
||||
public ref float DrowningDamageInterval => ref Schema.GetRef<float>(this.Handle, "CBasePlayerVData", "m_flDrowningDamageInterval");
|
||||
|
||||
// m_nDrowningDamageInitial
|
||||
public ref Int32 DrowningDamageInitial => ref Schema.GetRef<Int32>(this.Handle, "CBasePlayerVData", "m_nDrowningDamageInitial");
|
||||
|
||||
// m_nDrowningDamageMax
|
||||
public ref Int32 DrowningDamageMax => ref Schema.GetRef<Int32>(this.Handle, "CBasePlayerVData", "m_nDrowningDamageMax");
|
||||
|
||||
// m_nWaterSpeed
|
||||
public ref Int32 WaterSpeed => ref Schema.GetRef<Int32>(this.Handle, "CBasePlayerVData", "m_nWaterSpeed");
|
||||
|
||||
// m_flUseRange
|
||||
public ref float UseRange => ref Schema.GetRef<float>(this.Handle, "CBasePlayerVData", "m_flUseRange");
|
||||
|
||||
// m_flUseAngleTolerance
|
||||
public ref float UseAngleTolerance => ref Schema.GetRef<float>(this.Handle, "CBasePlayerVData", "m_flUseAngleTolerance");
|
||||
|
||||
// m_flCrouchTime
|
||||
public ref float CrouchTime => ref Schema.GetRef<float>(this.Handle, "CBasePlayerVData", "m_flCrouchTime");
|
||||
|
||||
}
|
||||
|
||||
public partial class CBasePlayerWeapon : CEconEntity
|
||||
{
|
||||
public CBasePlayerWeapon (IntPtr pointer) : base(pointer) {}
|
||||
@@ -4857,6 +4902,70 @@ public partial class CBasePlayerWeapon : CEconEntity
|
||||
|
||||
}
|
||||
|
||||
public partial class CBasePlayerWeaponVData : CEntitySubclassVDataBase
|
||||
{
|
||||
public CBasePlayerWeaponVData (IntPtr pointer) : base(pointer) {}
|
||||
|
||||
// m_bBuiltRightHanded
|
||||
public ref bool BuiltRightHanded => ref Schema.GetRef<bool>(this.Handle, "CBasePlayerWeaponVData", "m_bBuiltRightHanded");
|
||||
|
||||
// m_bAllowFlipping
|
||||
public ref bool AllowFlipping => ref Schema.GetRef<bool>(this.Handle, "CBasePlayerWeaponVData", "m_bAllowFlipping");
|
||||
|
||||
// m_bIsFullAuto
|
||||
public ref bool IsFullAuto => ref Schema.GetRef<bool>(this.Handle, "CBasePlayerWeaponVData", "m_bIsFullAuto");
|
||||
|
||||
// m_nNumBullets
|
||||
public ref Int32 NumBullets => ref Schema.GetRef<Int32>(this.Handle, "CBasePlayerWeaponVData", "m_nNumBullets");
|
||||
|
||||
// m_sMuzzleAttachment
|
||||
public string MuzzleAttachment
|
||||
{
|
||||
get { return Schema.GetUtf8String(this.Handle, "CBasePlayerWeaponVData", "m_sMuzzleAttachment"); }
|
||||
set { Schema.SetString(this.Handle, "CBasePlayerWeaponVData", "m_sMuzzleAttachment", value); }
|
||||
}
|
||||
|
||||
// m_iFlags
|
||||
public ref ItemFlagTypes_t Flags => ref Schema.GetRef<ItemFlagTypes_t>(this.Handle, "CBasePlayerWeaponVData", "m_iFlags");
|
||||
|
||||
// m_nPrimaryAmmoType
|
||||
public ref byte PrimaryAmmoType => ref Schema.GetRef<byte>(this.Handle, "CBasePlayerWeaponVData", "m_nPrimaryAmmoType");
|
||||
|
||||
// m_nSecondaryAmmoType
|
||||
public ref byte SecondaryAmmoType => ref Schema.GetRef<byte>(this.Handle, "CBasePlayerWeaponVData", "m_nSecondaryAmmoType");
|
||||
|
||||
// m_iMaxClip1
|
||||
public ref Int32 MaxClip1 => ref Schema.GetRef<Int32>(this.Handle, "CBasePlayerWeaponVData", "m_iMaxClip1");
|
||||
|
||||
// m_iMaxClip2
|
||||
public ref Int32 MaxClip2 => ref Schema.GetRef<Int32>(this.Handle, "CBasePlayerWeaponVData", "m_iMaxClip2");
|
||||
|
||||
// m_iDefaultClip1
|
||||
public ref Int32 DefaultClip1 => ref Schema.GetRef<Int32>(this.Handle, "CBasePlayerWeaponVData", "m_iDefaultClip1");
|
||||
|
||||
// m_iDefaultClip2
|
||||
public ref Int32 DefaultClip2 => ref Schema.GetRef<Int32>(this.Handle, "CBasePlayerWeaponVData", "m_iDefaultClip2");
|
||||
|
||||
// m_iWeight
|
||||
public ref Int32 Weight => ref Schema.GetRef<Int32>(this.Handle, "CBasePlayerWeaponVData", "m_iWeight");
|
||||
|
||||
// m_bAutoSwitchTo
|
||||
public ref bool AutoSwitchTo => ref Schema.GetRef<bool>(this.Handle, "CBasePlayerWeaponVData", "m_bAutoSwitchTo");
|
||||
|
||||
// m_bAutoSwitchFrom
|
||||
public ref bool AutoSwitchFrom => ref Schema.GetRef<bool>(this.Handle, "CBasePlayerWeaponVData", "m_bAutoSwitchFrom");
|
||||
|
||||
// m_iRumbleEffect
|
||||
public ref RumbleEffect_t RumbleEffect => ref Schema.GetRef<RumbleEffect_t>(this.Handle, "CBasePlayerWeaponVData", "m_iRumbleEffect");
|
||||
|
||||
// m_iSlot
|
||||
public ref Int32 Slot => ref Schema.GetRef<Int32>(this.Handle, "CBasePlayerWeaponVData", "m_iSlot");
|
||||
|
||||
// m_iPosition
|
||||
public ref Int32 Position => ref Schema.GetRef<Int32>(this.Handle, "CBasePlayerWeaponVData", "m_iPosition");
|
||||
|
||||
}
|
||||
|
||||
public partial class CBaseProp : CBaseAnimGraph
|
||||
{
|
||||
public CBaseProp (IntPtr pointer) : base(pointer) {}
|
||||
@@ -8932,6 +9041,269 @@ public partial class CCSWeaponBaseGun : CCSWeaponBase
|
||||
|
||||
}
|
||||
|
||||
public partial class CCSWeaponBaseVData : CBasePlayerWeaponVData
|
||||
{
|
||||
public CCSWeaponBaseVData (IntPtr pointer) : base(pointer) {}
|
||||
|
||||
// m_WeaponType
|
||||
public ref CSWeaponType WeaponType => ref Schema.GetRef<CSWeaponType>(this.Handle, "CCSWeaponBaseVData", "m_WeaponType");
|
||||
|
||||
// m_WeaponCategory
|
||||
public ref CSWeaponCategory WeaponCategory => ref Schema.GetRef<CSWeaponCategory>(this.Handle, "CCSWeaponBaseVData", "m_WeaponCategory");
|
||||
|
||||
// m_GearSlot
|
||||
public ref gear_slot_t GearSlot => ref Schema.GetRef<gear_slot_t>(this.Handle, "CCSWeaponBaseVData", "m_GearSlot");
|
||||
|
||||
// m_GearSlotPosition
|
||||
public ref Int32 GearSlotPosition => ref Schema.GetRef<Int32>(this.Handle, "CCSWeaponBaseVData", "m_GearSlotPosition");
|
||||
|
||||
// m_DefaultLoadoutSlot
|
||||
public ref loadout_slot_t DefaultLoadoutSlot => ref Schema.GetRef<loadout_slot_t>(this.Handle, "CCSWeaponBaseVData", "m_DefaultLoadoutSlot");
|
||||
|
||||
// m_sWrongTeamMsg
|
||||
public string WrongTeamMsg
|
||||
{
|
||||
get { return Schema.GetUtf8String(this.Handle, "CCSWeaponBaseVData", "m_sWrongTeamMsg"); }
|
||||
set { Schema.SetString(this.Handle, "CCSWeaponBaseVData", "m_sWrongTeamMsg", value); }
|
||||
}
|
||||
|
||||
// m_nPrice
|
||||
public ref Int32 Price => ref Schema.GetRef<Int32>(this.Handle, "CCSWeaponBaseVData", "m_nPrice");
|
||||
|
||||
// m_nKillAward
|
||||
public ref Int32 KillAward => ref Schema.GetRef<Int32>(this.Handle, "CCSWeaponBaseVData", "m_nKillAward");
|
||||
|
||||
// m_nPrimaryReserveAmmoMax
|
||||
public ref Int32 PrimaryReserveAmmoMax => ref Schema.GetRef<Int32>(this.Handle, "CCSWeaponBaseVData", "m_nPrimaryReserveAmmoMax");
|
||||
|
||||
// m_nSecondaryReserveAmmoMax
|
||||
public ref Int32 SecondaryReserveAmmoMax => ref Schema.GetRef<Int32>(this.Handle, "CCSWeaponBaseVData", "m_nSecondaryReserveAmmoMax");
|
||||
|
||||
// m_bMeleeWeapon
|
||||
public ref bool MeleeWeapon => ref Schema.GetRef<bool>(this.Handle, "CCSWeaponBaseVData", "m_bMeleeWeapon");
|
||||
|
||||
// m_bHasBurstMode
|
||||
public ref bool HasBurstMode => ref Schema.GetRef<bool>(this.Handle, "CCSWeaponBaseVData", "m_bHasBurstMode");
|
||||
|
||||
// m_bIsRevolver
|
||||
public ref bool IsRevolver => ref Schema.GetRef<bool>(this.Handle, "CCSWeaponBaseVData", "m_bIsRevolver");
|
||||
|
||||
// m_bCannotShootUnderwater
|
||||
public ref bool CannotShootUnderwater => ref Schema.GetRef<bool>(this.Handle, "CCSWeaponBaseVData", "m_bCannotShootUnderwater");
|
||||
|
||||
// m_szName
|
||||
public string Name
|
||||
{
|
||||
get { return Schema.GetUtf8String(this.Handle, "CCSWeaponBaseVData", "m_szName"); }
|
||||
set { Schema.SetString(this.Handle, "CCSWeaponBaseVData", "m_szName", value); }
|
||||
}
|
||||
|
||||
// m_szAnimExtension
|
||||
public string AnimExtension
|
||||
{
|
||||
get { return Schema.GetUtf8String(this.Handle, "CCSWeaponBaseVData", "m_szAnimExtension"); }
|
||||
set { Schema.SetString(this.Handle, "CCSWeaponBaseVData", "m_szAnimExtension", value); }
|
||||
}
|
||||
|
||||
// m_eSilencerType
|
||||
public ref CSWeaponSilencerType SilencerType => ref Schema.GetRef<CSWeaponSilencerType>(this.Handle, "CCSWeaponBaseVData", "m_eSilencerType");
|
||||
|
||||
// m_nCrosshairMinDistance
|
||||
public ref Int32 CrosshairMinDistance => ref Schema.GetRef<Int32>(this.Handle, "CCSWeaponBaseVData", "m_nCrosshairMinDistance");
|
||||
|
||||
// m_nCrosshairDeltaDistance
|
||||
public ref Int32 CrosshairDeltaDistance => ref Schema.GetRef<Int32>(this.Handle, "CCSWeaponBaseVData", "m_nCrosshairDeltaDistance");
|
||||
|
||||
// m_flCycleTime
|
||||
public CFiringModeFloat CycleTime => Schema.GetDeclaredClass<CFiringModeFloat>(this.Handle, "CCSWeaponBaseVData", "m_flCycleTime");
|
||||
|
||||
// m_flMaxSpeed
|
||||
public CFiringModeFloat MaxSpeed => Schema.GetDeclaredClass<CFiringModeFloat>(this.Handle, "CCSWeaponBaseVData", "m_flMaxSpeed");
|
||||
|
||||
// m_flSpread
|
||||
public CFiringModeFloat Spread => Schema.GetDeclaredClass<CFiringModeFloat>(this.Handle, "CCSWeaponBaseVData", "m_flSpread");
|
||||
|
||||
// m_flInaccuracyCrouch
|
||||
public CFiringModeFloat InaccuracyCrouch => Schema.GetDeclaredClass<CFiringModeFloat>(this.Handle, "CCSWeaponBaseVData", "m_flInaccuracyCrouch");
|
||||
|
||||
// m_flInaccuracyStand
|
||||
public CFiringModeFloat InaccuracyStand => Schema.GetDeclaredClass<CFiringModeFloat>(this.Handle, "CCSWeaponBaseVData", "m_flInaccuracyStand");
|
||||
|
||||
// m_flInaccuracyJump
|
||||
public CFiringModeFloat InaccuracyJump => Schema.GetDeclaredClass<CFiringModeFloat>(this.Handle, "CCSWeaponBaseVData", "m_flInaccuracyJump");
|
||||
|
||||
// m_flInaccuracyLand
|
||||
public CFiringModeFloat InaccuracyLand => Schema.GetDeclaredClass<CFiringModeFloat>(this.Handle, "CCSWeaponBaseVData", "m_flInaccuracyLand");
|
||||
|
||||
// m_flInaccuracyLadder
|
||||
public CFiringModeFloat InaccuracyLadder => Schema.GetDeclaredClass<CFiringModeFloat>(this.Handle, "CCSWeaponBaseVData", "m_flInaccuracyLadder");
|
||||
|
||||
// m_flInaccuracyFire
|
||||
public CFiringModeFloat InaccuracyFire => Schema.GetDeclaredClass<CFiringModeFloat>(this.Handle, "CCSWeaponBaseVData", "m_flInaccuracyFire");
|
||||
|
||||
// m_flInaccuracyMove
|
||||
public CFiringModeFloat InaccuracyMove => Schema.GetDeclaredClass<CFiringModeFloat>(this.Handle, "CCSWeaponBaseVData", "m_flInaccuracyMove");
|
||||
|
||||
// m_flRecoilAngle
|
||||
public CFiringModeFloat RecoilAngle => Schema.GetDeclaredClass<CFiringModeFloat>(this.Handle, "CCSWeaponBaseVData", "m_flRecoilAngle");
|
||||
|
||||
// m_flRecoilAngleVariance
|
||||
public CFiringModeFloat RecoilAngleVariance => Schema.GetDeclaredClass<CFiringModeFloat>(this.Handle, "CCSWeaponBaseVData", "m_flRecoilAngleVariance");
|
||||
|
||||
// m_flRecoilMagnitude
|
||||
public CFiringModeFloat RecoilMagnitude => Schema.GetDeclaredClass<CFiringModeFloat>(this.Handle, "CCSWeaponBaseVData", "m_flRecoilMagnitude");
|
||||
|
||||
// m_flRecoilMagnitudeVariance
|
||||
public CFiringModeFloat RecoilMagnitudeVariance => Schema.GetDeclaredClass<CFiringModeFloat>(this.Handle, "CCSWeaponBaseVData", "m_flRecoilMagnitudeVariance");
|
||||
|
||||
// m_nTracerFrequency
|
||||
public CFiringModeInt TracerFrequency => Schema.GetDeclaredClass<CFiringModeInt>(this.Handle, "CCSWeaponBaseVData", "m_nTracerFrequency");
|
||||
|
||||
// m_flInaccuracyJumpInitial
|
||||
public ref float InaccuracyJumpInitial => ref Schema.GetRef<float>(this.Handle, "CCSWeaponBaseVData", "m_flInaccuracyJumpInitial");
|
||||
|
||||
// m_flInaccuracyJumpApex
|
||||
public ref float InaccuracyJumpApex => ref Schema.GetRef<float>(this.Handle, "CCSWeaponBaseVData", "m_flInaccuracyJumpApex");
|
||||
|
||||
// m_flInaccuracyReload
|
||||
public ref float InaccuracyReload => ref Schema.GetRef<float>(this.Handle, "CCSWeaponBaseVData", "m_flInaccuracyReload");
|
||||
|
||||
// m_nRecoilSeed
|
||||
public ref Int32 RecoilSeed => ref Schema.GetRef<Int32>(this.Handle, "CCSWeaponBaseVData", "m_nRecoilSeed");
|
||||
|
||||
// m_nSpreadSeed
|
||||
public ref Int32 SpreadSeed => ref Schema.GetRef<Int32>(this.Handle, "CCSWeaponBaseVData", "m_nSpreadSeed");
|
||||
|
||||
// m_flTimeToIdleAfterFire
|
||||
public ref float TimeToIdleAfterFire => ref Schema.GetRef<float>(this.Handle, "CCSWeaponBaseVData", "m_flTimeToIdleAfterFire");
|
||||
|
||||
// m_flIdleInterval
|
||||
public ref float IdleInterval => ref Schema.GetRef<float>(this.Handle, "CCSWeaponBaseVData", "m_flIdleInterval");
|
||||
|
||||
// m_flAttackMovespeedFactor
|
||||
public ref float AttackMovespeedFactor => ref Schema.GetRef<float>(this.Handle, "CCSWeaponBaseVData", "m_flAttackMovespeedFactor");
|
||||
|
||||
// m_flHeatPerShot
|
||||
public ref float HeatPerShot => ref Schema.GetRef<float>(this.Handle, "CCSWeaponBaseVData", "m_flHeatPerShot");
|
||||
|
||||
// m_flInaccuracyPitchShift
|
||||
public ref float InaccuracyPitchShift => ref Schema.GetRef<float>(this.Handle, "CCSWeaponBaseVData", "m_flInaccuracyPitchShift");
|
||||
|
||||
// m_flInaccuracyAltSoundThreshold
|
||||
public ref float InaccuracyAltSoundThreshold => ref Schema.GetRef<float>(this.Handle, "CCSWeaponBaseVData", "m_flInaccuracyAltSoundThreshold");
|
||||
|
||||
// m_flBotAudibleRange
|
||||
public ref float BotAudibleRange => ref Schema.GetRef<float>(this.Handle, "CCSWeaponBaseVData", "m_flBotAudibleRange");
|
||||
|
||||
// m_szUseRadioSubtitle
|
||||
public string UseRadioSubtitle
|
||||
{
|
||||
get { return Schema.GetUtf8String(this.Handle, "CCSWeaponBaseVData", "m_szUseRadioSubtitle"); }
|
||||
set { Schema.SetString(this.Handle, "CCSWeaponBaseVData", "m_szUseRadioSubtitle", value); }
|
||||
}
|
||||
|
||||
// m_bUnzoomsAfterShot
|
||||
public ref bool UnzoomsAfterShot => ref Schema.GetRef<bool>(this.Handle, "CCSWeaponBaseVData", "m_bUnzoomsAfterShot");
|
||||
|
||||
// m_bHideViewModelWhenZoomed
|
||||
public ref bool HideViewModelWhenZoomed => ref Schema.GetRef<bool>(this.Handle, "CCSWeaponBaseVData", "m_bHideViewModelWhenZoomed");
|
||||
|
||||
// m_nZoomLevels
|
||||
public ref Int32 ZoomLevels => ref Schema.GetRef<Int32>(this.Handle, "CCSWeaponBaseVData", "m_nZoomLevels");
|
||||
|
||||
// m_nZoomFOV1
|
||||
public ref Int32 ZoomFOV1 => ref Schema.GetRef<Int32>(this.Handle, "CCSWeaponBaseVData", "m_nZoomFOV1");
|
||||
|
||||
// m_nZoomFOV2
|
||||
public ref Int32 ZoomFOV2 => ref Schema.GetRef<Int32>(this.Handle, "CCSWeaponBaseVData", "m_nZoomFOV2");
|
||||
|
||||
// m_flZoomTime0
|
||||
public ref float ZoomTime0 => ref Schema.GetRef<float>(this.Handle, "CCSWeaponBaseVData", "m_flZoomTime0");
|
||||
|
||||
// m_flZoomTime1
|
||||
public ref float ZoomTime1 => ref Schema.GetRef<float>(this.Handle, "CCSWeaponBaseVData", "m_flZoomTime1");
|
||||
|
||||
// m_flZoomTime2
|
||||
public ref float ZoomTime2 => ref Schema.GetRef<float>(this.Handle, "CCSWeaponBaseVData", "m_flZoomTime2");
|
||||
|
||||
// m_flIronSightPullUpSpeed
|
||||
public ref float IronSightPullUpSpeed => ref Schema.GetRef<float>(this.Handle, "CCSWeaponBaseVData", "m_flIronSightPullUpSpeed");
|
||||
|
||||
// m_flIronSightPutDownSpeed
|
||||
public ref float IronSightPutDownSpeed => ref Schema.GetRef<float>(this.Handle, "CCSWeaponBaseVData", "m_flIronSightPutDownSpeed");
|
||||
|
||||
// m_flIronSightFOV
|
||||
public ref float IronSightFOV => ref Schema.GetRef<float>(this.Handle, "CCSWeaponBaseVData", "m_flIronSightFOV");
|
||||
|
||||
// m_flIronSightPivotForward
|
||||
public ref float IronSightPivotForward => ref Schema.GetRef<float>(this.Handle, "CCSWeaponBaseVData", "m_flIronSightPivotForward");
|
||||
|
||||
// m_flIronSightLooseness
|
||||
public ref float IronSightLooseness => ref Schema.GetRef<float>(this.Handle, "CCSWeaponBaseVData", "m_flIronSightLooseness");
|
||||
|
||||
// m_angPivotAngle
|
||||
public QAngle PivotAngle => Schema.GetDeclaredClass<QAngle>(this.Handle, "CCSWeaponBaseVData", "m_angPivotAngle");
|
||||
|
||||
// m_vecIronSightEyePos
|
||||
public Vector IronSightEyePos => Schema.GetDeclaredClass<Vector>(this.Handle, "CCSWeaponBaseVData", "m_vecIronSightEyePos");
|
||||
|
||||
// m_nDamage
|
||||
public ref Int32 Damage => ref Schema.GetRef<Int32>(this.Handle, "CCSWeaponBaseVData", "m_nDamage");
|
||||
|
||||
// m_flHeadshotMultiplier
|
||||
public ref float HeadshotMultiplier => ref Schema.GetRef<float>(this.Handle, "CCSWeaponBaseVData", "m_flHeadshotMultiplier");
|
||||
|
||||
// m_flArmorRatio
|
||||
public ref float ArmorRatio => ref Schema.GetRef<float>(this.Handle, "CCSWeaponBaseVData", "m_flArmorRatio");
|
||||
|
||||
// m_flPenetration
|
||||
public ref float Penetration => ref Schema.GetRef<float>(this.Handle, "CCSWeaponBaseVData", "m_flPenetration");
|
||||
|
||||
// m_flRange
|
||||
public ref float Range => ref Schema.GetRef<float>(this.Handle, "CCSWeaponBaseVData", "m_flRange");
|
||||
|
||||
// m_flRangeModifier
|
||||
public ref float RangeModifier => ref Schema.GetRef<float>(this.Handle, "CCSWeaponBaseVData", "m_flRangeModifier");
|
||||
|
||||
// m_flFlinchVelocityModifierLarge
|
||||
public ref float FlinchVelocityModifierLarge => ref Schema.GetRef<float>(this.Handle, "CCSWeaponBaseVData", "m_flFlinchVelocityModifierLarge");
|
||||
|
||||
// m_flFlinchVelocityModifierSmall
|
||||
public ref float FlinchVelocityModifierSmall => ref Schema.GetRef<float>(this.Handle, "CCSWeaponBaseVData", "m_flFlinchVelocityModifierSmall");
|
||||
|
||||
// m_flRecoveryTimeCrouch
|
||||
public ref float RecoveryTimeCrouch => ref Schema.GetRef<float>(this.Handle, "CCSWeaponBaseVData", "m_flRecoveryTimeCrouch");
|
||||
|
||||
// m_flRecoveryTimeStand
|
||||
public ref float RecoveryTimeStand => ref Schema.GetRef<float>(this.Handle, "CCSWeaponBaseVData", "m_flRecoveryTimeStand");
|
||||
|
||||
// m_flRecoveryTimeCrouchFinal
|
||||
public ref float RecoveryTimeCrouchFinal => ref Schema.GetRef<float>(this.Handle, "CCSWeaponBaseVData", "m_flRecoveryTimeCrouchFinal");
|
||||
|
||||
// m_flRecoveryTimeStandFinal
|
||||
public ref float RecoveryTimeStandFinal => ref Schema.GetRef<float>(this.Handle, "CCSWeaponBaseVData", "m_flRecoveryTimeStandFinal");
|
||||
|
||||
// m_nRecoveryTransitionStartBullet
|
||||
public ref Int32 RecoveryTransitionStartBullet => ref Schema.GetRef<Int32>(this.Handle, "CCSWeaponBaseVData", "m_nRecoveryTransitionStartBullet");
|
||||
|
||||
// m_nRecoveryTransitionEndBullet
|
||||
public ref Int32 RecoveryTransitionEndBullet => ref Schema.GetRef<Int32>(this.Handle, "CCSWeaponBaseVData", "m_nRecoveryTransitionEndBullet");
|
||||
|
||||
// m_flThrowVelocity
|
||||
public ref float ThrowVelocity => ref Schema.GetRef<float>(this.Handle, "CCSWeaponBaseVData", "m_flThrowVelocity");
|
||||
|
||||
// m_vSmokeColor
|
||||
public Vector SmokeColor => Schema.GetDeclaredClass<Vector>(this.Handle, "CCSWeaponBaseVData", "m_vSmokeColor");
|
||||
|
||||
// m_szAnimClass
|
||||
public string AnimClass
|
||||
{
|
||||
get { return Schema.GetUtf8String(this.Handle, "CCSWeaponBaseVData", "m_szAnimClass"); }
|
||||
set { Schema.SetString(this.Handle, "CCSWeaponBaseVData", "m_szAnimClass", value); }
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
public partial class CDamageRecord : NativeObject
|
||||
{
|
||||
public CDamageRecord (IntPtr pointer) : base(pointer) {}
|
||||
@@ -9443,6 +9815,12 @@ public partial class CEntityIOOutput : NativeObject
|
||||
|
||||
}
|
||||
|
||||
public partial class CEntitySubclassVDataBase : NativeObject
|
||||
{
|
||||
public CEntitySubclassVDataBase (IntPtr pointer) : base(pointer) {}
|
||||
|
||||
}
|
||||
|
||||
public partial class CEnvBeam : CBeam
|
||||
{
|
||||
public CEnvBeam (IntPtr pointer) : base(pointer) {}
|
||||
@@ -10981,6 +11359,45 @@ public partial class CEnvWindShared : NativeObject
|
||||
|
||||
}
|
||||
|
||||
public partial class CExampleSchemaVData_Monomorphic : NativeObject
|
||||
{
|
||||
public CExampleSchemaVData_Monomorphic (IntPtr pointer) : base(pointer) {}
|
||||
|
||||
// m_nExample1
|
||||
public ref Int32 Example1 => ref Schema.GetRef<Int32>(this.Handle, "CExampleSchemaVData_Monomorphic", "m_nExample1");
|
||||
|
||||
// m_nExample2
|
||||
public ref Int32 Example2 => ref Schema.GetRef<Int32>(this.Handle, "CExampleSchemaVData_Monomorphic", "m_nExample2");
|
||||
|
||||
}
|
||||
|
||||
public partial class CExampleSchemaVData_PolymorphicBase : NativeObject
|
||||
{
|
||||
public CExampleSchemaVData_PolymorphicBase (IntPtr pointer) : base(pointer) {}
|
||||
|
||||
// m_nBase
|
||||
public ref Int32 Base => ref Schema.GetRef<Int32>(this.Handle, "CExampleSchemaVData_PolymorphicBase", "m_nBase");
|
||||
|
||||
}
|
||||
|
||||
public partial class CExampleSchemaVData_PolymorphicDerivedA : CExampleSchemaVData_PolymorphicBase
|
||||
{
|
||||
public CExampleSchemaVData_PolymorphicDerivedA (IntPtr pointer) : base(pointer) {}
|
||||
|
||||
// m_nDerivedA
|
||||
public ref Int32 DerivedA => ref Schema.GetRef<Int32>(this.Handle, "CExampleSchemaVData_PolymorphicDerivedA", "m_nDerivedA");
|
||||
|
||||
}
|
||||
|
||||
public partial class CExampleSchemaVData_PolymorphicDerivedB : CExampleSchemaVData_PolymorphicBase
|
||||
{
|
||||
public CExampleSchemaVData_PolymorphicDerivedB (IntPtr pointer) : base(pointer) {}
|
||||
|
||||
// m_nDerivedB
|
||||
public ref Int32 DerivedB => ref Schema.GetRef<Int32>(this.Handle, "CExampleSchemaVData_PolymorphicDerivedB", "m_nDerivedB");
|
||||
|
||||
}
|
||||
|
||||
public partial class CFilterAttributeInt : CBaseFilter
|
||||
{
|
||||
public CFilterAttributeInt (IntPtr pointer) : base(pointer) {}
|
||||
@@ -11194,6 +11611,24 @@ public partial class CFireSmoke : CBaseFire
|
||||
|
||||
}
|
||||
|
||||
public partial class CFiringModeFloat : NativeObject
|
||||
{
|
||||
public CFiringModeFloat (IntPtr pointer) : base(pointer) {}
|
||||
|
||||
// m_flValues
|
||||
public Span<float> Values => Schema.GetFixedArray<float>(this.Handle, "CFiringModeFloat", "m_flValues", 2);
|
||||
|
||||
}
|
||||
|
||||
public partial class CFiringModeInt : NativeObject
|
||||
{
|
||||
public CFiringModeInt (IntPtr pointer) : base(pointer) {}
|
||||
|
||||
// m_nValues
|
||||
public Span<Int32> Values => Schema.GetFixedArray<Int32>(this.Handle, "CFiringModeInt", "m_nValues", 2);
|
||||
|
||||
}
|
||||
|
||||
public partial class CFish : CBaseAnimGraph
|
||||
{
|
||||
public CFish (IntPtr pointer) : base(pointer) {}
|
||||
@@ -14982,6 +15417,15 @@ public partial class CMomentaryRotButton : CRotButton
|
||||
|
||||
}
|
||||
|
||||
public partial class CMoodVData : NativeObject
|
||||
{
|
||||
public CMoodVData (IntPtr pointer) : base(pointer) {}
|
||||
|
||||
// m_nMoodType
|
||||
public ref MoodType_t MoodType => ref Schema.GetRef<MoodType_t>(this.Handle, "CMoodVData", "m_nMoodType");
|
||||
|
||||
}
|
||||
|
||||
public partial class CMotorController : NativeObject
|
||||
{
|
||||
public CMotorController (IntPtr pointer) : base(pointer) {}
|
||||
@@ -15078,6 +15522,70 @@ public partial class CMultiSource : CLogicalEntity
|
||||
|
||||
}
|
||||
|
||||
public partial class CNavHullPresetVData : NativeObject
|
||||
{
|
||||
public CNavHullPresetVData (IntPtr pointer) : base(pointer) {}
|
||||
|
||||
// m_vecNavHulls
|
||||
public NetworkedVector<string> NavHulls => Schema.GetDeclaredClass<NetworkedVector<string>>(this.Handle, "CNavHullPresetVData", "m_vecNavHulls");
|
||||
|
||||
}
|
||||
|
||||
public partial class CNavHullVData : NativeObject
|
||||
{
|
||||
public CNavHullVData (IntPtr pointer) : base(pointer) {}
|
||||
|
||||
// m_bAgentEnabled
|
||||
public ref bool AgentEnabled => ref Schema.GetRef<bool>(this.Handle, "CNavHullVData", "m_bAgentEnabled");
|
||||
|
||||
// m_agentRadius
|
||||
public ref float AgentRadius => ref Schema.GetRef<float>(this.Handle, "CNavHullVData", "m_agentRadius");
|
||||
|
||||
// m_agentHeight
|
||||
public ref float AgentHeight => ref Schema.GetRef<float>(this.Handle, "CNavHullVData", "m_agentHeight");
|
||||
|
||||
// m_agentShortHeightEnabled
|
||||
public ref bool AgentShortHeightEnabled => ref Schema.GetRef<bool>(this.Handle, "CNavHullVData", "m_agentShortHeightEnabled");
|
||||
|
||||
// m_agentShortHeight
|
||||
public ref float AgentShortHeight => ref Schema.GetRef<float>(this.Handle, "CNavHullVData", "m_agentShortHeight");
|
||||
|
||||
// m_agentMaxClimb
|
||||
public ref float AgentMaxClimb => ref Schema.GetRef<float>(this.Handle, "CNavHullVData", "m_agentMaxClimb");
|
||||
|
||||
// m_agentMaxSlope
|
||||
public ref Int32 AgentMaxSlope => ref Schema.GetRef<Int32>(this.Handle, "CNavHullVData", "m_agentMaxSlope");
|
||||
|
||||
// m_agentMaxJumpDownDist
|
||||
public ref float AgentMaxJumpDownDist => ref Schema.GetRef<float>(this.Handle, "CNavHullVData", "m_agentMaxJumpDownDist");
|
||||
|
||||
// m_agentMaxJumpHorizDistBase
|
||||
public ref float AgentMaxJumpHorizDistBase => ref Schema.GetRef<float>(this.Handle, "CNavHullVData", "m_agentMaxJumpHorizDistBase");
|
||||
|
||||
// m_agentMaxJumpUpDist
|
||||
public ref float AgentMaxJumpUpDist => ref Schema.GetRef<float>(this.Handle, "CNavHullVData", "m_agentMaxJumpUpDist");
|
||||
|
||||
// m_agentBorderErosion
|
||||
public ref Int32 AgentBorderErosion => ref Schema.GetRef<Int32>(this.Handle, "CNavHullVData", "m_agentBorderErosion");
|
||||
|
||||
}
|
||||
|
||||
public partial class CNavLinkAnimgraphVar : NativeObject
|
||||
{
|
||||
public CNavLinkAnimgraphVar (IntPtr pointer) : base(pointer) {}
|
||||
|
||||
// m_strAnimgraphVar
|
||||
public string StrAnimgraphVar
|
||||
{
|
||||
get { return Schema.GetUtf8String(this.Handle, "CNavLinkAnimgraphVar", "m_strAnimgraphVar"); }
|
||||
set { Schema.SetString(this.Handle, "CNavLinkAnimgraphVar", "m_strAnimgraphVar", value); }
|
||||
}
|
||||
|
||||
// m_unAlignmentDegrees
|
||||
public ref UInt32 AlignmentDegrees => ref Schema.GetRef<UInt32>(this.Handle, "CNavLinkAnimgraphVar", "m_unAlignmentDegrees");
|
||||
|
||||
}
|
||||
|
||||
public partial class CNavLinkAreaEntity : CPointEntity
|
||||
{
|
||||
public CNavLinkAreaEntity (IntPtr pointer) : base(pointer) {}
|
||||
@@ -15135,6 +15643,21 @@ public partial class CNavLinkAreaEntity : CPointEntity
|
||||
|
||||
}
|
||||
|
||||
public partial class CNavLinkMovementVData : NativeObject
|
||||
{
|
||||
public CNavLinkMovementVData (IntPtr pointer) : base(pointer) {}
|
||||
|
||||
// m_bIsInterpolated
|
||||
public ref bool IsInterpolated => ref Schema.GetRef<bool>(this.Handle, "CNavLinkMovementVData", "m_bIsInterpolated");
|
||||
|
||||
// m_unRecommendedDistance
|
||||
public ref UInt32 RecommendedDistance => ref Schema.GetRef<UInt32>(this.Handle, "CNavLinkMovementVData", "m_unRecommendedDistance");
|
||||
|
||||
// m_vecAnimgraphVars
|
||||
public NetworkedVector<CNavLinkAnimgraphVar> AnimgraphVars => Schema.GetDeclaredClass<NetworkedVector<CNavLinkAnimgraphVar>>(this.Handle, "CNavLinkMovementVData", "m_vecAnimgraphVars");
|
||||
|
||||
}
|
||||
|
||||
public partial class CNavSpaceInfo : CPointEntity
|
||||
{
|
||||
public CNavSpaceInfo (IntPtr pointer) : base(pointer) {}
|
||||
@@ -17816,6 +18339,34 @@ public partial class CPrecipitationBlocker : CBaseModelEntity
|
||||
|
||||
}
|
||||
|
||||
public partial class CPrecipitationVData : CEntitySubclassVDataBase
|
||||
{
|
||||
public CPrecipitationVData (IntPtr pointer) : base(pointer) {}
|
||||
|
||||
// m_flInnerDistance
|
||||
public ref float InnerDistance => ref Schema.GetRef<float>(this.Handle, "CPrecipitationVData", "m_flInnerDistance");
|
||||
|
||||
// m_nAttachType
|
||||
public ref ParticleAttachment_t AttachType => ref Schema.GetRef<ParticleAttachment_t>(this.Handle, "CPrecipitationVData", "m_nAttachType");
|
||||
|
||||
// m_bBatchSameVolumeType
|
||||
public ref bool BatchSameVolumeType => ref Schema.GetRef<bool>(this.Handle, "CPrecipitationVData", "m_bBatchSameVolumeType");
|
||||
|
||||
// m_nRTEnvCP
|
||||
public ref Int32 RTEnvCP => ref Schema.GetRef<Int32>(this.Handle, "CPrecipitationVData", "m_nRTEnvCP");
|
||||
|
||||
// m_nRTEnvCPComponent
|
||||
public ref Int32 RTEnvCPComponent => ref Schema.GetRef<Int32>(this.Handle, "CPrecipitationVData", "m_nRTEnvCPComponent");
|
||||
|
||||
// m_szModifier
|
||||
public string Modifier
|
||||
{
|
||||
get { return Schema.GetUtf8String(this.Handle, "CPrecipitationVData", "m_szModifier"); }
|
||||
set { Schema.SetString(this.Handle, "CPrecipitationVData", "m_szModifier", value); }
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
public partial class CPredictedViewModel : CBaseViewModel
|
||||
{
|
||||
public CPredictedViewModel (IntPtr pointer) : base(pointer) {}
|
||||
@@ -18109,6 +18660,15 @@ public partial class CRagdollPropAttached : CRagdollProp
|
||||
|
||||
}
|
||||
|
||||
public partial class CRangeFloat : NativeObject
|
||||
{
|
||||
public CRangeFloat (IntPtr pointer) : base(pointer) {}
|
||||
|
||||
// m_pValue
|
||||
public Span<float> Value => Schema.GetFixedArray<float>(this.Handle, "CRangeFloat", "m_pValue", 2);
|
||||
|
||||
}
|
||||
|
||||
public partial class CRectLight : CBarnLight
|
||||
{
|
||||
public CRectLight (IntPtr pointer) : base(pointer) {}
|
||||
@@ -18958,6 +19518,24 @@ public partial class CSkeletonInstance : CGameSceneNode
|
||||
|
||||
}
|
||||
|
||||
public partial class CSkillFloat : NativeObject
|
||||
{
|
||||
public CSkillFloat (IntPtr pointer) : base(pointer) {}
|
||||
|
||||
// m_pValue
|
||||
public Span<float> Value => Schema.GetFixedArray<float>(this.Handle, "CSkillFloat", "m_pValue", 4);
|
||||
|
||||
}
|
||||
|
||||
public partial class CSkillInt : NativeObject
|
||||
{
|
||||
public CSkillInt (IntPtr pointer) : base(pointer) {}
|
||||
|
||||
// m_pValue
|
||||
public Span<Int32> Value => Schema.GetFixedArray<Int32>(this.Handle, "CSkillInt", "m_pValue", 4);
|
||||
|
||||
}
|
||||
|
||||
public partial class CSkyboxReference : CBaseEntity
|
||||
{
|
||||
public CSkyboxReference (IntPtr pointer) : base(pointer) {}
|
||||
@@ -21386,6 +21964,12 @@ public partial class InfoForResourceTypeCTextureBase : NativeObject
|
||||
|
||||
}
|
||||
|
||||
public partial class InfoForResourceTypeCVDataResource : NativeObject
|
||||
{
|
||||
public InfoForResourceTypeCVDataResource (IntPtr pointer) : base(pointer) {}
|
||||
|
||||
}
|
||||
|
||||
public partial class InfoForResourceTypeIMaterial2 : NativeObject
|
||||
{
|
||||
public InfoForResourceTypeIMaterial2 (IntPtr pointer) : base(pointer) {}
|
||||
|
||||
@@ -73,11 +73,14 @@ namespace CounterStrikeSharp.API.Core.Plugin
|
||||
|
||||
_fileWatcher.Deleted += async (s, e) =>
|
||||
{
|
||||
if (e.FullPath == path)
|
||||
Server.NextWorldUpdate(() =>
|
||||
{
|
||||
_logger.LogInformation("Plugin {Name} has been deleted, unloading...", Plugin.ModuleName);
|
||||
Unload(true);
|
||||
}
|
||||
if (e.FullPath == path)
|
||||
{
|
||||
_logger.LogInformation("Plugin {Name} has been deleted, unloading...", Plugin.ModuleName);
|
||||
Unload(true);
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
_fileWatcher.Filter = "*.dll";
|
||||
@@ -88,11 +91,14 @@ namespace CounterStrikeSharp.API.Core.Plugin
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
|
||||
@@ -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,
|
||||
}
|
||||
39
managed/CounterStrikeSharp.API/Modules/Entities/EntityIO.cs
Normal file
39
managed/CounterStrikeSharp.API/Modules/Entities/EntityIO.cs
Normal file
@@ -0,0 +1,39 @@
|
||||
/*
|
||||
* 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.Entities
|
||||
{
|
||||
public class EntityIO
|
||||
{
|
||||
public delegate HookResult EntityOutputHandler(CEntityIOOutput output, string name, CEntityInstance activator, CEntityInstance caller, CVariant value, float delay);
|
||||
|
||||
internal class EntityOutputCallback
|
||||
{
|
||||
public string Classname;
|
||||
|
||||
public string Output;
|
||||
|
||||
public EntityOutputHandler Handler;
|
||||
|
||||
public EntityOutputCallback(string classname, string output, EntityOutputHandler handler)
|
||||
{
|
||||
Classname = classname;
|
||||
Output = output;
|
||||
Handler = handler;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,4 +1,5 @@
|
||||
using System;
|
||||
using CounterStrikeSharp.API.Modules.Entities.Constants;
|
||||
using CounterStrikeSharp.API.Modules.Utils;
|
||||
|
||||
namespace CounterStrikeSharp.API.Modules.Entities
|
||||
{
|
||||
@@ -7,19 +8,25 @@ namespace CounterStrikeSharp.API.Modules.Entities
|
||||
const long Base = 76561197960265728;
|
||||
public ulong SteamId64 { get; set; }
|
||||
|
||||
public SteamID(ulong id) => SteamId64 = id;
|
||||
public SteamID(string id) => SteamId64 = id.StartsWith("[") ? ParseId3(id) : ParseId(id);
|
||||
public SteamID(ulong id)
|
||||
{
|
||||
if (id <= 0) throw new ArgumentOutOfRangeException(nameof(id));
|
||||
SteamId64 = id >= Base ? id : id + Base;
|
||||
}
|
||||
|
||||
public SteamID(string id) : this(id.StartsWith('[') ? ParseId3(id) : ParseId(id)) { }
|
||||
|
||||
public static explicit operator SteamID(ulong u) => new(u);
|
||||
public static explicit operator SteamID(string s) => new(s);
|
||||
ulong ParseId(string id)
|
||||
|
||||
static ulong ParseId(string id)
|
||||
{
|
||||
var parts = id.Split(':');
|
||||
if (parts.Length != 3 || !ulong.TryParse(parts[2], out var num)) throw new FormatException();
|
||||
return Base + num * 2 + (parts[1] == "1" ? 1UL : 0);
|
||||
return Base + (num * 2) + (parts[1] == "1" ? 1UL : 0);
|
||||
}
|
||||
|
||||
ulong ParseId3(string id)
|
||||
static ulong ParseId3(string id)
|
||||
{
|
||||
var parts = id.Replace("[", "").Replace("]", "").Split(':');
|
||||
if (parts.Length != 3 || !ulong.TryParse(parts[2], out var num)) throw new FormatException();
|
||||
@@ -34,18 +41,56 @@ 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);
|
||||
}
|
||||
|
||||
|
||||
public int SteamId32
|
||||
{
|
||||
get => (int)(SteamId64 - Base);
|
||||
set => SteamId64 = (ulong)value + Base;
|
||||
}
|
||||
|
||||
public int AccountId => (int)(SteamId64 & 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()
|
||||
{
|
||||
return AccountType switch
|
||||
{
|
||||
SteamAccountType.Individual => new Uri("https://steamcommunity.com/profiles/" + SteamId64),
|
||||
SteamAccountType.Clan => new Uri("https://steamcommunity.com/gid/" + SteamId64),
|
||||
_ => new Uri(string.Empty),
|
||||
};
|
||||
}
|
||||
|
||||
public bool Equals(SteamID? other)
|
||||
{
|
||||
return other != null && SteamId64 == other.SteamId64;
|
||||
@@ -56,7 +101,7 @@ namespace CounterStrikeSharp.API.Modules.Entities
|
||||
if (obj?.GetType() != this.GetType()) return false;
|
||||
return Equals((SteamID)obj);
|
||||
}
|
||||
|
||||
|
||||
public static bool TryParse(string s, out SteamID? steamId)
|
||||
{
|
||||
try
|
||||
|
||||
@@ -10,5 +10,14 @@ public class CStrongHandle<T> : NativeObject
|
||||
{
|
||||
}
|
||||
|
||||
public unsafe ulong Value => Unsafe.Read<ulong>((void*)Handle);
|
||||
}
|
||||
|
||||
public class CWeakHandle<T> : NativeObject
|
||||
{
|
||||
public CWeakHandle(IntPtr pointer) : base(pointer)
|
||||
{
|
||||
}
|
||||
|
||||
public unsafe ulong Value => Unsafe.Read<ulong>((void*)Handle);
|
||||
}
|
||||
@@ -45,12 +45,28 @@ namespace CounterStrikeSharp.API
|
||||
// Currently only used to keep the delegate from being garbage collected
|
||||
private static List<Action> nextFrameTasks = new List<Action>();
|
||||
|
||||
/// <summary>
|
||||
/// Queue a task to be executed on the next game frame.
|
||||
/// <remarks>Does not execute if the server is hibernating.</remarks>
|
||||
/// </summary>
|
||||
public static void NextFrame(Action task)
|
||||
{
|
||||
nextFrameTasks.Add(task);
|
||||
var ptr = Marshal.GetFunctionPointerForDelegate(task);
|
||||
NativeAPI.QueueTaskForNextFrame(ptr);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Queue a task to be executed on the next pre world update.
|
||||
/// <remarks>Executes if the server is hibernating.</remarks>
|
||||
/// </summary>
|
||||
/// <param name="task"></param>
|
||||
public static void NextWorldUpdate(Action task)
|
||||
{
|
||||
nextFrameTasks.Add(task);
|
||||
var ptr = Marshal.GetFunctionPointerForDelegate(task);
|
||||
NativeAPI.QueueTaskForNextWorldUpdate(ptr);
|
||||
}
|
||||
|
||||
public static void PrintToChatAll(string message)
|
||||
{
|
||||
|
||||
@@ -150,5 +150,16 @@ namespace CounterStrikeSharp.API
|
||||
return Encoding.UTF8.GetString(buffer);
|
||||
}
|
||||
}
|
||||
|
||||
public static T? GetPointer<T>(IntPtr pointer) where T : NativeObject
|
||||
{
|
||||
var pointerTo = Marshal.ReadIntPtr(pointer);
|
||||
if (pointerTo == IntPtr.Zero)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
return (T)Activator.CreateInstance(typeof(T), pointerTo)!;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -28,7 +28,18 @@ internal static partial class Program
|
||||
"IChoreoServices::ChoreoState_t",
|
||||
"SpawnPointCoopEnemy::BotDefaultBehavior_t",
|
||||
"CLogicBranchList::LogicBranchListenerLastState_t",
|
||||
"SimpleConstraintSoundProfile::SimpleConstraintsSoundProfileKeypoints_t"
|
||||
"SimpleConstraintSoundProfile::SimpleConstraintsSoundProfileKeypoints_t",
|
||||
"MoodAnimationLayer_t"
|
||||
};
|
||||
|
||||
private static readonly IReadOnlySet<string> IgnoreClassWildcards = new HashSet<string>
|
||||
{
|
||||
"CResourceNameTyped",
|
||||
"CEntityOutputTemplate",
|
||||
"CVariantBase",
|
||||
"HSCRIPT",
|
||||
"KeyValues3",
|
||||
"Unknown"
|
||||
};
|
||||
|
||||
public static string SanitiseTypeName(string typeName) => typeName.Replace(":", "");
|
||||
@@ -159,11 +170,18 @@ internal static partial class Program
|
||||
|
||||
// Manually whitelist some classes
|
||||
visited.Add("CTakeDamageInfo");
|
||||
visited.Add("CEntitySubclassVDataBase");
|
||||
visited.Add("CFiringModeFloat");
|
||||
visited.Add("CFiringModeInt");
|
||||
visited.Add("CSkillFloat");
|
||||
visited.Add("CSkillInt");
|
||||
visited.Add("CRangeFloat");
|
||||
visited.Add("CNavLinkAnimgraphVar");
|
||||
|
||||
var visitedClassNames = new HashSet<string>();
|
||||
foreach (var (className, schemaClass) in allClasses)
|
||||
{
|
||||
if (visited.Contains(className))
|
||||
if (visited.Contains(className) || className.Contains("VData"))
|
||||
{
|
||||
var isPointeeType = pointeeTypes.Contains(className);
|
||||
|
||||
@@ -211,10 +229,11 @@ internal static partial class Program
|
||||
|
||||
foreach (var field in schemaClass.Fields)
|
||||
{
|
||||
if (IgnoreClassWildcards.Any(y => field.Type.Name.Contains(y)))
|
||||
continue;
|
||||
|
||||
// Putting these in the too hard basket for now.
|
||||
if (field.Name == "m_VoteOptions" || field.Type.Name.Contains("CEntityOutputTemplate") ||
|
||||
field.Type.Name.Contains("CVariantBase") ||
|
||||
field.Type.Name == "HSCRIPT" || field.Type.Name == "KeyValues3") continue;
|
||||
if (field.Name == "m_VoteOptions" || field.Name == "m_aShootSounds") continue;
|
||||
|
||||
if (field.Type is { Category: SchemaTypeCategory.Atomic, Atomic: SchemaAtomicCategory.Collection })
|
||||
{
|
||||
|
||||
@@ -22,6 +22,12 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "WithCommands", "..\examples
|
||||
EndProject
|
||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "WithGameEventHandlers", "..\examples\WithGameEventHandlers\WithGameEventHandlers.csproj", "{3032F3FA-E20A-4581-9A08-2FB5FF1524F4}"
|
||||
EndProject
|
||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "WithDatabaseDapper", "..\examples\WithDatabaseDapper\WithDatabaseDapper.csproj", "{A641D8D7-35F1-48AB-AABA-EDFB6B7FC49B}"
|
||||
EndProject
|
||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "WithEntityOutputHooks", "..\examples\WithEntityOutputHooks\WithEntityOutputHooks.csproj", "{31EABE0B-871F-497B-BF36-37FFC6FAD15F}"
|
||||
EndProject
|
||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "CounterStrikeSharp.API.Tests", "CounterStrikeSharp.API.Tests\CounterStrikeSharp.API.Tests.csproj", "{BBA80E1B-109D-4ABD-9ADF-46EB0FEDFCD3}"
|
||||
EndProject
|
||||
Global
|
||||
GlobalSection(SolutionConfigurationPlatforms) = preSolution
|
||||
Debug|Any CPU = Debug|Any CPU
|
||||
@@ -68,6 +74,18 @@ Global
|
||||
{3032F3FA-E20A-4581-9A08-2FB5FF1524F4}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{3032F3FA-E20A-4581-9A08-2FB5FF1524F4}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{3032F3FA-E20A-4581-9A08-2FB5FF1524F4}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
{A641D8D7-35F1-48AB-AABA-EDFB6B7FC49B}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{A641D8D7-35F1-48AB-AABA-EDFB6B7FC49B}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{A641D8D7-35F1-48AB-AABA-EDFB6B7FC49B}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{A641D8D7-35F1-48AB-AABA-EDFB6B7FC49B}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
{31EABE0B-871F-497B-BF36-37FFC6FAD15F}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{31EABE0B-871F-497B-BF36-37FFC6FAD15F}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{31EABE0B-871F-497B-BF36-37FFC6FAD15F}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{31EABE0B-871F-497B-BF36-37FFC6FAD15F}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
{BBA80E1B-109D-4ABD-9ADF-46EB0FEDFCD3}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{BBA80E1B-109D-4ABD-9ADF-46EB0FEDFCD3}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{BBA80E1B-109D-4ABD-9ADF-46EB0FEDFCD3}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{BBA80E1B-109D-4ABD-9ADF-46EB0FEDFCD3}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
EndGlobalSection
|
||||
GlobalSection(NestedProjects) = preSolution
|
||||
{57E64289-5D69-4AA1-BEF0-D0D96A55EE8F} = {7DF99C35-881D-4FF2-B1C9-246BD3DECB9A}
|
||||
@@ -77,5 +95,7 @@ Global
|
||||
{E497E40C-A7B4-41A7-A1C6-2EC6698FF3BF} = {7DF99C35-881D-4FF2-B1C9-246BD3DECB9A}
|
||||
{EA2F596E-2236-4999-B476-B1FDA287674A} = {7DF99C35-881D-4FF2-B1C9-246BD3DECB9A}
|
||||
{3032F3FA-E20A-4581-9A08-2FB5FF1524F4} = {7DF99C35-881D-4FF2-B1C9-246BD3DECB9A}
|
||||
{A641D8D7-35F1-48AB-AABA-EDFB6B7FC49B} = {7DF99C35-881D-4FF2-B1C9-246BD3DECB9A}
|
||||
{31EABE0B-871F-497B-BF36-37FFC6FAD15F} = {7DF99C35-881D-4FF2-B1C9-246BD3DECB9A}
|
||||
EndGlobalSection
|
||||
EndGlobal
|
||||
|
||||
@@ -93,6 +93,7 @@ namespace TestPlugin
|
||||
SetupListeners();
|
||||
SetupCommands();
|
||||
SetupMenus();
|
||||
SetupEntityOutputHooks();
|
||||
|
||||
// ValveInterface provides pointers to loaded modules via Interface Name exposed from the engine (e.g. Source2Server001)
|
||||
var server = ValveInterface.Server;
|
||||
@@ -406,6 +407,29 @@ namespace TestPlugin
|
||||
});
|
||||
}
|
||||
|
||||
private void SetupEntityOutputHooks()
|
||||
{
|
||||
HookEntityOutput("weapon_knife", "OnPlayerPickup", (output, name, activator, caller, value, delay) =>
|
||||
{
|
||||
Logger.LogInformation("weapon_knife called OnPlayerPickup ({name}, {activator}, {caller}, {delay})", output.Description.Name, activator.DesignerName, caller.DesignerName, delay);
|
||||
|
||||
return HookResult.Continue;
|
||||
});
|
||||
|
||||
HookEntityOutput("*", "*", (output, name, activator, caller, value, delay) =>
|
||||
{
|
||||
Logger.LogInformation("All EntityOutput ({name}, {activator}, {caller}, {delay})", output.Description.Name, activator.DesignerName, caller.DesignerName, delay);
|
||||
|
||||
return HookResult.Continue;
|
||||
});
|
||||
|
||||
HookEntityOutput("*", "OnStartTouch", (output, name, activator, caller, value, delay) =>
|
||||
{
|
||||
Logger.LogInformation("OnStartTouch: ({name}, {activator}, {caller}, {delay})", name, activator.DesignerName, caller.DesignerName, delay);
|
||||
return HookResult.Continue;
|
||||
});
|
||||
}
|
||||
|
||||
[GameEventHandler]
|
||||
public HookResult OnPlayerConnect(EventPlayerConnect @event, GameEventInfo info)
|
||||
{
|
||||
@@ -460,7 +484,8 @@ namespace TestPlugin
|
||||
|
||||
foreach (var weapon in player.PlayerPawn.Value.WeaponServices.MyWeapons)
|
||||
{
|
||||
command.ReplyToCommand(weapon.Value.DesignerName);
|
||||
var vData = weapon.Value.As<CCSWeaponBase>().VData;
|
||||
command.ReplyToCommand(string.Format("{0}, {1}, {2}, {3}, {4}, {5}", vData.Name, vData.GearSlot, vData.Price, vData.WeaponCategory, vData.WeaponType, vData.KillAward));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -544,5 +569,13 @@ namespace TestPlugin
|
||||
|
||||
return HookResult.Continue;
|
||||
}
|
||||
|
||||
[EntityOutputHook("*", "OnPlayerPickup")]
|
||||
public HookResult OnPickup(CEntityIOOutput output, string name, CEntityInstance activator, CEntityInstance caller, CVariant value, float delay)
|
||||
{
|
||||
Logger.LogInformation("[EntityOutputHook Attribute] Called OnPlayerPickup ({name}, {activator}, {caller}, {delay})", name, activator.DesignerName, caller.DesignerName, delay);
|
||||
|
||||
return HookResult.Continue;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -78,6 +78,7 @@ ChatManager chatManager;
|
||||
ServerManager serverManager;
|
||||
|
||||
GetLegacyGameEventListener_t* GetLegacyGameEventListener = nullptr;
|
||||
std::thread::id gameThreadId;
|
||||
|
||||
void Initialize()
|
||||
{
|
||||
|
||||
@@ -6,6 +6,8 @@
|
||||
#undef protected
|
||||
#undef private
|
||||
|
||||
#include <thread>
|
||||
|
||||
#include "ISmmAPI.h"
|
||||
#include "eiface.h"
|
||||
#include "iserver.h"
|
||||
@@ -107,6 +109,7 @@ extern CGameConfig* gameConfig;
|
||||
typedef IGameEventListener2 *GetLegacyGameEventListener_t(CPlayerSlot slot);
|
||||
|
||||
extern GetLegacyGameEventListener_t* GetLegacyGameEventListener;
|
||||
extern std::thread::id gameThreadId;
|
||||
|
||||
void Initialize();
|
||||
// Should only be called within the active game loop (i e map should be loaded
|
||||
|
||||
@@ -15,6 +15,11 @@
|
||||
*/
|
||||
|
||||
#include "core/managers/entity_manager.h"
|
||||
#include "core/gameconfig.h"
|
||||
#include "core/log.h"
|
||||
|
||||
#include <funchook.h>
|
||||
#include <vector>
|
||||
|
||||
#include <public/eiface.h>
|
||||
#include "scripting/callback_manager.h"
|
||||
@@ -25,15 +30,31 @@ EntityManager::EntityManager() {}
|
||||
|
||||
EntityManager::~EntityManager() {}
|
||||
|
||||
void EntityManager::OnAllInitialized() {
|
||||
void EntityManager::OnAllInitialized()
|
||||
{
|
||||
on_entity_spawned_callback = globals::callbackManager.CreateCallback("OnEntitySpawned");
|
||||
on_entity_created_callback = globals::callbackManager.CreateCallback("OnEntityCreated");
|
||||
on_entity_deleted_callback = globals::callbackManager.CreateCallback("OnEntityDeleted");
|
||||
on_entity_parent_changed_callback = globals::callbackManager.CreateCallback("OnEntityParentChanged");
|
||||
on_entity_parent_changed_callback =
|
||||
globals::callbackManager.CreateCallback("OnEntityParentChanged");
|
||||
|
||||
m_pFireOutputInternal = reinterpret_cast<FireOutputInternal>(modules::server->FindSignature(
|
||||
globals::gameConfig->GetSignature("CEntityIOOutput_FireOutputInternal")));
|
||||
|
||||
if (m_pFireOutputInternal == nullptr) {
|
||||
CSSHARP_CORE_CRITICAL("Failed to find signature for \'CEntityIOOutput_FireOutputInternal\'");
|
||||
return;
|
||||
}
|
||||
|
||||
auto m_hook = funchook_create();
|
||||
funchook_prepare(m_hook, (void**)&m_pFireOutputInternal, (void*)&DetourFireOutputInternal);
|
||||
funchook_install(m_hook, 0);
|
||||
|
||||
// Listener is added in ServerStartup as entity system is not initialised at this stage.
|
||||
}
|
||||
|
||||
void EntityManager::OnShutdown() {
|
||||
void EntityManager::OnShutdown()
|
||||
{
|
||||
globals::callbackManager.ReleaseCallback(on_entity_spawned_callback);
|
||||
globals::callbackManager.ReleaseCallback(on_entity_created_callback);
|
||||
globals::callbackManager.ReleaseCallback(on_entity_deleted_callback);
|
||||
@@ -41,7 +62,8 @@ void EntityManager::OnShutdown() {
|
||||
globals::entitySystem->RemoveListenerEntity(&entityListener);
|
||||
}
|
||||
|
||||
void CEntityListener::OnEntitySpawned(CEntityInstance *pEntity) {
|
||||
void CEntityListener::OnEntitySpawned(CEntityInstance* pEntity)
|
||||
{
|
||||
auto callback = globals::entityManager.on_entity_spawned_callback;
|
||||
|
||||
if (callback && callback->GetFunctionCount()) {
|
||||
@@ -50,7 +72,8 @@ void CEntityListener::OnEntitySpawned(CEntityInstance *pEntity) {
|
||||
callback->Execute();
|
||||
}
|
||||
}
|
||||
void CEntityListener::OnEntityCreated(CEntityInstance *pEntity) {
|
||||
void CEntityListener::OnEntityCreated(CEntityInstance* pEntity)
|
||||
{
|
||||
auto callback = globals::entityManager.on_entity_created_callback;
|
||||
|
||||
if (callback && callback->GetFunctionCount()) {
|
||||
@@ -59,7 +82,8 @@ void CEntityListener::OnEntityCreated(CEntityInstance *pEntity) {
|
||||
callback->Execute();
|
||||
}
|
||||
}
|
||||
void CEntityListener::OnEntityDeleted(CEntityInstance *pEntity) {
|
||||
void CEntityListener::OnEntityDeleted(CEntityInstance* pEntity)
|
||||
{
|
||||
auto callback = globals::entityManager.on_entity_deleted_callback;
|
||||
|
||||
if (callback && callback->GetFunctionCount()) {
|
||||
@@ -68,7 +92,8 @@ void CEntityListener::OnEntityDeleted(CEntityInstance *pEntity) {
|
||||
callback->Execute();
|
||||
}
|
||||
}
|
||||
void CEntityListener::OnEntityParentChanged(CEntityInstance *pEntity, CEntityInstance *pNewParent) {
|
||||
void CEntityListener::OnEntityParentChanged(CEntityInstance* pEntity, CEntityInstance* pNewParent)
|
||||
{
|
||||
auto callback = globals::entityManager.on_entity_parent_changed_callback;
|
||||
|
||||
if (callback && callback->GetFunctionCount()) {
|
||||
@@ -79,4 +104,119 @@ void CEntityListener::OnEntityParentChanged(CEntityInstance *pEntity, CEntityIns
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace counterstrikesharp
|
||||
void EntityManager::HookEntityOutput(const char* szClassname, const char* szOutput,
|
||||
CallbackT fnCallback, HookMode mode)
|
||||
{
|
||||
auto outputKey = OutputKey_t(szClassname, szOutput);
|
||||
CallbackPair* pCallbackPair;
|
||||
|
||||
auto search = m_pHookMap.find(outputKey);
|
||||
if (search == m_pHookMap.end()) {
|
||||
m_pHookMap[outputKey] = new CallbackPair();
|
||||
pCallbackPair = m_pHookMap[outputKey];
|
||||
} else
|
||||
pCallbackPair = search->second;
|
||||
|
||||
auto* pCallback = mode == HookMode::Pre ? pCallbackPair->pre : pCallbackPair->post;
|
||||
pCallback->AddListener(fnCallback);
|
||||
}
|
||||
|
||||
void EntityManager::UnhookEntityOutput(const char* szClassname, const char* szOutput,
|
||||
CallbackT fnCallback, HookMode mode)
|
||||
{
|
||||
auto outputKey = OutputKey_t(szClassname, szOutput);
|
||||
|
||||
auto search = m_pHookMap.find(outputKey);
|
||||
if (search != m_pHookMap.end()) {
|
||||
auto* pCallbackPair = search->second;
|
||||
|
||||
auto* pCallback = mode == Pre ? pCallbackPair->pre : pCallbackPair->post;
|
||||
|
||||
pCallback->RemoveListener(fnCallback);
|
||||
|
||||
if (!pCallbackPair->HasCallbacks()) {
|
||||
m_pHookMap.erase(outputKey);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void DetourFireOutputInternal(CEntityIOOutput* const pThis, CEntityInstance* pActivator,
|
||||
CEntityInstance* pCaller, const CVariant* const value, float flDelay)
|
||||
{
|
||||
std::vector vecSearchKeys{OutputKey_t("*", pThis->m_pDesc->m_pName),
|
||||
OutputKey_t("*", "*")};
|
||||
|
||||
if (pCaller) {
|
||||
vecSearchKeys.push_back(OutputKey_t(pCaller->GetClassname(), pThis->m_pDesc->m_pName));
|
||||
OutputKey_t(pCaller->GetClassname(), "*");
|
||||
}
|
||||
|
||||
std::vector<CallbackPair*> vecCallbackPairs;
|
||||
|
||||
if (pCaller) {
|
||||
CSSHARP_CORE_TRACE("[EntityManager][FireOutputHook] - {}, {}", pThis->m_pDesc->m_pName,
|
||||
pCaller->GetClassname());
|
||||
|
||||
auto& hookMap = globals::entityManager.m_pHookMap;
|
||||
|
||||
for (auto& searchKey : vecSearchKeys) {
|
||||
auto search = hookMap.find(searchKey);
|
||||
if (search != hookMap.end()) {
|
||||
vecCallbackPairs.push_back(search->second);
|
||||
}
|
||||
}
|
||||
} else
|
||||
CSSHARP_CORE_TRACE("[EntityManager][FireOutputHook] - {}, unknown caller",
|
||||
pThis->m_pDesc->m_pName);
|
||||
|
||||
HookResult result = HookResult::Continue;
|
||||
|
||||
for (auto pCallbackPair : vecCallbackPairs) {
|
||||
if (pCallbackPair->pre->GetFunctionCount()) {
|
||||
pCallbackPair->pre->ScriptContext().Reset();
|
||||
pCallbackPair->pre->ScriptContext().Push(pThis);
|
||||
pCallbackPair->pre->ScriptContext().Push(pThis->m_pDesc->m_pName);
|
||||
pCallbackPair->pre->ScriptContext().Push(pActivator);
|
||||
pCallbackPair->pre->ScriptContext().Push(pCaller);
|
||||
pCallbackPair->pre->ScriptContext().Push(value);
|
||||
pCallbackPair->pre->ScriptContext().Push(flDelay);
|
||||
|
||||
for (auto fnMethodToCall : pCallbackPair->pre->GetFunctions()) {
|
||||
if (!fnMethodToCall)
|
||||
continue;
|
||||
fnMethodToCall(&pCallbackPair->pre->ScriptContextStruct());
|
||||
|
||||
auto thisResult = pCallbackPair->pre->ScriptContext().GetResult<HookResult>();
|
||||
|
||||
if (thisResult >= HookResult::Stop) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (thisResult > result) {
|
||||
result = thisResult;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (result >= HookResult::Handled) {
|
||||
return;
|
||||
}
|
||||
|
||||
m_pFireOutputInternal(pThis, pActivator, pCaller, value, flDelay);
|
||||
|
||||
for (auto pCallbackPair : vecCallbackPairs) {
|
||||
if (pCallbackPair->post->GetFunctionCount()) {
|
||||
pCallbackPair->post->ScriptContext().Reset();
|
||||
pCallbackPair->post->ScriptContext().Push(pThis);
|
||||
pCallbackPair->post->ScriptContext().Push(pThis->m_pDesc->m_pName);
|
||||
pCallbackPair->post->ScriptContext().Push(pActivator);
|
||||
pCallbackPair->post->ScriptContext().Push(pCaller);
|
||||
pCallbackPair->post->ScriptContext().Push(value);
|
||||
pCallbackPair->post->ScriptContext().Push(flDelay);
|
||||
pCallbackPair->post->Execute();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace counterstrikesharp
|
||||
@@ -23,10 +23,18 @@
|
||||
#include "core/global_listener.h"
|
||||
#include "scripting/script_engine.h"
|
||||
#include "entitysystem.h"
|
||||
#include "scripting/callback_manager.h"
|
||||
|
||||
// variant.h depends on ivscript.h, lets not include the whole thing
|
||||
DECLARE_POINTER_HANDLE(HSCRIPT);
|
||||
|
||||
#include <variant.h>
|
||||
|
||||
namespace counterstrikesharp {
|
||||
class ScriptCallback;
|
||||
|
||||
typedef std::pair<std::string, std::string> OutputKey_t;
|
||||
|
||||
class CEntityListener : public IEntityListener {
|
||||
void OnEntitySpawned(CEntityInstance *pEntity) override;
|
||||
void OnEntityCreated(CEntityInstance *pEntity) override;
|
||||
@@ -41,7 +49,10 @@ public:
|
||||
~EntityManager();
|
||||
void OnAllInitialized() override;
|
||||
void OnShutdown() override;
|
||||
void HookEntityOutput(const char* szClassname, const char* szOutput, CallbackT fnCallback, HookMode mode);
|
||||
void UnhookEntityOutput(const char* szClassname, const char* szOutput, CallbackT fnCallback, HookMode mode);
|
||||
CEntityListener entityListener;
|
||||
std::map<OutputKey_t, CallbackPair*> m_pHookMap;
|
||||
private:
|
||||
ScriptCallback *on_entity_spawned_callback;
|
||||
ScriptCallback *on_entity_created_callback;
|
||||
@@ -49,4 +60,58 @@ private:
|
||||
ScriptCallback *on_entity_parent_changed_callback;
|
||||
};
|
||||
|
||||
|
||||
enum EntityIOTargetType_t
|
||||
{
|
||||
ENTITY_IO_TARGET_INVALID = 0xFFFFFFFF,
|
||||
ENTITY_IO_TARGET_CLASSNAME = 0x0,
|
||||
ENTITY_IO_TARGET_CLASSNAME_DERIVES_FROM = 0x1,
|
||||
ENTITY_IO_TARGET_ENTITYNAME = 0x2,
|
||||
ENTITY_IO_TARGET_CONTAINS_COMPONENT = 0x3,
|
||||
ENTITY_IO_TARGET_SPECIAL_ACTIVATOR = 0x4,
|
||||
ENTITY_IO_TARGET_SPECIAL_CALLER = 0x5,
|
||||
ENTITY_IO_TARGET_EHANDLE = 0x6,
|
||||
ENTITY_IO_TARGET_ENTITYNAME_OR_CLASSNAME = 0x7,
|
||||
};
|
||||
|
||||
struct EntityIOConnectionDesc_t
|
||||
{
|
||||
string_t m_targetDesc;
|
||||
string_t m_targetInput;
|
||||
string_t m_valueOverride;
|
||||
CEntityHandle m_hTarget;
|
||||
EntityIOTargetType_t m_nTargetType;
|
||||
int32 m_nTimesToFire;
|
||||
float m_flDelay;
|
||||
};
|
||||
|
||||
struct EntityIOConnection_t : EntityIOConnectionDesc_t
|
||||
{
|
||||
bool m_bMarkedForRemoval;
|
||||
EntityIOConnection_t* m_pNext;
|
||||
};
|
||||
|
||||
struct EntityIOOutputDesc_t
|
||||
{
|
||||
const char* m_pName;
|
||||
uint32 m_nFlags;
|
||||
uint32 m_nOutputOffset;
|
||||
};
|
||||
|
||||
class CEntityIOOutput
|
||||
{
|
||||
public:
|
||||
void* vtable;
|
||||
EntityIOConnection_t* m_pConnections;
|
||||
EntityIOOutputDesc_t* m_pDesc;
|
||||
};
|
||||
|
||||
typedef void (*FireOutputInternal)(CEntityIOOutput* const, CEntityInstance*, CEntityInstance*,
|
||||
const CVariant* const, float);
|
||||
|
||||
static void DetourFireOutputInternal(CEntityIOOutput* const pThis, CEntityInstance* pActivator,
|
||||
CEntityInstance* pCaller, const CVariant* const value, float flDelay);
|
||||
|
||||
static FireOutputInternal m_pFireOutputInternal = nullptr;
|
||||
|
||||
} // namespace counterstrikesharp
|
||||
@@ -170,6 +170,18 @@ void ServerManager::UpdateWhenNotInGame(float flFrameTime)
|
||||
|
||||
void ServerManager::PreWorldUpdate(bool bSimulating)
|
||||
{
|
||||
std::lock_guard<std::mutex> lock(m_nextWorldUpdateTasksLock);
|
||||
|
||||
if (!m_nextWorldUpdateTasks.empty()) {
|
||||
CSSHARP_CORE_TRACE("Executing queued tasks of size: {0} at time {1}", m_nextWorldUpdateTasks.size(),
|
||||
globals::getGlobalVars()->curtime);
|
||||
|
||||
for (size_t i = 0; i < m_nextWorldUpdateTasks.size(); i++) {
|
||||
m_nextWorldUpdateTasks[i]();
|
||||
}
|
||||
|
||||
m_nextWorldUpdateTasks.clear();
|
||||
}
|
||||
|
||||
auto callback = globals::serverManager.on_server_pre_world_update;
|
||||
|
||||
@@ -180,4 +192,9 @@ void ServerManager::PreWorldUpdate(bool bSimulating)
|
||||
}
|
||||
}
|
||||
|
||||
void ServerManager::AddTaskForNextWorldUpdate(std::function<void()>&& task)
|
||||
{
|
||||
std::lock_guard<std::mutex> lock(m_nextWorldUpdateTasksLock);
|
||||
m_nextWorldUpdateTasks.push_back(std::forward<decltype(task)>(task));
|
||||
}
|
||||
} // namespace counterstrikesharp
|
||||
@@ -31,6 +31,7 @@ public:
|
||||
void OnShutdown() override;
|
||||
void* GetEconItemSystem();
|
||||
bool IsPaused();
|
||||
void AddTaskForNextWorldUpdate(std::function<void()> &&task);
|
||||
|
||||
private:
|
||||
void ServerHibernationUpdate(bool bHibernating);
|
||||
@@ -41,6 +42,7 @@ private:
|
||||
void UpdateWhenNotInGame(float flFrameTime);
|
||||
void PreWorldUpdate(bool bSimulating);
|
||||
|
||||
|
||||
ScriptCallback *on_server_hibernation_update_callback;
|
||||
ScriptCallback *on_server_steam_api_activated_callback;
|
||||
ScriptCallback *on_server_steam_api_deactivated_callback;
|
||||
@@ -48,6 +50,9 @@ private:
|
||||
ScriptCallback *on_server_pre_fatal_shutdown;
|
||||
ScriptCallback *on_server_update_when_not_in_game;
|
||||
ScriptCallback *on_server_pre_world_update;
|
||||
|
||||
std::vector<std::function<void()>> m_nextWorldUpdateTasks;
|
||||
std::mutex m_nextWorldUpdateTasksLock;
|
||||
};
|
||||
|
||||
} // namespace counterstrikesharp
|
||||
@@ -37,7 +37,7 @@ CModule::CModule(const char* path, const char* module) : m_pszModule(module), m_
|
||||
|
||||
void* CModule::FindSignature(const char* signature)
|
||||
{
|
||||
if (strlen(signature) == 0) {
|
||||
if (signature == nullptr || strlen(signature) == 0) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
|
||||
@@ -41,6 +41,17 @@ DLL_EXPORT void InvokeNative(counterstrikesharp::fxNativeContext& context)
|
||||
if (context.nativeIdentifier == 0)
|
||||
return;
|
||||
|
||||
if (context.nativeIdentifier != counterstrikesharp::hash_string_const("QUEUE_TASK_FOR_NEXT_FRAME") &&
|
||||
context.nativeIdentifier != counterstrikesharp::hash_string_const("QUEUE_TASK_FOR_NEXT_WORLD_UPDATE") &&
|
||||
counterstrikesharp::globals::gameThreadId != std::this_thread::get_id())
|
||||
{
|
||||
counterstrikesharp::ScriptContextRaw scriptContext(context);
|
||||
scriptContext.ThrowNativeError("Invoked on a non-main thread");
|
||||
|
||||
CSSHARP_CORE_CRITICAL("Native {:x} was invoked on a non-main thread", context.nativeIdentifier);
|
||||
return;
|
||||
}
|
||||
|
||||
counterstrikesharp::ScriptEngine::InvokeNative(context);
|
||||
}
|
||||
|
||||
@@ -67,6 +78,7 @@ bool CounterStrikeSharpMMPlugin::Load(PluginId id, ISmmAPI* ismm, char* error, s
|
||||
{
|
||||
PLUGIN_SAVEVARS();
|
||||
globals::ismm = ismm;
|
||||
globals::gameThreadId = std::this_thread::get_id();
|
||||
|
||||
Log::Init();
|
||||
|
||||
@@ -164,6 +176,8 @@ void CounterStrikeSharpMMPlugin::AllPluginsLoaded()
|
||||
|
||||
void CounterStrikeSharpMMPlugin::AddTaskForNextFrame(std::function<void()>&& task)
|
||||
{
|
||||
|
||||
std::lock_guard<std::mutex> lock(m_nextTasksLock);
|
||||
m_nextTasks.push_back(std::forward<decltype(task)>(task));
|
||||
}
|
||||
|
||||
@@ -177,6 +191,8 @@ void CounterStrikeSharpMMPlugin::Hook_GameFrame(bool simulating, bool bFirstTick
|
||||
*/
|
||||
globals::timerSystem.OnGameFrame(simulating);
|
||||
|
||||
std::lock_guard<std::mutex> lock(m_nextTasksLock);
|
||||
|
||||
if (m_nextTasks.empty())
|
||||
return;
|
||||
|
||||
@@ -225,4 +241,4 @@ const char* CounterStrikeSharpMMPlugin::GetURL()
|
||||
{
|
||||
return "https://github.com/roflmuffin/CounterStrikeSharp";
|
||||
}
|
||||
} // namespace counterstrikesharp
|
||||
} // namespace counterstrikesharp
|
||||
|
||||
@@ -61,6 +61,7 @@ public:
|
||||
|
||||
private:
|
||||
std::vector<std::function<void()>> m_nextTasks;
|
||||
std::mutex m_nextTasksLock;
|
||||
};
|
||||
|
||||
static ScriptCallback *on_activate_callback;
|
||||
|
||||
@@ -118,4 +118,24 @@ void CallbackManager::PrintCallbackDebug()
|
||||
CSSHARP_CORE_INFO("{0} ({0})\n", pCallback->GetName().c_str(), 1);
|
||||
}
|
||||
}
|
||||
CallbackPair::CallbackPair()
|
||||
{
|
||||
pre = globals::callbackManager.CreateCallback("");
|
||||
post = globals::callbackManager.CreateCallback("");
|
||||
}
|
||||
|
||||
CallbackPair::CallbackPair(bool bNoCallbacks)
|
||||
{
|
||||
if (!bNoCallbacks) {
|
||||
pre = globals::callbackManager.CreateCallback("");
|
||||
post = globals::callbackManager.CreateCallback("");
|
||||
}
|
||||
}
|
||||
|
||||
CallbackPair::~CallbackPair()
|
||||
{
|
||||
globals::callbackManager.ReleaseCallback(pre);
|
||||
globals::callbackManager.ReleaseCallback(post);
|
||||
}
|
||||
|
||||
} // namespace counterstrikesharp
|
||||
@@ -35,7 +35,6 @@ class ScriptCallback
|
||||
unsigned int GetFunctionCount() { return m_functions.size(); }
|
||||
std::vector<CallbackT> GetFunctions() { return m_functions; }
|
||||
|
||||
|
||||
void Execute(bool bResetContext = true);
|
||||
void Reset();
|
||||
ScriptContextRaw& ScriptContext() { return m_script_context_raw; }
|
||||
@@ -64,4 +63,18 @@ class CallbackManager : public GlobalClass
|
||||
std::vector<ScriptCallback*> m_managed;
|
||||
};
|
||||
|
||||
class CallbackPair
|
||||
{
|
||||
public:
|
||||
CallbackPair();
|
||||
CallbackPair(bool bNoCallbacks);
|
||||
~CallbackPair();
|
||||
bool HasCallbacks() const
|
||||
{ return pre->GetFunctionCount() > 0 || post->GetFunctionCount() > 0; }
|
||||
|
||||
public:
|
||||
ScriptCallback* pre;
|
||||
ScriptCallback* post;
|
||||
};
|
||||
|
||||
} // namespace counterstrikesharp
|
||||
@@ -30,6 +30,7 @@
|
||||
#include "core/memory.h"
|
||||
#include "core/log.h"
|
||||
#include "core/function.h"
|
||||
#include "core/managers/server_manager.h"
|
||||
// clang-format on
|
||||
|
||||
#if _WIN32
|
||||
@@ -217,6 +218,14 @@ void QueueTaskForNextFrame(ScriptContext& script_context)
|
||||
globals::mmPlugin->AddTaskForNextFrame([func]() { reinterpret_cast<voidfunc*>(func)(); });
|
||||
}
|
||||
|
||||
void QueueTaskForNextWorldUpdate(ScriptContext& script_context)
|
||||
{
|
||||
auto func = script_context.GetArgument<void*>(0);
|
||||
|
||||
typedef void(voidfunc)(void);
|
||||
globals::serverManager.AddTaskForNextWorldUpdate([func]() { reinterpret_cast<voidfunc*>(func)(); });
|
||||
}
|
||||
|
||||
enum InterfaceType
|
||||
{
|
||||
Engine,
|
||||
@@ -308,6 +317,7 @@ REGISTER_NATIVES(engine, {
|
||||
ScriptEngine::RegisterNativeHandler("TRACE_RAY", TraceRay);
|
||||
ScriptEngine::RegisterNativeHandler("GET_TICKED_TIME", GetTickedTime);
|
||||
ScriptEngine::RegisterNativeHandler("QUEUE_TASK_FOR_NEXT_FRAME", QueueTaskForNextFrame);
|
||||
ScriptEngine::RegisterNativeHandler("QUEUE_TASK_FOR_NEXT_WORLD_UPDATE", QueueTaskForNextWorldUpdate);
|
||||
ScriptEngine::RegisterNativeHandler("GET_VALVE_INTERFACE", GetValveInterface);
|
||||
ScriptEngine::RegisterNativeHandler("GET_COMMAND_PARAM_VALUE", GetCommandParamValue);
|
||||
ScriptEngine::RegisterNativeHandler("PRINT_TO_SERVER_CONSOLE", PrintToServerConsole);
|
||||
|
||||
@@ -21,6 +21,7 @@ TRACE_FILTER_PROXY_SET_SHOULD_HIT_ENTITY_CALLBACK: trace_filter:pointer, callbac
|
||||
NEW_TRACE_RESULT: -> pointer
|
||||
GET_TICKED_TIME: -> double
|
||||
QUEUE_TASK_FOR_NEXT_FRAME: callback:pointer -> void
|
||||
QUEUE_TASK_FOR_NEXT_WORLD_UPDATE: callback:pointer -> void
|
||||
GET_VALVE_INTERFACE: interfaceType:int, interfaceName:string -> pointer
|
||||
GET_COMMAND_PARAM_VALUE: param:string, dataType:DataType_t, defaultValue:any -> any
|
||||
PRINT_TO_SERVER_CONSOLE: msg:string -> void
|
||||
@@ -22,6 +22,7 @@
|
||||
#include "core/memory.h"
|
||||
#include "core/log.h"
|
||||
#include "core/managers/player_manager.h"
|
||||
#include "core/managers/entity_manager.h"
|
||||
|
||||
#include <public/entity2/entitysystem.h>
|
||||
|
||||
@@ -143,6 +144,24 @@ const char* GetPlayerIpAddress(ScriptContext& script_context) {
|
||||
return pPlayer->GetIpAddress();
|
||||
}
|
||||
|
||||
void HookEntityOutput(ScriptContext& script_context)
|
||||
{
|
||||
auto szClassname = script_context.GetArgument<const char*>(0);
|
||||
auto szOutput = script_context.GetArgument<const char*>(1);
|
||||
auto callback = script_context.GetArgument<CallbackT>(2);
|
||||
auto mode = script_context.GetArgument<HookMode>(3);
|
||||
globals::entityManager.HookEntityOutput(szClassname, szOutput, callback, mode);
|
||||
}
|
||||
|
||||
void UnhookEntityOutput(ScriptContext& script_context)
|
||||
{
|
||||
auto szClassname = script_context.GetArgument<const char*>(0);
|
||||
auto szOutput = script_context.GetArgument<const char*>(1);
|
||||
auto callback = script_context.GetArgument<CallbackT>(2);
|
||||
auto mode = script_context.GetArgument<HookMode>(3);
|
||||
globals::entityManager.UnhookEntityOutput(szClassname, szOutput, callback, mode);
|
||||
}
|
||||
|
||||
REGISTER_NATIVES(entities, {
|
||||
ScriptEngine::RegisterNativeHandler("GET_ENTITY_FROM_INDEX", GetEntityFromIndex);
|
||||
ScriptEngine::RegisterNativeHandler("GET_USERID_FROM_INDEX", GetUserIdFromIndex);
|
||||
@@ -157,5 +176,7 @@ REGISTER_NATIVES(entities, {
|
||||
ScriptEngine::RegisterNativeHandler("GET_FIRST_ACTIVE_ENTITY", GetFirstActiveEntity);
|
||||
ScriptEngine::RegisterNativeHandler("GET_PLAYER_AUTHORIZED_STEAMID", GetPlayerAuthorizedSteamID);
|
||||
ScriptEngine::RegisterNativeHandler("GET_PLAYER_IP_ADDRESS", GetPlayerIpAddress);
|
||||
ScriptEngine::RegisterNativeHandler("HOOK_ENTITY_OUTPUT", HookEntityOutput);
|
||||
ScriptEngine::RegisterNativeHandler("UNHOOK_ENTITY_OUTPUT", UnhookEntityOutput);
|
||||
})
|
||||
} // namespace counterstrikesharp
|
||||
@@ -9,4 +9,6 @@ IS_REF_VALID_ENTITY: entityRef:uint -> bool
|
||||
PRINT_TO_CONSOLE: index:int, message:string -> void
|
||||
GET_FIRST_ACTIVE_ENTITY: -> pointer
|
||||
GET_PLAYER_AUTHORIZED_STEAMID: slot:int -> uint64
|
||||
GET_PLAYER_IP_ADDRESS: slot:int -> string
|
||||
GET_PLAYER_IP_ADDRESS: slot:int -> string
|
||||
HOOK_ENTITY_OUTPUT: classname:string, outputName:string, callback:func, mode:HookMode -> void
|
||||
UNHOOK_ENTITY_OUTPUT: classname:string, outputName:string, callback:func, mode:HookMode -> void
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user