mirror of
https://github.com/roflmuffin/CounterStrikeSharp.git
synced 2025-12-06 08:03:12 -08:00
Compare commits
37 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
83bc1a95fb | ||
|
|
71c694b52e | ||
|
|
a452d79ba3 | ||
|
|
dfc9859806 | ||
|
|
f99f58402a | ||
|
|
6317559bd2 | ||
|
|
ad6e1ca2e2 | ||
|
|
2564ef9f39 | ||
|
|
83a341d3cf | ||
|
|
534fc42444 | ||
|
|
41355d05fa | ||
|
|
d9da15be83 | ||
|
|
75e2f6e8aa | ||
|
|
37b34e1d41 | ||
|
|
5ce04649fd | ||
|
|
7b7202fe8a | ||
|
|
cadb817ed2 | ||
|
|
211516cce5 | ||
|
|
ab211a42e6 | ||
|
|
696ecadee4 | ||
|
|
e4d598dba8 | ||
|
|
5c67d88844 | ||
|
|
9d8b6beae6 | ||
|
|
39604b7ad7 | ||
|
|
1b1f1d04dd | ||
|
|
dbc348c1bf | ||
|
|
d295589c44 | ||
|
|
16767fd494 | ||
|
|
36a97bfffd | ||
|
|
178f7472c6 | ||
|
|
cba5144bbf | ||
|
|
0de951cb6f | ||
|
|
c3d44a87bc | ||
|
|
bd3c0c76e3 | ||
|
|
656c0e3a84 | ||
|
|
40c842149c | ||
|
|
64d1c0a9f4 |
@@ -1,21 +1,72 @@
|
||||
BasedOnStyle: LLVM
|
||||
|
||||
# Spacing
|
||||
IndentWidth: 4
|
||||
ColumnLimit: 100
|
||||
UseTab: Never
|
||||
ColumnLimit: 140
|
||||
|
||||
# Line Endings
|
||||
LineEnding: LF
|
||||
InsertNewlineAtEOF: true
|
||||
DerivePointerAlignment: false
|
||||
PointerAlignment: Left
|
||||
|
||||
AlignAfterOpenBracket: Align
|
||||
KeepEmptyLinesAtTheStartOfBlocks: false
|
||||
SortIncludes: false
|
||||
SpaceBeforeParens: ControlStatements
|
||||
AllowAllArgumentsOnNextLine: true
|
||||
AllowShortIfStatementsOnASingleLine: false
|
||||
IndentCaseLabels: false
|
||||
IndentCaseLabels: true
|
||||
|
||||
# Line Breaks
|
||||
BreakBeforeBraces: Custom
|
||||
BraceWrapping:
|
||||
AfterCaseLabel: true
|
||||
AfterClass: true
|
||||
AfterStruct: true
|
||||
AfterControlStatement: Always
|
||||
AfterEnum: true
|
||||
AfterUnion: true
|
||||
AfterNamespace: false
|
||||
AfterFunction: true
|
||||
AfterNamespace: false
|
||||
AfterStruct: true
|
||||
AfterUnion: true
|
||||
AfterExternBlock: true
|
||||
BeforeCatch: true
|
||||
BeforeElse: true
|
||||
BeforeLambdaBody: false
|
||||
BeforeWhile: false
|
||||
IndentBraces: false
|
||||
SplitEmptyFunction: true
|
||||
SplitEmptyRecord: true
|
||||
SplitEmptyNamespace: true
|
||||
|
||||
PointerAlignment: Left
|
||||
SortIncludes: CaseSensitive
|
||||
IncludeBlocks: Regroup
|
||||
IncludeCategories:
|
||||
# External headers in <> with extension or /
|
||||
- Regex: '<[-\w\/-_]+[\.\/][-\w\/-_]+>'
|
||||
Priority: 2
|
||||
# Standard headers in <>
|
||||
- Regex: '<[-\w\/-_]+>'
|
||||
Priority: 3
|
||||
# Local headers in ""
|
||||
- Regex: '"[-\w\/-_]*"'
|
||||
Priority: 4
|
||||
|
||||
ReflowComments: true
|
||||
CompactNamespaces: false
|
||||
Cpp11BracedListStyle: false
|
||||
|
||||
AlignConsecutiveMacros:
|
||||
Enabled: true
|
||||
AcrossEmptyLines: false
|
||||
AcrossComments: false
|
||||
|
||||
AlignEscapedNewlines: Left
|
||||
AlignTrailingComments: Never
|
||||
|
||||
AllowShortBlocksOnASingleLine: Empty
|
||||
AllowShortIfStatementsOnASingleLine: OnlyFirstIf
|
||||
AllowShortLambdasOnASingleLine: Empty
|
||||
BinPackArguments: true
|
||||
BinPackParameters: false
|
||||
|
||||
LambdaBodyIndentation: OuterScope
|
||||
|
||||
14
.editorconfig
Normal file
14
.editorconfig
Normal file
@@ -0,0 +1,14 @@
|
||||
# top-most EditorConfig file
|
||||
root = true
|
||||
|
||||
# Unix-style newlines with a newline ending every file
|
||||
[*]
|
||||
end_of_line = lf
|
||||
insert_final_newline = true
|
||||
indent_style = space
|
||||
indent_size = 4
|
||||
max_line_length = 140
|
||||
trim_trailing_whitespace = true
|
||||
|
||||
[*.json]
|
||||
indent_size = 2
|
||||
99
.github/workflows/cmake-single-platform.yml
vendored
99
.github/workflows/cmake-single-platform.yml
vendored
@@ -3,22 +3,46 @@ name: Build & Publish
|
||||
on:
|
||||
push:
|
||||
paths-ignore:
|
||||
- 'docfx/**'
|
||||
branches: [ "main", "dev" ]
|
||||
- "docfx/**"
|
||||
branches: ["main", "dev"]
|
||||
pull_request:
|
||||
branches: [ "main", "dev" ]
|
||||
branches: ["main", "dev"]
|
||||
|
||||
env:
|
||||
BUILD_TYPE: Release
|
||||
|
||||
jobs:
|
||||
setup:
|
||||
permissions:
|
||||
contents: write
|
||||
runs-on: ubuntu-latest
|
||||
outputs:
|
||||
buildnumber: ${{ steps.buildnumber.outputs.build_number }}
|
||||
steps:
|
||||
- name: Generate build number
|
||||
if: ${{ github.event_name == 'push' && github.ref == 'refs/heads/main' }}
|
||||
id: buildnumber
|
||||
uses: onyxmueller/build-tag-number@v1
|
||||
with:
|
||||
token: ${{secrets.github_token}}
|
||||
|
||||
build_windows:
|
||||
needs: setup
|
||||
runs-on: windows-latest
|
||||
steps:
|
||||
- name: Prepare env
|
||||
shell: bash
|
||||
run: echo "GITHUB_SHA_SHORT=${GITHUB_SHA::7}" >> $GITHUB_ENV
|
||||
|
||||
- name: Fallback build number
|
||||
if: ${{ github.event_name == 'pull_request' || github.ref != 'refs/heads/main' }}
|
||||
shell: bash
|
||||
run: echo "BUILD_NUMBER=0" >> $GITHUB_ENV
|
||||
|
||||
- name: Main build number
|
||||
if: ${{ github.event_name == 'push' && github.ref == 'refs/heads/main' }}
|
||||
run: echo "BUILD_NUMBER=${{ needs.setup.outputs.buildnumber }}" >> $GITHUB_ENV
|
||||
|
||||
- name: Visual Studio environment
|
||||
shell: cmd
|
||||
run: |
|
||||
@@ -34,7 +58,7 @@ jobs:
|
||||
|
||||
- uses: actions/checkout@v3
|
||||
with:
|
||||
submodules: 'recursive'
|
||||
submodules: "recursive"
|
||||
|
||||
- name: Build
|
||||
run: |
|
||||
@@ -56,6 +80,7 @@ jobs:
|
||||
path: build/output/
|
||||
|
||||
build_linux:
|
||||
needs: setup
|
||||
runs-on: ubuntu-latest
|
||||
# Could not figure out how to run in a container only on some matrix paths, so I've split it out into its own build.
|
||||
container:
|
||||
@@ -65,9 +90,18 @@ jobs:
|
||||
shell: bash
|
||||
run: echo "GITHUB_SHA_SHORT=${GITHUB_SHA::7}" >> $GITHUB_ENV
|
||||
|
||||
- name: Fallback build number
|
||||
if: ${{ github.event_name == 'pull_request' || github.ref != 'refs/heads/main' }}
|
||||
shell: bash
|
||||
run: echo "BUILD_NUMBER=0" >> $GITHUB_ENV
|
||||
|
||||
- name: Main build number
|
||||
if: ${{ github.event_name == 'push' && github.ref == 'refs/heads/main' }}
|
||||
run: echo "BUILD_NUMBER=${{ needs.setup.outputs.buildnumber }}" >> $GITHUB_ENV
|
||||
|
||||
- uses: actions/checkout@v3
|
||||
with:
|
||||
submodules: 'recursive'
|
||||
submodules: "recursive"
|
||||
|
||||
- name: Build
|
||||
run: |
|
||||
@@ -87,11 +121,10 @@ jobs:
|
||||
path: build/output/
|
||||
|
||||
build_managed:
|
||||
needs: setup
|
||||
permissions:
|
||||
contents: write
|
||||
runs-on: ubuntu-latest
|
||||
outputs:
|
||||
buildnumber: ${{ steps.buildnumber.outputs.build_number }}
|
||||
steps:
|
||||
- name: Prepare env
|
||||
shell: bash
|
||||
@@ -102,20 +135,17 @@ jobs:
|
||||
shell: bash
|
||||
run: echo "BUILD_NUMBER=0" >> $GITHUB_ENV
|
||||
|
||||
- name: Main build number
|
||||
if: ${{ github.event_name == 'push' && github.ref == 'refs/heads/main' }}
|
||||
run: echo "BUILD_NUMBER=${{ needs.setup.outputs.buildnumber }}" >> $GITHUB_ENV
|
||||
|
||||
# We don't need expensive submodules for the managed side.
|
||||
- uses: actions/checkout@v3
|
||||
|
||||
- name: Generate build number
|
||||
if: ${{ github.event_name == 'push' && github.ref == 'refs/heads/main' }}
|
||||
id: buildnumber
|
||||
uses: onyxmueller/build-tag-number@v1
|
||||
with:
|
||||
token: ${{secrets.github_token}}
|
||||
|
||||
- name: Build runtime v${{ env.BUILD_NUMBER }}
|
||||
uses: actions/setup-dotnet@v3
|
||||
with:
|
||||
dotnet-version: '7.0.x'
|
||||
dotnet-version: "8.0.x"
|
||||
|
||||
- name: Install dependencies
|
||||
run: dotnet restore managed/CounterStrikeSharp.sln
|
||||
@@ -133,7 +163,7 @@ jobs:
|
||||
- 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
|
||||
dotnet pack -c Release /p:Version=1.0.${{ env.BUILD_NUMBER }} managed/CounterStrikeSharp.API
|
||||
|
||||
- uses: actions/upload-artifact@v3
|
||||
with:
|
||||
@@ -144,7 +174,7 @@ jobs:
|
||||
if: ${{ github.event_name == 'push' && github.ref == 'refs/heads/main' }}
|
||||
permissions:
|
||||
contents: write
|
||||
needs: [ "build_linux", "build_windows", "build_managed" ]
|
||||
needs: ["setup", "build_linux", "build_windows", "build_managed"]
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Prepare env
|
||||
@@ -171,49 +201,48 @@ jobs:
|
||||
run: |
|
||||
mkdir -p build/linux/addons/counterstrikesharp/api
|
||||
mkdir -p build/windows/addons/counterstrikesharp/api
|
||||
cp -r build/api/net7.0/publish/* build/linux/addons/counterstrikesharp/api
|
||||
cp -r build/api/net7.0/publish/* build/windows/addons/counterstrikesharp/api
|
||||
cp -r build/api/net8.0/publish/* build/linux/addons/counterstrikesharp/api
|
||||
cp -r build/api/net8.0/publish/* build/windows/addons/counterstrikesharp/api
|
||||
|
||||
- name: Zip Builds
|
||||
run: |
|
||||
(cd build/linux && zip -qq -r ../../counterstrikesharp-build-${{ needs.build_managed.outputs.buildnumber }}-linux-${{ env.GITHUB_SHA_SHORT }}.zip *)
|
||||
(cd build/windows && zip -qq -r ../../counterstrikesharp-build-${{ needs.build_managed.outputs.buildnumber }}-windows-${{ env.GITHUB_SHA_SHORT }}.zip *)
|
||||
(cd build/linux && zip -qq -r ../../counterstrikesharp-build-${{ needs.setup.outputs.buildnumber }}-linux-${{ env.GITHUB_SHA_SHORT }}.zip *)
|
||||
(cd build/windows && zip -qq -r ../../counterstrikesharp-build-${{ needs.setup.outputs.buildnumber }}-windows-${{ env.GITHUB_SHA_SHORT }}.zip *)
|
||||
|
||||
- name: Add dotnet runtime
|
||||
run: |
|
||||
mkdir -p build/linux/addons/counterstrikesharp/dotnet
|
||||
curl -s -L https://download.visualstudio.microsoft.com/download/pr/dc2c0a53-85a8-4fda-a283-fa28adb5fbe2/8ccade5bc400a5bb40cd9240f003b45c/aspnetcore-runtime-7.0.11-linux-x64.tar.gz \
|
||||
curl -s -L https://download.visualstudio.microsoft.com/download/pr/c1371dc2-eed2-47be-9af3-ae060dbe3c7d/bd509e0a87629764ed47608466d183e6/aspnetcore-runtime-8.0.3-linux-x64.tar.gz \
|
||||
| tar xvz -C build/linux/addons/counterstrikesharp/dotnet
|
||||
mv build/linux/addons/counterstrikesharp/dotnet/shared/Microsoft.NETCore.App/7.0.11/* build/linux/addons/counterstrikesharp/dotnet/shared/Microsoft.NETCore.App/
|
||||
|
||||
|
||||
mkdir -p build/windows/addons/counterstrikesharp/dotnet
|
||||
curl -s -L https://download.visualstudio.microsoft.com/download/pr/a99861c8-2e00-4587-aaef-60366ca77307/a44ceec2c5d34165ae881600f52edc43/aspnetcore-runtime-7.0.11-win-x64.zip -o dotnet.zip
|
||||
curl -s -L https://download.visualstudio.microsoft.com/download/pr/086d1dd6-57a5-437a-a1ef-549cf702fb48/dd4a8fe6c53a1016a414d6f2925c1323/aspnetcore-runtime-8.0.3-win-x64.zip -o dotnet.zip
|
||||
unzip -qq dotnet.zip -d build/windows/addons/counterstrikesharp/dotnet
|
||||
|
||||
- name: Zip Builds
|
||||
run: |
|
||||
(cd build/linux && zip -qq -r ../../counterstrikesharp-with-runtime-build-${{ needs.build_managed.outputs.buildnumber }}-linux-${{ env.GITHUB_SHA_SHORT }}.zip *)
|
||||
(cd build/windows && zip -qq -r ../../counterstrikesharp-with-runtime-build-${{ needs.build_managed.outputs.buildnumber }}-windows-${{ env.GITHUB_SHA_SHORT }}.zip *)
|
||||
(cd build/linux && zip -qq -r ../../counterstrikesharp-with-runtime-build-${{ needs.setup.outputs.buildnumber }}-linux-${{ env.GITHUB_SHA_SHORT }}.zip *)
|
||||
(cd build/windows && zip -qq -r ../../counterstrikesharp-with-runtime-build-${{ needs.setup.outputs.buildnumber }}-windows-${{ env.GITHUB_SHA_SHORT }}.zip *)
|
||||
|
||||
- name: Release
|
||||
id: release
|
||||
uses: softprops/action-gh-release@v1
|
||||
with:
|
||||
tag_name: v${{ needs.build_managed.outputs.buildnumber }}
|
||||
tag_name: v${{ needs.setup.outputs.buildnumber }}
|
||||
files: |
|
||||
counterstrikesharp-build-${{ needs.build_managed.outputs.buildnumber }}-windows-${{ env.GITHUB_SHA_SHORT }}.zip
|
||||
counterstrikesharp-with-runtime-build-${{ needs.build_managed.outputs.buildnumber }}-windows-${{ env.GITHUB_SHA_SHORT }}.zip
|
||||
counterstrikesharp-build-${{ needs.build_managed.outputs.buildnumber }}-linux-${{ env.GITHUB_SHA_SHORT }}.zip
|
||||
counterstrikesharp-with-runtime-build-${{ needs.build_managed.outputs.buildnumber }}-linux-${{ env.GITHUB_SHA_SHORT }}.zip
|
||||
counterstrikesharp-build-${{ needs.setup.outputs.buildnumber }}-windows-${{ env.GITHUB_SHA_SHORT }}.zip
|
||||
counterstrikesharp-with-runtime-build-${{ needs.setup.outputs.buildnumber }}-windows-${{ env.GITHUB_SHA_SHORT }}.zip
|
||||
counterstrikesharp-build-${{ needs.setup.outputs.buildnumber }}-linux-${{ env.GITHUB_SHA_SHORT }}.zip
|
||||
counterstrikesharp-with-runtime-build-${{ needs.setup.outputs.buildnumber }}-linux-${{ env.GITHUB_SHA_SHORT }}.zip
|
||||
|
||||
- name: Publish NuGet package
|
||||
run: |
|
||||
dotnet nuget push build/api/CounterStrikeSharp.API.1.0.${{ needs.build_managed.outputs.buildnumber }}.nupkg --api-key ${{ secrets.NUGET_API_KEY }} --source https://api.nuget.org/v3/index.json --skip-duplicate
|
||||
dotnet nuget push build/api/CounterStrikeSharp.API.1.0.${{ needs.build_managed.outputs.buildnumber }}.snupkg --api-key ${{ secrets.NUGET_API_KEY }} --source https://api.nuget.org/v3/index.json --skip-duplicate
|
||||
dotnet nuget push build/api/CounterStrikeSharp.API.1.0.${{ needs.setup.outputs.buildnumber }}.nupkg --api-key ${{ secrets.NUGET_API_KEY }} --source https://api.nuget.org/v3/index.json --skip-duplicate
|
||||
dotnet nuget push build/api/CounterStrikeSharp.API.1.0.${{ needs.setup.outputs.buildnumber }}.snupkg --api-key ${{ secrets.NUGET_API_KEY }} --source https://api.nuget.org/v3/index.json --skip-duplicate
|
||||
|
||||
- name: Send Notification to Discord
|
||||
env:
|
||||
DISCORD_WEBHOOK: ${{ secrets.DISCORD_WEBHOOK }}
|
||||
uses: Ilshidur/action-discord@0.3.2
|
||||
with:
|
||||
args: "A new release of CS# has been tagged (v${{ needs.build_managed.outputs.buildnumber }}) at ${{ steps.release.outputs.url }}"
|
||||
args: "A new release of CS# has been tagged (v${{ needs.setup.outputs.buildnumber }}) at ${{ steps.release.outputs.url }}"
|
||||
|
||||
3
.gitignore
vendored
3
.gitignore
vendored
@@ -1,8 +1,7 @@
|
||||
.ccls-cache/
|
||||
.cmake/
|
||||
cmake-build-debug*/
|
||||
cmake-build-*/
|
||||
.kdev4/
|
||||
.vscode/
|
||||
generated/
|
||||
|
||||
# configure_file auto generated.
|
||||
|
||||
4
.vscode/settings.json
vendored
Normal file
4
.vscode/settings.json
vendored
Normal file
@@ -0,0 +1,4 @@
|
||||
{
|
||||
"editor.defaultFormatter": null,
|
||||
"editor.formatOnSave": true
|
||||
}
|
||||
@@ -49,6 +49,8 @@ SET(SOURCE_FILES
|
||||
src/core/managers/event_manager.cpp
|
||||
src/core/timer_system.h
|
||||
src/core/timer_system.cpp
|
||||
src/core/tick_scheduler.h
|
||||
src/core/tick_scheduler.cpp
|
||||
src/scripting/autonative.h
|
||||
src/scripting/natives/natives_engine.cpp
|
||||
src/core/engine_trace.h
|
||||
@@ -68,7 +70,6 @@ SET(SOURCE_FILES
|
||||
src/core/memory_module.h
|
||||
src/core/memory_module.cpp
|
||||
src/core/cs2_sdk/interfaces/cgameresourceserviceserver.h
|
||||
src/core/cs2_sdk/interfaces/cschemasystem.h
|
||||
src/core/cs2_sdk/interfaces/cs2_interfaces.h
|
||||
src/core/cs2_sdk/interfaces/cs2_interfaces.cpp
|
||||
src/core/cs2_sdk/schema.h
|
||||
|
||||
103
CONTRIBUTING.md
Normal file
103
CONTRIBUTING.md
Normal file
@@ -0,0 +1,103 @@
|
||||
# Contributing to CounterStrikeSharp
|
||||
|
||||
We'd love for you to contribute to CS# to make it better than it is today!
|
||||
|
||||
Here are the guidelines we'd like you to follow:
|
||||
|
||||
- [Question or Problem?](#question)
|
||||
- [Issues and Bugs](#issue)
|
||||
- [Submission Guidelines](#submit)
|
||||
- [Coding Format](#format)
|
||||
|
||||
## <a name="question"></a> Got a Question or Problem?
|
||||
|
||||
If you have questions about how to contribute to CounterStrikeSharp, please join our [Discord][discord] server.
|
||||
|
||||
## <a name="issue"></a> Found an Issue?
|
||||
|
||||
If you find a bug in the source code or a mistake in the documentation, you can help us by
|
||||
submitting an issue to our [GitHub Repository][github]. Even better you can submit a Pull Request
|
||||
with a fix.
|
||||
|
||||
**Please see the [Submission Guidelines](#submit) below.**
|
||||
|
||||
## <a name="submit"></a> Submission Guidelines
|
||||
|
||||
### Submitting an Issue
|
||||
Before you submit your issue please search the archive, maybe your question was already answered.
|
||||
|
||||
If your issue appears to be a bug and hasn't been reported, open a new issue. Help us to maximize
|
||||
the effort we can spend fixing issues and adding new features, by not reporting duplicate issues.
|
||||
Providing the following information will increase the chances of your issue being dealt with
|
||||
quickly:
|
||||
|
||||
* **Overview of the Issue** - if an error is being thrown a stack trace helps
|
||||
* **Operating System** - is this a problem with a specific OS (Windows or Linux)?
|
||||
* **Reproduce the Error** - provide details, if possible, on how to reproduce the error
|
||||
* **Related Issues** - has a similar issue been reported before?
|
||||
* **Suggest a Fix** - if you can't fix the bug yourself, perhaps you can point to what might be causing the problem (line of code or commit)
|
||||
|
||||
### Submitting a Pull Request
|
||||
Before you submit your pull request consider the following guidelines:
|
||||
|
||||
* Search [GitHub](https://github.com/roflmuffin/CounterStrikeSharp/pulls) for an open or closed Pull Request
|
||||
that relates to your submission. You don't want to duplicate effort.
|
||||
* If adding a feature or enhancement, we recommend you first [start a discussion for
|
||||
it](https://github.com/roflmuffin/CounterStrikeSharp/discussions) before submitting a Pull Request.
|
||||
* [Fork](https://help.github.com/articles/fork-a-repo/) this repo.
|
||||
* [Clone](https://help.github.com/articles/cloning-a-repository/) your copy.
|
||||
```shell
|
||||
git clone https://github.com/YOUR_USERNAME/CounterStrikeSharp.git
|
||||
cd CounterStrikeSharp/
|
||||
```
|
||||
* After cloning, set a new remote [upstream](https://help.github.com/articles/configuring-a-remote-for-a-fork/) (this helps to keep your fork up to date)
|
||||
|
||||
```shell
|
||||
git remote add upstream https://github.com/roflmuffin/CounterStrikeSharp.git
|
||||
```
|
||||
|
||||
* Make your changes in a new git branch:
|
||||
|
||||
```shell
|
||||
git checkout -b my-fix-branch master
|
||||
```
|
||||
|
||||
* Create your patch and run appropriate tests.
|
||||
* Commit your changes using a descriptive commit message that uses the imperative, present tense: "change" not "changed" nor "changes".
|
||||
|
||||
```shell
|
||||
git commit -a
|
||||
```
|
||||
Note: the optional commit `-a` command line option will automatically "add" and "rm" edited files.
|
||||
|
||||
* Push your branch to GitHub:
|
||||
|
||||
```shell
|
||||
git push origin my-fix-branch
|
||||
```
|
||||
|
||||
In GitHub, send a pull request to `CounterStrikeSharp:master`.
|
||||
If we suggest changes, then:
|
||||
|
||||
* Make the required updates.
|
||||
* Re-run CounterStrikeSharp to ensure everything is still working & tests are passing.
|
||||
* Commit your changes to your branch (e.g. `my-fix-branch`).
|
||||
* Push the changes to your GitHub repository (this will update your Pull Request).
|
||||
|
||||
If the PR gets too outdated we may ask you to rebase and force push to update the PR:
|
||||
|
||||
```shell
|
||||
git fetch upstream
|
||||
git rebase upstream/master
|
||||
git push origin my-fix-branch -f
|
||||
```
|
||||
|
||||
That's it! Thank you for your contribution!
|
||||
|
||||
#### After your pull request is merged
|
||||
|
||||
After your pull request is merged, you can safely delete your branch and pull the changes
|
||||
from the main (upstream) repository.
|
||||
|
||||
[github]: https://github.com/roflmuffin/CounterStrikeSharp
|
||||
[discord]: https://discord.gg/eAZU3guKWU
|
||||
10
README.md
10
README.md
@@ -1,6 +1,6 @@
|
||||
# CounterStrikeSharp
|
||||
|
||||
CounterStrikeSharp is a server side modding framework for Counter-Strike: Global Offensive. This project attempts to implement a .NET Core scripting layer on top of a Metamod Source Plugin, allowing developers to create plugins that interact with the game server in a modern language (C#) to facilitate the creation of maintainable and testable code.
|
||||
CounterStrikeSharp is a server side modding framework for Counter-Strike 2. This project implements a .NET 8 scripting layer on top of a Metamod Source Plugin, allowing developers to create plugins that interact with the game server in a modern language (C#) to facilitate the creation of maintainable and testable code.
|
||||
|
||||
[Come and join our Discord](https://discord.gg/eAZU3guKWU)
|
||||
|
||||
@@ -18,14 +18,12 @@ Detailed installation instructions can be found in the [docs](https://docs.cssha
|
||||
|
||||
## What works?
|
||||
|
||||
_(Note, these were features in the previous VSP.NET project, but have not been implemented yet in this project)_
|
||||
|
||||
These features are the core of the platform and work pretty well/have a low risk of causing issues.
|
||||
|
||||
- [x] Console Commands, Server Commands (e.g. css_mycommand)
|
||||
- [x] Chat Commands with `!` and `/` prefixes (e.g. !mycommand)
|
||||
- [ ] **(In Progress)** Console Variables
|
||||
- [x] Game Event Handlers & Custom Events (e.g. player_death)
|
||||
- [x] Fake Console Variables (commands which mimic ConVar behaviour as these have not been fully reverse engineered)
|
||||
- [x] Game Event Handlers & Firing of Events (e.g. player_death)
|
||||
- [x] Basic event value get/set (string, bool, int32, float)
|
||||
- [x] Complex event values get/set (ehandle, pawn, player controller)
|
||||
- [x] Game Tick Based Timers (e.g. repeating map timers)
|
||||
@@ -34,7 +32,7 @@ These features are the core of the platform and work pretty well/have a low risk
|
||||
- [x] Client Listeners (e.g. connect, disconnect, put in server)
|
||||
- [x] OnMapStart
|
||||
- [x] OnTick
|
||||
- [x] Server Information (current map, game time, tick rate, model precaching)
|
||||
- [x] Server Information (current map, game time)
|
||||
- [x] Schema System Access (access player values like current weapon, money, location etc.)
|
||||
|
||||
## Links
|
||||
|
||||
@@ -3,5 +3,6 @@
|
||||
"SilentChatTrigger": [ "/" ],
|
||||
"FollowCS2ServerGuidelines": true,
|
||||
"PluginHotReloadEnabled": true,
|
||||
"PluginAutoLoadEnabled": true,
|
||||
"ServerLanguage": "en"
|
||||
}
|
||||
@@ -9,7 +9,7 @@ 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>.
|
||||
First, ensure you have the relevant .NET 8.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/8.0" target="_blank"> official Microsoft download page</a>.
|
||||
|
||||
### Creating a Class Library
|
||||
|
||||
@@ -25,7 +25,7 @@ Use your IDE (Visual Studio/Rider) to add a reference to the `CounterStrikeSharp
|
||||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
|
||||
<PropertyGroup>
|
||||
<TargetFramework>net7.0</TargetFramework>
|
||||
<TargetFramework>net8.0</TargetFramework>
|
||||
<ImplicitUsings>enable</ImplicitUsings>
|
||||
<Nullable>enable</Nullable>
|
||||
</PropertyGroup>
|
||||
@@ -65,7 +65,7 @@ public class HelloWorldPlugin : BasePlugin
|
||||
}
|
||||
```
|
||||
|
||||
Now build your project using your ide or the `dotnet build` command. You should now have a built binary file in your `bin/Debug/net7.0` subdirectory in the project.
|
||||
Now build your project using your ide or the `dotnet build` command. You should now have a built binary file in your `bin/Debug/net8.0` subdirectory in the project.
|
||||
|
||||
### Installing your Plugin
|
||||
|
||||
|
||||
@@ -33,6 +33,10 @@ receive a ban.
|
||||
|
||||
When enabled, plugins are automatically reloaded when their .dll file is updated.
|
||||
|
||||
## PluginAutoLoadEnabled
|
||||
|
||||
When enabled, plugins are automatically loaded from the plugins directory on server start.
|
||||
|
||||
## ServerLanguage
|
||||
|
||||
Configures the default language to use for server commands & messages. The format for the culture name based on RFC 4646 is `languagecode2-country`/`regioncode2`, where `languagecode2` is the two-letter language code and `country/regioncode2` is the two-letter subculture code. Examples include `ja-JP` for Japanese (Japan) and `en-US` for English (United States). Defaults to "en".
|
||||
37
eng/formatting/download-tools.ps1
Normal file
37
eng/formatting/download-tools.ps1
Normal file
@@ -0,0 +1,37 @@
|
||||
# Tool taken from dotnet/runtime
|
||||
# https://github.com/dotnet/runtime/blob/a8158c170b694f8c1dbae114c63c346b38244901/eng/formatting/download-tools.ps1
|
||||
|
||||
function DownloadClangTool {
|
||||
param (
|
||||
[string]
|
||||
$toolName,
|
||||
[string]
|
||||
$downloadOutputPath
|
||||
)
|
||||
|
||||
$clangVersion = "17.0.6"
|
||||
$clangToolsRootUrl = "https://clrjit2.blob.core.windows.net/clang-tools"
|
||||
$clangPlatform = "windows-x64"
|
||||
|
||||
$toolUrl = "$clangToolsRootUrl/$clangVersion/$clangPlatform/$toolName.exe"
|
||||
$targetPath = "$downloadOutputPath\$toolName.exe"
|
||||
|
||||
if (-not $(ls $downloadOutputPath | Where-Object { $_.Name -eq "$toolName.exe" })) {
|
||||
Write-Output "Downloading '$toolUrl' to '$targetPath'"
|
||||
# Pass -PassThru as otherwise Invoke-WebRequest leaves a corrupted file if the download fails. With -PassThru the download is buffered first.
|
||||
# -UseBasicParsing is necessary for older PowerShells when Internet Explorer might not be installed/configured
|
||||
$null = Invoke-WebRequest -Uri "$toolUrl" -OutFile $(Join-Path $downloadOutputPath -ChildPath "$toolName.exe") -PassThru -UseBasicParsing
|
||||
}
|
||||
else {
|
||||
Write-Output "Found '$targetPath'"
|
||||
}
|
||||
}
|
||||
|
||||
$downloadPathFolder = Split-Path $PSScriptRoot -Parent | Split-Path -Parent | Join-Path -ChildPath "artifacts" | Join-Path -ChildPath "tools"
|
||||
|
||||
mkdir $downloadPathFolder -ErrorAction SilentlyContinue
|
||||
|
||||
DownloadClangTool "clang-format" "$downloadPathFolder"
|
||||
|
||||
# Add to path to enable scripts to skip additional downloading steps since the tools will already be on the path.
|
||||
$env:PATH = "$downloadPathFolder;$env:PATH"
|
||||
60
eng/formatting/download-tools.sh
Normal file
60
eng/formatting/download-tools.sh
Normal file
@@ -0,0 +1,60 @@
|
||||
# Tool taken from dotnet/runtime
|
||||
# https://github.com/dotnet/runtime/blob/a8158c170b694f8c1dbae114c63c346b38244901/eng/formatting/download-tools.sh
|
||||
|
||||
#!/usr/bin/env bash
|
||||
|
||||
set -ue
|
||||
|
||||
source="${BASH_SOURCE[0]}"
|
||||
|
||||
# resolve $source until the file is no longer a symlink
|
||||
while [[ -h "$source" ]]; do
|
||||
scriptroot="$( cd -P "$( dirname "$source" )" && pwd )"
|
||||
source="$(readlink "$source")"
|
||||
# if $source was a relative symlink, we need to resolve it relative to the path where the
|
||||
# symlink file was located
|
||||
[[ $source != /* ]] && source="$scriptroot/$source"
|
||||
done
|
||||
scriptroot="$( cd -P "$( dirname "$source" )" && pwd )"
|
||||
|
||||
function DownloadClangTool {
|
||||
|
||||
clangVersion="17.0.6"
|
||||
clangToolsRootUrl="https://clrjit2.blob.core.windows.net/clang-tools"
|
||||
|
||||
clangPlatform="$(dotnet --info | grep 'RID:')"
|
||||
clangPlatform="${clangPlatform##*RID:* }"
|
||||
echo "dotnet RID: ${clangPlatform}"
|
||||
|
||||
# override common RIDs with compatible version so we don't need to upload binaries for each RID
|
||||
case $clangPlatform in
|
||||
ubuntu.*-x64)
|
||||
clangPlatform=linux-x64
|
||||
;;
|
||||
esac
|
||||
|
||||
toolUrl="${clangToolsRootUrl}/${clangVersion}/${clangPlatform}/$1"
|
||||
toolOutput=$2/$1
|
||||
|
||||
echo "Downloading $1 from ${toolUrl} to ${toolOutput}"
|
||||
|
||||
if [[ ! -x "$toolOutput" ]]; then
|
||||
curl --silent --retry 5 --fail -o "${toolOutput}" "$toolUrl"
|
||||
chmod 751 $toolOutput
|
||||
fi
|
||||
|
||||
if [[ ! -x "$toolOutput" ]]; then
|
||||
echo "Failed to download $1"
|
||||
exit 1
|
||||
fi
|
||||
}
|
||||
|
||||
|
||||
engFolder="$(cd -P "$( dirname "$scriptroot" )" && pwd )"
|
||||
downloadPathFolder="$(cd -P "$( dirname "$engFolder" )" && pwd )/artifacts/tools"
|
||||
|
||||
mkdir -p "$downloadPathFolder"
|
||||
|
||||
DownloadClangTool "clang-format" "$downloadPathFolder"
|
||||
|
||||
export PATH=$downloadPathFolder:$PATH
|
||||
29
eng/formatting/format.sh
Normal file
29
eng/formatting/format.sh
Normal file
@@ -0,0 +1,29 @@
|
||||
# Tool taken from dotnet/runtime
|
||||
# https://github.com/dotnet/runtime/blob/a8158c170b694f8c1dbae114c63c346b38244901/eng/formatting/format.sh
|
||||
|
||||
#!/bin/sh
|
||||
|
||||
LC_ALL=C
|
||||
# Select files to format
|
||||
NATIVE_FILES=$(git diff --cached --name-only --diff-filter=ACM "*.h" "*.hpp" "*.c" "*.cpp" "*.inl" | sed 's| |\\ |g')
|
||||
MANAGED_FILES=$(git diff --cached --name-only --diff-filter=ACM "*.cs" "*.vb" | sed 's| |\\ |g')
|
||||
|
||||
exec 1>&2
|
||||
|
||||
if [ -n "$NATIVE_FILES" ]; then
|
||||
# Format all selected files
|
||||
echo "$NATIVE_FILES" | cat | xargs | sed -e 's/ /,/g' | xargs "./artifacts/tools/clang-format" -style=file -i
|
||||
|
||||
# Add back the modified files to staging
|
||||
echo "$NATIVE_FILES" | xargs git add
|
||||
fi
|
||||
|
||||
if [ -n "$MANAGED_FILES" ]; then
|
||||
# Format all selected files
|
||||
echo "$MANAGED_FILES" | cat | xargs | sed -e 's/ /,/g' | dotnet format whitespace --include - --folder
|
||||
|
||||
# Add back the modified files to staging
|
||||
echo "$MANAGED_FILES" | xargs git add
|
||||
fi
|
||||
|
||||
exit 0
|
||||
71
eng/install/install.ps1
Normal file
71
eng/install/install.ps1
Normal file
@@ -0,0 +1,71 @@
|
||||
# Install script that downloads Metamod:Source and Counter-Strike Sharp (with runtime)
|
||||
|
||||
$MM_DOWNLOAD_URL = "https://mms.alliedmods.net/mmsdrop/2.0/mmsource-2.0.0-git1286-windows.zip"
|
||||
$TARGET_DIR = "./game/csgo"
|
||||
$GAMEINFO_FILE = Join-Path $TARGET_DIR "gameinfo.gi"
|
||||
$ProgressPreference = 'SilentlyContinue'
|
||||
|
||||
# Verification
|
||||
if (-not (Test-Path $GAMEINFO_FILE)) {
|
||||
Write-Error "Error: $GAMEINFO_FILE does not exist in the specified directory."
|
||||
exit 1
|
||||
}
|
||||
|
||||
# GitHub API for Counter-Strike Sharp Releases
|
||||
$RELEASE_INFO = (Invoke-WebRequest -Uri "https://api.github.com/repos/roflmuffin/CounterStrikeSharp/releases/latest").Content | ConvertFrom-Json
|
||||
|
||||
# Filtering download URLs
|
||||
$CSSHARP_DOWNLOAD_URL = $RELEASE_INFO.assets |
|
||||
Where-Object { $_.browser_download_url -like '*windows*.zip*' -and $_.browser_download_url -notlike '*with-runtime*' } |
|
||||
Select-Object -First 1 -ExpandProperty browser_download_url
|
||||
|
||||
$CSSHARP_RUNTIME_DOWNLOAD_URL = $RELEASE_INFO.assets |
|
||||
Where-Object { $_.browser_download_url -like '*windows*.zip*' -and $_.browser_download_url -like '*with-runtime*' } |
|
||||
Select-Object -First 1 -ExpandProperty browser_download_url
|
||||
|
||||
### METAMOD:SOURCE ###
|
||||
Write-Output "Downloading Metamod:Source..."
|
||||
|
||||
Invoke-WebRequest -Uri $MM_DOWNLOAD_URL -OutFile metamod.zip
|
||||
Write-Output "Extracting Metamod:Source to $TARGET_DIR..."
|
||||
Expand-Archive -Force -Path metamod.zip -DestinationPath $TARGET_DIR
|
||||
Remove-Item metamod.zip
|
||||
|
||||
### GAMEINFO.GI UPDATE ###
|
||||
$NEW_ENTRY = " Game csgo/addons/metamod"
|
||||
$FILE_CONTENT = Get-Content $GAMEINFO_FILE
|
||||
|
||||
Write-Output "Updating $GAMEINFO_FILE..."
|
||||
if ($FILE_CONTENT -contains $NEW_ENTRY) {
|
||||
Write-Output "The entry '$NEW_ENTRY' already exists in $GAMEINFO_FILE. No changes were made."
|
||||
} else {
|
||||
$Pattern = "Game_LowViolence"
|
||||
$Modified = $false
|
||||
$NewContent = @()
|
||||
|
||||
foreach ($line in $FILE_CONTENT) {
|
||||
if ($line -match $Pattern -and -not $Modified) {
|
||||
$NewContent += $line
|
||||
$NewContent += $NEW_ENTRY
|
||||
$Modified = $true
|
||||
} else {
|
||||
$NewContent += $line
|
||||
}
|
||||
}
|
||||
|
||||
$NewContent | Set-Content $GAMEINFO_FILE
|
||||
Write-Host "The file $GAMEINFO_FILE has been modified successfully. '$NEW_ENTRY' has been added."
|
||||
}
|
||||
|
||||
### COUNTER-STRIKE SHARP ###
|
||||
Write-Output "Downloading Counter-Strike Sharp (with runtime)..."
|
||||
|
||||
# Determine if runtime needs to be downloaded
|
||||
if (-not (Test-Path "./game/csgo/addons/CounterStrikeSharp/dotnet/dotnet.exe")) {
|
||||
$CSSHARP_DOWNLOAD_URL = $CSSHARP_RUNTIME_DOWNLOAD_URL
|
||||
}
|
||||
|
||||
Invoke-WebRequest -Uri $CSSHARP_DOWNLOAD_URL -OutFile cssharp.zip
|
||||
Write-Output "Extracting Counter-Strike Sharp to $TARGET_DIR..."
|
||||
Expand-Archive -Force -Path cssharp.zip -DestinationPath $TARGET_DIR
|
||||
Remove-Item cssharp.zip
|
||||
72
eng/install/install.sh
Executable file
72
eng/install/install.sh
Executable file
@@ -0,0 +1,72 @@
|
||||
#!/bin/bash
|
||||
|
||||
# Install script that downloads Metamod:Source and Counter-Strike Sharp (with runtime)
|
||||
|
||||
MM_DOWNLOAD_URL="https://mms.alliedmods.net/mmsdrop/2.0/mmsource-2.0.0-git1286-linux.tar.gz"
|
||||
TARGET_DIR="./game/csgo"
|
||||
GAMEINFO_FILE="${TARGET_DIR}/gameinfo.gi"
|
||||
|
||||
if [ ! -f "${GAMEINFO_FILE}" ]; then
|
||||
printf "Error: %s does not exist in the specified directory.\n" "$GAMEINFO_FILE"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
RELEASE_INFO=$(curl -s https://api.github.com/repos/roflmuffin/CounterStrikeSharp/releases/latest)
|
||||
|
||||
# Filter and store download URLs
|
||||
CSSHARP_DOWNLOAD_URL=$(echo "$RELEASE_INFO" | grep -o "browser_download_url.*linux.*\.zip" | cut -d '"' -f 3 | grep -v "with-runtime")
|
||||
CSSHARP_RUNTIME_DOWNLOAD_URL=$(echo "$RELEASE_INFO" | grep -o "browser_download_url.*linux.*\.zip" | cut -d '"' -f 3 | grep "with-runtime")
|
||||
|
||||
### METAMOD:SOURCE ###
|
||||
printf "Downloading Metamod:Source...\n"
|
||||
|
||||
curl -s -L -o metamod.tar.gz "$MM_DOWNLOAD_URL"
|
||||
|
||||
if [ $? -eq 0 ]; then
|
||||
printf "Extracting Metamod:Source to %s...\n" "$TARGET_DIR"
|
||||
tar -xzf metamod.tar.gz -C "$TARGET_DIR"
|
||||
|
||||
rm metamod.tar.gz
|
||||
else
|
||||
echo "Download failed. Please check the URL and your connection."
|
||||
fi
|
||||
|
||||
### GAMEINFO.GI UPDATE ###
|
||||
NEW_ENTRY=" Game csgo/addons/metamod"
|
||||
|
||||
printf "Updating %s...\n" "$GAMEINFO_FILE"
|
||||
if grep -Fxq "$NEW_ENTRY" "$GAMEINFO_FILE"; then
|
||||
echo "The entry '$(echo $NEW_ENTRY | xargs)' already exists in ${GAMEINFO_FILE}. No changes were made."
|
||||
else
|
||||
awk -v new_entry="$NEW_ENTRY" '
|
||||
BEGIN { found=0; }
|
||||
// {
|
||||
if (found) {
|
||||
print new_entry;
|
||||
found=0;
|
||||
}
|
||||
print;
|
||||
}
|
||||
/Game_LowViolence/ { found=1; }
|
||||
' "$GAMEINFO_FILE" > "$GAMEINFO_FILE.tmp" && mv "$GAMEINFO_FILE.tmp" "$GAMEINFO_FILE"
|
||||
|
||||
printf "The file %s has been modified successfully. '%s' has been added.\n" "$GAMEINFO_FILE" "$(echo $NEW_ENTRY | xargs)"
|
||||
fi
|
||||
|
||||
printf "Downloading Counter-Strike Sharp (with runtime)...\n"
|
||||
|
||||
# If ./game/csgo/addons/CounterStrikeSharp/dotnet/dotnet does not exist, use the runtime download url
|
||||
if [ ! -f "./game/csgo/addons/CounterStrikeSharp/dotnet/dotnet" ]; then
|
||||
CSSHARP_DOWNLOAD_URL="$CSSHARP_RUNTIME_DOWNLOAD_URL"
|
||||
fi
|
||||
|
||||
curl -s -L -o cssharp.zip "$CSSHARP_DOWNLOAD_URL"
|
||||
|
||||
if [ $? -eq 0 ]; then
|
||||
printf "Extracting Counter-Strike Sharp to %s...\n" "$TARGET_DIR"
|
||||
unzip -q -o cssharp.zip -d "$TARGET_DIR"
|
||||
|
||||
rm cssharp.zip
|
||||
else
|
||||
echo "Download failed. Please check the URL and your connection."
|
||||
fi
|
||||
@@ -1,6 +1,6 @@
|
||||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
<PropertyGroup>
|
||||
<TargetFramework>net7.0</TargetFramework>
|
||||
<TargetFramework>net8.0</TargetFramework>
|
||||
<ImplicitUsings>enable</ImplicitUsings>
|
||||
<Nullable>enable</Nullable>
|
||||
<GenerateAssemblyInfo>false</GenerateAssemblyInfo>
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
|
||||
<PropertyGroup>
|
||||
<TargetFramework>net7.0</TargetFramework>
|
||||
<TargetFramework>net8.0</TargetFramework>
|
||||
<ImplicitUsings>enable</ImplicitUsings>
|
||||
<Nullable>enable</Nullable>
|
||||
</PropertyGroup>
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
<PropertyGroup>
|
||||
<TargetFramework>net7.0</TargetFramework>
|
||||
<TargetFramework>net8.0</TargetFramework>
|
||||
<OutputType>Library</OutputType>
|
||||
<GenerateAssemblyInfo>false</GenerateAssemblyInfo>
|
||||
<CopyLocalLockFileAssemblies>true</CopyLocalLockFileAssemblies>
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
<PropertyGroup>
|
||||
<TargetFramework>net7.0</TargetFramework>
|
||||
<TargetFramework>net8.0</TargetFramework>
|
||||
<ImplicitUsings>enable</ImplicitUsings>
|
||||
<Nullable>enable</Nullable>
|
||||
<GenerateAssemblyInfo>false</GenerateAssemblyInfo>
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
<PropertyGroup>
|
||||
<TargetFramework>net7.0</TargetFramework>
|
||||
<TargetFramework>net8.0</TargetFramework>
|
||||
<ImplicitUsings>enable</ImplicitUsings>
|
||||
<Nullable>enable</Nullable>
|
||||
<GenerateAssemblyInfo>false</GenerateAssemblyInfo>
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
<PropertyGroup>
|
||||
<TargetFramework>net7.0</TargetFramework>
|
||||
<TargetFramework>net8.0</TargetFramework>
|
||||
<ImplicitUsings>enable</ImplicitUsings>
|
||||
<Nullable>enable</Nullable>
|
||||
<GenerateAssemblyInfo>false</GenerateAssemblyInfo>
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
<PropertyGroup>
|
||||
<TargetFramework>net7.0</TargetFramework>
|
||||
<TargetFramework>net8.0</TargetFramework>
|
||||
<ImplicitUsings>enable</ImplicitUsings>
|
||||
<Nullable>enable</Nullable>
|
||||
<GenerateAssemblyInfo>false</GenerateAssemblyInfo>
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
<PropertyGroup>
|
||||
<TargetFramework>net7.0</TargetFramework>
|
||||
<TargetFramework>net8.0</TargetFramework>
|
||||
<ImplicitUsings>enable</ImplicitUsings>
|
||||
<Nullable>enable</Nullable>
|
||||
<GenerateAssemblyInfo>false</GenerateAssemblyInfo>
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
<PropertyGroup>
|
||||
<TargetFramework>net7.0</TargetFramework>
|
||||
<TargetFramework>net8.0</TargetFramework>
|
||||
<ImplicitUsings>enable</ImplicitUsings>
|
||||
<Nullable>enable</Nullable>
|
||||
<GenerateAssemblyInfo>false</GenerateAssemblyInfo>
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
<PropertyGroup>
|
||||
<TargetFramework>net7.0</TargetFramework>
|
||||
<TargetFramework>net8.0</TargetFramework>
|
||||
<ImplicitUsings>enable</ImplicitUsings>
|
||||
<Nullable>enable</Nullable>
|
||||
<GenerateAssemblyInfo>false</GenerateAssemblyInfo>
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
<PropertyGroup>
|
||||
<TargetFramework>net7.0</TargetFramework>
|
||||
<TargetFramework>net8.0</TargetFramework>
|
||||
<ImplicitUsings>enable</ImplicitUsings>
|
||||
<Nullable>enable</Nullable>
|
||||
<GenerateAssemblyInfo>false</GenerateAssemblyInfo>
|
||||
|
||||
@@ -5,7 +5,7 @@ using MySharedTypes.Contracts;
|
||||
|
||||
namespace WithSharedTypes;
|
||||
|
||||
[MinimumApiVersion(143)]
|
||||
[MinimumApiVersion(184)]
|
||||
public class WithSharedTypesPlugin : BasePlugin
|
||||
{
|
||||
public override string ModuleName => "Example: Shared Types";
|
||||
@@ -54,4 +54,4 @@ public class WithSharedTypesPlugin : BasePlugin
|
||||
public override void Unload(bool hotReload)
|
||||
{
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
<PropertyGroup>
|
||||
<TargetFramework>net7.0</TargetFramework>
|
||||
<TargetFramework>net8.0</TargetFramework>
|
||||
<ImplicitUsings>enable</ImplicitUsings>
|
||||
<Nullable>enable</Nullable>
|
||||
<GenerateAssemblyInfo>false</GenerateAssemblyInfo>
|
||||
|
||||
@@ -6,7 +6,7 @@ using MySharedTypes.Contracts;
|
||||
|
||||
namespace WithSharedTypesConsumer;
|
||||
|
||||
[MinimumApiVersion(142)]
|
||||
[MinimumApiVersion(184)]
|
||||
public class WithSharedTypesConsumerPlugin : BasePlugin
|
||||
{
|
||||
public override string ModuleName => "Example: Shared Types (Consumer)";
|
||||
@@ -53,4 +53,4 @@ public class WithSharedTypesConsumerPlugin : BasePlugin
|
||||
public override void Unload(bool hotReload)
|
||||
{
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
<PropertyGroup>
|
||||
<TargetFramework>net7.0</TargetFramework>
|
||||
<TargetFramework>net8.0</TargetFramework>
|
||||
<ImplicitUsings>enable</ImplicitUsings>
|
||||
<Nullable>enable</Nullable>
|
||||
<GenerateAssemblyInfo>false</GenerateAssemblyInfo>
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
<PropertyGroup>
|
||||
<TargetFramework>net7.0</TargetFramework>
|
||||
<TargetFramework>net8.0</TargetFramework>
|
||||
<ImplicitUsings>enable</ImplicitUsings>
|
||||
<Nullable>enable</Nullable>
|
||||
<GenerateAssemblyInfo>false</GenerateAssemblyInfo>
|
||||
|
||||
Submodule libraries/hl2sdk-cs2 updated: 43bfe744a1...aaaaaf040b
3747
libraries/moodycamel/concurrentqueue.h
Normal file
3747
libraries/moodycamel/concurrentqueue.h
Normal file
File diff suppressed because it is too large
Load Diff
@@ -12,7 +12,7 @@ set(CMAKE_CONFIGURATION_TYPES "Debug;Release" CACHE STRING
|
||||
)
|
||||
|
||||
# TODO: Use C++20 instead.
|
||||
set(CMAKE_CXX_STANDARD 17)
|
||||
set(CMAKE_CXX_STANDARD 20)
|
||||
|
||||
if (LINUX)
|
||||
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fPIC")
|
||||
@@ -29,6 +29,18 @@ set(SOURCESDK_LIB ${SOURCESDK}/lib)
|
||||
|
||||
add_definitions(-DMETA_IS_SOURCE2)
|
||||
|
||||
if(DEFINED ENV{GITHUB_SHA_SHORT})
|
||||
add_definitions(-DGITHUB_SHA="$ENV{GITHUB_SHA_SHORT}")
|
||||
else()
|
||||
add_definitions(-DGITHUB_SHA="Local")
|
||||
endif()
|
||||
|
||||
if(DEFINED ENV{BUILD_NUMBER})
|
||||
add_definitions(-DBUILD_NUMBER="$ENV{BUILD_NUMBER}")
|
||||
else()
|
||||
add_definitions(-DBUILD_NUMBER="0")
|
||||
endif()
|
||||
|
||||
include_directories(
|
||||
${SOURCESDK}
|
||||
${SOURCESDK}/thirdparty/protobuf-3.21.8/src
|
||||
@@ -43,6 +55,7 @@ include_directories(
|
||||
${SOURCESDK}/public/entity2
|
||||
${SOURCESDK}/public/game/server
|
||||
${SOURCESDK}/public/entity2
|
||||
${SOURCESDK}/public/schemasystem
|
||||
${METAMOD_DIR}/core
|
||||
${METAMOD_DIR}/core/sourcehook
|
||||
libraries/dyncall/dynload
|
||||
@@ -51,6 +64,7 @@ include_directories(
|
||||
libraries/tl
|
||||
libraries/funchook/include
|
||||
libraries/DynoHook/src
|
||||
libraries/moodycamel
|
||||
libraries
|
||||
)
|
||||
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
|
||||
<PropertyGroup>
|
||||
<TargetFramework>net7.0</TargetFramework>
|
||||
<TargetFramework>net8.0</TargetFramework>
|
||||
<ImplicitUsings>enable</ImplicitUsings>
|
||||
<Nullable>enable</Nullable>
|
||||
|
||||
|
||||
@@ -13,4 +13,14 @@ public class Api
|
||||
{
|
||||
return Assembly.GetAssembly(typeof(BasePlugin))!.GetName().Version!.Build;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Returns the assembly version of CounterStrikeSharp running on the server as a string including git commit hash
|
||||
/// </summary>
|
||||
/// <example>1.0.0+9d8b6be</example>
|
||||
public static string GetVersionString()
|
||||
{
|
||||
return Assembly.GetAssembly(typeof(BasePlugin))!.GetCustomAttribute<AssemblyInformationalVersionAttribute>()!
|
||||
.InformationalVersion;
|
||||
}
|
||||
}
|
||||
Binary file not shown.
BIN
managed/CounterStrikeSharp.API/ApiCompat/v202.dll
Normal file
BIN
managed/CounterStrikeSharp.API/ApiCompat/v202.dll
Normal file
Binary file not shown.
File diff suppressed because it is too large
Load Diff
@@ -315,16 +315,6 @@ namespace CounterStrikeSharp.API.Core
|
||||
}
|
||||
}
|
||||
|
||||
public static float GetGameFrameTime(){
|
||||
lock (ScriptContext.GlobalScriptContext.Lock) {
|
||||
ScriptContext.GlobalScriptContext.Reset();
|
||||
ScriptContext.GlobalScriptContext.SetIdentifier(0x97E331CA);
|
||||
ScriptContext.GlobalScriptContext.Invoke();
|
||||
ScriptContext.GlobalScriptContext.CheckErrors();
|
||||
return (float)ScriptContext.GlobalScriptContext.GetResult(typeof(float));
|
||||
}
|
||||
}
|
||||
|
||||
public static double GetEngineTime(){
|
||||
lock (ScriptContext.GlobalScriptContext.Lock) {
|
||||
ScriptContext.GlobalScriptContext.Reset();
|
||||
@@ -512,6 +502,17 @@ namespace CounterStrikeSharp.API.Core
|
||||
}
|
||||
}
|
||||
|
||||
public static void QueueTaskForFrame(int tick, InputArgument callback){
|
||||
lock (ScriptContext.GlobalScriptContext.Lock) {
|
||||
ScriptContext.GlobalScriptContext.Reset();
|
||||
ScriptContext.GlobalScriptContext.Push(tick);
|
||||
ScriptContext.GlobalScriptContext.Push((InputArgument)callback);
|
||||
ScriptContext.GlobalScriptContext.SetIdentifier(0x2F92C340);
|
||||
ScriptContext.GlobalScriptContext.Invoke();
|
||||
ScriptContext.GlobalScriptContext.CheckErrors();
|
||||
}
|
||||
}
|
||||
|
||||
public static void QueueTaskForNextWorldUpdate(InputArgument callback){
|
||||
lock (ScriptContext.GlobalScriptContext.Lock) {
|
||||
ScriptContext.GlobalScriptContext.Reset();
|
||||
@@ -749,6 +750,16 @@ namespace CounterStrikeSharp.API.Core
|
||||
}
|
||||
}
|
||||
|
||||
public static void FreeEvent(IntPtr gameevent){
|
||||
lock (ScriptContext.GlobalScriptContext.Lock) {
|
||||
ScriptContext.GlobalScriptContext.Reset();
|
||||
ScriptContext.GlobalScriptContext.Push(gameevent);
|
||||
ScriptContext.GlobalScriptContext.SetIdentifier(0x7E8B60C2);
|
||||
ScriptContext.GlobalScriptContext.Invoke();
|
||||
ScriptContext.GlobalScriptContext.CheckErrors();
|
||||
}
|
||||
}
|
||||
|
||||
public static void FireEvent(IntPtr gameevent, bool dontbroadcast){
|
||||
lock (ScriptContext.GlobalScriptContext.Lock) {
|
||||
ScriptContext.GlobalScriptContext.Reset();
|
||||
@@ -1085,6 +1096,16 @@ namespace CounterStrikeSharp.API.Core
|
||||
}
|
||||
}
|
||||
|
||||
public static void RemoveAllNetworkVectorElements(IntPtr vec){
|
||||
lock (ScriptContext.GlobalScriptContext.Lock) {
|
||||
ScriptContext.GlobalScriptContext.Reset();
|
||||
ScriptContext.GlobalScriptContext.Push(vec);
|
||||
ScriptContext.GlobalScriptContext.SetIdentifier(0x67206C08);
|
||||
ScriptContext.GlobalScriptContext.Invoke();
|
||||
ScriptContext.GlobalScriptContext.CheckErrors();
|
||||
}
|
||||
}
|
||||
|
||||
public static short GetSchemaOffset(string classname, string propname){
|
||||
lock (ScriptContext.GlobalScriptContext.Lock) {
|
||||
ScriptContext.GlobalScriptContext.Reset();
|
||||
|
||||
@@ -106,13 +106,13 @@ namespace CounterStrikeSharp.API.Core
|
||||
[RequiresPermissions("@css/generic")]
|
||||
private void OnCSSCommand(CCSPlayerController? caller, CommandInfo info)
|
||||
{
|
||||
var currentVersion = Api.GetVersion();
|
||||
var versionString = $"v{Api.GetVersion()} ({Api.GetVersionString()})";
|
||||
|
||||
info.ReplyToCommand(
|
||||
" CounterStrikeSharp was created and is maintained by Michael \"roflmuffin\" Wilson.\n" +
|
||||
" Counter-Strike Sharp uses code borrowed from SourceMod, Source.Python, FiveM, Saul Rennison, source2gen and CS2Fixes.\n" +
|
||||
" See ACKNOWLEDGEMENTS.md for more information.\n" +
|
||||
" Current API Version: " + currentVersion);
|
||||
" Current API Version: " + versionString);
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
@@ -122,9 +122,6 @@ namespace CounterStrikeSharp.API.Core
|
||||
public readonly Dictionary<Delegate, CallbackSubscriber> CommandListeners =
|
||||
new Dictionary<Delegate, CallbackSubscriber>();
|
||||
|
||||
public readonly Dictionary<Delegate, CallbackSubscriber> ConvarChangeHandlers =
|
||||
new Dictionary<Delegate, CallbackSubscriber>();
|
||||
|
||||
public readonly Dictionary<Delegate, CallbackSubscriber> Listeners =
|
||||
new Dictionary<Delegate, CallbackSubscriber>();
|
||||
|
||||
@@ -159,7 +156,23 @@ namespace CounterStrikeSharp.API.Core
|
||||
var name = typeof(T).GetCustomAttribute<EventNameAttribute>()?.Name;
|
||||
RegisterEventHandlerInternal(name, handler, hookMode == HookMode.Post);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// De-registers a game event handler.
|
||||
/// </summary>
|
||||
/// <inheritdoc cref="RegisterEventHandler{T}"/>
|
||||
public void DeregisterEventHandler<T>(GameEventHandler<T> handler, HookMode hookMode = HookMode.Post) where T : GameEvent
|
||||
{
|
||||
var name = typeof(T).GetCustomAttribute<EventNameAttribute>()!.Name;
|
||||
|
||||
if (!Handlers.TryGetValue(handler, out var subscriber)) return;
|
||||
|
||||
NativeAPI.UnhookEvent(name, subscriber.GetInputArgument(), hookMode == HookMode.Post);
|
||||
FunctionReference.Remove(subscriber.GetReferenceIdentifier());
|
||||
Handlers.Remove(handler);
|
||||
}
|
||||
|
||||
[Obsolete("Use the generic version of this method")]
|
||||
public void DeregisterEventHandler(string name, Delegate handler, bool post)
|
||||
{
|
||||
if (!Handlers.TryGetValue(handler, out var subscriber)) return;
|
||||
@@ -187,6 +200,12 @@ namespace CounterStrikeSharp.API.Core
|
||||
CommandManager.RegisterCommand(definition);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Adds a command listener which will be called before or after the command is executed on the server by a player.
|
||||
/// </summary>
|
||||
/// <param name="name">Name of the command, e.g. `jointeam`</param>
|
||||
/// <param name="handler">Code to run when command is executed. Return <see cref="HookResult.Handled"/> or higher to prevent command execution.</param>
|
||||
/// <param name="mode">Whether to hook before or after the command is executed.</param>
|
||||
public void AddCommandListener(string? name, CommandInfo.CommandListenerCallback handler, HookMode mode = HookMode.Pre)
|
||||
{
|
||||
var wrappedHandler = new Func<int, IntPtr, HookResult>((i, ptr) =>
|
||||
@@ -202,6 +221,11 @@ namespace CounterStrikeSharp.API.Core
|
||||
CommandListeners[handler] = subscriber;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Removes a server command.
|
||||
/// </summary>
|
||||
/// <param name="name">The name of the command.</param>
|
||||
/// <param name="handler">The callback function to be invoked when the command is executed.</param>
|
||||
public void RemoveCommand(string name, CommandInfo.CommandCallback handler)
|
||||
{
|
||||
if (CommandHandlers.ContainsKey(handler))
|
||||
@@ -215,6 +239,10 @@ namespace CounterStrikeSharp.API.Core
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Remove a command listener.
|
||||
/// </summary>
|
||||
/// <inheritdoc cref="AddCommandListener"/>
|
||||
public void RemoveCommandListener(string name, CommandInfo.CommandListenerCallback handler, HookMode mode)
|
||||
{
|
||||
if (CommandListeners.ContainsKey(handler))
|
||||
@@ -228,39 +256,24 @@ namespace CounterStrikeSharp.API.Core
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
|
||||
public void HookConVarChange(ConVar convar, ConVar.ConVarChangedCallback handler)
|
||||
{
|
||||
var wrappedHandler = new Action<IntPtr, string, string>((ptr, oldVal, newVal) =>
|
||||
{
|
||||
handler?.Invoke(new ConVar(ptr), oldVal, newVal);
|
||||
});
|
||||
|
||||
var subscriber = new CallbackSubscriber(convar, handler, wrappedHandler);
|
||||
NativeAPI.HookConvarChange(convar.Handle, subscriber.GetInputArgument());
|
||||
ConvarChangeHandlers[handler] = subscriber;
|
||||
}
|
||||
|
||||
public void UnhookConVarChange(ConVar convar, ConVar.ConVarChangedCallback handler)
|
||||
{
|
||||
if (ConvarChangeHandlers.ContainsKey(handler))
|
||||
{
|
||||
var subscriber = ConvarChangeHandlers[handler];
|
||||
|
||||
NativeAPI.UnhookConvarChange(convar.Handle, subscriber.GetInputArgument());
|
||||
FunctionReference.Remove(subscriber.GetReferenceIdentifier());
|
||||
CommandHandlers.Remove(handler);
|
||||
}
|
||||
}*/
|
||||
|
||||
// Adds global listener, e.g. OnTick, OnClientConnect
|
||||
/// <summary>
|
||||
/// Registers a global listener, e.g. <see cref="Listeners.OnTick"/>, <see cref="Listeners.OnClientConnect"/>.
|
||||
/// </summary>
|
||||
/// <param name="handler"></param>
|
||||
/// <typeparam name="T">Listener delegate type</typeparam>
|
||||
/// <exception cref="ArgumentException">Invalid listener <see cref="T"/> provided</exception>
|
||||
/// <example>
|
||||
/// <code lang="C#">
|
||||
/// RegisterListener<Listeners.OnTick>(OnTick);
|
||||
/// </code>
|
||||
/// </example>
|
||||
public void RegisterListener<T>(T handler) where T : Delegate
|
||||
{
|
||||
var listenerName = typeof(T).GetCustomAttribute<ListenerNameAttribute>()?.Name;
|
||||
if (string.IsNullOrEmpty(listenerName))
|
||||
{
|
||||
throw new Exception("Listener of type T is invalid and does not have a name attribute");
|
||||
throw new ArgumentException("Listener of type T is invalid and does not have a name attribute",
|
||||
nameof(T));
|
||||
}
|
||||
|
||||
var parameterTypes = typeof(T).GetMethod("Invoke").GetParameters().Select(p => p.ParameterType).ToArray();
|
||||
@@ -291,6 +304,34 @@ namespace CounterStrikeSharp.API.Core
|
||||
Listeners[handler] = subscriber;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Removes a global listener.
|
||||
/// </summary>
|
||||
/// <param name="handler"></param>
|
||||
/// <typeparam name="T"></typeparam>
|
||||
/// <exception cref="ArgumentException">Invalid listener <see cref="T"/> provided</exception>
|
||||
public void RemoveListener<T>(T handler) where T : Delegate
|
||||
{
|
||||
var listenerName = typeof(T).GetCustomAttribute<ListenerNameAttribute>()?.Name;
|
||||
if (string.IsNullOrEmpty(listenerName))
|
||||
{
|
||||
throw new ArgumentException("Listener of type T is invalid and does not have a name attribute",
|
||||
nameof(T));
|
||||
}
|
||||
|
||||
if (!Listeners.TryGetValue(handler, out var subscriber)) return;
|
||||
|
||||
NativeAPI.RemoveListener(listenerName, subscriber.GetInputArgument());
|
||||
FunctionReference.Remove(subscriber.GetReferenceIdentifier());
|
||||
Listeners.Remove(handler);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Removes a global listener.
|
||||
/// </summary>
|
||||
/// <param name="name"></param>
|
||||
/// <param name="handler"></param>
|
||||
[Obsolete("Use the generic version of this method")]
|
||||
public void RemoveListener(string name, Delegate handler)
|
||||
{
|
||||
if (!Listeners.TryGetValue(handler, out var subscriber)) return;
|
||||
@@ -300,6 +341,14 @@ namespace CounterStrikeSharp.API.Core
|
||||
Listeners.Remove(handler);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Adds a timer that will call the given callback after the specified amount of seconds.
|
||||
/// By default will only run once unless the <see cref="TimerFlags.REPEAT"/> flag is set.
|
||||
/// </summary>
|
||||
/// <param name="interval">Interval/Delay in seconds</param>
|
||||
/// <param name="callback">Code to run when timer elapses</param>
|
||||
/// <param name="flags">Controls if the timer is a one-off, repeat or stops on map change etc.</param>
|
||||
/// <returns>An instance of the <see cref="Timer"/></returns>
|
||||
public Timer AddTimer(float interval, Action callback, TimerFlags? flags = null)
|
||||
{
|
||||
var timer = new Timer(interval, callback, flags ?? 0);
|
||||
@@ -307,7 +356,11 @@ namespace CounterStrikeSharp.API.Core
|
||||
return timer;
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Registers all attribute handlers on the given instance.
|
||||
/// Can be used to register event handlers, console commands, entity outputs etc. from classes that are not derived from `BasePlugin`.
|
||||
/// </summary>
|
||||
/// <param name="instance"></param>
|
||||
public void RegisterAllAttributes(object instance)
|
||||
{
|
||||
this.RegisterAttributeHandlers(instance);
|
||||
@@ -342,7 +395,7 @@ namespace CounterStrikeSharp.API.Core
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Registers all game event handlers that are decorated with the `[GameEventHandler]` attribute.
|
||||
/// Registers all game event handlers that are decorated with the <see cref="GameEventHandlerAttribute"/> attribute.
|
||||
/// </summary>
|
||||
/// <param name="instance">The instance of the object where the event handlers are defined.</param>
|
||||
public void RegisterAttributeHandlers(object instance)
|
||||
@@ -372,6 +425,10 @@ namespace CounterStrikeSharp.API.Core
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Registers all console command handlers that are decorated with the <see cref="ConsoleCommandAttribute"/> attribute.
|
||||
/// </summary>
|
||||
/// <param name="instance">The instance of the object where the console command handlers are defined.</param>
|
||||
public void RegisterConsoleCommandAttributeHandlers(object instance)
|
||||
{
|
||||
var eventHandlers = instance.GetType()
|
||||
@@ -399,6 +456,10 @@ namespace CounterStrikeSharp.API.Core
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Registers all entity output handlers that are decorated with the <see cref="EntityOutputHookAttribute"/> attribute.
|
||||
/// </summary>
|
||||
/// <param name="instance">The instance of the object where entity output hook handlers are defined.</param>
|
||||
public void RegisterEntityOutputAttributeHandlers(object instance)
|
||||
{
|
||||
var handlers = instance.GetType()
|
||||
@@ -453,6 +514,12 @@ namespace CounterStrikeSharp.API.Core
|
||||
RegisterFakeConVars(instance.GetType(), instance);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Hooks an <a href="https://developer.valvesoftware.com/wiki/Inputs_and_Outputs">entity output</a>.
|
||||
/// </summary>
|
||||
/// <param name="classname">Classname to hook, or `*` for wildcard</param>
|
||||
/// <param name="outputName">Output name to hook, or `*` for wildcard</param>
|
||||
/// <param name="handler">Handler to call</param>
|
||||
public void HookEntityOutput(string classname, string outputName, EntityIO.EntityOutputHandler handler, HookMode mode = HookMode.Pre)
|
||||
{
|
||||
var subscriber = new CallbackSubscriber(handler, handler,
|
||||
@@ -462,6 +529,10 @@ namespace CounterStrikeSharp.API.Core
|
||||
EntityOutputHooks[handler] = subscriber;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Unhooks an entity output.
|
||||
/// </summary>
|
||||
/// <inheritdoc cref="HookEntityOutput"/>
|
||||
public void UnhookEntityOutput(string classname, string outputName, EntityIO.EntityOutputHandler handler, HookMode mode = HookMode.Pre)
|
||||
{
|
||||
if (!EntityOutputHooks.TryGetValue(handler, out var subscriber)) return;
|
||||
@@ -471,6 +542,12 @@ namespace CounterStrikeSharp.API.Core
|
||||
EntityOutputHooks.Remove(handler);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Hooks an entity output for a single entity instance.
|
||||
/// </summary>
|
||||
/// <param name="entityInstance">Entity instance to hook</param>
|
||||
/// <param name="outputName">Output name to hook, or `*` for wildcard</param>
|
||||
/// <param name="handler">Handler to call</param>
|
||||
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
|
||||
@@ -494,6 +571,10 @@ namespace CounterStrikeSharp.API.Core
|
||||
EntitySingleOutputHooks[handler] = new EntityIO.EntityOutputCallback(entityInstance.DesignerName, outputName, internalHandler);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Unhooks an entity output for a single entity instance.
|
||||
/// </summary>
|
||||
/// <inheritdoc cref="HookSingleEntityOutput"/>
|
||||
public void UnhookSingleEntityOutput(CEntityInstance entityInstance, string outputName, EntityIO.EntityOutputHandler handler)
|
||||
{
|
||||
UnhookSingleEntityOutputInternal(entityInstance.DesignerName, outputName, handler);
|
||||
@@ -532,10 +613,6 @@ namespace CounterStrikeSharp.API.Core
|
||||
subscriber.Dispose();
|
||||
}
|
||||
|
||||
foreach (var kv in ConvarChangeHandlers)
|
||||
{
|
||||
}
|
||||
|
||||
foreach (var subscriber in Listeners.Values)
|
||||
{
|
||||
subscriber.Dispose();
|
||||
|
||||
@@ -50,6 +50,9 @@ namespace CounterStrikeSharp.API.Core
|
||||
[JsonPropertyName("PluginHotReloadEnabled")]
|
||||
public bool PluginHotReloadEnabled { get; set; } = true;
|
||||
|
||||
[JsonPropertyName("PluginAutoLoadEnabled")]
|
||||
public bool PluginAutoLoadEnabled { get; set; } = true;
|
||||
|
||||
[JsonPropertyName("ServerLanguage")]
|
||||
public string ServerLanguage { get; set; } = "en";
|
||||
}
|
||||
@@ -95,7 +98,13 @@ namespace CounterStrikeSharp.API.Core
|
||||
/// </summary>
|
||||
public static bool PluginHotReloadEnabled => _coreConfig.PluginHotReloadEnabled;
|
||||
|
||||
/// <summary>
|
||||
/// When enabled, plugins are automatically loaded from the plugins directory on server start.
|
||||
/// </summary>
|
||||
public static bool PluginAutoLoadEnabled => _coreConfig.PluginAutoLoadEnabled;
|
||||
|
||||
public static string ServerLanguage => _coreConfig.ServerLanguage;
|
||||
|
||||
}
|
||||
|
||||
public partial class CoreConfig : IStartupService
|
||||
|
||||
@@ -14,11 +14,9 @@
|
||||
* along with CounterStrikeSharp. If not, see <https://www.gnu.org/licenses/>. *
|
||||
*/
|
||||
|
||||
using System;
|
||||
using System.Collections.Concurrent;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Runtime.InteropServices;
|
||||
using System.Threading.Tasks;
|
||||
using Microsoft.Extensions.Logging;
|
||||
|
||||
namespace CounterStrikeSharp.API.Core
|
||||
@@ -30,140 +28,149 @@ namespace CounterStrikeSharp.API.Core
|
||||
{
|
||||
/// <summary>Delegate will be removed after the first invocation.</summary>
|
||||
SingleUse,
|
||||
/// <summary>Delegate will remain in memory for the lifetime of the application.</summary>
|
||||
|
||||
/// <summary>Delegate will remain in memory for the lifetime of the application (or until <see cref="FunctionReference.Remove"/> is called).</summary>
|
||||
Permanent
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Represents a reference to a function that can be called from native code.
|
||||
/// </summary>
|
||||
public class FunctionReference
|
||||
{
|
||||
private readonly Delegate m_method;
|
||||
|
||||
public FunctionLifetime Lifetime { get; set; } = FunctionLifetime.Permanent;
|
||||
|
||||
public unsafe delegate void CallbackDelegate(fxScriptContext* context);
|
||||
private CallbackDelegate s_callback;
|
||||
|
||||
private FunctionReference(Delegate method)
|
||||
private static readonly ConcurrentDictionary<int, FunctionReference> IdToFunctionReferencesMap = new();
|
||||
private static readonly ConcurrentDictionary<Delegate, FunctionReference> TargetMethodToFunctionReferencesMap = new();
|
||||
|
||||
private static readonly object ReferenceCounterLock = new();
|
||||
private static int _referenceCounter;
|
||||
|
||||
private readonly Delegate _targetMethod;
|
||||
private readonly CallbackDelegate _nativeCallback;
|
||||
|
||||
private readonly TaskCompletionSource _taskCompletionSource = new();
|
||||
|
||||
private FunctionReference(Delegate method, FunctionLifetime lifetime)
|
||||
{
|
||||
m_method = method;
|
||||
|
||||
unsafe
|
||||
{
|
||||
var dg = new CallbackDelegate((fxScriptContext* context) =>
|
||||
{
|
||||
try
|
||||
{
|
||||
var scriptContext = new ScriptContext(context);
|
||||
|
||||
if (method.Method.GetParameters().FirstOrDefault()?.ParameterType == typeof(ScriptContext))
|
||||
{
|
||||
var returnO = m_method.DynamicInvoke(scriptContext);
|
||||
if (returnO != null)
|
||||
{
|
||||
scriptContext.SetResult(returnO, context);
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
var paramsList = method.Method.GetParameters().Select((x, i) =>
|
||||
{
|
||||
var param = method.Method.GetParameters()[i];
|
||||
object obj = null;
|
||||
if (typeof(NativeObject).IsAssignableFrom(param.ParameterType))
|
||||
{
|
||||
obj = Activator.CreateInstance(param.ParameterType,
|
||||
new[] { scriptContext.GetArgument(typeof(IntPtr), i) });
|
||||
}
|
||||
else
|
||||
{
|
||||
obj = scriptContext.GetArgument(param.ParameterType, i);
|
||||
}
|
||||
|
||||
return obj;
|
||||
}).ToArray();
|
||||
|
||||
var returnObj = m_method.DynamicInvoke(paramsList);
|
||||
|
||||
if (returnObj != null)
|
||||
{
|
||||
scriptContext.SetResult(returnObj, context);
|
||||
}
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
Application.Instance.Logger.LogError(e, "Error invoking callback");
|
||||
}
|
||||
finally
|
||||
{
|
||||
if (Lifetime == FunctionLifetime.SingleUse)
|
||||
{
|
||||
Remove(Identifier);
|
||||
if (references.ContainsKey(m_method))
|
||||
references.Remove(m_method, out _);
|
||||
}
|
||||
}
|
||||
});
|
||||
s_callback = dg;
|
||||
}
|
||||
|
||||
Lifetime = lifetime;
|
||||
_targetMethod = method;
|
||||
_nativeCallback = CreateWrappedCallback();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// <inheritdoc cref="FunctionLifetime"/>
|
||||
/// </summary>
|
||||
public FunctionLifetime Lifetime { get; }
|
||||
|
||||
/// <summary>
|
||||
/// For <see cref="FunctionLifetime.SingleUse"/> function references, this task will complete when
|
||||
/// the function has finished invoking.
|
||||
/// </summary>
|
||||
public Task CompletionTask => _taskCompletionSource.Task;
|
||||
|
||||
public int Identifier { get; private set; }
|
||||
|
||||
public static FunctionReference Create(Delegate method)
|
||||
private unsafe CallbackDelegate CreateWrappedCallback()
|
||||
{
|
||||
if (references.TryGetValue(method, out var existingReference))
|
||||
return context =>
|
||||
{
|
||||
try
|
||||
{
|
||||
var scriptContext = new ScriptContext(context);
|
||||
|
||||
// Allow for manual handling of the script context
|
||||
if (_targetMethod.Method.GetParameters().FirstOrDefault()?.ParameterType == typeof(ScriptContext))
|
||||
{
|
||||
var returnValue = _targetMethod.DynamicInvoke(scriptContext);
|
||||
if (returnValue != null)
|
||||
{
|
||||
scriptContext.SetResult(returnValue, context);
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
var parameterList = _targetMethod.Method.GetParameters().Select((_, i) =>
|
||||
{
|
||||
var parameter = _targetMethod.Method.GetParameters()[i];
|
||||
return scriptContext.GetArgument(parameter.ParameterType, i);
|
||||
}).ToArray();
|
||||
|
||||
var returnObj = _targetMethod.DynamicInvoke(parameterList);
|
||||
|
||||
if (returnObj != null)
|
||||
{
|
||||
scriptContext.SetResult(returnObj, context);
|
||||
}
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
Application.Instance.Logger.LogError(e, "Error invoking callback");
|
||||
}
|
||||
finally
|
||||
{
|
||||
if (Lifetime == FunctionLifetime.SingleUse)
|
||||
{
|
||||
RemoveSelf();
|
||||
}
|
||||
|
||||
_taskCompletionSource.TrySetResult();
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
public static FunctionReference Create(Delegate method, FunctionLifetime lifetime = FunctionLifetime.Permanent)
|
||||
{
|
||||
// We always want to create a new reference if the lifetime is single use.
|
||||
if (lifetime == FunctionLifetime.Permanent && TargetMethodToFunctionReferencesMap.TryGetValue(method, out var existingReference))
|
||||
{
|
||||
return existingReference;
|
||||
}
|
||||
|
||||
var reference = new FunctionReference(method);
|
||||
var reference = new FunctionReference(method, lifetime);
|
||||
var referenceId = Register(reference);
|
||||
|
||||
reference.Identifier = referenceId;
|
||||
|
||||
|
||||
return reference;
|
||||
}
|
||||
|
||||
private static ConcurrentDictionary<int, FunctionReference> ms_references = new ConcurrentDictionary<int, FunctionReference>();
|
||||
private static int ms_referenceId;
|
||||
|
||||
private static ConcurrentDictionary<Delegate, FunctionReference> references =
|
||||
new ConcurrentDictionary<Delegate, FunctionReference>();
|
||||
|
||||
private static int Register(FunctionReference reference)
|
||||
{
|
||||
var thisRefId = ms_referenceId;
|
||||
ms_references[thisRefId] = reference;
|
||||
references[reference.m_method] = reference;
|
||||
|
||||
unchecked { ms_referenceId++; }
|
||||
|
||||
return thisRefId;
|
||||
}
|
||||
|
||||
public static FunctionReference Get(int reference)
|
||||
{
|
||||
if (ms_references.ContainsKey(reference))
|
||||
lock (ReferenceCounterLock)
|
||||
{
|
||||
return ms_references[reference];
|
||||
}
|
||||
var thisRefId = _referenceCounter;
|
||||
IdToFunctionReferencesMap[thisRefId] = reference;
|
||||
TargetMethodToFunctionReferencesMap[reference._targetMethod] = reference;
|
||||
|
||||
return null;
|
||||
unchecked
|
||||
{
|
||||
_referenceCounter++;
|
||||
}
|
||||
|
||||
return thisRefId;
|
||||
}
|
||||
}
|
||||
|
||||
public IntPtr GetFunctionPointer()
|
||||
|
||||
public IntPtr GetFunctionPointer() => Marshal.GetFunctionPointerForDelegate(_nativeCallback);
|
||||
|
||||
private void RemoveSelf()
|
||||
{
|
||||
IntPtr cb = Marshal.GetFunctionPointerForDelegate(s_callback);
|
||||
return cb;
|
||||
Remove(Identifier);
|
||||
}
|
||||
|
||||
public static void Remove(int reference)
|
||||
{
|
||||
if (ms_references.TryGetValue(reference, out var funcRef))
|
||||
if (IdToFunctionReferencesMap.TryGetValue(reference, out var functionReference))
|
||||
{
|
||||
ms_references.Remove(reference, out _);
|
||||
if (TargetMethodToFunctionReferencesMap.ContainsKey(functionReference._targetMethod))
|
||||
{
|
||||
TargetMethodToFunctionReferencesMap.Remove(functionReference._targetMethod, out _);
|
||||
}
|
||||
|
||||
IdToFunctionReferencesMap.Remove(reference, out _);
|
||||
|
||||
Application.Instance.Logger.LogDebug("Removing function/callback reference: {Reference}", reference);
|
||||
}
|
||||
|
||||
@@ -28,17 +28,23 @@ namespace CounterStrikeSharp.API.Core
|
||||
public interface IPlugin : IDisposable
|
||||
{
|
||||
/// <summary>
|
||||
/// Name of the plugin.
|
||||
/// Name of the plugin as it will appear in the plugin list.
|
||||
/// </summary>
|
||||
string ModuleName { get; }
|
||||
|
||||
/// <summary>
|
||||
/// Module version.
|
||||
/// Module version as it will appear in the plugin list.
|
||||
/// </summary>
|
||||
string ModuleVersion { get; }
|
||||
|
||||
/// <summary>
|
||||
/// Author of the plugin as it will appear in the plugin list.
|
||||
/// </summary>
|
||||
string ModuleAuthor { get; }
|
||||
|
||||
/// <summary>
|
||||
/// Brief description of the plugin as it will appear in the plugin list.
|
||||
/// </summary>
|
||||
string ModuleDescription { get; }
|
||||
|
||||
/// <summary>
|
||||
@@ -61,12 +67,15 @@ namespace CounterStrikeSharp.API.Core
|
||||
/// <param name="hotReload"></param>
|
||||
void OnAllPluginsLoaded(bool hotReload);
|
||||
|
||||
/// <summary>
|
||||
/// The path to the plugin's DLL file.
|
||||
/// </summary>
|
||||
string ModulePath { get; internal set; }
|
||||
|
||||
ILogger Logger { get; set; }
|
||||
|
||||
|
||||
IStringLocalizer Localizer { get; set; }
|
||||
|
||||
|
||||
ICommandManager CommandManager { get; set; }
|
||||
|
||||
void RegisterAllAttributes(object instance);
|
||||
|
||||
@@ -8,10 +8,14 @@ namespace CounterStrikeSharp.API.Core;
|
||||
public partial class CBaseEntity
|
||||
{
|
||||
/// <exception cref="InvalidOperationException">Entity is not valid</exception>
|
||||
public void Teleport(Vector position, QAngle angles, Vector velocity)
|
||||
public void Teleport(Vector? position = null, QAngle? angles = null, Vector? velocity = null)
|
||||
{
|
||||
Guard.IsValidEntity(this);
|
||||
|
||||
position ??= AbsOrigin!;
|
||||
angles ??= AbsRotation!;
|
||||
velocity ??= AbsVelocity;
|
||||
|
||||
VirtualFunction.CreateVoid<IntPtr, IntPtr, IntPtr, IntPtr>(Handle, GameData.GetOffset("CBaseEntity_Teleport"))(
|
||||
Handle, position.Handle, angles.Handle, velocity.Handle);
|
||||
}
|
||||
@@ -39,6 +43,6 @@ public partial class CBaseEntity
|
||||
{
|
||||
Guard.IsValidEntity(this);
|
||||
|
||||
return (T) Activator.CreateInstance(typeof(T), Marshal.ReadIntPtr(SubclassID.Handle + 4));
|
||||
return (T)Activator.CreateInstance(typeof(T), Marshal.ReadIntPtr(SubclassID.Handle + 4));
|
||||
}
|
||||
}
|
||||
@@ -26,6 +26,6 @@ public partial class CCSGameRules
|
||||
/// </summary>
|
||||
public void TerminateRound(float delay, RoundEndReason roundEndReason)
|
||||
{
|
||||
VirtualFunctions.TerminateRound(Handle, roundEndReason, delay);
|
||||
VirtualFunctions.TerminateRound(Handle, roundEndReason, delay, 0, 0);
|
||||
}
|
||||
}
|
||||
@@ -75,6 +75,7 @@ public partial class CCSPlayerController
|
||||
Userid = this
|
||||
};
|
||||
@event.FireEventToClient(this);
|
||||
@event.Free();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
|
||||
@@ -33,6 +33,11 @@ public partial class NetworkedVector<T> : NativeObject, IReadOnlyCollection<T>
|
||||
}
|
||||
}
|
||||
|
||||
public void RemoveAll()
|
||||
{
|
||||
NativeAPI.RemoveAllNetworkVectorElements(Handle);
|
||||
}
|
||||
|
||||
public IEnumerator<T> GetEnumerator()
|
||||
{
|
||||
for (int i = 0; i < Count; i++)
|
||||
|
||||
@@ -36,7 +36,7 @@ public class PluginManager : IPluginManager
|
||||
config => { config.PreferSharedTypes = true; });
|
||||
var assembly = loader.LoadDefaultAssembly();
|
||||
|
||||
_sharedAssemblies[assembly.GetName().FullName] = assembly;
|
||||
_sharedAssemblies[assembly.GetName().Name] = assembly;
|
||||
}
|
||||
|
||||
private void LoadSharedLibraries()
|
||||
@@ -76,31 +76,40 @@ public class PluginManager : IPluginManager
|
||||
_loadedSharedLibs = true;
|
||||
}
|
||||
|
||||
if (!_sharedAssemblies.TryGetValue(name.FullName, out var assembly))
|
||||
if (!_sharedAssemblies.TryGetValue(name.Name, out var assembly))
|
||||
{
|
||||
_logger.LogError("Failed to use existing shared assembly: {Name}", name);
|
||||
return null;
|
||||
}
|
||||
|
||||
return assembly;
|
||||
};
|
||||
|
||||
foreach (var path in pluginAssemblyPaths)
|
||||
if (CoreConfig.PluginAutoLoadEnabled)
|
||||
{
|
||||
foreach (var path in pluginAssemblyPaths)
|
||||
{
|
||||
try
|
||||
{
|
||||
LoadPlugin(path);
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
_logger.LogError(e, "Failed to load plugin from {Path}", path);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
foreach (var plugin in _loadedPluginContexts)
|
||||
{
|
||||
try
|
||||
{
|
||||
LoadPlugin(path);
|
||||
plugin.Plugin?.OnAllPluginsLoaded(false);
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
_logger.LogError(e, "Failed to load plugin from {Path}", path);
|
||||
_logger.LogError(e, "OnAllPluginsLoaded failed");
|
||||
}
|
||||
}
|
||||
|
||||
foreach (var plugin in _loadedPluginContexts)
|
||||
{
|
||||
plugin.Plugin.OnAllPluginsLoaded(false);
|
||||
}
|
||||
}
|
||||
|
||||
public IEnumerable<PluginContext> GetLoadedPlugins()
|
||||
@@ -115,4 +124,4 @@ public class PluginManager : IPluginManager
|
||||
_loadedPluginContexts.Add(plugin);
|
||||
plugin.Load();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -62,8 +62,4 @@ public partial class CC4 : CCSWeaponBase
|
||||
[SchemaMember("CC4", "m_bBombPlanted")]
|
||||
public ref bool BombPlanted => ref Schema.GetRef<bool>(this.Handle, "CC4", "m_bBombPlanted");
|
||||
|
||||
// m_bDroppedFromDeath
|
||||
[SchemaMember("CC4", "m_bDroppedFromDeath")]
|
||||
public ref bool DroppedFromDeath => ref Schema.GetRef<bool>(this.Handle, "CC4", "m_bDroppedFromDeath");
|
||||
|
||||
}
|
||||
|
||||
@@ -450,6 +450,10 @@ public partial class CCSGameRules : CTeamplayRules
|
||||
[SchemaMember("CCSGameRules", "m_arrSelectedHostageSpawnIndices")]
|
||||
public NetworkedVector<Int32> SelectedHostageSpawnIndices => Schema.GetDeclaredClass<NetworkedVector<Int32>>(this.Handle, "CCSGameRules", "m_arrSelectedHostageSpawnIndices");
|
||||
|
||||
// m_nSpawnPointsRandomSeed
|
||||
[SchemaMember("CCSGameRules", "m_nSpawnPointsRandomSeed")]
|
||||
public ref Int32 SpawnPointsRandomSeed => ref Schema.GetRef<Int32>(this.Handle, "CCSGameRules", "m_nSpawnPointsRandomSeed");
|
||||
|
||||
// m_bFirstConnected
|
||||
[SchemaMember("CCSGameRules", "m_bFirstConnected")]
|
||||
public ref bool FirstConnected => ref Schema.GetRef<bool>(this.Handle, "CCSGameRules", "m_bFirstConnected");
|
||||
@@ -686,14 +690,26 @@ public partial class CCSGameRules : CTeamplayRules
|
||||
[SchemaMember("CCSGameRules", "m_TerroristSpawnPointsMasterList")]
|
||||
public NetworkedVector<SpawnPoint?> TerroristSpawnPointsMasterList => Schema.GetDeclaredClass<NetworkedVector<SpawnPoint?>>(this.Handle, "CCSGameRules", "m_TerroristSpawnPointsMasterList");
|
||||
|
||||
// m_bRespawningAllRespawnablePlayers
|
||||
[SchemaMember("CCSGameRules", "m_bRespawningAllRespawnablePlayers")]
|
||||
public ref bool RespawningAllRespawnablePlayers => ref Schema.GetRef<bool>(this.Handle, "CCSGameRules", "m_bRespawningAllRespawnablePlayers");
|
||||
|
||||
// m_iNextCTSpawnPoint
|
||||
[SchemaMember("CCSGameRules", "m_iNextCTSpawnPoint")]
|
||||
public ref Int32 NextCTSpawnPoint => ref Schema.GetRef<Int32>(this.Handle, "CCSGameRules", "m_iNextCTSpawnPoint");
|
||||
|
||||
// m_flCTSpawnPointUsedTime
|
||||
[SchemaMember("CCSGameRules", "m_flCTSpawnPointUsedTime")]
|
||||
public ref float CTSpawnPointUsedTime => ref Schema.GetRef<float>(this.Handle, "CCSGameRules", "m_flCTSpawnPointUsedTime");
|
||||
|
||||
// m_iNextTerroristSpawnPoint
|
||||
[SchemaMember("CCSGameRules", "m_iNextTerroristSpawnPoint")]
|
||||
public ref Int32 NextTerroristSpawnPoint => ref Schema.GetRef<Int32>(this.Handle, "CCSGameRules", "m_iNextTerroristSpawnPoint");
|
||||
|
||||
// m_flTerroristSpawnPointUsedTime
|
||||
[SchemaMember("CCSGameRules", "m_flTerroristSpawnPointUsedTime")]
|
||||
public ref float TerroristSpawnPointUsedTime => ref Schema.GetRef<float>(this.Handle, "CCSGameRules", "m_flTerroristSpawnPointUsedTime");
|
||||
|
||||
// m_CTSpawnPoints
|
||||
[SchemaMember("CCSGameRules", "m_CTSpawnPoints")]
|
||||
public NetworkedVector<SpawnPoint?> CTSpawnPoints => Schema.GetDeclaredClass<NetworkedVector<SpawnPoint?>>(this.Handle, "CCSGameRules", "m_CTSpawnPoints");
|
||||
@@ -878,10 +894,6 @@ public partial class CCSGameRules : CTeamplayRules
|
||||
[SchemaMember("CCSGameRules", "m_nRoundStartCount")]
|
||||
public ref byte RoundStartCount => ref Schema.GetRef<byte>(this.Handle, "CCSGameRules", "m_nRoundStartCount");
|
||||
|
||||
// m_nRoundStartTicks
|
||||
[SchemaMember("CCSGameRules", "m_nRoundStartTicks")]
|
||||
public NetworkedVector<Int32> RoundStartTicks => Schema.GetDeclaredClass<NetworkedVector<Int32>>(this.Handle, "CCSGameRules", "m_nRoundStartTicks");
|
||||
|
||||
// m_flLastPerfSampleTime
|
||||
[SchemaMember("CCSGameRules", "m_flLastPerfSampleTime")]
|
||||
public ref double LastPerfSampleTime => ref Schema.GetRef<double>(this.Handle, "CCSGameRules", "m_flLastPerfSampleTime");
|
||||
|
||||
@@ -294,6 +294,22 @@ public partial class CCSPlayerController : CBasePlayerController
|
||||
[SchemaMember("CCSPlayerController", "m_vecKills")]
|
||||
public NetworkedVector<EKillTypes_t> Kills => Schema.GetDeclaredClass<NetworkedVector<EKillTypes_t>>(this.Handle, "CCSPlayerController", "m_vecKills");
|
||||
|
||||
// m_bMvpNoMusic
|
||||
[SchemaMember("CCSPlayerController", "m_bMvpNoMusic")]
|
||||
public ref bool MvpNoMusic => ref Schema.GetRef<bool>(this.Handle, "CCSPlayerController", "m_bMvpNoMusic");
|
||||
|
||||
// m_eMvpReason
|
||||
[SchemaMember("CCSPlayerController", "m_eMvpReason")]
|
||||
public ref Int32 MvpReason => ref Schema.GetRef<Int32>(this.Handle, "CCSPlayerController", "m_eMvpReason");
|
||||
|
||||
// m_iMusicKitID
|
||||
[SchemaMember("CCSPlayerController", "m_iMusicKitID")]
|
||||
public ref Int32 MusicKitID => ref Schema.GetRef<Int32>(this.Handle, "CCSPlayerController", "m_iMusicKitID");
|
||||
|
||||
// m_iMusicKitMVPs
|
||||
[SchemaMember("CCSPlayerController", "m_iMusicKitMVPs")]
|
||||
public ref Int32 MusicKitMVPs => ref Schema.GetRef<Int32>(this.Handle, "CCSPlayerController", "m_iMusicKitMVPs");
|
||||
|
||||
// m_iMVPs
|
||||
[SchemaMember("CCSPlayerController", "m_iMVPs")]
|
||||
public ref Int32 MVPs => ref Schema.GetRef<Int32>(this.Handle, "CCSPlayerController", "m_iMVPs");
|
||||
|
||||
@@ -202,13 +202,9 @@ public partial class CCSPlayerPawnBase : CBasePlayerPawn
|
||||
[SchemaMember("CCSPlayerPawnBase", "m_iShouldHaveCash")]
|
||||
public ref Int32 ShouldHaveCash => ref Schema.GetRef<Int32>(this.Handle, "CCSPlayerPawnBase", "m_iShouldHaveCash");
|
||||
|
||||
// m_bInvalidSteamLogonDelayed
|
||||
[SchemaMember("CCSPlayerPawnBase", "m_bInvalidSteamLogonDelayed")]
|
||||
public ref bool InvalidSteamLogonDelayed => ref Schema.GetRef<bool>(this.Handle, "CCSPlayerPawnBase", "m_bInvalidSteamLogonDelayed");
|
||||
|
||||
// m_flLastAction
|
||||
[SchemaMember("CCSPlayerPawnBase", "m_flLastAction")]
|
||||
public ref float LastAction => ref Schema.GetRef<float>(this.Handle, "CCSPlayerPawnBase", "m_flLastAction");
|
||||
// m_flIdleTimeSinceLastAction
|
||||
[SchemaMember("CCSPlayerPawnBase", "m_flIdleTimeSinceLastAction")]
|
||||
public ref float IdleTimeSinceLastAction => ref Schema.GetRef<float>(this.Handle, "CCSPlayerPawnBase", "m_flIdleTimeSinceLastAction");
|
||||
|
||||
// m_flNameChangeHistory
|
||||
[SchemaMember("CCSPlayerPawnBase", "m_flNameChangeHistory")]
|
||||
|
||||
@@ -114,10 +114,6 @@ public partial class CPlantedC4 : CBaseAnimGraph
|
||||
[SchemaMember("CPlantedC4", "m_flNextBotBeepTime")]
|
||||
public ref float NextBotBeepTime => ref Schema.GetRef<float>(this.Handle, "CPlantedC4", "m_flNextBotBeepTime");
|
||||
|
||||
// m_bPlantedAfterPickup
|
||||
[SchemaMember("CPlantedC4", "m_bPlantedAfterPickup")]
|
||||
public ref bool PlantedAfterPickup => ref Schema.GetRef<bool>(this.Handle, "CPlantedC4", "m_bPlantedAfterPickup");
|
||||
|
||||
// m_angCatchUpToPlayerEye
|
||||
[SchemaMember("CPlantedC4", "m_angCatchUpToPlayerEye")]
|
||||
public QAngle CatchUpToPlayerEye => Schema.GetDeclaredClass<QAngle>(this.Handle, "CPlantedC4", "m_angCatchUpToPlayerEye");
|
||||
|
||||
@@ -25,5 +25,6 @@ public enum PulseValueType_t : uint
|
||||
PVAL_CURSOR_FLOW = 0xD,
|
||||
PVAL_ANY = 0xE,
|
||||
PVAL_SCHEMA_ENUM = 0xF,
|
||||
PVAL_COUNT = 0x10,
|
||||
PVAL_PANORAMA_PANEL_HANDLE = 0x10,
|
||||
PVAL_COUNT = 0x11,
|
||||
}
|
||||
|
||||
@@ -1,63 +1,73 @@
|
||||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
<PropertyGroup>
|
||||
<TargetFramework>net7.0</TargetFramework>
|
||||
<EnableDynamicLoading>true</EnableDynamicLoading>
|
||||
<GenerateDocumentationFile>true</GenerateDocumentationFile>
|
||||
<GenerateCompatibilitySuppressionFile>true</GenerateCompatibilitySuppressionFile>
|
||||
<EnablePackageValidation>true</EnablePackageValidation>
|
||||
<NoWarn>$(NoWarn);CS1591;CP0003</NoWarn>
|
||||
<Nullable>enable</Nullable>
|
||||
<GenerateCompatibilitySuppressionFile>true</GenerateCompatibilitySuppressionFile>
|
||||
<Authors>Roflmuffin</Authors>
|
||||
<Description>Official server side runtime assembly for CounterStrikeSharp</Description>
|
||||
<PackageProjectUrl>http://docs.cssharp.dev/</PackageProjectUrl>
|
||||
<RepositoryUrl>https://github.com/roflmuffin/CounterStrikeSharp</RepositoryUrl>
|
||||
<PackageLicenseExpression>GPL-3.0-only</PackageLicenseExpression>
|
||||
<PublishRepositoryUrl>true</PublishRepositoryUrl>
|
||||
<IncludeSymbols>true</IncludeSymbols>
|
||||
<SymbolPackageFormat>snupkg</SymbolPackageFormat>
|
||||
<!-- <GenerateCompatibilitySuppressionFile>true</GenerateCompatibilitySuppressionFile> -->
|
||||
</PropertyGroup>
|
||||
<PropertyGroup>
|
||||
<ApiCompatValidateAssemblies>true</ApiCompatValidateAssemblies>
|
||||
<ApiCompatContractAssembly>.\ApiCompat\v151.dll</ApiCompatContractAssembly>
|
||||
</PropertyGroup>
|
||||
<ItemGroup>
|
||||
<None Remove="Modules\Commands\CommandInfo" />
|
||||
<None Remove="Modules\Disabled\**" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<PackageReference Include="McMaster.NETCore.Plugins" Version="1.4.0" />
|
||||
<PackageReference Include="Microsoft.CSharp" Version="4.7.0" />
|
||||
<PackageReference Include="Microsoft.DotNet.ApiCompat.Task" Version="7.0.404" />
|
||||
<PackageReference Include="Microsoft.Extensions.Hosting" Version="7.0.0" />
|
||||
<PackageReference Include="Microsoft.Extensions.Hosting.Abstractions" Version="7.0.0" />
|
||||
<PackageReference Include="Microsoft.Extensions.Localization.Abstractions" Version="7.0.3" />
|
||||
<PackageReference Include="Microsoft.Extensions.Logging" Version="7.0.0" />
|
||||
<PackageReference Include="Scrutor" Version="4.2.2" />
|
||||
<PackageReference Include="Serilog.Extensions.Logging" Version="7.0.0" />
|
||||
<PackageReference Include="Serilog.Sinks.Console" Version="5.0.0" />
|
||||
<PackageReference Include="Serilog.Sinks.File" Version="5.0.0" />
|
||||
<PackageReference Include="System.Data.DataSetExtensions" Version="4.5.0" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<Folder Include="Core\Schema\" />
|
||||
<Folder Include="Modules\Errors" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<Compile Remove="Modules\Disabled\**" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<EmbeddedResource Remove="Modules\Disabled\**" />
|
||||
</ItemGroup>
|
||||
<PropertyGroup />
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|AnyCPU'">
|
||||
<AllowUnsafeBlocks>true</AllowUnsafeBlocks>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|AnyCPU'">
|
||||
<AllowUnsafeBlocks>true</AllowUnsafeBlocks>
|
||||
</PropertyGroup>
|
||||
<!-- <Target Name="PreBuild" BeforeTargets="PreBuildEvent">-->
|
||||
<!-- <Exec Command="dotnet run --project ../../tooling/CodeGen.Natives" />-->
|
||||
<!-- </Target>-->
|
||||
<PropertyGroup>
|
||||
<TargetFramework>net8.0</TargetFramework>
|
||||
<EnableDynamicLoading>true</EnableDynamicLoading>
|
||||
<GenerateDocumentationFile>true</GenerateDocumentationFile>
|
||||
<GenerateCompatibilitySuppressionFile>true</GenerateCompatibilitySuppressionFile>
|
||||
<EnablePackageValidation>true</EnablePackageValidation>
|
||||
<NoWarn>$(NoWarn);CS1591;CP0003</NoWarn>
|
||||
<Nullable>enable</Nullable>
|
||||
<Authors>Roflmuffin</Authors>
|
||||
<Description>Official server side runtime assembly for CounterStrikeSharp</Description>
|
||||
<PackageProjectUrl>http://docs.cssharp.dev/</PackageProjectUrl>
|
||||
<RepositoryUrl>https://github.com/roflmuffin/CounterStrikeSharp</RepositoryUrl>
|
||||
<PackageLicenseExpression>GPL-3.0-only</PackageLicenseExpression>
|
||||
<PublishRepositoryUrl>true</PublishRepositoryUrl>
|
||||
<IncludeSymbols>true</IncludeSymbols>
|
||||
<SymbolPackageFormat>snupkg</SymbolPackageFormat>
|
||||
<SourceControlInformationFeatureSupported>true</SourceControlInformationFeatureSupported>
|
||||
<!-- <GenerateCompatibilitySuppressionFile>true</GenerateCompatibilitySuppressionFile> -->
|
||||
</PropertyGroup>
|
||||
<PropertyGroup>
|
||||
<ApiCompatValidateAssemblies>true</ApiCompatValidateAssemblies>
|
||||
<ApiCompatContractAssembly>.\ApiCompat\v202.dll</ApiCompatContractAssembly>
|
||||
</PropertyGroup>
|
||||
<ItemGroup>
|
||||
<None Remove="Modules\Commands\CommandInfo"/>
|
||||
<None Remove="Modules\Disabled\**"/>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<PackageReference Include="McMaster.NETCore.Plugins" Version="1.4.0"/>
|
||||
<PackageReference Include="Microsoft.CSharp" Version="4.7.0"/>
|
||||
<PackageReference Include="Microsoft.DotNet.ApiCompat.Task" Version="8.0.203"/>
|
||||
<PackageReference Include="Microsoft.Extensions.Hosting" Version="8.0.0"/>
|
||||
<PackageReference Include="Microsoft.Extensions.Hosting.Abstractions" Version="8.0.0"/>
|
||||
<PackageReference Include="Microsoft.Extensions.Localization.Abstractions" Version="8.0.3"/>
|
||||
<PackageReference Include="Microsoft.Extensions.Logging" Version="8.0.0"/>
|
||||
<PackageReference Include="Scrutor" Version="4.2.2"/>
|
||||
<PackageReference Include="Serilog.Extensions.Logging" Version="8.0.0"/>
|
||||
<PackageReference Include="Serilog.Sinks.Console" Version="5.0.0"/>
|
||||
<PackageReference Include="Serilog.Sinks.File" Version="5.0.0"/>
|
||||
<PackageReference Include="System.Data.DataSetExtensions" Version="4.5.0"/>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<Folder Include="Core\Schema\"/>
|
||||
<Folder Include="Modules\Errors"/>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<Compile Remove="Modules\Disabled\**"/>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<EmbeddedResource Remove="Modules\Disabled\**"/>
|
||||
</ItemGroup>
|
||||
<PropertyGroup/>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|AnyCPU'">
|
||||
<AllowUnsafeBlocks>true</AllowUnsafeBlocks>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|AnyCPU'">
|
||||
<AllowUnsafeBlocks>true</AllowUnsafeBlocks>
|
||||
</PropertyGroup>
|
||||
<Target Name="SetSourceRevisionId" BeforeTargets="InitializeSourceControlInformation">
|
||||
<Exec
|
||||
Command="git describe --long --always --exclude=* --abbrev=7"
|
||||
ConsoleToMSBuild="True"
|
||||
IgnoreExitCode="False"
|
||||
>
|
||||
<Output PropertyName="SourceRevisionId" TaskParameter="ConsoleOutput"/>
|
||||
</Exec>
|
||||
</Target>
|
||||
|
||||
<!-- <Target Name="PreBuild" BeforeTargets="PreBuildEvent">-->
|
||||
<!-- <Exec Command="dotnet run --project ../../tooling/CodeGen.Natives" />-->
|
||||
<!-- </Target>-->
|
||||
</Project>
|
||||
@@ -1,5 +1,7 @@
|
||||
// Global using directives
|
||||
|
||||
global using System;
|
||||
global using System.Linq;
|
||||
global using System.IO;
|
||||
global using System.Collections.Generic;
|
||||
global using CounterStrikeSharp.API.Core;
|
||||
@@ -23,6 +23,10 @@ namespace CounterStrikeSharp.API.Modules.Commands
|
||||
{
|
||||
public delegate void CommandCallback(CCSPlayerController? player, CommandInfo commandInfo);
|
||||
|
||||
/// <summary>
|
||||
/// Command listener callback.
|
||||
/// <returns>If returning <see cref="HookResult.Handled"/> or higher, will prevent the command from executing.</returns>
|
||||
/// </summary>
|
||||
public delegate HookResult CommandListenerCallback(CCSPlayerController? player, CommandInfo commandInfo);
|
||||
|
||||
public CCSPlayerController? CallingPlayer { get; }
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
using System.Collections.Generic;
|
||||
using System.Collections.Frozen;
|
||||
using System.Collections.Generic;
|
||||
using System.Diagnostics.CodeAnalysis;
|
||||
using System.Linq;
|
||||
using CounterStrikeSharp.API.Modules.Entities;
|
||||
@@ -12,7 +13,7 @@ public class Target
|
||||
private string Raw { get; }
|
||||
private string Slug { get; }
|
||||
|
||||
private static readonly Dictionary<string, TargetType> TargetTypeMap = new(StringComparer.OrdinalIgnoreCase)
|
||||
public static readonly IReadOnlyDictionary<string, TargetType> TargetTypeMap = new Dictionary<string, TargetType>(StringComparer.OrdinalIgnoreCase)
|
||||
{
|
||||
{ "@all", TargetType.GroupAll },
|
||||
{ "@bots", TargetType.GroupBots },
|
||||
@@ -24,7 +25,7 @@ public class Target
|
||||
{ "@ct", TargetType.TeamCt },
|
||||
{ "@t", TargetType.TeamT },
|
||||
{ "@spec", TargetType.TeamSpec }
|
||||
};
|
||||
}.ToFrozenDictionary();
|
||||
|
||||
|
||||
private static bool ConstTargetType(string target, out TargetType targetType)
|
||||
|
||||
@@ -18,34 +18,37 @@ namespace CounterStrikeSharp.API.Modules.Entities.Constants
|
||||
{
|
||||
public enum CollisionGroup
|
||||
{
|
||||
COLLISION_GROUP_NONE = 0,
|
||||
COLLISION_GROUP_DEBRIS, // Collides with nothing but world and static stuff
|
||||
COLLISION_GROUP_DEBRIS_TRIGGER, // Same as debris, but hits triggers
|
||||
COLLISION_GROUP_INTERACTIVE_DEBRIS, // Collides with everything except other interactive debris or debris
|
||||
COLLISION_GROUP_INTERACTIVE, // Collides with everything except interactive debris or debris
|
||||
COLLISION_GROUP_NONE = 0,
|
||||
COLLISION_GROUP_NEVER,
|
||||
COLLISION_GROUP_TRIGGER,
|
||||
COLLISION_GROUP_CONDITIONALLY_SOLID,
|
||||
COLLISION_GROUP_DEFAULT,
|
||||
COLLISION_GROUP_DEBRIS, // Collides with nothing but world and static stuff
|
||||
COLLISION_GROUP_INTERACTIVE_DEBRIS, // Collides with everything except other interactive debris or debris
|
||||
COLLISION_GROUP_INTERACTIVE, // Collides with everything except interactive debris or debris
|
||||
COLLISION_GROUP_PLAYER,
|
||||
COLLISION_GROUP_BREAKABLE_GLASS,
|
||||
COLLISION_GROUP_VEHICLE,
|
||||
COLLISION_GROUP_PLAYER_MOVEMENT, // For HL2, same as Collision_Group_Player, for
|
||||
// TF2, this filters out other players and CBaseObjects
|
||||
COLLISION_GROUP_NPC, // Generic NPC group
|
||||
COLLISION_GROUP_IN_VEHICLE, // for any entity inside a vehicle
|
||||
COLLISION_GROUP_WEAPON, // for any weapons that need collision detection
|
||||
COLLISION_GROUP_VEHICLE_CLIP, // vehicle clip brush to restrict vehicle movement
|
||||
COLLISION_GROUP_PROJECTILE, // Projectiles!
|
||||
COLLISION_GROUP_DOOR_BLOCKER, // Blocks entities not permitted to get near moving doors
|
||||
COLLISION_GROUP_PASSABLE_DOOR, // Doors that the player shouldn't collide with
|
||||
COLLISION_GROUP_DISSOLVING, // Things that are dissolving are in this group
|
||||
COLLISION_GROUP_PUSHAWAY, // Nonsolid on client and server, pushaway in player code
|
||||
COLLISION_GROUP_PLAYER_MOVEMENT, // For HL2, same as Collision_Group_Player, for
|
||||
|
||||
COLLISION_GROUP_NPC_ACTOR, // Used so NPCs in scripts ignore the player.
|
||||
COLLISION_GROUP_NPC_SCRIPTED, // USed for NPCs in scripts that should not collide with each other
|
||||
// TF2, this filters out other players and CBaseObjects
|
||||
COLLISION_GROUP_NPC, // Generic NPC group
|
||||
COLLISION_GROUP_IN_VEHICLE, // for any entity inside a vehicle
|
||||
COLLISION_GROUP_WEAPON, // for any weapons that need collision detection
|
||||
COLLISION_GROUP_VEHICLE_CLIP, // vehicle clip brush to restrict vehicle movement
|
||||
COLLISION_GROUP_PROJECTILE, // Projectiles!
|
||||
COLLISION_GROUP_DOOR_BLOCKER, // Blocks entities not permitted to get near moving doors
|
||||
COLLISION_GROUP_PASSABLE_DOOR, // Doors that the player shouldn't collide with
|
||||
COLLISION_GROUP_DISSOLVING, // Things that are dissolving are in this group
|
||||
COLLISION_GROUP_PUSHAWAY, // Nonsolid on client and server, pushaway in player code
|
||||
|
||||
COLLISION_GROUP_NPC_ACTOR, // Used so NPCs in scripts ignore the player.
|
||||
COLLISION_GROUP_NPC_SCRIPTED, // USed for NPCs in scripts that should not collide with each other
|
||||
COLLISION_GROUP_PZ_CLIP,
|
||||
|
||||
|
||||
|
||||
COLLISION_GROUP_DEBRIS_BLOCK_PROJECTILE, // Only collides with bullets
|
||||
COLLISION_GROUP_PROPS,
|
||||
|
||||
LAST_SHARED_COLLISION_GROUP
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -32,12 +32,16 @@ namespace CounterStrikeSharp.API.Modules.Events
|
||||
|
||||
public class GameEvent : NativeObject
|
||||
{
|
||||
// Used to track freeable state for manually created events.
|
||||
private bool _freeable = false;
|
||||
|
||||
public GameEvent(IntPtr pointer) : base(pointer)
|
||||
{
|
||||
}
|
||||
|
||||
public GameEvent(string name, bool force) : this(NativeAPI.CreateEvent(name, force))
|
||||
{
|
||||
_freeable = true;
|
||||
}
|
||||
|
||||
public string EventName => NativeAPI.GetEventName(Handle);
|
||||
@@ -121,8 +125,28 @@ namespace CounterStrikeSharp.API.Modules.Events
|
||||
|
||||
protected void SetEntityIndex(string name, int value) => NativeAPI.SetEventEntityIndex(Handle, name, value);
|
||||
|
||||
public void FireEvent(bool dontBroadcast) => NativeAPI.FireEvent(Handle, dontBroadcast);
|
||||
|
||||
public void FireEvent(bool dontBroadcast)
|
||||
{
|
||||
NativeAPI.FireEvent(Handle, dontBroadcast);
|
||||
_freeable = false;
|
||||
}
|
||||
|
||||
public void FireEventToClient(CCSPlayerController player) => NativeAPI.FireEventToClient(Handle, (int)player.Index);
|
||||
|
||||
/// <summary>
|
||||
/// Used to manually free the event.
|
||||
/// <remarks>If <see cref="FireEvent"/> is called, Free will be called automatically.</remarks>
|
||||
/// </summary>
|
||||
public void Free()
|
||||
{
|
||||
if (!_freeable)
|
||||
{
|
||||
throw new InvalidOperationException("Event is not able to be freed.");
|
||||
}
|
||||
|
||||
NativeAPI.FreeEvent(Handle);
|
||||
|
||||
_freeable = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,4 +1,4 @@
|
||||
using System;
|
||||
using System;
|
||||
using CounterStrikeSharp.API.Core;
|
||||
|
||||
namespace CounterStrikeSharp.API.Modules.Memory.DynamicFunctions;
|
||||
@@ -14,7 +14,13 @@ public class DynamicHook : NativeObject
|
||||
return NativeAPI.DynamicHookGetParam<T>(Handle, (int)typeof(T).ToValidDataType(), index);
|
||||
}
|
||||
|
||||
[Obsolete("Use GetReturn<T>() instead")]
|
||||
public T GetReturn<T>(int index)
|
||||
{
|
||||
return GetReturn<T>();
|
||||
}
|
||||
|
||||
public T GetReturn<T>()
|
||||
{
|
||||
return NativeAPI.DynamicHookGetReturn<T>(Handle, (int)typeof(T).ToValidDataType());
|
||||
}
|
||||
@@ -28,4 +34,4 @@ public class DynamicHook : NativeObject
|
||||
{
|
||||
NativeAPI.DynamicHookSetReturn(Handle, (int)typeof(T).ToValidDataType(), value);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -46,10 +46,10 @@ public static class VirtualFunctions
|
||||
|
||||
public static Action<IntPtr, string> SetModel = SetModelFunc.Invoke;
|
||||
|
||||
public static MemoryFunctionVoid<nint, RoundEndReason, float> TerminateRoundFunc =
|
||||
public static MemoryFunctionVoid<nint, RoundEndReason, float, nint, byte> TerminateRoundFunc =
|
||||
new(GameData.GetSignature("CCSGameRules_TerminateRound"));
|
||||
|
||||
public static Action<IntPtr, RoundEndReason, float> TerminateRound = TerminateRoundFunc.Invoke;
|
||||
public static Action<IntPtr, RoundEndReason, float, nint, byte> TerminateRound = TerminateRoundFunc.Invoke;
|
||||
|
||||
public static MemoryFunctionWithReturn<string, int, IntPtr> UTIL_CreateEntityByNameFunc =
|
||||
new(GameData.GetSignature("UTIL_CreateEntityByName"));
|
||||
@@ -89,7 +89,7 @@ public static class VirtualFunctions
|
||||
new(GameData.GetSignature("StateChanged"));
|
||||
public static Action<IntPtr, IntPtr, int, short, short> StateChanged = StateChangedFunc.Invoke;
|
||||
|
||||
public static MemoryFunctionVoid<IntPtr, int, long> NetworkStateChangedFunc = new("NetworkStateChanged");
|
||||
public static MemoryFunctionVoid<IntPtr, int, long> NetworkStateChangedFunc = new(GameData.GetSignature("NetworkStateChanged"));
|
||||
public static Action<IntPtr, int, long> NetworkStateChanged = NetworkStateChangedFunc.Invoke;
|
||||
|
||||
}
|
||||
@@ -28,22 +28,35 @@ public enum PostSelectAction
|
||||
public abstract class BaseMenu : IMenu
|
||||
{
|
||||
public string Title { get; set; }
|
||||
|
||||
public List<ChatMenuOption> MenuOptions { get; } = new();
|
||||
public PostSelectAction PostSelectAction { get; set; } = PostSelectAction.Reset;
|
||||
|
||||
public bool ExitButton { get; set; } = true;
|
||||
|
||||
protected BaseMenu(string title)
|
||||
{
|
||||
Title = title;
|
||||
}
|
||||
|
||||
public virtual ChatMenuOption AddMenuOption(string display, Action<CCSPlayerController, ChatMenuOption> onSelect, bool disabled = false)
|
||||
|
||||
public virtual ChatMenuOption AddMenuOption(string display, Action<CCSPlayerController, ChatMenuOption> onSelect,
|
||||
bool disabled = false)
|
||||
{
|
||||
var option = new ChatMenuOption(display, disabled, onSelect);
|
||||
MenuOptions.Add(option);
|
||||
return option;
|
||||
}
|
||||
|
||||
public abstract void Open(CCSPlayerController player);
|
||||
|
||||
public void OpenToAll()
|
||||
{
|
||||
foreach (var player in Utilities.GetPlayers())
|
||||
{
|
||||
Open(player);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// This must be called ChatMenuOption to maintain backwards compatibility with the old API
|
||||
public class ChatMenuOption
|
||||
{
|
||||
@@ -76,8 +89,8 @@ public abstract class BaseMenuInstance : IMenuInstance
|
||||
}
|
||||
|
||||
protected bool HasPrevButton => Page > 0;
|
||||
protected bool HasNextButton => CurrentOffset + NumPerPage < Menu.MenuOptions.Count;
|
||||
protected int MenuItemsPerPage => NumPerPage + 2 - (HasNextButton ? 1 : 0) - (HasPrevButton ? 1 : 0);
|
||||
protected bool HasNextButton => Menu.MenuOptions.Count > NumPerPage && CurrentOffset + NumPerPage < Menu.MenuOptions.Count;
|
||||
protected virtual int MenuItemsPerPage => NumPerPage;
|
||||
|
||||
public virtual void Display()
|
||||
{
|
||||
@@ -113,7 +126,7 @@ public abstract class BaseMenuInstance : IMenuInstance
|
||||
if (menuItemIndex >= 0 && menuItemIndex < Menu.MenuOptions.Count)
|
||||
{
|
||||
var menuOption = Menu.MenuOptions[menuItemIndex];
|
||||
|
||||
|
||||
if (!menuOption.Disabled)
|
||||
{
|
||||
menuOption.OnSelect(Player, menuOption);
|
||||
@@ -141,8 +154,8 @@ public abstract class BaseMenuInstance : IMenuInstance
|
||||
Page = 0;
|
||||
PrevPageOffsets.Clear();
|
||||
}
|
||||
|
||||
public void Close()
|
||||
|
||||
public virtual void Close()
|
||||
{
|
||||
MenuManager.CloseActiveMenu(Player);
|
||||
}
|
||||
|
||||
@@ -21,17 +21,43 @@ namespace CounterStrikeSharp.API.Modules.Menu;
|
||||
|
||||
public class CenterHtmlMenu : BaseMenu
|
||||
{
|
||||
private readonly BasePlugin? _plugin;
|
||||
public string TitleColor { get; set; } = "yellow";
|
||||
public string EnabledColor { get; set; } = "green";
|
||||
public string DisabledColor { get; set; } = "grey";
|
||||
public string PrevPageColor { get; set; } = "yellow";
|
||||
public string NextPageColor { get; set; } = "yellow";
|
||||
public string CloseColor { get; set; } = "red";
|
||||
|
||||
public CenterHtmlMenu(string title, BasePlugin plugin) : base(ModifyTitle(title))
|
||||
{
|
||||
_plugin = plugin;
|
||||
}
|
||||
|
||||
[Obsolete("Use the constructor that takes a BasePlugin")]
|
||||
public CenterHtmlMenu(string title) : base(ModifyTitle(title))
|
||||
{
|
||||
}
|
||||
|
||||
public override void Open(CCSPlayerController player)
|
||||
{
|
||||
if (_plugin == null)
|
||||
{
|
||||
throw new InvalidOperationException("This method is unsupported with the CenterHtmlMenu constructor used." +
|
||||
"Please provide a BasePlugin in the constructor.");
|
||||
};
|
||||
|
||||
public override ChatMenuOption AddMenuOption(string display, Action<CCSPlayerController, ChatMenuOption> onSelect, bool disabled = false)
|
||||
MenuManager.OpenCenterHtmlMenu(_plugin, player, this);
|
||||
}
|
||||
|
||||
public override ChatMenuOption AddMenuOption(string display, Action<CCSPlayerController, ChatMenuOption> onSelect,
|
||||
bool disabled = false)
|
||||
{
|
||||
var option = new ChatMenuOption(ModifyOptionDisplay(display), disabled, onSelect);
|
||||
MenuOptions.Add(option);
|
||||
return option;
|
||||
}
|
||||
|
||||
|
||||
private static string ModifyTitle(string title)
|
||||
{
|
||||
if (title.Length > 32)
|
||||
@@ -59,14 +85,15 @@ public class CenterHtmlMenuInstance : BaseMenuInstance
|
||||
{
|
||||
private readonly BasePlugin _plugin;
|
||||
public override int NumPerPage => 5; // one less than the actual number of items per page to avoid truncated options
|
||||
|
||||
protected override int MenuItemsPerPage => (Menu.ExitButton ? 0 : 1) + ((HasPrevButton && HasNextButton) ? NumPerPage - 1 : NumPerPage);
|
||||
|
||||
public CenterHtmlMenuInstance(BasePlugin plugin, CCSPlayerController player, IMenu menu) : base(player, menu)
|
||||
{
|
||||
_plugin = plugin;
|
||||
RemoveOnTickListener();
|
||||
plugin.RegisterListener<Core.Listeners.OnTick>(Display);
|
||||
}
|
||||
|
||||
|
||||
public override void Display()
|
||||
{
|
||||
if (MenuManager.GetActiveMenu(Player) != this)
|
||||
@@ -74,45 +101,53 @@ public class CenterHtmlMenuInstance : BaseMenuInstance
|
||||
Reset();
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
if (Menu is not CenterHtmlMenu centerHtmlMenu)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
var builder = new StringBuilder();
|
||||
builder.Append($"<b><font color='yellow'>{Menu.Title}</font></b>");
|
||||
builder.Append($"<b><font color='{centerHtmlMenu.TitleColor}'>{centerHtmlMenu.Title}</font></b>");
|
||||
builder.AppendLine("<br>");
|
||||
|
||||
var keyOffset = 1;
|
||||
|
||||
for (var i = CurrentOffset; i < Math.Min(CurrentOffset + MenuItemsPerPage, Menu.MenuOptions.Count); i++)
|
||||
for (var i = CurrentOffset; i < Math.Min(CurrentOffset + MenuItemsPerPage, centerHtmlMenu.MenuOptions.Count); i++)
|
||||
{
|
||||
var option = Menu.MenuOptions[i];
|
||||
string color = option.Disabled ? "grey" : "green";
|
||||
var option = centerHtmlMenu.MenuOptions[i];
|
||||
string color = option.Disabled ? centerHtmlMenu.DisabledColor : centerHtmlMenu.EnabledColor;
|
||||
builder.Append($"<font color='{color}'>!{keyOffset++}</font> {option.Text}");
|
||||
builder.AppendLine("<br>");
|
||||
}
|
||||
|
||||
|
||||
if (HasPrevButton)
|
||||
{
|
||||
builder.AppendFormat("<font color='yellow'>!7</font> <- Prev");
|
||||
builder.AppendFormat($"<font color='{centerHtmlMenu.PrevPageColor}'>!7</font> <- Prev");
|
||||
builder.AppendLine("<br>");
|
||||
}
|
||||
|
||||
if (HasNextButton)
|
||||
{
|
||||
builder.AppendFormat("<font color='yellow'>!8</font> -> Next");
|
||||
builder.AppendFormat($"<font color='{centerHtmlMenu.NextPageColor}'>!8</font> -> Next");
|
||||
builder.AppendLine("<br>");
|
||||
}
|
||||
|
||||
builder.AppendFormat("<font color='red'>!9</font> -> Close");
|
||||
builder.AppendLine("<br>");
|
||||
if (centerHtmlMenu.ExitButton)
|
||||
{
|
||||
builder.AppendFormat($"<font color='{centerHtmlMenu.CloseColor}'>!9</font> -> Close");
|
||||
builder.AppendLine("<br>");
|
||||
}
|
||||
|
||||
var currentPageText = builder.ToString();
|
||||
Player.PrintToCenterHtml(currentPageText);
|
||||
}
|
||||
|
||||
public override void Reset()
|
||||
public override void Close()
|
||||
{
|
||||
base.Reset();
|
||||
base.Close();
|
||||
RemoveOnTickListener();
|
||||
|
||||
|
||||
// Send a blank message to clear the menu
|
||||
Player.PrintToCenterHtml(" ");
|
||||
}
|
||||
|
||||
@@ -18,10 +18,22 @@ using CounterStrikeSharp.API.Modules.Utils;
|
||||
|
||||
namespace CounterStrikeSharp.API.Modules.Menu;
|
||||
|
||||
public class ChatMenu: BaseMenu
|
||||
public class ChatMenu : BaseMenu
|
||||
{
|
||||
public char TitleColor { get; set; } = ChatColors.Yellow;
|
||||
public char EnabledColor { get; set; } = ChatColors.Green;
|
||||
public char DisabledColor { get; set; } = ChatColors.Grey;
|
||||
public char PrevPageColor { get; set; } = ChatColors.Yellow;
|
||||
public char NextPageColor { get; set; } = ChatColors.Yellow;
|
||||
public char CloseColor { get; set; } = ChatColors.Red;
|
||||
public ChatMenu(string title) : base(title)
|
||||
{
|
||||
ExitButton = false;
|
||||
}
|
||||
|
||||
public override void Open(CCSPlayerController player)
|
||||
{
|
||||
MenuManager.OpenChatMenu(player, this);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -33,29 +45,35 @@ public class ChatMenuInstance : BaseMenuInstance
|
||||
|
||||
public override void Display()
|
||||
{
|
||||
Player.PrintToChat(Menu.Title);
|
||||
if (Menu is not ChatMenu chatMenu)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
Player.PrintToChat($" {chatMenu.TitleColor} {chatMenu.Title}");
|
||||
Player.PrintToChat("---");
|
||||
|
||||
var keyOffset = 1;
|
||||
|
||||
for (var i = CurrentOffset;
|
||||
i < Math.Min(CurrentOffset + MenuItemsPerPage, Menu.MenuOptions.Count);
|
||||
i++)
|
||||
for (var i = CurrentOffset; i < Math.Min(CurrentOffset + MenuItemsPerPage, Menu.MenuOptions.Count); i++)
|
||||
{
|
||||
var option = Menu.MenuOptions[i];
|
||||
|
||||
Player.PrintToChat(
|
||||
$" {(option.Disabled ? ChatColors.Grey : ChatColors.Green)} !{keyOffset++} {ChatColors.Default}{option.Text}");
|
||||
char color = option.Disabled ? chatMenu.DisabledColor : chatMenu.EnabledColor;
|
||||
Player.PrintToChat($" {color} !{keyOffset++} {ChatColors.Default}{option.Text}");
|
||||
}
|
||||
|
||||
if (HasPrevButton)
|
||||
{
|
||||
Player.PrintToChat($" {ChatColors.Yellow}!7 {ChatColors.Default}-> Prev");
|
||||
Player.PrintToChat($" {chatMenu.PrevPageColor}!7 {ChatColors.Default}-> Prev");
|
||||
}
|
||||
|
||||
if (HasNextButton)
|
||||
{
|
||||
Player.PrintToChat($" {ChatColors.Yellow}!8 {ChatColors.Default}-> Next");
|
||||
Player.PrintToChat($" {chatMenu.NextPageColor}!8 {ChatColors.Default}-> Next");
|
||||
}
|
||||
|
||||
if (Menu.ExitButton)
|
||||
{
|
||||
Player.PrintToChat($" {chatMenu.CloseColor}!9 {ChatColors.Default}-> Close");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -21,6 +21,11 @@ public class ConsoleMenu : BaseMenu
|
||||
public ConsoleMenu(string title) : base(title)
|
||||
{
|
||||
}
|
||||
|
||||
public override void Open(CCSPlayerController player)
|
||||
{
|
||||
MenuManager.OpenConsoleMenu(player, this);
|
||||
}
|
||||
}
|
||||
|
||||
public class ConsoleMenuInstance : BaseMenuInstance
|
||||
@@ -42,7 +47,7 @@ public class ConsoleMenuInstance : BaseMenuInstance
|
||||
{
|
||||
var option = Menu.MenuOptions[i];
|
||||
|
||||
Player.PrintToConsole($"{(option.Disabled ? "[Enabled]" : "[Disabled] - ")} css_{keyOffset++} {option.Text}");
|
||||
Player.PrintToConsole($"{(option.Disabled ? "[Disabled] - " : "[Enabled]")} css_{keyOffset++} {option.Text}");
|
||||
}
|
||||
|
||||
if (HasPrevButton)
|
||||
@@ -54,5 +59,10 @@ public class ConsoleMenuInstance : BaseMenuInstance
|
||||
{
|
||||
Player.PrintToConsole("css_8 -> Next");
|
||||
}
|
||||
|
||||
if (Menu.ExitButton)
|
||||
{
|
||||
Player.PrintToConsole("css_9 -> Close");
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -20,15 +20,18 @@ namespace CounterStrikeSharp.API.Modules.Menu;
|
||||
|
||||
public interface IMenu
|
||||
{
|
||||
public string Title { get; set; }
|
||||
public List<ChatMenuOption> MenuOptions { get; }
|
||||
public PostSelectAction PostSelectAction
|
||||
string Title { get; set; }
|
||||
List<ChatMenuOption> MenuOptions { get; }
|
||||
PostSelectAction PostSelectAction
|
||||
{
|
||||
get { throw new NotImplementedException(); }
|
||||
set { throw new NotImplementedException(); }
|
||||
}
|
||||
bool ExitButton { get; set; }
|
||||
|
||||
public ChatMenuOption AddMenuOption(string display, Action<CCSPlayerController, ChatMenuOption> onSelect, bool disabled = false);
|
||||
ChatMenuOption AddMenuOption(string display, Action<CCSPlayerController, ChatMenuOption> onSelect, bool disabled = false);
|
||||
void Open(CCSPlayerController player);
|
||||
void OpenToAll();
|
||||
}
|
||||
|
||||
public interface IMenuInstance
|
||||
|
||||
@@ -41,7 +41,7 @@ public static class MenuManager
|
||||
|
||||
ActiveMenus.Remove(player.Handle);
|
||||
}
|
||||
|
||||
|
||||
public static void OpenChatMenu(CCSPlayerController player, ChatMenu menu)
|
||||
{
|
||||
CloseActiveMenu(player);
|
||||
@@ -49,7 +49,7 @@ public static class MenuManager
|
||||
ActiveMenus[player.Handle] = new ChatMenuInstance(player, menu);
|
||||
ActiveMenus[player.Handle].Display();
|
||||
}
|
||||
|
||||
|
||||
public static void OpenCenterHtmlMenu(BasePlugin plugin, CCSPlayerController player, CenterHtmlMenu menu)
|
||||
{
|
||||
CloseActiveMenu(player);
|
||||
@@ -57,7 +57,7 @@ public static class MenuManager
|
||||
ActiveMenus[player.Handle] = new CenterHtmlMenuInstance(plugin, player, menu);
|
||||
ActiveMenus[player.Handle].Display();
|
||||
}
|
||||
|
||||
|
||||
public static void OpenConsoleMenu(CCSPlayerController player, ConsoleMenu menu)
|
||||
{
|
||||
CloseActiveMenu(player);
|
||||
|
||||
@@ -14,9 +14,6 @@
|
||||
* along with CounterStrikeSharp. If not, see <https://www.gnu.org/licenses/>. *
|
||||
*/
|
||||
|
||||
using System;
|
||||
using CounterStrikeSharp.API.Core;
|
||||
|
||||
namespace CounterStrikeSharp.API.Modules.Utils
|
||||
{
|
||||
/// <summary>
|
||||
@@ -30,6 +27,8 @@ namespace CounterStrikeSharp.API.Modules.Utils
|
||||
/// </summary>
|
||||
public class Angle : NativeObject
|
||||
{
|
||||
public static readonly Angle Zero = new();
|
||||
|
||||
public Angle(IntPtr pointer) : base(pointer)
|
||||
{
|
||||
}
|
||||
@@ -46,8 +45,6 @@ namespace CounterStrikeSharp.API.Modules.Utils
|
||||
this.Y = y ?? 0;
|
||||
this.Z = z ?? 0;
|
||||
}
|
||||
|
||||
|
||||
|
||||
#region Accessors
|
||||
|
||||
@@ -366,15 +363,15 @@ namespace CounterStrikeSharp.API.Modules.Utils
|
||||
return this.IsEqualTol(v, 0.01f);
|
||||
}
|
||||
|
||||
public override string ToString()
|
||||
{
|
||||
return $"{X:n2} {Y:n2} {Z:n2}";
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
protected override void OnDispose()
|
||||
{
|
||||
}*/
|
||||
|
||||
public override string ToString()
|
||||
{
|
||||
return $"{X:n2} {Y:n2} {Z:n2}";
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -14,14 +14,14 @@
|
||||
* along with CounterStrikeSharp. If not, see <https://www.gnu.org/licenses/>. *
|
||||
*/
|
||||
|
||||
using System;
|
||||
using System.Runtime.CompilerServices;
|
||||
using CounterStrikeSharp.API.Core;
|
||||
|
||||
namespace CounterStrikeSharp.API.Modules.Utils
|
||||
{
|
||||
public class QAngle : NativeObject
|
||||
{
|
||||
public static readonly QAngle Zero = new();
|
||||
|
||||
public QAngle(IntPtr pointer) : base(pointer)
|
||||
{
|
||||
}
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
/*
|
||||
/*
|
||||
* 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
|
||||
@@ -14,11 +14,7 @@
|
||||
* along with CounterStrikeSharp. If not, see <https://www.gnu.org/licenses/>. *
|
||||
*/
|
||||
|
||||
using System;
|
||||
using System.Runtime.CompilerServices;
|
||||
using System.Runtime.InteropServices;
|
||||
using CounterStrikeSharp.API.Core;
|
||||
using CounterStrikeSharp.API.Modules.Utils;
|
||||
|
||||
namespace CounterStrikeSharp.API.Modules.Utils
|
||||
{
|
||||
@@ -33,11 +29,12 @@ namespace CounterStrikeSharp.API.Modules.Utils
|
||||
/// </summary>
|
||||
public class Vector : NativeObject
|
||||
{
|
||||
public static readonly Vector Zero = new();
|
||||
|
||||
public Vector(IntPtr pointer) : base(pointer)
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
public Vector(float? x = null, float? y = null, float? z = null) : this(NativeAPI.VectorNew())
|
||||
{
|
||||
this.X = x ?? 0;
|
||||
@@ -75,7 +72,7 @@ namespace CounterStrikeSharp.API.Modules.Utils
|
||||
{
|
||||
this.X += vector.X;
|
||||
this.Y += vector.Y;
|
||||
this.Z = this.Z = vector.Z;
|
||||
this.Z += vector.Z;
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -19,6 +19,7 @@ using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Runtime.InteropServices;
|
||||
using System.Threading.Tasks;
|
||||
using CounterStrikeSharp.API.Core;
|
||||
using CounterStrikeSharp.API.Modules.Memory;
|
||||
using CounterStrikeSharp.API.Modules.Utils;
|
||||
@@ -27,19 +28,77 @@ namespace CounterStrikeSharp.API
|
||||
{
|
||||
public class Server
|
||||
{
|
||||
public static float TickInterval => NativeAPI.GetTickInterval();
|
||||
/// <summary>
|
||||
/// Duration of a single game tick in seconds, based on a 64 tick server (hard coded in CS2).
|
||||
/// </summary>
|
||||
public static float TickInterval => 0.015625f;
|
||||
|
||||
/// <summary>
|
||||
/// Executes a command on the server, as if it was entered from the console.
|
||||
/// </summary>
|
||||
/// <param name="command"></param>
|
||||
public static void ExecuteCommand(string command) => NativeAPI.IssueServerCommand(command);
|
||||
|
||||
public static string MapName => NativeAPI.GetMapName();
|
||||
// public static void PrintToConsole(string message) => NativeAPI.PrintToConsole(message);
|
||||
|
||||
/// <summary>
|
||||
/// Returns the total time the server has been running in seconds.
|
||||
/// </summary>
|
||||
/// <remarks>Does not increment when server is hibernating</remarks>
|
||||
public static double TickedTime => NativeAPI.GetTickedTime();
|
||||
|
||||
/// <summary>
|
||||
/// Returns the current map time in seconds, as an interval of the server's tick interval.
|
||||
/// e.g. 70.046875 would represent 70 seconds of map time and the 4483rd tick of the server (70.046875 / 0.015625).
|
||||
/// </summary>
|
||||
/// <remarks>Increments even when server is hibernating</remarks>
|
||||
public static float CurrentTime => NativeAPI.GetCurrentTime();
|
||||
|
||||
/// <summary>
|
||||
/// Returns the current map tick count.
|
||||
/// CS2 is a 64 tick server, so the value will increment by 64 every second.
|
||||
/// </summary>
|
||||
public static int TickCount => NativeAPI.GetTickCount();
|
||||
public static float GameFrameTime => NativeAPI.GetGameFrameTime();
|
||||
|
||||
/// <summary>
|
||||
/// Returns the total time the server has been running in seconds.
|
||||
/// </summary>
|
||||
/// <remarks>Increments even when server is hibernating</remarks>
|
||||
public static double EngineTime => NativeAPI.GetEngineTime();
|
||||
|
||||
public static void PrecacheModel(string name) => NativeAPI.PrecacheModel(name);
|
||||
|
||||
/// <summary>
|
||||
/// <inheritdoc cref="RunOnTick"/>
|
||||
/// Returns Task that completes once the synchronous task has been completed.
|
||||
/// </summary>
|
||||
public static Task RunOnTickAsync(int tick, Action task)
|
||||
{
|
||||
var functionReference = FunctionReference.Create(task, FunctionLifetime.SingleUse);
|
||||
NativeAPI.QueueTaskForFrame(tick, functionReference);
|
||||
return functionReference.CompletionTask;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Queue a task to be executed on the specified tick.
|
||||
/// See <see cref="TickCount"/> to retrieve the current tick.
|
||||
/// <remarks>Does not execute if the server is hibernating.</remarks>
|
||||
/// </summary>
|
||||
public static void RunOnTick(int tick, Action task)
|
||||
{
|
||||
RunOnTickAsync(tick, task);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// <inheritdoc cref="NextFrame"/>
|
||||
/// Returns Task that completes once the synchronous task has been completed.
|
||||
/// </summary>
|
||||
public static Task NextFrameAsync(Action task)
|
||||
{
|
||||
var functionReference = FunctionReference.Create(task, FunctionLifetime.SingleUse);
|
||||
NativeAPI.QueueTaskForNextFrame(functionReference);
|
||||
return functionReference.CompletionTask;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Queue a task to be executed on the next game frame.
|
||||
@@ -47,9 +106,18 @@ namespace CounterStrikeSharp.API
|
||||
/// </summary>
|
||||
public static void NextFrame(Action task)
|
||||
{
|
||||
var functionReference = FunctionReference.Create(task);
|
||||
functionReference.Lifetime = FunctionLifetime.SingleUse;
|
||||
NativeAPI.QueueTaskForNextFrame(functionReference);
|
||||
NextFrameAsync(task);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// <inheritdoc cref="NextWorldUpdate"/>
|
||||
/// Returns Task that completes once the synchronous task has been completed.
|
||||
/// </summary>
|
||||
public static Task NextWorldUpdateAsync(Action task)
|
||||
{
|
||||
var functionReference = FunctionReference.Create(task, FunctionLifetime.SingleUse);
|
||||
NativeAPI.QueueTaskForNextWorldUpdate(functionReference);
|
||||
return functionReference.CompletionTask;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -59,9 +127,7 @@ namespace CounterStrikeSharp.API
|
||||
/// <param name="task"></param>
|
||||
public static void NextWorldUpdate(Action task)
|
||||
{
|
||||
var functionReference = FunctionReference.Create(task);
|
||||
functionReference.Lifetime = FunctionLifetime.SingleUse;
|
||||
NativeAPI.QueueTaskForNextWorldUpdate(functionReference);
|
||||
NextWorldUpdateAsync(task);
|
||||
}
|
||||
|
||||
public static void PrintToChatAll(string message)
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
|
||||
<PropertyGroup>
|
||||
<OutputType>Exe</OutputType>
|
||||
<TargetFramework>net7.0</TargetFramework>
|
||||
<TargetFramework>net8.0</TargetFramework>
|
||||
<ImplicitUsings>enable</ImplicitUsings>
|
||||
<Nullable>enable</Nullable>
|
||||
<TreatWarningsAsErrors>true</TreatWarningsAsErrors>
|
||||
|
||||
@@ -10654,13 +10654,6 @@
|
||||
"category": 0,
|
||||
"name": "bool"
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "m_bDroppedFromDeath",
|
||||
"type": {
|
||||
"category": 0,
|
||||
"name": "bool"
|
||||
}
|
||||
}
|
||||
],
|
||||
"parent": "CCSWeaponBase"
|
||||
@@ -12803,6 +12796,13 @@
|
||||
"name": "CUtlVector< int32 >"
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "m_nSpawnPointsRandomSeed",
|
||||
"type": {
|
||||
"category": 0,
|
||||
"name": "int32"
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "m_bFirstConnected",
|
||||
"type": {
|
||||
@@ -13237,6 +13237,13 @@
|
||||
"name": "CUtlVector< SpawnPoint* >"
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "m_bRespawningAllRespawnablePlayers",
|
||||
"type": {
|
||||
"category": 0,
|
||||
"name": "bool"
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "m_iNextCTSpawnPoint",
|
||||
"type": {
|
||||
@@ -13244,6 +13251,13 @@
|
||||
"name": "int32"
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "m_flCTSpawnPointUsedTime",
|
||||
"type": {
|
||||
"category": 0,
|
||||
"name": "float32"
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "m_iNextTerroristSpawnPoint",
|
||||
"type": {
|
||||
@@ -13251,6 +13265,13 @@
|
||||
"name": "int32"
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "m_flTerroristSpawnPointUsedTime",
|
||||
"type": {
|
||||
"category": 0,
|
||||
"name": "float32"
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "m_CTSpawnPoints",
|
||||
"type": {
|
||||
@@ -13611,18 +13632,6 @@
|
||||
"name": "uint8"
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "m_nRoundStartTicks",
|
||||
"type": {
|
||||
"atomic": 2,
|
||||
"category": 4,
|
||||
"inner": {
|
||||
"category": 0,
|
||||
"name": "int32"
|
||||
},
|
||||
"name": "CUtlVector< int32 >"
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "m_flLastPerfSampleTime",
|
||||
"type": {
|
||||
@@ -14294,6 +14303,34 @@
|
||||
"name": "CNetworkUtlVectorBase< EKillTypes_t >"
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "m_bMvpNoMusic",
|
||||
"type": {
|
||||
"category": 0,
|
||||
"name": "bool"
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "m_eMvpReason",
|
||||
"type": {
|
||||
"category": 0,
|
||||
"name": "int32"
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "m_iMusicKitID",
|
||||
"type": {
|
||||
"category": 0,
|
||||
"name": "int32"
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "m_iMusicKitMVPs",
|
||||
"type": {
|
||||
"category": 0,
|
||||
"name": "int32"
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "m_iMVPs",
|
||||
"type": {
|
||||
@@ -15339,17 +15376,10 @@
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "m_bInvalidSteamLogonDelayed",
|
||||
"name": "m_flIdleTimeSinceLastAction",
|
||||
"type": {
|
||||
"category": 0,
|
||||
"name": "bool"
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "m_flLastAction",
|
||||
"type": {
|
||||
"category": 5,
|
||||
"name": "GameTime_t"
|
||||
"name": "float32"
|
||||
}
|
||||
},
|
||||
{
|
||||
@@ -42189,13 +42219,6 @@
|
||||
"name": "GameTime_t"
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "m_bPlantedAfterPickup",
|
||||
"type": {
|
||||
"category": 0,
|
||||
"name": "bool"
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "m_angCatchUpToPlayerEye",
|
||||
"type": {
|
||||
@@ -97606,8 +97629,12 @@
|
||||
"value": 15
|
||||
},
|
||||
{
|
||||
"name": "PVAL_COUNT",
|
||||
"name": "PVAL_PANORAMA_PANEL_HANDLE",
|
||||
"value": 16
|
||||
},
|
||||
{
|
||||
"name": "PVAL_COUNT",
|
||||
"value": 17
|
||||
}
|
||||
]
|
||||
},
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
|
||||
<PropertyGroup>
|
||||
<TargetFramework>net7.0</TargetFramework>
|
||||
<TargetFramework>net8.0</TargetFramework>
|
||||
<Platforms>AnyCPU;x86</Platforms>
|
||||
<GenerateAssemblyInfo>false</GenerateAssemblyInfo>
|
||||
<CopyLocalLockFileAssemblies>true</CopyLocalLockFileAssemblies>
|
||||
|
||||
@@ -51,6 +51,7 @@ bool CCoreConfig::Init(char* conf_error, int conf_error_size)
|
||||
SilentChatTrigger = m_json.value("SilentChatTrigger", SilentChatTrigger);
|
||||
FollowCS2ServerGuidelines = m_json.value("FollowCS2ServerGuidelines", FollowCS2ServerGuidelines);
|
||||
PluginHotReloadEnabled = m_json.value("PluginHotReloadEnabled", PluginHotReloadEnabled);
|
||||
PluginAutoLoadEnabled = m_json.value("PluginAutoLoadEnabled", PluginAutoLoadEnabled);
|
||||
ServerLanguage = m_json.value("ServerLanguage", ServerLanguage);
|
||||
} catch (const std::exception& ex) {
|
||||
V_snprintf(conf_error, conf_error_size, "Failed to parse CoreConfig file: %s", ex.what());
|
||||
|
||||
@@ -29,6 +29,7 @@ class CCoreConfig
|
||||
std::vector<std::string> SilentChatTrigger = { std::string("/") };
|
||||
bool FollowCS2ServerGuidelines = true;
|
||||
bool PluginHotReloadEnabled = true;
|
||||
bool PluginAutoLoadEnabled = true;
|
||||
std::string ServerLanguage = "en";
|
||||
|
||||
using json = nlohmann::json;
|
||||
|
||||
@@ -1,130 +0,0 @@
|
||||
#pragma once
|
||||
|
||||
#include <array>
|
||||
#include <cstdint>
|
||||
#include <vector>
|
||||
using UtlTsHashHandleT = std::uint64_t;
|
||||
|
||||
class CUtlMemoryPool {
|
||||
public:
|
||||
// returns number of allocated blocks
|
||||
int BlockSize() const {
|
||||
return m_blocks_per_blob_;
|
||||
}
|
||||
int Count() const {
|
||||
return m_block_allocated_size_;
|
||||
}
|
||||
int PeakCount() const {
|
||||
return m_peak_alloc_;
|
||||
}
|
||||
private:
|
||||
std::int32_t m_block_size_ = 0; // 0x0558
|
||||
std::int32_t m_blocks_per_blob_ = 0; // 0x055C
|
||||
std::int32_t m_grow_mode_ = 0; // 0x0560
|
||||
std::int32_t m_blocks_allocated_ = 0; // 0x0564
|
||||
std::int32_t m_block_allocated_size_ = 0; // 0x0568
|
||||
std::int32_t m_peak_alloc_ = 0; // 0x056C
|
||||
};
|
||||
|
||||
template <class T, class Keytype = std::uint64_t>
|
||||
class CUtlTSHash {
|
||||
public:
|
||||
// Invalid handle.
|
||||
static UtlTsHashHandleT InvalidHandle(void) {
|
||||
return static_cast<UtlTsHashHandleT>(0);
|
||||
}
|
||||
|
||||
// Returns the number of elements in the hash table
|
||||
[[nodiscard]] int BlockSize() const {
|
||||
return m_entry_memory_.BlockSize();
|
||||
}
|
||||
[[nodiscard]] int Count() const {
|
||||
return m_entry_memory_.Count();
|
||||
}
|
||||
|
||||
// Returns elements in the table
|
||||
std::vector<T> GetElements(void);
|
||||
public:
|
||||
// Templatized for memory tracking purposes
|
||||
template <typename DataT>
|
||||
struct HashFixedDataInternalT {
|
||||
Keytype m_ui_key;
|
||||
HashFixedDataInternalT<DataT>* m_next;
|
||||
DataT m_data;
|
||||
};
|
||||
|
||||
using HashFixedDataT = HashFixedDataInternalT<T>;
|
||||
|
||||
// Templatized for memory tracking purposes
|
||||
template <typename DataT>
|
||||
struct HashFixedStructDataInternalT {
|
||||
DataT m_data;
|
||||
Keytype m_ui_key;
|
||||
char pad_0x0020[0x8];
|
||||
};
|
||||
|
||||
using HashFixedStructDataT = HashFixedStructDataInternalT<T>;
|
||||
|
||||
struct HashStructDataT {
|
||||
char pad_0x0000[0x10]; // 0x0000
|
||||
std::array<HashFixedStructDataT, 256> m_list;
|
||||
};
|
||||
|
||||
struct HashAllocatedDataT {
|
||||
public:
|
||||
auto GetList() {
|
||||
return m_list_;
|
||||
}
|
||||
private:
|
||||
char pad_0x0000[0x18]; // 0x0000
|
||||
std::array<HashFixedDataT, 128> m_list_;
|
||||
};
|
||||
|
||||
// Templatized for memory tracking purposes
|
||||
template <typename DataT>
|
||||
struct HashBucketDataInternalT {
|
||||
DataT m_data;
|
||||
HashFixedDataInternalT<DataT>* m_next;
|
||||
Keytype m_ui_key;
|
||||
};
|
||||
|
||||
using HashBucketDataT = HashBucketDataInternalT<T>;
|
||||
|
||||
struct HashUnallocatedDataT {
|
||||
HashUnallocatedDataT* m_next_ = nullptr; // 0x0000
|
||||
Keytype m_6114; // 0x0008
|
||||
Keytype m_ui_key; // 0x0010
|
||||
Keytype m_i_unk_1; // 0x0018
|
||||
std::array<HashBucketDataT, 256> m_current_block_list; // 0x0020
|
||||
};
|
||||
|
||||
struct HashBucketT {
|
||||
HashStructDataT* m_struct_data = nullptr;
|
||||
void* m_mutex_list = nullptr;
|
||||
HashAllocatedDataT* m_allocated_data = nullptr;
|
||||
HashUnallocatedDataT* m_unallocated_data = nullptr;
|
||||
};
|
||||
|
||||
CUtlMemoryPool m_entry_memory_;
|
||||
HashBucketT m_buckets_;
|
||||
bool m_needs_commit_ = false;
|
||||
};
|
||||
|
||||
template <class T, class Keytype>
|
||||
std::vector<T> CUtlTSHash<T, Keytype>::GetElements(void) {
|
||||
std::vector<T> list;
|
||||
|
||||
const int n_count = Count();
|
||||
auto n_index = 0;
|
||||
auto& unallocated_data = m_buckets_.m_unallocated_data;
|
||||
for (auto element = unallocated_data; element; element = element->m_next_) {
|
||||
for (auto i = 0; i < BlockSize() && i != n_count; i++) {
|
||||
list.emplace_back(element->m_current_block_list.at(i).m_data);
|
||||
n_index++;
|
||||
|
||||
if (n_index >= n_count)
|
||||
break;
|
||||
}
|
||||
}
|
||||
return list;
|
||||
}
|
||||
@@ -32,7 +32,5 @@ void interfaces::Initialize() {
|
||||
g_pCVar = (ICvar*)modules::tier0->FindInterface(CVAR_INTERFACE_VERSION);
|
||||
g_pSource2GameEntities = (ISource2GameEntities*)modules::server->FindInterface(
|
||||
SOURCE2GAMEENTITIES_INTERFACE_VERSION);
|
||||
pSchemaSystem =
|
||||
(CSchemaSystem*)modules::schemasystem->FindInterface(SCHEMASYSTEM_INTERFACE_VERSION);
|
||||
}
|
||||
} // namespace counterstrikesharp
|
||||
|
||||
@@ -20,13 +20,11 @@
|
||||
#pragma once
|
||||
|
||||
#include "cgameresourceserviceserver.h"
|
||||
#include "cschemasystem.h"
|
||||
|
||||
namespace counterstrikesharp {
|
||||
namespace interfaces {
|
||||
void Initialize();
|
||||
|
||||
inline CGameResourceService *pGameResourceServiceServer = nullptr;
|
||||
inline CSchemaSystem *pSchemaSystem = nullptr;
|
||||
} // namespace interfaces
|
||||
} // namespace counterstrikesharp
|
||||
@@ -1,418 +0,0 @@
|
||||
// Copyright (C) 2023 neverlosecc
|
||||
// See end of file for extended copyright information.
|
||||
/**
|
||||
* =============================================================================
|
||||
* Source2Gen
|
||||
* Copyright (C) 2023 neverlose (https://github.com/neverlosecc/source2gen)
|
||||
* =============================================================================
|
||||
**/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <vector>
|
||||
#include <utils/virtual.h>
|
||||
#include <string_view>
|
||||
#include <array>
|
||||
#include "core/cs2_sdk/interfaces/CUtlTSHash.h"
|
||||
#define CS2
|
||||
|
||||
#define CSCHEMATYPE_GETSIZES_INDEX 3
|
||||
#define SCHEMASYSTEM_TYPE_SCOPES_OFFSET 0x190
|
||||
#define SCHEMASYSTEMTYPESCOPE_OFF1 0x47E
|
||||
#define SCHEMASYSTEMTYPESCOPE_OFF2 0x2808
|
||||
#define SCHEMASYSTEM_FIND_DECLARED_CLASS_TYPE 2
|
||||
|
||||
class CSchemaClassInfo;
|
||||
class CSchemaSystemTypeScope;
|
||||
class CSchemaType;
|
||||
|
||||
struct SchemaMetadataEntryData_t;
|
||||
struct SchemaMetadataSetData_t;
|
||||
struct SchemaClassInfoData_t;
|
||||
|
||||
using SchemaString_t = const char*;
|
||||
|
||||
template <typename T> struct SchemaArray
|
||||
{
|
||||
public:
|
||||
T* begin() const { return m_data; }
|
||||
|
||||
T* end() const { return m_data + m_size; }
|
||||
|
||||
T* m_data;
|
||||
unsigned int m_size;
|
||||
};
|
||||
|
||||
struct CSchemaNetworkValue
|
||||
{
|
||||
union
|
||||
{
|
||||
const char* m_sz_value;
|
||||
int m_n_value;
|
||||
float m_f_value;
|
||||
std::uintptr_t m_p_value;
|
||||
};
|
||||
};
|
||||
|
||||
struct CSchemaClassBinding
|
||||
{
|
||||
CSchemaClassBinding* parent;
|
||||
const char* m_binary_name; // ex: C_World
|
||||
const char* m_module_name; // ex: libclient.so
|
||||
const char* m_class_name; // ex: client
|
||||
void* m_class_info_old_synthesized;
|
||||
void* m_class_info;
|
||||
void* m_this_module_binding_pointer;
|
||||
CSchemaType* m_schema_type;
|
||||
};
|
||||
|
||||
struct SchemaEnumeratorInfoData_t
|
||||
{
|
||||
SchemaString_t m_name;
|
||||
|
||||
union
|
||||
{
|
||||
unsigned char m_value_char;
|
||||
unsigned short m_value_short;
|
||||
unsigned int m_value_int;
|
||||
unsigned long long m_value;
|
||||
};
|
||||
|
||||
char pad_0x0010[0x10]; // 0x0010
|
||||
};
|
||||
|
||||
class CSchemaEnumInfo
|
||||
{
|
||||
public:
|
||||
SchemaEnumeratorInfoData_t m_field_;
|
||||
};
|
||||
|
||||
class CSchemaEnumBinding
|
||||
{
|
||||
public:
|
||||
virtual const char* GetBindingName() = 0;
|
||||
virtual CSchemaClassBinding* AsClassBinding() = 0;
|
||||
virtual CSchemaEnumBinding* AsEnumBinding() = 0;
|
||||
virtual const char* GetBinaryName() = 0;
|
||||
virtual const char* GetProjectName() = 0;
|
||||
|
||||
public:
|
||||
char* m_binding_name_; // 0x0008
|
||||
char* m_dll_name_; // 0x0010
|
||||
std::int8_t m_align_; // 0x0018
|
||||
char pad_0x0019[0x3]; // 0x0019
|
||||
std::int16_t m_size_; // 0x001C
|
||||
std::int16_t m_flags_; // 0x001E
|
||||
SchemaEnumeratorInfoData_t* m_enum_info_;
|
||||
char pad_0x0028[0x8]; // 0x0028
|
||||
CSchemaSystemTypeScope* m_type_scope_; // 0x0030
|
||||
char pad_0x0038[0x8]; // 0x0038
|
||||
std::int32_t m_i_unk1_; // 0x0040
|
||||
};
|
||||
|
||||
enum SchemaClassFlags_t
|
||||
{
|
||||
SCHEMA_CLASS_HAS_VIRTUAL_MEMBERS = 1,
|
||||
SCHEMA_CLASS_IS_ABSTRACT = 2,
|
||||
SCHEMA_CLASS_HAS_TRIVIAL_CONSTRUCTOR = 4,
|
||||
SCHEMA_CLASS_HAS_TRIVIAL_DESTRUCTOR = 8,
|
||||
SCHEMA_CLASS_TEMP_HACK_HAS_NOSCHEMA_MEMBERS = 16,
|
||||
SCHEMA_CLASS_TEMP_HACK_HAS_CONSTRUCTOR_LIKE_METHODS = 32,
|
||||
SCHEMA_CLASS_TEMP_HACK_HAS_DESTRUCTOR_LIKE_METHODS = 64,
|
||||
SCHEMA_CLASS_IS_NOSCHEMA_CLASS = 128,
|
||||
};
|
||||
|
||||
enum ETypeCategory
|
||||
{
|
||||
Schema_Builtin = 0,
|
||||
Schema_Ptr = 1,
|
||||
Schema_Bitfield = 2,
|
||||
Schema_FixedArray = 3,
|
||||
Schema_Atomic = 4,
|
||||
Schema_DeclaredClass = 5,
|
||||
Schema_DeclaredEnum = 6,
|
||||
Schema_None = 7
|
||||
};
|
||||
|
||||
enum EAtomicCategory
|
||||
{
|
||||
Atomic_Basic,
|
||||
Atomic_T,
|
||||
Atomic_CollectionOfT,
|
||||
Atomic_TT,
|
||||
Atomic_I,
|
||||
Atomic_None
|
||||
};
|
||||
|
||||
#define __thiscall
|
||||
|
||||
class CSchemaType
|
||||
{
|
||||
public:
|
||||
bool GetSizes(int* out_size1, uint8_t* unk_probably_not_size)
|
||||
{
|
||||
return reinterpret_cast<int(__thiscall*)(void*, int*, uint8_t*)>(
|
||||
_vtable[CSCHEMATYPE_GETSIZES_INDEX])(this, out_size1, unk_probably_not_size);
|
||||
}
|
||||
|
||||
public:
|
||||
bool GetSize(int* out_size)
|
||||
{
|
||||
uint8_t smh = 0;
|
||||
return GetSizes(out_size, &smh);
|
||||
}
|
||||
|
||||
public:
|
||||
uintptr_t* _vtable; // 0x0000
|
||||
const char* m_name_; // 0x0008
|
||||
|
||||
CSchemaSystemTypeScope* m_type_scope_; // 0x0010
|
||||
uint8_t type_category; // ETypeCategory 0x0018
|
||||
uint8_t atomic_category; // EAtomicCategory 0x0019
|
||||
|
||||
// find out to what class pointer points.
|
||||
CSchemaType* GetRefClass()
|
||||
{
|
||||
if (type_category != Schema_Ptr)
|
||||
return nullptr;
|
||||
|
||||
auto ptr = m_schema_type_;
|
||||
while (ptr && ptr->type_category == ETypeCategory::Schema_Ptr)
|
||||
ptr = ptr->m_schema_type_;
|
||||
|
||||
return ptr;
|
||||
}
|
||||
|
||||
struct array_t
|
||||
{
|
||||
uint32_t array_size;
|
||||
uint32_t unknown;
|
||||
CSchemaType* element_type_;
|
||||
};
|
||||
|
||||
struct generic_type_t
|
||||
{
|
||||
uint64_t unknown;
|
||||
const char* m_name_; // 0x0008
|
||||
};
|
||||
|
||||
struct atomic_t
|
||||
{ // same goes for CollectionOfT
|
||||
generic_type_t* generic_type;
|
||||
uint64_t unknown;
|
||||
CSchemaType* template_typename;
|
||||
};
|
||||
|
||||
struct atomic_tt
|
||||
{
|
||||
uint64_t gap[2];
|
||||
CSchemaType* templates[2];
|
||||
};
|
||||
|
||||
struct atomic_i
|
||||
{
|
||||
uint64_t gap[2];
|
||||
uint64_t integer;
|
||||
};
|
||||
|
||||
// this union depends on CSchema implementation, all members above
|
||||
// is from base class ( CSchemaType )
|
||||
union // 0x020
|
||||
{
|
||||
CSchemaType* m_schema_type_;
|
||||
CSchemaClassInfo* m_class_info;
|
||||
CSchemaEnumBinding* m_enum_binding_;
|
||||
array_t m_array_;
|
||||
atomic_t m_atomic_t_;
|
||||
atomic_tt m_atomic_tt_;
|
||||
atomic_i m_atomic_i_;
|
||||
};
|
||||
};
|
||||
static_assert(offsetof(CSchemaType, m_schema_type_) == 0x20);
|
||||
|
||||
struct SchemaMetadataEntryData_t
|
||||
{
|
||||
SchemaString_t m_name;
|
||||
CSchemaNetworkValue* m_value;
|
||||
// CSchemaType* m_pDataType;
|
||||
// void* unaccounted;
|
||||
};
|
||||
|
||||
struct SchemaMetadataSetData_t
|
||||
{
|
||||
SchemaMetadataEntryData_t m_static_entries;
|
||||
};
|
||||
|
||||
struct SchemaClassFieldData_t
|
||||
{
|
||||
SchemaString_t m_name; // 0x0000
|
||||
CSchemaType* m_type; // 0x0008
|
||||
std::int32_t m_single_inheritance_offset; // 0x0010
|
||||
std::int32_t m_metadata_size; // 0x0014
|
||||
SchemaMetadataEntryData_t* m_metadata; // 0x0018
|
||||
};
|
||||
|
||||
struct SchemaStaticFieldData_t
|
||||
{
|
||||
const char* name; // 0x0000
|
||||
CSchemaType* m_type; // 0x0008
|
||||
void* m_instance; // 0x0010
|
||||
char pad_0x0018[0x10]; // 0x0018
|
||||
};
|
||||
|
||||
struct SchemaBaseClassInfoData_t
|
||||
{
|
||||
unsigned int m_offset;
|
||||
CSchemaClassInfo* m_class;
|
||||
};
|
||||
|
||||
// Classes
|
||||
struct SchemaClassInfoData_t
|
||||
{
|
||||
char pad_0x0000[0x8]; // 0x0000
|
||||
|
||||
const char* m_name; // 0x0008
|
||||
char* m_module; // 0x0010
|
||||
|
||||
int m_size; // 0x0018
|
||||
std::int16_t m_align; // 0x001C
|
||||
|
||||
std::int16_t m_static_size; // 0x001E
|
||||
std::int16_t m_metadata_size; // 0x0020
|
||||
std::int16_t m_i_unk1; // 0x0022
|
||||
std::int16_t m_i_unk2; // 0x0024
|
||||
std::int16_t m_i_unk3; // 0x0026
|
||||
|
||||
SchemaClassFieldData_t* m_fields; // 0x0028
|
||||
|
||||
SchemaStaticFieldData_t* m_static_fields; // 0x0030
|
||||
SchemaBaseClassInfoData_t* m_schema_parent; // 0x0038
|
||||
|
||||
char pad_0x0038[0x10]; // 0x0038
|
||||
|
||||
SchemaMetadataSetData_t* m_metadata; // 0x0048
|
||||
CSchemaSystemTypeScope* m_type_scope; // 0x0050
|
||||
CSchemaType* m_shema_type; // 0x0058
|
||||
SchemaClassFlags_t m_class_flags : 8; // 0x0060
|
||||
};
|
||||
|
||||
class CSchemaClassInfo : public SchemaClassInfoData_t
|
||||
{
|
||||
public:
|
||||
bool GetMetaStrings(const char* metaName, std::vector<const char**>& strings);
|
||||
|
||||
unsigned int CalculateInheritanceDataSize(bool ignoreVirtuals = false);
|
||||
|
||||
bool DependsOn(CSchemaClassInfo* other);
|
||||
bool InheritsFrom(CSchemaClassInfo* other);
|
||||
bool UsesClass(CSchemaClassInfo* other);
|
||||
bool InheritsVirtuals();
|
||||
|
||||
void FillClassFieldsList(std::vector<SchemaClassFieldData_t*>& fields);
|
||||
void FillInheritanceList(std::vector<const char*>& inheritance);
|
||||
CSchemaClassInfo* GetParent()
|
||||
{
|
||||
if (!m_schema_parent)
|
||||
return nullptr;
|
||||
|
||||
return m_schema_parent->m_class;
|
||||
}
|
||||
|
||||
private:
|
||||
};
|
||||
|
||||
class CSchemaSystemTypeScope
|
||||
{
|
||||
public:
|
||||
CSchemaClassInfo* FindDeclaredClass(const char* class_name)
|
||||
{
|
||||
#ifdef _WIN32
|
||||
CSchemaClassInfo* rv = nullptr;
|
||||
CALL_VIRTUAL(void, 2, this, &rv, class_name);
|
||||
return rv;
|
||||
#else
|
||||
return CALL_VIRTUAL(CSchemaClassInfo*, 2, this, class_name);
|
||||
#endif
|
||||
}
|
||||
|
||||
CSchemaEnumBinding* FindDeclaredEnum(const char* name)
|
||||
{
|
||||
#ifdef _WIN32
|
||||
CSchemaEnumBinding* rv = nullptr;
|
||||
CALL_VIRTUAL(void, 3, this, &rv, name);
|
||||
return rv;
|
||||
#else
|
||||
return CALL_VIRTUAL(CSchemaEnumBinding*, 3, this, name);
|
||||
#endif
|
||||
}
|
||||
|
||||
CSchemaType* FindSchemaTypeByName(const char* name, std::uintptr_t* pSchema)
|
||||
{
|
||||
return CALL_VIRTUAL(CSchemaType*, 4, this, name, pSchema);
|
||||
}
|
||||
|
||||
CSchemaType* FindTypeDeclaredClass(const char* name)
|
||||
{
|
||||
return CALL_VIRTUAL(CSchemaType*, 5, this, name);
|
||||
}
|
||||
|
||||
CSchemaType* FindTypeDeclaredEnum(const char* name)
|
||||
{
|
||||
return CALL_VIRTUAL(CSchemaType*, 6, this, name);
|
||||
}
|
||||
|
||||
CSchemaClassBinding* FindRawClassBinding(const char* name)
|
||||
{
|
||||
return CALL_VIRTUAL(CSchemaClassBinding*, 7, this, name);
|
||||
}
|
||||
|
||||
CSchemaEnumBinding* FindRawEnumBinding(const char* name)
|
||||
{
|
||||
return CALL_VIRTUAL(CSchemaEnumBinding*, 8, this, name);
|
||||
}
|
||||
|
||||
std::string_view GetScopeName() { return {m_name_.data()}; }
|
||||
|
||||
[[nodiscard]] CUtlTSHash<CSchemaClassBinding*> GetClasses() const { return m_classes_; }
|
||||
|
||||
[[nodiscard]] CUtlTSHash<CSchemaEnumBinding*> GetEnums() const { return m_enumes_; }
|
||||
|
||||
private:
|
||||
char pad_0x0000[0x8]; // 0x0000
|
||||
std::array<char, 256> m_name_ = {};
|
||||
char pad_0x0108[SCHEMASYSTEMTYPESCOPE_OFF1]; // 0x0108
|
||||
CUtlTSHash<CSchemaClassBinding*> m_classes_; // 0x0588
|
||||
char pad_0x0594[SCHEMASYSTEMTYPESCOPE_OFF2]; // 0x05C8
|
||||
CUtlTSHash<CSchemaEnumBinding*> m_enumes_; // 0x2DD0
|
||||
private:
|
||||
static constexpr unsigned int s_class_list = 0x580;
|
||||
};
|
||||
|
||||
class CSchemaSystem
|
||||
{
|
||||
public:
|
||||
CSchemaSystemTypeScope* GlobalTypeScope(void)
|
||||
{
|
||||
return CALL_VIRTUAL(CSchemaSystemTypeScope*, 11, this);
|
||||
}
|
||||
|
||||
CSchemaSystemTypeScope* FindTypeScopeForModule(const char* m_module_name)
|
||||
{
|
||||
return CALL_VIRTUAL(CSchemaSystemTypeScope*, 13, this, m_module_name, nullptr);
|
||||
}
|
||||
};
|
||||
|
||||
// source2gen - Source2 games SDK generator
|
||||
// Copyright 2023 neverlosecc
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
@@ -25,6 +25,7 @@
|
||||
#include "core/log.h"
|
||||
|
||||
#include "tier1/utlmap.h"
|
||||
#include <schemasystem.h>
|
||||
|
||||
// memdbgon must be the last include file in a .cpp file!!!
|
||||
#include "tier0/memdbgon.h"
|
||||
@@ -33,9 +34,9 @@ using SchemaKeyValueMap_t = CUtlMap<uint32_t, SchemaKey>;
|
||||
using SchemaTableMap_t = CUtlMap<uint32_t, SchemaKeyValueMap_t*>;
|
||||
|
||||
bool IsFieldNetworked(SchemaClassFieldData_t& field) {
|
||||
for (int i = 0; i < field.m_metadata_size; i++) {
|
||||
for (int i = 0; i < field.m_nStaticMetadataCount; i++) {
|
||||
static auto networkEnabled = hash_32_fnv1a_const("MNetworkEnable");
|
||||
if (networkEnabled == hash_32_fnv1a_const(field.m_metadata[i].m_name)) return true;
|
||||
if (networkEnabled == hash_32_fnv1a_const(field.m_pStaticMetadata[i].m_pszName)) return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
@@ -44,12 +45,11 @@ bool IsFieldNetworked(SchemaClassFieldData_t& field) {
|
||||
static bool InitSchemaFieldsForClass(SchemaTableMap_t* tableMap,
|
||||
const char* className,
|
||||
uint32_t classKey) {
|
||||
CSchemaSystemTypeScope* pType =
|
||||
counterstrikesharp::interfaces::pSchemaSystem->FindTypeScopeForModule(MODULE_PREFIX "server" MODULE_EXT);
|
||||
CSchemaSystemTypeScope* pType = counterstrikesharp::globals::schemaSystem->FindTypeScopeForModule(MODULE_PREFIX "server" MODULE_EXT);
|
||||
|
||||
if (!pType) return false;
|
||||
|
||||
SchemaClassInfoData_t* pClassInfo = pType->FindDeclaredClass(className);
|
||||
SchemaClassInfoData_t* pClassInfo = pType->FindDeclaredClass(className).Get();
|
||||
|
||||
if (!pClassInfo) {
|
||||
SchemaKeyValueMap_t* map = new SchemaKeyValueMap_t(0, 0, DefLessFunc(uint32_t));
|
||||
@@ -59,8 +59,8 @@ static bool InitSchemaFieldsForClass(SchemaTableMap_t* tableMap,
|
||||
return false;
|
||||
}
|
||||
|
||||
short fieldsSize = pClassInfo->m_align;
|
||||
SchemaClassFieldData_t* pFields = pClassInfo->m_fields;
|
||||
short fieldsSize = pClassInfo->m_nFieldCount;
|
||||
SchemaClassFieldData_t* pFields = pClassInfo->m_pFields;
|
||||
|
||||
SchemaKeyValueMap_t* keyValueMap = new SchemaKeyValueMap_t(0, 0, DefLessFunc(uint32_t));
|
||||
keyValueMap->EnsureCapacity(fieldsSize);
|
||||
@@ -69,8 +69,8 @@ static bool InitSchemaFieldsForClass(SchemaTableMap_t* tableMap,
|
||||
for (int i = 0; i < fieldsSize; ++i) {
|
||||
SchemaClassFieldData_t& field = pFields[i];
|
||||
|
||||
keyValueMap->Insert(hash_32_fnv1a_const(field.m_name),
|
||||
{field.m_single_inheritance_offset, IsFieldNetworked(field)});
|
||||
keyValueMap->Insert(hash_32_fnv1a_const(field.m_pszName),
|
||||
{field.m_nSingleInheritanceOffset, IsFieldNetworked(field)});
|
||||
}
|
||||
|
||||
return true;
|
||||
@@ -78,23 +78,23 @@ static bool InitSchemaFieldsForClass(SchemaTableMap_t* tableMap,
|
||||
|
||||
int16_t schema::FindChainOffset(const char* className) {
|
||||
CSchemaSystemTypeScope* pType =
|
||||
counterstrikesharp::interfaces::pSchemaSystem->FindTypeScopeForModule(MODULE_PREFIX "server" MODULE_EXT);
|
||||
counterstrikesharp::globals::schemaSystem->FindTypeScopeForModule(MODULE_PREFIX "server" MODULE_EXT);
|
||||
|
||||
if (!pType) return false;
|
||||
|
||||
auto* pClassInfo = pType->FindDeclaredClass(className);
|
||||
auto* pClassInfo = pType->FindDeclaredClass(className).Get();
|
||||
|
||||
do {
|
||||
SchemaClassFieldData_t* pFields = pClassInfo->m_fields;
|
||||
short fieldsSize = pClassInfo->m_align;
|
||||
SchemaClassFieldData_t* pFields = pClassInfo->m_pFields;
|
||||
short fieldsSize = pClassInfo->m_nFieldCount;
|
||||
for (int i = 0; i < fieldsSize; ++i) {
|
||||
SchemaClassFieldData_t& field = pFields[i];
|
||||
|
||||
if (V_strcmp(field.m_name, "__m_pChainEntity") == 0) {
|
||||
return field.m_single_inheritance_offset;
|
||||
if (V_strcmp(field.m_pszName, "__m_pChainEntity") == 0) {
|
||||
return field.m_nSingleInheritanceOffset;
|
||||
}
|
||||
}
|
||||
} while ((pClassInfo = pClassInfo->GetParent()) != nullptr);
|
||||
} while ((pClassInfo = pClassInfo->m_pBaseClasses->m_pClass) != nullptr);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -165,11 +165,11 @@ void* CGameConfig::ResolveSignature(const char* name)
|
||||
return nullptr;
|
||||
}
|
||||
size_t iLength = 0;
|
||||
byte* pSignature = HexToByte(signature, iLength);
|
||||
if (!pSignature) {
|
||||
auto pSignature = HexToByte(signature);
|
||||
if (pSignature.empty()) {
|
||||
return nullptr;
|
||||
}
|
||||
address = (*module)->FindSignature(pSignature, iLength);
|
||||
address = (*module)->FindSignature(pSignature);
|
||||
}
|
||||
|
||||
if (!address) {
|
||||
@@ -190,47 +190,63 @@ std::string CGameConfig::GetDirectoryName(const std::string& directoryPathInput)
|
||||
return "";
|
||||
}
|
||||
|
||||
int CGameConfig::HexStringToUint8Array(const char* hexString, uint8_t* byteArray, size_t maxBytes)
|
||||
std::vector<int16_t> CGameConfig::HexToByte(std::string_view src)
|
||||
{
|
||||
if (!hexString) {
|
||||
printf("Invalid hex string.\n");
|
||||
if (src.empty()) {
|
||||
return {};
|
||||
}
|
||||
|
||||
auto hex_char_to_byte = [](char c) -> int16_t {
|
||||
if (c >= '0' && c <= '9')
|
||||
return c - '0';
|
||||
if (c >= 'A' && c <= 'F')
|
||||
return c - 'A' + 10;
|
||||
if (c >= 'a' && c <= 'f')
|
||||
return c - 'a' + 10;
|
||||
|
||||
// a valid hex char can never go up to 0xFF
|
||||
return -1;
|
||||
}
|
||||
};
|
||||
|
||||
size_t hexStringLength = strlen(hexString);
|
||||
size_t byteCount = hexStringLength / 4; // Each "\\x" represents one byte.
|
||||
std::vector<int16_t> result{};
|
||||
|
||||
if (hexStringLength % 4 != 0 || byteCount == 0 || byteCount > maxBytes) {
|
||||
printf("Invalid hex string format or byte count.\n");
|
||||
return -1; // Return an error code.
|
||||
}
|
||||
const bool is_code_style = src[0] == '\\';
|
||||
|
||||
for (size_t i = 0; i < hexStringLength; i += 4) {
|
||||
if (sscanf(hexString + i, "\\x%2hhX", &byteArray[i / 4]) != 1) {
|
||||
printf("Failed to parse hex string at position %zu.\n", i);
|
||||
return -1; // Return an error code.
|
||||
const std::string_view pattern = is_code_style ? R"(\x)" : " ";
|
||||
const std::string_view wildcard = is_code_style ? "2A" : "?";
|
||||
|
||||
auto split = std::views::split(src, pattern);
|
||||
|
||||
for (auto&& str : split) {
|
||||
if (str.empty()) [[unlikely]] {
|
||||
continue;
|
||||
}
|
||||
|
||||
// std::string_view(std::subrange) constructor only exists in C++23 or above
|
||||
// use this when compiler is GCC >= 12.1 or Clang >= 16
|
||||
// const std::string_view byte(str.begin(), str.end());
|
||||
|
||||
// a workaround for GCC < 12.1, it doesn't work with Clang < 16
|
||||
// https://stackoverflow.com/a/48403210
|
||||
std::string_view byte (&*str.begin(), std::ranges::distance(str));
|
||||
|
||||
if (byte.starts_with(wildcard)) {
|
||||
result.emplace_back(-1);
|
||||
continue;
|
||||
}
|
||||
|
||||
const auto high = hex_char_to_byte(byte[0]);
|
||||
const auto low = hex_char_to_byte(byte[1]);
|
||||
|
||||
// if then is malformed, return nothing
|
||||
// maybe print error message here?
|
||||
if (high == 0xFF || low == 0xFF) [[unlikely]] {
|
||||
return {};
|
||||
}
|
||||
|
||||
result.emplace_back((high << 4) | low);
|
||||
}
|
||||
|
||||
byteArray[byteCount] = '\0'; // Add a null-terminating character.
|
||||
|
||||
return byteCount; // Return the number of bytes successfully converted.
|
||||
return result;
|
||||
}
|
||||
|
||||
byte* CGameConfig::HexToByte(const char* src, size_t& length)
|
||||
{
|
||||
if (!src || strlen(src) <= 0) {
|
||||
CSSHARP_CORE_INFO("Invalid hex string\n");
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
length = strlen(src) / 4;
|
||||
uint8_t* dest = new uint8_t[length];
|
||||
int byteCount = HexStringToUint8Array(src, dest, length);
|
||||
if (byteCount <= 0) {
|
||||
CSSHARP_CORE_INFO("Invalid hex format %s\n", src);
|
||||
return nullptr;
|
||||
}
|
||||
return dest;
|
||||
}
|
||||
} // namespace counterstrikesharp
|
||||
} // namespace counterstrikesharp
|
||||
|
||||
@@ -33,8 +33,7 @@ class CGameConfig
|
||||
void* ResolveSignature(const char* name);
|
||||
|
||||
static std::string GetDirectoryName(const std::string& directoryPathInput);
|
||||
static int HexStringToUint8Array(const char* hexString, uint8_t* byteArray, size_t maxBytes);
|
||||
static byte* HexToByte(const char* src, size_t& length);
|
||||
static std::vector<int16_t> HexToByte(std::string_view src);
|
||||
|
||||
private:
|
||||
std::string m_sPath;
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
#include "mm_plugin.h"
|
||||
#include "core/globals.h"
|
||||
#include "core/managers/player_manager.h"
|
||||
#include "core/tick_scheduler.h"
|
||||
#include "iserver.h"
|
||||
#include "managers/event_manager.h"
|
||||
#include "scripting/callback_manager.h"
|
||||
@@ -51,6 +52,7 @@ IFileSystem* fileSystem = nullptr;
|
||||
IServerGameDLL* serverGameDll = nullptr;
|
||||
IServerGameClients* serverGameClients = nullptr;
|
||||
INetworkServerService* networkServerService = nullptr;
|
||||
CSchemaSystem* schemaSystem = nullptr;
|
||||
IServerTools* serverTools = nullptr;
|
||||
IPhysics* physics = nullptr;
|
||||
IPhysicsCollision* physicsCollision = nullptr;
|
||||
@@ -79,6 +81,7 @@ EntityManager entityManager;
|
||||
ChatManager chatManager;
|
||||
ServerManager serverManager;
|
||||
VoiceManager voiceManager;
|
||||
TickScheduler tickScheduler;
|
||||
|
||||
bool gameLoopInitialized = false;
|
||||
GetLegacyGameEventListener_t* GetLegacyGameEventListener = nullptr;
|
||||
|
||||
@@ -37,6 +37,7 @@ class IGameEventSystem;
|
||||
class CounterStrikeSharpMMPlugin;
|
||||
class CGameEntitySystem;
|
||||
class IGameEventListener2;
|
||||
class CSchemaSystem;
|
||||
|
||||
namespace counterstrikesharp {
|
||||
class EntityListener;
|
||||
@@ -47,6 +48,7 @@ class CallbackManager;
|
||||
class ConVarManager;
|
||||
class PlayerManager;
|
||||
class MenuManager;
|
||||
class TickScheduler;
|
||||
class TimerSystem;
|
||||
class ChatCommands;
|
||||
class HookManager;
|
||||
@@ -74,6 +76,7 @@ extern IFileSystem *fileSystem;
|
||||
extern IServerGameDLL *serverGameDll;
|
||||
extern IServerGameClients *serverGameClients;
|
||||
extern INetworkServerService *networkServerService;
|
||||
extern CSchemaSystem *schemaSystem;
|
||||
extern IServerTools *serverTools;
|
||||
extern IPhysics *physics;
|
||||
extern IPhysicsCollision *physicsCollision;
|
||||
@@ -100,6 +103,7 @@ extern ChatCommands chatCommands;
|
||||
extern ChatManager chatManager;
|
||||
extern ServerManager serverManager;
|
||||
extern VoiceManager voiceManager;
|
||||
extern TickScheduler tickScheduler;
|
||||
|
||||
extern HookManager hookManager;
|
||||
extern SourceHook::ISourceHook *source_hook;
|
||||
|
||||
@@ -38,11 +38,12 @@
|
||||
|
||||
#include "scripting/callback_manager.h"
|
||||
#include "core/log.h"
|
||||
#include "core/cs2_sdk/interfaces/cschemasystem.h"
|
||||
#include "core/utils.h"
|
||||
#include "core/memory.h"
|
||||
#include "interfaces/cs2_interfaces.h"
|
||||
#include <schematypes.h>
|
||||
#include <nlohmann/json.hpp>
|
||||
#include <schemasystem.h>
|
||||
|
||||
#include "metamod_oslink.h"
|
||||
using json = nlohmann::json;
|
||||
@@ -51,26 +52,35 @@ namespace counterstrikesharp {
|
||||
|
||||
json WriteTypeJson(json obj, CSchemaType* current_type)
|
||||
{
|
||||
obj["name"] = current_type->m_name_;
|
||||
obj["category"] = current_type->type_category;
|
||||
obj["name"] = current_type->m_sTypeName.Get();
|
||||
obj["category"] = current_type->m_eTypeCategory;
|
||||
|
||||
if (current_type->type_category == Schema_Atomic) {
|
||||
obj["atomic"] = current_type->atomic_category;
|
||||
if (current_type->m_eTypeCategory == SCHEMA_TYPE_ATOMIC) {
|
||||
obj["atomic"] = current_type->m_eAtomicCategory;
|
||||
|
||||
if (current_type->atomic_category == Atomic_T &&
|
||||
current_type->m_atomic_t_.generic_type != nullptr) {
|
||||
obj["outer"] = current_type->m_atomic_t_.generic_type->m_name_;
|
||||
if (current_type->m_eAtomicCategory == SCHEMA_ATOMIC_T) {
|
||||
auto atomicTType = static_cast<CSchemaType_Atomic_T*>(current_type);
|
||||
|
||||
if (atomicTType->m_pAtomicInfo != nullptr) {
|
||||
obj["outer"] = atomicTType->m_pAtomicInfo->m_pszName1;
|
||||
}
|
||||
}
|
||||
|
||||
if (current_type->atomic_category == Atomic_T ||
|
||||
current_type->atomic_category == Atomic_CollectionOfT) {
|
||||
obj["inner"] =
|
||||
WriteTypeJson(json::object(), current_type->m_atomic_t_.template_typename);
|
||||
if (current_type->m_eAtomicCategory == SCHEMA_ATOMIC_T ||
|
||||
current_type->m_eAtomicCategory == SCHEMA_ATOMIC_COLLECTION_OF_T) {
|
||||
|
||||
auto atomicType = static_cast<CSchemaType_Atomic_T*>(current_type);
|
||||
|
||||
if (atomicType->GetInnerType().Get() != nullptr) {
|
||||
obj["inner"] = WriteTypeJson(json::object(), atomicType->GetInnerType().Get());
|
||||
}
|
||||
}
|
||||
} else if (current_type->type_category == Schema_FixedArray) {
|
||||
obj["inner"] = WriteTypeJson(json::object(), current_type->m_array_.element_type_);
|
||||
} else if (current_type->type_category == Schema_Ptr) {
|
||||
obj["inner"] = WriteTypeJson(json::object(), current_type->m_schema_type_);
|
||||
} else if (current_type->m_eTypeCategory == SCHEMA_TYPE_FIXED_ARRAY) {
|
||||
auto fixedArrayType = static_cast<CSchemaType_FixedArray*>(current_type);
|
||||
obj["inner"] = WriteTypeJson(json::object(), fixedArrayType->m_pElementType);
|
||||
} else if (current_type->m_eTypeCategory == SCHEMA_TYPE_PTR) {
|
||||
auto ptrType = static_cast<CSchemaType_Ptr*>(current_type);
|
||||
obj["inner"] = WriteTypeJson(json::object(), ptrType->m_pObjectType);
|
||||
}
|
||||
|
||||
return obj;
|
||||
@@ -102,53 +112,53 @@ CON_COMMAND(dump_schema, "dump schema symbols")
|
||||
}
|
||||
|
||||
CSchemaSystemTypeScope* pType =
|
||||
interfaces::pSchemaSystem->FindTypeScopeForModule(MODULE_PREFIX "server" MODULE_EXT);
|
||||
globals::schemaSystem->FindTypeScopeForModule(MODULE_PREFIX "server" MODULE_EXT);
|
||||
|
||||
json j;
|
||||
j["classes"] = json::object();
|
||||
j["enums"] = json::object();
|
||||
|
||||
for (const auto& line : classNames) {
|
||||
SchemaClassInfoData_t* pClassInfo = pType->FindDeclaredClass(line.c_str());
|
||||
auto* pClassInfo = pType->FindDeclaredClass(line.c_str()).Get();
|
||||
if (!pClassInfo)
|
||||
continue;
|
||||
|
||||
short fieldsSize = pClassInfo->m_align;
|
||||
SchemaClassFieldData_t* pFields = pClassInfo->m_fields;
|
||||
short fieldsSize = pClassInfo->m_nFieldCount;
|
||||
SchemaClassFieldData_t* pFields = pClassInfo->m_pFields;
|
||||
|
||||
j["classes"][pClassInfo->m_name] = json::object();
|
||||
if (pClassInfo->m_schema_parent) {
|
||||
j["classes"][pClassInfo->m_name]["parent"] =
|
||||
pClassInfo->m_schema_parent->m_class->m_name;
|
||||
j["classes"][pClassInfo->m_pszName] = json::object();
|
||||
if (pClassInfo->m_pBaseClasses) {
|
||||
j["classes"][pClassInfo->m_pszName]["parent"] =
|
||||
pClassInfo->m_pBaseClasses->m_pClass->m_pszName;
|
||||
}
|
||||
|
||||
j["classes"][pClassInfo->m_name]["fields"] = json::array();
|
||||
j["classes"][pClassInfo->m_pszName]["fields"] = json::array();
|
||||
|
||||
for (int i = 0; i < fieldsSize; ++i) {
|
||||
SchemaClassFieldData_t& field = pFields[i];
|
||||
|
||||
j["classes"][pClassInfo->m_name]["fields"].push_back({
|
||||
{"name", field.m_name},
|
||||
{"type", WriteTypeJson(json::object(), field.m_type)},
|
||||
j["classes"][pClassInfo->m_pszName]["fields"].push_back({
|
||||
{"name", field.m_pszName},
|
||||
{"type", WriteTypeJson(json::object(), field.m_pType)},
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
for (const auto& line : enumNames) {
|
||||
auto* pEnumInfo = pType->FindDeclaredEnum(line.c_str());
|
||||
auto* pEnumInfo = pType->FindDeclaredEnum(line.c_str()).Get();
|
||||
if (!pEnumInfo)
|
||||
continue;
|
||||
|
||||
j["enums"][pEnumInfo->m_binding_name_] = json::object();
|
||||
j["enums"][pEnumInfo->m_binding_name_]["align"] = pEnumInfo->m_align_;
|
||||
j["enums"][pEnumInfo->m_binding_name_]["items"] = json::array();
|
||||
j["enums"][pEnumInfo->m_pszName] = json::object();
|
||||
j["enums"][pEnumInfo->m_pszName]["align"] = pEnumInfo->m_nSize;
|
||||
j["enums"][pEnumInfo->m_pszName]["items"] = json::array();
|
||||
|
||||
for (int i = 0; i < pEnumInfo->m_size_; ++i) {
|
||||
auto& field = pEnumInfo->m_enum_info_[i];
|
||||
for (int i = 0; i < pEnumInfo->m_nEnumeratorCount; ++i) {
|
||||
auto& field = pEnumInfo->m_pEnumerators[i];
|
||||
|
||||
j["enums"][pEnumInfo->m_binding_name_]["items"].push_back({
|
||||
{"name", field.m_name},
|
||||
{"value", field.m_value},
|
||||
j["enums"][pEnumInfo->m_pszName]["items"].push_back({
|
||||
{"name", field.m_pszName},
|
||||
{"value", field.m_nValue},
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
@@ -549,11 +549,6 @@ float CPlayer::GetTimeConnected() const
|
||||
return GetNetInfo()->GetTimeConnected();
|
||||
}
|
||||
|
||||
float CPlayer::GetLatency() const
|
||||
{
|
||||
return GetNetInfo()->GetLatency(FLOW_INCOMING) + GetNetInfo()->GetLatency(FLOW_OUTGOING);
|
||||
}
|
||||
|
||||
void CPlayer::SetListen(CPlayerSlot slot, ListenOverride listen)
|
||||
{
|
||||
m_listenMap[slot.Get()] = listen;
|
||||
|
||||
@@ -111,7 +111,6 @@ class CPlayer
|
||||
const char* GetModelName() const;
|
||||
int GetUserId() const;
|
||||
float GetTimeConnected() const;
|
||||
float GetLatency() const;
|
||||
void SetListen(CPlayerSlot slot, ListenOverride listen);
|
||||
void SetVoiceFlags(VoiceFlag_t flags);
|
||||
VoiceFlag_t GetVoiceFlags();
|
||||
|
||||
@@ -20,6 +20,7 @@
|
||||
#include "scripting/callback_manager.h"
|
||||
|
||||
#include "core/game_system.h"
|
||||
#include <concurrentqueue.h>
|
||||
|
||||
SH_DECL_HOOK1_void(ISource2Server, ServerHibernationUpdate, SH_NOATTRIB, 0, bool);
|
||||
SH_DECL_HOOK0_void(ISource2Server, GameServerSteamAPIActivated, SH_NOATTRIB, 0);
|
||||
@@ -176,17 +177,17 @@ void ServerManager::UpdateWhenNotInGame(float flFrameTime)
|
||||
|
||||
void ServerManager::PreWorldUpdate(bool bSimulating)
|
||||
{
|
||||
std::lock_guard<std::mutex> lock(m_nextWorldUpdateTasksLock);
|
||||
std::vector<std::function<void()>> out_list(1024);
|
||||
|
||||
if (!m_nextWorldUpdateTasks.empty()) {
|
||||
CSSHARP_CORE_TRACE("Executing queued tasks of size: {0} at time {1}", m_nextWorldUpdateTasks.size(),
|
||||
globals::getGlobalVars()->curtime);
|
||||
auto size = m_nextWorldUpdateTasks.try_dequeue_bulk(out_list.begin(), 1024);
|
||||
|
||||
for (size_t i = 0; i < m_nextWorldUpdateTasks.size(); i++) {
|
||||
m_nextWorldUpdateTasks[i]();
|
||||
if (size > 0) {
|
||||
CSSHARP_CORE_TRACE("Executing queued tasks of size: {0} at time {1}", size,
|
||||
globals::getGlobalVars()->curtime);
|
||||
|
||||
for (size_t i = 0; i < size; i++) {
|
||||
out_list[i]();
|
||||
}
|
||||
|
||||
m_nextWorldUpdateTasks.clear();
|
||||
}
|
||||
|
||||
auto callback = globals::serverManager.on_server_pre_world_update;
|
||||
@@ -200,8 +201,7 @@ 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));
|
||||
m_nextWorldUpdateTasks.enqueue(std::forward<decltype(task)>(task));
|
||||
}
|
||||
|
||||
void ServerManager::OnPrecacheResources(IEntityResourceManifest* pResourceManifest)
|
||||
|
||||
@@ -19,6 +19,7 @@
|
||||
#include "core/globals.h"
|
||||
#include "core/global_listener.h"
|
||||
#include "scripting/script_engine.h"
|
||||
#include <concurrentqueue.h>
|
||||
|
||||
#include "core/game_system.h"
|
||||
|
||||
@@ -56,8 +57,7 @@ private:
|
||||
|
||||
ScriptCallback *on_server_precache_resources;
|
||||
|
||||
std::vector<std::function<void()>> m_nextWorldUpdateTasks;
|
||||
std::mutex m_nextWorldUpdateTasksLock;
|
||||
moodycamel::ConcurrentQueue<std::function<void()>> m_nextWorldUpdateTasks;
|
||||
};
|
||||
|
||||
} // namespace counterstrikesharp
|
||||
@@ -30,12 +30,15 @@
|
||||
#include <Psapi.h>
|
||||
#endif
|
||||
|
||||
#include <cstdio>
|
||||
#include "gameconfig.h"
|
||||
|
||||
#include <cstdio>
|
||||
#include "memory_module.h"
|
||||
#include "metamod_oslink.h"
|
||||
#include "wchartypes.h"
|
||||
|
||||
#include <vector>
|
||||
|
||||
#if __linux__
|
||||
struct ModuleInfo {
|
||||
const char *path; // in
|
||||
@@ -118,29 +121,13 @@ int GetModuleInformation(void *hModule, void **base, size_t *length) {
|
||||
}
|
||||
#endif
|
||||
|
||||
byte *ConvertToByteArray(const char *str, size_t *outLength) {
|
||||
size_t len = strlen(str) / 4; // Every byte is represented as \xHH
|
||||
byte *result = (byte *)malloc(len);
|
||||
|
||||
for (size_t i = 0, j = 0; i < len; ++i, j += 4) {
|
||||
sscanf(str + j, "\\x%2hhx", &result[i]);
|
||||
}
|
||||
|
||||
*outLength = len;
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
void* FindSignature(const char* moduleName, const char* bytesStr) {
|
||||
size_t iSigLength;
|
||||
auto sigBytes = ConvertToByteArray(bytesStr, &iSigLength);
|
||||
|
||||
auto module = dlmount(moduleName);
|
||||
if (module == nullptr) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
void *moduleBase;
|
||||
void* moduleBase;
|
||||
size_t moduleSize;
|
||||
#if __linux__
|
||||
if (GetModuleInformation(module, &moduleBase, &moduleSize) != 0) {
|
||||
@@ -154,18 +141,30 @@ void* FindSignature(const char* moduleName, const char* bytesStr) {
|
||||
moduleSize = m_hModuleInfo.SizeOfImage;
|
||||
#endif
|
||||
|
||||
unsigned char *pMemory;
|
||||
void *returnAddr = nullptr;
|
||||
auto sigBytes = counterstrikesharp::CGameConfig::HexToByte(bytesStr);
|
||||
|
||||
pMemory = (byte *)moduleBase;
|
||||
if (sigBytes.empty()) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
for (size_t i = 0; i < moduleSize; i++) {
|
||||
size_t matches = 0;
|
||||
while (*(pMemory + i + matches) == sigBytes[matches] || sigBytes[matches] == '\x2A') {
|
||||
matches++;
|
||||
if (matches == iSigLength) {
|
||||
returnAddr = (void *)(pMemory + i);
|
||||
}
|
||||
void* returnAddr = nullptr;
|
||||
|
||||
const auto first_byte = sigBytes[0];
|
||||
|
||||
auto pMemory = (byte*)moduleBase;
|
||||
std::uint8_t* end = pMemory + moduleSize - sigBytes.size();
|
||||
|
||||
for (std::uint8_t* current = pMemory; current <= end; ++current) {
|
||||
if (first_byte != -1)
|
||||
current = std::find(current, end, first_byte);
|
||||
|
||||
if (current == end) {
|
||||
break;
|
||||
}
|
||||
|
||||
if (std::equal(sigBytes.begin() + 1, sigBytes.end(), current + 1,
|
||||
[](auto opt, auto byte) { return opt == -1 || opt == byte; })) {
|
||||
return current;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -174,4 +173,4 @@ void* FindSignature(const char* moduleName, const char* bytesStr) {
|
||||
}
|
||||
|
||||
return returnAddr;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -41,29 +41,35 @@ void* CModule::FindSignature(const char* signature)
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
size_t iSigLength = 0;
|
||||
byte* pData = CGameConfig::HexToByte(signature, iSigLength);
|
||||
auto pData = CGameConfig::HexToByte(signature);
|
||||
if (pData.empty()) [[unlikely]]
|
||||
return nullptr;
|
||||
|
||||
return this->FindSignature(pData, iSigLength);
|
||||
return this->FindSignature(pData);
|
||||
}
|
||||
|
||||
void* CModule::FindSignature(const byte* pData, size_t iSigLength)
|
||||
void* CModule::FindSignature(const std::vector<int16_t>& sigBytes)
|
||||
{
|
||||
unsigned char* pMemory;
|
||||
void* return_addr = nullptr;
|
||||
const auto first_byte = sigBytes[0];
|
||||
|
||||
pMemory = (byte*)m_base;
|
||||
auto pMemory = (std::uint8_t*)m_base;
|
||||
std::uint8_t* end = pMemory + m_size - sigBytes.size();
|
||||
|
||||
for (size_t i = 0; i < m_size; i++) {
|
||||
size_t Matches = 0;
|
||||
while (*(pMemory + i + Matches) == pData[Matches] || pData[Matches] == '\x2A') {
|
||||
Matches++;
|
||||
if (Matches == iSigLength)
|
||||
return_addr = (void*)(pMemory + i);
|
||||
for (std::uint8_t* current = pMemory; current <= end; ++current) {
|
||||
if (first_byte != -1)
|
||||
current = std::find(current, end, first_byte);
|
||||
|
||||
if (current == end) {
|
||||
break;
|
||||
}
|
||||
|
||||
if (std::equal(sigBytes.begin() + 1, sigBytes.end(), current + 1,
|
||||
[](auto opt, auto byte) { return opt == -1 || opt == byte; })) {
|
||||
return current;
|
||||
}
|
||||
}
|
||||
|
||||
return return_addr;
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
void* CModule::FindInterface(const char* name)
|
||||
|
||||
@@ -23,6 +23,8 @@
|
||||
#include "interface.h"
|
||||
#include "strtools.h"
|
||||
#include "metamod_oslink.h"
|
||||
|
||||
#include <vector>
|
||||
#undef snprintf
|
||||
|
||||
namespace counterstrikesharp::modules {
|
||||
@@ -34,7 +36,7 @@ class CModule
|
||||
|
||||
void* FindSignature(const char* signature);
|
||||
|
||||
void* FindSignature(const byte* pData, size_t iSigLength);
|
||||
void* FindSignature(const std::vector<int16_t>& sigBytes);
|
||||
|
||||
void* FindInterface(const char* name);
|
||||
|
||||
|
||||
45
src/core/tick_scheduler.cpp
Normal file
45
src/core/tick_scheduler.cpp
Normal file
@@ -0,0 +1,45 @@
|
||||
/*
|
||||
* 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/>. *
|
||||
*/
|
||||
|
||||
#include "tick_scheduler.h"
|
||||
|
||||
namespace counterstrikesharp {
|
||||
|
||||
void TickScheduler::schedule(int tick, std::function<void()> callback)
|
||||
{
|
||||
std::lock_guard<std::mutex> lock(taskMutex);
|
||||
scheduledTasks.push(std::make_pair(tick, callback));
|
||||
}
|
||||
|
||||
std::vector<std::function<void()>> TickScheduler::getCallbacks(int currentTick)
|
||||
{
|
||||
std::vector<std::function<void()>> callbacksToRun;
|
||||
|
||||
std::lock_guard<std::mutex> lock(taskMutex);
|
||||
|
||||
if (scheduledTasks.empty()) {
|
||||
return callbacksToRun;
|
||||
}
|
||||
|
||||
// Process tasks due for the current tick
|
||||
while (!scheduledTasks.empty() && scheduledTasks.top().first <= currentTick) {
|
||||
callbacksToRun.push_back(scheduledTasks.top().second);
|
||||
scheduledTasks.pop();
|
||||
}
|
||||
|
||||
return callbacksToRun;
|
||||
}
|
||||
} // namespace counterstrikesharp
|
||||
44
src/core/tick_scheduler.h
Normal file
44
src/core/tick_scheduler.h
Normal file
@@ -0,0 +1,44 @@
|
||||
/*
|
||||
* 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/>. *
|
||||
*/
|
||||
|
||||
#include <functional>
|
||||
#include <queue>
|
||||
#include <mutex>
|
||||
#include <condition_variable>
|
||||
|
||||
namespace counterstrikesharp {
|
||||
class TickScheduler
|
||||
{
|
||||
public:
|
||||
struct TaskComparator
|
||||
{
|
||||
bool operator()(const std::pair<int, std::function<void()>>& a,
|
||||
const std::pair<int, std::function<void()>>& b) const
|
||||
{
|
||||
return a.first > b.first;
|
||||
}
|
||||
};
|
||||
|
||||
void schedule(int tick, std::function<void()> callback);
|
||||
std::vector<std::function<void()>> getCallbacks(int currentTick);
|
||||
private:
|
||||
std::priority_queue<std::pair<int, std::function<void()>>,
|
||||
std::vector<std::pair<int, std::function<void()>>>,
|
||||
TaskComparator>
|
||||
scheduledTasks;
|
||||
std::mutex taskMutex;
|
||||
};
|
||||
} // namespace counterstrikesharp
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user