Compare commits

...

70 Commits

Author SHA1 Message Date
Michael Wilson
c9f8e477d3 release: 1.0.314 2025-03-27 04:06:33 +00:00
Michael Wilson
2398ba0a5d fix: manually revert EventPlayerChat to old value (#827) 2025-03-27 13:56:15 +10:00
roflmuffin
e45c20481d ci: hide release commits in changelog 2025-03-25 20:56:03 +10:00
roflmuffin
fe321ee93d ci: include full changelog link in discord message 2025-03-25 20:31:42 +10:00
roflmuffin
be19103556 chore: remove footer from cliff changelog 2025-03-25 20:29:16 +10:00
roflmuffin
64cb26b86d chore: fix newlines in changelog 2025-03-25 20:24:26 +10:00
roflmuffin
637224dc55 ci: fix cliff generation 2025-03-25 20:18:15 +10:00
roflmuffin
3aca7c37f1 ci: add changelog to release & webhook 2025-03-25 20:07:02 +10:00
roflmuffin
87f38d72ee release: v1.0.313 2025-03-25 19:28:06 +10:00
roflmuffin
5daf94791f chore(changelog): update cliff.toml 2025-03-25 19:18:19 +10:00
Michael Wilson
c50213c442 feat(config): add toml loading support (#804) 2025-03-25 19:12:29 +10:00
roflmuffin
c02d31cb2e chore: add links to contributors github page 2025-03-24 19:49:53 +10:00
roflmuffin
98cbca44d4 chore: update changelog to use semantic tags 2025-03-24 19:44:22 +10:00
Michael Wilson
4cf88fc03e fix(gameevents): promote core.gameevents to have higher priority (#819) 2025-03-24 19:32:47 +10:00
Michael Wilson
f1dff6d4d3 chrore: Implement SemVer instead of build numbers (#816) 2025-03-24 19:15:46 +10:00
Michael Wilson
414a59a36d fix(schema): inherited schema classes with clashing properties (#818) 2025-03-24 18:43:41 +10:00
Michael Wilson
f1c108087b fix(concommand): don't remove reference flags when running convar/concmd unlocker (#817) 2025-03-24 17:49:09 +10:00
roflmuffin
47ddf42c11 [no ci] add CHANGELOG.md 2025-03-24 12:27:09 +10:00
samyyc
ded133f1db Fix EmitSoundFilter signature for linux (#815) 2025-03-23 19:29:09 +10:00
samyyc
bbc621acdc feat: Implement EmitSoundFilter (#808)
Co-authored-by: Michael Wilson <roflmuffin@users.noreply.github.com>
2025-03-23 07:56:34 +00:00
Michael Wilson
f7784c26c6 fix: change terrorist chat colour to orange to be more in line with the game (#813) 2025-03-23 14:07:05 +10:00
qstage
2da5448c8e feat: add ListenerHandlerAttribute<T> (#757)
Co-authored-by: Michael Wilson <roflmuffin@users.noreply.github.com>
2025-03-17 02:16:33 +00:00
Michael Wilson
e406b78044 [no ci] chore: update protobuf (#803) 2025-03-17 12:10:01 +10:00
Michael Wilson
3839831ea9 [no ci] Update publish-docs.yml (#802) 2025-03-17 11:55:12 +10:00
samyyc
54ad6c0b79 feat: Expose Metamod MetaFactory to NativeAPI (#801) 2025-03-17 11:45:38 +10:00
Michael Wilson
7c2cc8a7f6 [no ci] chore: fix deprecated CI steps (#759) 2025-02-05 13:23:24 +10:00
qstage
e99d27ca30 fix: errors when reloading auto generated config (#754) 2025-01-30 21:08:44 +10:00
dependabot[bot]
44d3c51bc7 [no ci] chore(deps): bump libraries/Protobufs from b46090a to 157162d (#753)
Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2025-01-30 11:22:36 +10:00
Joakim
f72e6d5daf feat: add ReplicateConVar (#751) 2025-01-27 22:10:14 +00:00
samyyc
c8bccb07e0 Remove the characters limit for CenterHtmlMenu (#747) 2025-01-23 13:06:06 +00:00
qstage
2c0640700a fix: ArgumentOutOfRangeException when calling GetArgTargetResult (#745) 2025-01-23 22:53:51 +10:00
Ian Lucas
0f71e1aebe feat: handle quotes for FakeConVar<string> (#743) 2025-01-20 12:09:44 +10:00
dependabot[bot]
ac38ec249b chore(deps): bump libraries/hl2sdk-cs2 from a658a0f to a26ca82 (#739)
Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2025-01-15 23:45:00 +10:00
Roflmuffin
cff24f4321 Revert "Make NetworkedVector support Vector and QAngle (#728)"
This reverts commit bd1105d752.
2025-01-14 00:18:56 +10:00
Michael Wilson
f05cc5e043 fix: NetworkedVector throwing error 2025-01-09 11:07:40 +10:00
Yarukon
bd1105d752 Make NetworkedVector support Vector and QAngle (#728) 2025-01-09 09:14:56 +10:00
Michael Wilson
9b4ee727c7 Fix RemoveMapChangeTimers (#720) 2024-12-24 23:30:44 +10:00
Michael Wilson
38d248defe [no ci] chore: use ninja in linux build (#722) 2024-12-24 16:14:59 +10:00
Michael Wilson
6b4306948b Update Schema to Latest (#721) 2024-12-24 16:01:10 +10:00
Michael Wilson
3fee00e8c4 [no ci] Update getting-started.md 2024-12-24 16:00:36 +10:00
Michael Wilson
d22af142cb [no ci] chore: upgrade to cxx20 (#719) 2024-12-24 15:34:12 +10:00
dependabot[bot]
c1176a3192 [no ci] chore(deps): bump libraries/hl2sdk-cs2 from 14e77af to a658a0f (#718)
Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2024-12-24 15:32:38 +10:00
dependabot[bot]
3c321be5a0 [no ci] chore(deps): bump libraries/Protobufs from 76e070d to b46090a (#717)
Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2024-12-24 15:32:20 +10:00
Michael Wilson
466da1b193 chore: back to using hl2sdk 2024-12-20 23:34:21 +00:00
Michael Wilson
ba860a92d2 fix: temporary patch hl2sdk entity listeners 2024-12-20 12:37:50 +00:00
Ian Lucas
461fc0ea67 Fix GiveNamedItem and CanAcquire signatures (#713) 2024-12-20 22:12:14 +10:00
Michael Wilson
6349c11d07 fix: revert base entity teleport changes, add warning to player controller (#688) 2024-11-27 21:25:12 +10:00
ZoNiCaL
b2046b21c4 [no ci] Shuffle player documentation, add to game event documentation (#685) 2024-11-25 10:48:25 +10:00
Michael Wilson
3c6be481c5 [no ci] Update publish-docs.yml 2024-11-25 10:48:05 +10:00
Michael Wilson
0a6fe0946d [no ci] Allow manual publish-docs.yml 2024-11-25 10:47:01 +10:00
schwarper
79297511e3 Added hitgroup to CTakeDamageInfo (#665)
Co-authored-by: Michael Wilson <roflmuffin@users.noreply.github.com>
2024-11-23 10:55:22 +00:00
schwarper
c6d3988902 CBaseEntity player teleport adjustment update (#661)
Co-authored-by: Michael Wilson <roflmuffin@users.noreply.github.com>
2024-11-23 10:07:12 +00:00
schwarper
8a063f4fb6 Added PluginConfigExtensions (#675) 2024-11-23 20:00:39 +10:00
Gold KingZ
6cf124bfb6 System.ArgumentException: Player with slot X not found (#667) 2024-11-13 08:08:47 +00:00
schwarper
1f904a52a7 Added TargetType.PlayerAim (#639)
Co-authored-by: KillStr3aK <KillStr3aK@users.noreply.github.com>
Co-authored-by: Michael Wilson <roflmuffin@users.noreply.github.com>
2024-11-06 06:52:28 +00:00
Nexd
32c99b2e49 Implemented entity transmit feature (#608)
Co-authored-by: KillStr3aK <KillStr3aK@users.noreply.github.com>
2024-11-06 16:46:03 +10:00
Nexd
5c9d38b2b0 fix: only close the menu if it has exit button (#622)
Co-authored-by: KillStr3aK <KillStr3aK@users.noreply.github.com>
2024-10-20 23:41:25 +00:00
Nexd
b54f5c3dee fix: gamedata update (#631)
Co-authored-by: KillStr3aK <KillStr3aK@users.noreply.github.com>
2024-10-21 09:35:38 +10:00
schwarper
761380dff6 CCSPlayer_ItemServices_CanAcquire and GetCSWeaponDataFromKey signatures update (#636) 2024-10-19 10:07:07 +10:00
Interesting
71ae253e5e Add GetGameframeTime to NativeAPI (#627)
Co-authored-by: Michael Wilson <roflmuffin@users.noreply.github.com>
2024-10-17 03:32:10 +00:00
schwarper
c2f212df51 Add GetCSWeaponDataFromKey and CCSPlayer_ItemServices_CanAcquire (#628) 2024-10-17 00:44:32 +00:00
Ian Lucas
ad7f7bd365 fix: InvalidOperationException when removing command in its callback (#626) 2024-10-13 09:29:06 +10:00
Ian Lucas
a0fcb7817e fix: remove command to use command manager (#579)
Co-authored-by: Michael Wilson <roflmuffin@users.noreply.github.com>
2024-10-11 02:15:01 +00:00
Nexd
cdb7a6ed17 New NetworkDisconnectionReason values (#621)
Co-authored-by: KillStr3aK <KillStr3aK@users.noreply.github.com>
2024-10-11 12:10:11 +10:00
dependabot[bot]
38e29531c3 [no ci] chore(deps): bump libraries/hl2sdk-cs2 from 9be8cba to fc4b98f (#620)
Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2024-10-10 01:43:51 +00:00
dependabot[bot]
5f95969980 [no ci] chore(deps): bump libraries/Protobufs from 3ea793c to 76e070d (#619)
Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2024-10-10 11:32:36 +10:00
dependabot[bot]
42dd270b78 chore(deps): bump libraries/Protobufs from 686a062 to 3ea793c (#607)
Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2024-10-06 14:17:45 +10:00
dependabot[bot]
b807c3eda8 chore(deps): bump libraries/hl2sdk-cs2 from 1f1d158 to 9be8cba (#606)
Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2024-10-06 14:06:59 +10:00
Michael Wilson
3ede4c366c [no ci] Update dependabot.yaml 2024-10-06 14:02:28 +10:00
number201724
49cc91e373 fix CreateEvent leak (#604) 2024-10-06 14:01:18 +10:00
110 changed files with 6880 additions and 813 deletions

View File

@@ -6,7 +6,8 @@ updates:
allow:
- dependency-name: "libraries/hl2sdk-cs2"
- dependency-name: "libraries/metamod-source"
- dependency-name: "libraries/Protobufs"
schedule:
interval: "daily"
commit-message:
prefix: "chore(deps)"
prefix: "chore(deps)"

270
.github/workflows/build-and-publish.yml vendored Normal file
View File

@@ -0,0 +1,270 @@
name: Build & Publish
env:
BUILD_TYPE: Release
# Remove default permissions of GITHUB_TOKEN for security
# https://docs.github.com/en/actions/using-jobs/assigning-permissions-to-jobs
permissions: {}
on:
push:
paths-ignore:
- "docfx/**"
branches: ["main"]
tags:
- "v*"
pull_request:
branches: ["main"]
jobs:
setup:
runs-on: ubuntu-latest
outputs:
gitversion_semver: ${{ steps.gitversion.outputs.semVer }}
gitversion_fullsemver: ${{ steps.gitversion.outputs.fullSemVer }}
gitversion_assemblysemver: ${{ steps.gitversion.outputs.assemblySemVer }}
gitversion_informationalversion: ${{ steps.gitversion.outputs.informationalVersion }}
steps:
- name: Install GitVersion
uses: gittools/actions/gitversion/setup@v1
with:
versionSpec: 6.0.x
- uses: actions/checkout@v4
with:
fetch-depth: 0
- name: Execute GitVersion
id: gitversion
uses: gittools/actions/gitversion/execute@v1
with:
useConfigFile: true
build_windows:
needs: setup
runs-on: windows-latest
steps:
- name: Prepare env
shell: bash
run: |
echo "GITHUB_SHA_SHORT=${GITHUB_SHA::7}" >> $GITHUB_ENV
echo "SEMVER=${{ needs.setup.outputs.gitversion_semver }}" >> $GITHUB_ENV
- name: Visual Studio environment
shell: cmd
run: |
:: See https://github.com/microsoft/vswhere/wiki/Find-VC
for /f "usebackq delims=*" %%i in (`vswhere -latest -property installationPath`) do (
call "%%i"\Common7\Tools\vsdevcmd.bat -arch=x64 -host_arch=x64
)
:: Loop over all environment variables and make them global.
for /f "delims== tokens=1,2" %%a in ('set') do (
echo>>"%GITHUB_ENV%" %%a=%%b
)
- uses: actions/checkout@v4
with:
submodules: "recursive"
- name: Build
run: |
mkdir -p build
cd build
cmake -DCMAKE_BUILD_TYPE=${{env.BUILD_TYPE}} ..
cmake --build . --config ${{env.BUILD_TYPE}} -- /m:16
- name: Clean build directory
run: |
mkdir -p build/addons/counterstrikesharp/bin/win64
mv build/${{env.BUILD_TYPE}}/*.dll build/addons/counterstrikesharp/bin/win64
mkdir build/output/
mv build/addons build/output
- uses: actions/upload-artifact@v4
with:
name: counterstrikesharp-windows-${{ needs.setup.outputs.gitversion_semver }}
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:
image: registry.gitlab.steamos.cloud/steamrt/sniper/sdk:latest
steps:
- name: Prepare env
shell: bash
run: |
echo "GITHUB_SHA_SHORT=${GITHUB_SHA::7}" >> $GITHUB_ENV
echo "SEMVER=${{ needs.setup.outputs.gitversion_semver }}" >> $GITHUB_ENV
- uses: actions/checkout@v4
with:
submodules: "recursive"
- name: Build
run: |
mkdir -p build
cd build
cmake -G Ninja -DCMAKE_BUILD_TYPE=${{env.BUILD_TYPE}} ..
cmake --build . --config ${{env.BUILD_TYPE}} -- -j16
- name: Clean build directory
run: |
mkdir build/output/
mv build/addons build/output
- uses: actions/upload-artifact@v4
with:
name: counterstrikesharp-linux-${{ needs.setup.outputs.gitversion_semver }}
path: build/output/
build_managed:
needs: setup
permissions:
contents: write
runs-on: ubuntu-latest
steps:
- name: Prepare env
shell: bash
run: echo "GITHUB_SHA_SHORT=${GITHUB_SHA::7}" >> $GITHUB_ENV
# We don't need expensive submodules for the managed side.
- uses: actions/checkout@v4
- name: Build runtime v${{ needs.setup.outputs.gitversion_semver }}
uses: actions/setup-dotnet@v4
with:
dotnet-version: "8.0.x"
- name: Install dependencies
run: dotnet restore managed/CounterStrikeSharp.sln
- name: Run tests
run: dotnet test --logger trx --results-directory "TestResults-${{ needs.setup.outputs.gitversion_semver }}" managed/CounterStrikeSharp.API.Tests/CounterStrikeSharp.API.Tests.csproj
- name: Upload dotnet test results
uses: actions/upload-artifact@v4
with:
name: test-results-${{ needs.setup.outputs.gitversion_semver }}
path: TestResults-${{ needs.setup.outputs.gitversion_semver }}
if: ${{ always() }}
- name: Publish artifacts
run: |
dotnet publish -c Release \
/p:Version=${{ needs.setup.outputs.gitversion_semver }} \
/p:AssemblyVersion=${{ needs.setup.outputs.gitversion_assemblySemver }} \
/p:InformationalVersion=${{ needs.setup.outputs.gitversion_informationalversion }} \
managed/CounterStrikeSharp.API
dotnet pack -c Release \
/p:Version=${{ needs.setup.outputs.gitversion_semver }} \
/p:AssemblyVersion=${{ needs.setup.outputs.gitversion_assemblySemver }} \
/p:InformationalVersion=${{ needs.setup.outputs.gitversion_informationalversion }} \
managed/CounterStrikeSharp.API
- uses: actions/upload-artifact@v4
with:
name: counterstrikesharp-api-${{ needs.setup.outputs.gitversion_semver }}
path: managed/CounterStrikeSharp.API/bin/Release
publish:
if: ${{ github.event_name == 'push' && startsWith(github.ref, 'refs/tags/v') && github.repository == 'roflmuffin/CounterStrikeSharp' }}
permissions:
contents: write
needs: ["setup", "build_linux", "build_windows", "build_managed"]
runs-on: ubuntu-latest
steps:
- name: Prepare env
shell: bash
run: echo "GITHUB_SHA_SHORT=${GITHUB_SHA::7}" >> $GITHUB_ENV
- name: Checkout
uses: actions/checkout@v4
with:
fetch-depth: 0
- uses: actions/download-artifact@v4
with:
name: counterstrikesharp-windows-${{ needs.setup.outputs.gitversion_semver }}
path: build/windows
- uses: actions/download-artifact@v4
with:
name: counterstrikesharp-linux-${{ needs.setup.outputs.gitversion_semver }}
path: build/linux
- uses: actions/download-artifact@v4
with:
name: counterstrikesharp-api-${{ needs.setup.outputs.gitversion_semver }}
path: build/api
# TODO: This stuff should really be in a matrix
- name: Add API to Artifacts
run: |
mkdir -p build/linux/addons/counterstrikesharp/api
mkdir -p build/windows/addons/counterstrikesharp/api
cp -r build/api/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-linux-${{ needs.setup.outputs.gitversion_semver }}.zip *)
(cd build/windows && zip -qq -r ../../counterstrikesharp-windows-${{ needs.setup.outputs.gitversion_semver }}.zip *)
- name: Add dotnet runtime
run: |
mkdir -p build/linux/addons/counterstrikesharp/dotnet
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
mkdir -p build/windows/addons/counterstrikesharp/dotnet
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-linux-${{ needs.setup.outputs.gitversion_semver }}.zip *)
(cd build/windows && zip -qq -r ../../counterstrikesharp-with-runtime-windows-${{ needs.setup.outputs.gitversion_semver }}.zip *)
- name: Generate a changelog
uses: orhun/git-cliff-action@v4
id: git-cliff
with:
config: cliff.toml
args: --current -s footer
- name: Release
id: release
uses: softprops/action-gh-release@v1
with:
append_body: true
body: |
${{ steps.git-cliff.outputs.content }}
Please refer to [CHANGELOG.md](https://github.com/roflmuffin/CounterStrikeSharp/blob/${{ github.ref_name }}/CHANGELOG.md) for details.
files: |
counterstrikesharp-windows-${{ needs.setup.outputs.gitversion_semver }}.zip
counterstrikesharp-with-runtime-windows-${{ needs.setup.outputs.gitversion_semver }}.zip
counterstrikesharp-linux-${{ needs.setup.outputs.gitversion_semver }}.zip
counterstrikesharp-with-runtime-linux-${{ needs.setup.outputs.gitversion_semver }}.zip
- name: Publish NuGet package
run: |
dotnet nuget push build/api/CounterStrikeSharp.API.${{ needs.setup.outputs.gitversion_semver }}.nupkg --api-key ${{ secrets.NUGET_API_KEY }} --source https://api.nuget.org/v3/index.json --skip-duplicate
dotnet nuget push build/api/CounterStrikeSharp.API.${{ needs.setup.outputs.gitversion_semver }}.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.setup.outputs.gitversion_semver }}](${{ steps.release.outputs.url }})
${{ steps.git-cliff.outputs.content }}
Please refer to [CHANGELOG.md](https://github.com/roflmuffin/CounterStrikeSharp/blob/${{ github.ref_name }}/CHANGELOG.md) for details.

View File

@@ -1,248 +0,0 @@
name: Build & Publish
on:
push:
paths-ignore:
- "docfx/**"
branches: ["main", "dev"]
pull_request:
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: |
:: See https://github.com/microsoft/vswhere/wiki/Find-VC
for /f "usebackq delims=*" %%i in (`vswhere -latest -property installationPath`) do (
call "%%i"\Common7\Tools\vsdevcmd.bat -arch=x64 -host_arch=x64
)
:: Loop over all environment variables and make them global.
for /f "delims== tokens=1,2" %%a in ('set') do (
echo>>"%GITHUB_ENV%" %%a=%%b
)
- uses: actions/checkout@v3
with:
submodules: "recursive"
- name: Build
run: |
mkdir -p build
cd build
cmake -DCMAKE_BUILD_TYPE=${{env.BUILD_TYPE}} ..
cmake --build . --config ${{env.BUILD_TYPE}} -- /m:16
- name: Clean build directory
run: |
mkdir -p build/addons/counterstrikesharp/bin/win64
mv build/${{env.BUILD_TYPE}}/*.dll build/addons/counterstrikesharp/bin/win64
mkdir build/output/
mv build/addons build/output
- uses: actions/upload-artifact@v3
with:
name: counterstrikesharp-build-windows-${{ env.GITHUB_SHA_SHORT }}
path: build/output/
build_linux:
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:
image: registry.gitlab.steamos.cloud/steamrt/sniper/sdk:latest
steps:
- name: Prepare env
shell: bash
run: echo "GITHUB_SHA_SHORT=${GITHUB_SHA::7}" >> $GITHUB_ENV
- 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"
- name: Build
run: |
mkdir -p build
cd build
cmake -DCMAKE_BUILD_TYPE=${{env.BUILD_TYPE}} ..
cmake --build . --config ${{env.BUILD_TYPE}} -- -j16
- name: Clean build directory
run: |
mkdir build/output/
mv build/addons build/output
- uses: actions/upload-artifact@v3
with:
name: counterstrikesharp-build-linux-${{ env.GITHUB_SHA_SHORT }}
path: build/output/
build_managed:
needs: setup
permissions:
contents: write
runs-on: ubuntu-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
# We don't need expensive submodules for the managed side.
- uses: actions/checkout@v3
- name: Build runtime v${{ env.BUILD_NUMBER }}
uses: actions/setup-dotnet@v3
with:
dotnet-version: "8.0.x"
- name: Install dependencies
run: dotnet restore managed/CounterStrikeSharp.sln
- name: Run tests
run: dotnet test --logger trx --results-directory "TestResults-${{ env.GITHUB_SHA_SHORT }}" managed/CounterStrikeSharp.API.Tests/CounterStrikeSharp.API.Tests.csproj
- name: Upload dotnet test results
uses: actions/upload-artifact@v3
with:
name: test-results-${{ env.GITHUB_SHA_SHORT }}
path: TestResults-${{ env.GITHUB_SHA_SHORT }}
if: ${{ always() }}
- name: Publish artifacts
run: |
dotnet publish -c Release /p:Version=1.0.${{ env.BUILD_NUMBER }} managed/CounterStrikeSharp.API
dotnet pack -c Release /p:Version=1.0.${{ env.BUILD_NUMBER }} managed/CounterStrikeSharp.API
- uses: actions/upload-artifact@v3
with:
name: counterstrikesharp-build-api-${{ env.GITHUB_SHA_SHORT }}
path: managed/CounterStrikeSharp.API/bin/Release
publish:
if: ${{ github.event_name == 'push' && github.ref == 'refs/heads/main' }}
permissions:
contents: write
needs: ["setup", "build_linux", "build_windows", "build_managed"]
runs-on: ubuntu-latest
steps:
- name: Prepare env
shell: bash
run: echo "GITHUB_SHA_SHORT=${GITHUB_SHA::7}" >> $GITHUB_ENV
- uses: actions/download-artifact@v3
with:
name: counterstrikesharp-build-windows-${{ env.GITHUB_SHA_SHORT }}
path: build/windows
- uses: actions/download-artifact@v3
with:
name: counterstrikesharp-build-linux-${{ env.GITHUB_SHA_SHORT }}
path: build/linux
- uses: actions/download-artifact@v3
with:
name: counterstrikesharp-build-api-${{ env.GITHUB_SHA_SHORT }}
path: build/api
# TODO: This stuff should really be in a matrix
- name: Add API to Artifacts
run: |
mkdir -p build/linux/addons/counterstrikesharp/api
mkdir -p build/windows/addons/counterstrikesharp/api
cp -r build/api/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.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/c1371dc2-eed2-47be-9af3-ae060dbe3c7d/bd509e0a87629764ed47608466d183e6/aspnetcore-runtime-8.0.3-linux-x64.tar.gz \
| tar xvz -C build/linux/addons/counterstrikesharp/dotnet
mkdir -p build/windows/addons/counterstrikesharp/dotnet
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.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.setup.outputs.buildnumber }}
files: |
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.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.setup.outputs.buildnumber }}) at ${{ steps.release.outputs.url }}"

View File

@@ -2,6 +2,7 @@ on:
push:
branches:
- main
workflow_dispatch:
permissions:
contents: read
@@ -22,10 +23,10 @@ jobs:
steps:
- name: Checkout
uses: actions/checkout@v3
uses: actions/checkout@v4
- name: Dotnet Setup
uses: actions/setup-dotnet@v3
uses: actions/setup-dotnet@v4
with:
dotnet-version: 8.x
@@ -34,13 +35,13 @@ jobs:
- run: docfx docfx/docfx.json
- name: Setup Pages
uses: actions/configure-pages@v3
uses: actions/configure-pages@v4
- name: Upload artifact
uses: actions/upload-pages-artifact@v2
uses: actions/upload-pages-artifact@v3
with:
path: "docfx/_site"
- name: Deploy to GitHub Pages
id: deployment
uses: actions/deploy-pages@v2
uses: actions/deploy-pages@v4

1343
CHANGELOG.md Normal file

File diff suppressed because it is too large Load Diff

View File

@@ -83,6 +83,7 @@ set(SOURCE_FILES
src/scripting/natives/natives_schema.cpp
src/scripting/natives/natives_entities.cpp
src/scripting/natives/natives_voice.cpp
src/scripting/natives/natives_metamod.cpp
src/core/managers/entity_manager.cpp
src/core/managers/entity_manager.h
src/core/managers/chat_manager.cpp

1
GitVersion.yml Normal file
View File

@@ -0,0 +1 @@
workflow: GitHubFlow/v1

84
cliff.toml Normal file
View File

@@ -0,0 +1,84 @@
# git-cliff ~ configuration file
# https://git-cliff.org/docs/configuration
# [remote.github]
# owner = "roflmuffin"
# repo = "CounterStrikeSharp"
# token = ""
[changelog]
# A Tera template to be rendered for each release in the changelog.
# See https://keats.github.io/tera/docs/#introduction
body = """
## What's Changed
{%- if version %} in {{ version }}{%- endif -%}
{% for commit in commits %}
* {{ commit.message | split(pat="\n") | first | trim }} \
{% if commit.remote.username and commit.remote.username != remote.github.owner %} by \
[@{{ commit.remote.username }}](https://github.com/{{ commit.remote.username }}) \
{%- endif -%}
{% if commit.remote.pr_number %} in \
[#{{ commit.remote.pr_number }}]({{ self::remote_url() }}/pull/{{ commit.remote.pr_number }}) \
{%- endif -%}
([{{ commit.id | truncate(length=7, end="") }}]({{ self::remote_url()}}/commit/{{ commit.id }}))
{%- endfor -%}
{%- if github -%}
{% if github.contributors | filter(attribute="is_first_time", value=true) | length != 0 %}
{% raw %}\n{% endraw -%}
## New Contributors
{%- endif %}\
{% for contributor in github.contributors | filter(attribute="is_first_time", value=true) %}
* [@{{ contributor.username }}](https://github.com/{{ contributor.username }}) made their first contribution
{%- if contributor.pr_number %} in \
[#{{ contributor.pr_number }}]({{ self::remote_url() }}/pull/{{ contributor.pr_number }}) \
{%- endif %}
{%- endfor -%}
{%- endif -%}
{% if version %}
{% else -%}
{% raw %}\n{% endraw %}
{% endif %}
{%- macro remote_url() -%}
https://github.com/{{ remote.github.owner }}/{{ remote.github.repo }}
{%- endmacro -%}
"""
# Remove leading and trailing whitespaces from the changelog's body.
trim = true
# A Tera template to be rendered as the changelog's footer.
# See https://keats.github.io/tera/docs/#introduction
footer = """
<!-- generated by git-cliff -->
"""
# An array of regex based postprocessors to modify the changelog.
# Replace the placeholder `<REPO>` with a URL.
postprocessors = []
[git]
# Parse commits according to the conventional commits specification.
# See https://www.conventionalcommits.org
conventional_commits = false
# Exclude commits that do not match the conventional commits specification.
filter_unconventional = true
# Split commits on newlines, treating each line as an individual commit.
split_commits = false
# An array of regex based parsers to modify commit messages prior to further processing.
commit_preprocessors = [
{ pattern = '\((\w+\s)?#([0-9]+)\)', replace = "" },
{ pattern = '\[no ci\]', replace = "" }
]
commit_parsers = [
{ message = "^release:", skip = true }
]
# Exclude commits that are not matched by any commit parser.
filter_commits = false
# Order releases topologically instead of chronologically.
topo_order = false
# Order of commits in each group/release within the changelog.
# Allowed values: newest, oldest
sort_commits = "newest"
tag_pattern = "v[0-9]+\\.[0-9]+\\.[0-9]+"

View File

@@ -57,7 +57,7 @@
"signatures": {
"library": "server",
"windows": "48 89 5C 24 ? 48 89 74 24 ? 55 57 41 ? 41 ? 41 ? 48 ? ? ? ? 48 ? ? ? ? ? ? 4D ? ? 48",
"linux": "55 48 89 E5 41 57 41 56 49 89 D6 41 55 49 89 CD 41 54 49 89 F4 53 48 89 FB 48 8D 3D"
"linux": "55 48 89 E5 41 57 41 56 4D 89 C6 41 55 49 89 D5 41 54 49 89 F4"
}
},
"UTIL_Remove": {
@@ -84,10 +84,24 @@
"CCSPlayer_WeaponServices_CanUse": {
"signatures": {
"library": "server",
"windows": "48 89 5C 24 ? 48 89 6C 24 ? 56 57 41 56 48 83 EC 30 48 8B 01",
"windows": "48 89 5C 24 ? 48 89 6C 24 ? 56 57 41 56 48 83 EC ? 48 8B 01 48 8B FA",
"linux": "55 48 8D 15 ? ? ? ? 48 89 E5 41 55 49 89 FD 41 54 49 89 F4"
}
},
"CCSPlayer_ItemServices_CanAcquire": {
"signatures": {
"library": "server",
"windows": "44 89 44 24 ? 48 89 54 24 ? 48 89 4C 24 ? 55 56 57 41 54 41 55 41 56 41 57 48 8B EC",
"linux": "55 48 89 E5 41 57 41 56 41 55 49 89 CD 41 54 53 48 83 EC"
}
},
"GetCSWeaponDataFromKey": {
"signatures": {
"library": "server",
"windows": "48 89 5C 24 ? 48 89 74 24 ? 57 48 83 EC ? 48 8B FA 8B F1 48 85 D2 0F 84",
"linux": "55 48 89 E5 41 57 41 56 41 89 FE 41 55 41 54 45"
}
},
"CCSPlayer_ItemServices_GiveNamedItem": {
"offsets": {
"windows": 19,
@@ -119,6 +133,12 @@
"linux": "55 48 89 E5 41 57 41 56 41 55 41 54 49 89 FC 53 48 81 EC 88 00 00 00 48 8D 05 ? ? ? ?"
}
},
"CCSGameRules_FindPickerEntity": {
"offsets": {
"windows": 27,
"linux": 28
}
},
"UTIL_CreateEntityByName": {
"signatures": {
"library": "server",
@@ -133,6 +153,13 @@
"linux": "48 85 FF 74 ? 55 48 89 E5 41 56"
}
},
"CBaseEntity_EmitSoundFilter": {
"signatures": {
"library": "server",
"windows": "48 89 5C 24 08 48 89 6C 24 10 48 89 74 24 18 48 89 7C 24 20 41 56 48 83 EC 30 48 8B EA",
"linux": "55 48 89 E5 41 56 49 89 D6 41 55 41 89 F5 41 54 48"
}
},
"CEntityInstance_AcceptInput": {
"signatures": {
"library": "server",
@@ -156,8 +183,8 @@
},
"CBasePlayerPawn_CommitSuicide": {
"offsets": {
"windows": 377,
"linux": 377
"windows": 380,
"linux": 380
}
},
"CBasePlayerPawn_RemovePlayerItem": {
@@ -239,5 +266,11 @@
"windows": 2,
"linux": 0
}
},
"CheckTransmitPlayerSlot": {
"offsets": {
"windows": 584,
"linux": 584
}
}
}
}

View File

@@ -54,6 +54,9 @@ The specific subclass of `GameEvent` will provide strongly typed parameters from
These event properties are mutable so you can update them as normal and they will update in the event instance.
> [!CAUTION]
> `GameEvent` instances and their properties will cease to exist after the event listener function is called, which means that you will encounter errors when accessing properties in timers and functions like `Server.NextFrame()`. You should store the value of properties in variables before calling functions like `Server.NextFrame()` so you can read the data safely.
## Preventing Broadcast
You can modify a game event so that it does not get broadcast to clients by modifying the `bool info.DontBroadcast` property. e.g.

View File

@@ -10,7 +10,7 @@ In this guide you will learn how to install CounterStrikeSharp onto your vanilla
If you're more of a visual person, here is a <a href="https://www.youtube.com/watch?v=FlsKzStHJuY" target="_blank">Youtube video</a> that covers everything.
## Prerequisites
- <a href="https://www.sourcemm.net/downloads.php/?branch=master" target="_blank">Metamod: Source 2.X Dev Build</a>
- <a href="https://www.metamodsource.net/downloads.php/?branch=master" target="_blank">Metamod: Source 2.X Dev Build</a>
- <a href="https://github.com/roflmuffin/CounterStrikeSharp/releases" target="_blank">CounterStrikeSharp With Runtime</a>
## Installing Metamod

View File

@@ -6,3 +6,6 @@
- name: Dependency Injection
href: dependency-injection.md
- name: Referencing Players
href: referencing-players.md

View File

@@ -1,5 +1,2 @@
- name: Core Configuration
href: core-configuration.md
- name: Referencing Players
href: referencing-players.md
href: core-configuration.md

View File

@@ -0,0 +1,2 @@
# With CheckTransmit
This example shows how to work with the `CheckTransmit` listener.

View File

@@ -0,0 +1,13 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFramework>net8.0</TargetFramework>
<ImplicitUsings>enable</ImplicitUsings>
<Nullable>enable</Nullable>
</PropertyGroup>
<ItemGroup>
<ProjectReference Include="..\..\managed\CounterStrikeSharp.API\CounterStrikeSharp.API.csproj" />
</ItemGroup>
</Project>

View File

@@ -0,0 +1,115 @@
using CounterStrikeSharp.API;
using CounterStrikeSharp.API.Core;
using CounterStrikeSharp.API.Core.Attributes;
namespace WithCheckTransmit;
[MinimumApiVersion(276)]
public class WithCheckTransmitPlugin : BasePlugin
{
public override string ModuleName => "Example: With CheckTransmit";
public override string ModuleVersion => "1.0.0";
public override string ModuleAuthor => "CounterStrikeSharp & Contributors";
public override string ModuleDescription => "A simple plugin that uses the CheckTransmit listener!";
private Dictionary<int, bool> ShouldSeeDoors = new Dictionary<int, bool>();
public override void Load(bool hotReload)
{
// This command is related to the following example.
AddCommand("nodoors", "Toggle door transmit", (player, info) =>
{
if (player == null)
return;
if (ShouldSeeDoors.ContainsKey(player.Slot))
{
ShouldSeeDoors[player.Slot] = !ShouldSeeDoors[player.Slot];
} else
{
ShouldSeeDoors.Add(player.Slot, false);
}
info.ReplyToCommand($"You should {(ShouldSeeDoors[player.Slot] ? "see" : "not see")} doors");
});
// In this example, we will hide every door for players that have enabled the option with the command 'nodoors'
RegisterListener<Listeners.CheckTransmit>((CCheckTransmitInfoList infoList) =>
{
// Get the list of the currently available doors (prop_door_rotating)
IEnumerable<CPropDoorRotating> doors = Utilities.FindAllEntitiesByDesignerName<CPropDoorRotating>("prop_door_rotating");
// Do nothing if there is none.
if (!doors.Any())
return;
// Go through every received info
foreach ((CCheckTransmitInfo info, CCSPlayerController? player) in infoList)
{
// If no player is found, we can continue
if (player == null)
continue;
// Otherwise, lets do the work:
// Check if we should clear or not:
// If we have no data saved for this player, then we should not continue
if (!ShouldSeeDoors.ContainsKey(player.Slot))
continue;
// If this value is true, then this player should see doors
if (ShouldSeeDoors[player.Slot])
continue;
// Otherwise, lets remove the door entity indexes from the info list so they won't be transmitted
foreach (CPropDoorRotating door in doors)
{
info.TransmitEntities.Remove(door);
}
// NOTE: this is a barebone example, saving data and doing sanity checks is up to you.
}
});
// In this example, we will hide other players in the same team as the player.
// NOTE: 'Hiding' players requires extra work to do, killing non-transmitted players results in crash.
RegisterListener<Listeners.CheckTransmit>((CCheckTransmitInfoList infoList) =>
{
// Get the list of the current players, we only work with this value later on
List<CCSPlayerController> players = Utilities.GetPlayers();
// Go through every received info
foreach ((CCheckTransmitInfo info, CCSPlayerController? player) in infoList)
{
// If no player is found, we can continue
if (player == null)
continue;
// Otherwise, lets do the work:
// as an example, lets hide everyone for this player who is in the same team.
IEnumerable<CCSPlayerController> targetPlayers = players.Where(p =>
// is the player and its pawn valid
p.IsValid && p.Pawn.IsValid &&
// we shouldn't hide ourselves
p.Slot != player.Slot &&
// is the player is in the same team
p.Team == player.Team &&
// is alive
p.PlayerPawn.Value?.LifeState == (byte)LifeState_t.LIFE_ALIVE
);
foreach (CCSPlayerController targetPlayer in targetPlayers)
{
// Calling 'Remove' will clear the entity index of the target player pawn from the transmission list
// so it won't be transmitted for the 'player'.
info.TransmitEntities.Remove(targetPlayer.Pawn);
}
}
});
}
}

View File

@@ -1,38 +1,60 @@
using System.Text.Json.Serialization;
using CounterStrikeSharp.API.Core;
using CounterStrikeSharp.API.Core.Attributes;
namespace WithConfig;
public class SampleConfig : BasePluginConfig
{
[JsonPropertyName("ChatPrefix")] public string ChatPrefix { get; set; } = "My Cool Plugin";
[JsonPropertyName("ChatInterval")] public float ChatInterval { get; set; } = 60;
}
[MinimumApiVersion(80)]
public class WithConfigPlugin : BasePlugin, IPluginConfig<SampleConfig>
{
public override string ModuleName => "Example: With Config";
public override string ModuleVersion => "1.0.0";
public SampleConfig Config { get; set; }
public void OnConfigParsed(SampleConfig config)
{
// Do manual verification of the config and override any invalid values
if (config.ChatInterval > 60)
{
config.ChatInterval = 60;
}
if (config.ChatPrefix.Length > 25)
{
throw new Exception($"Invalid value has been set to config value 'ChatPrefix': {config.ChatPrefix}");
}
// Once we've validated the config, we can set it to the instance
Config = config;
}
}
using System.Text.Json.Serialization;
using CounterStrikeSharp.API.Core;
using CounterStrikeSharp.API.Core.Attributes;
using CounterStrikeSharp.API.Core.Attributes.Registration;
using CounterStrikeSharp.API.Modules.Admin;
using CounterStrikeSharp.API.Modules.Commands;
using CounterStrikeSharp.API.Modules.Config;
using CounterStrikeSharp.API.Modules.Extensions;
namespace WithConfig;
public class SampleConfig : BasePluginConfig
{
[JsonPropertyName("ChatPrefix")] public string ChatPrefix { get; set; } = "My Cool Plugin";
[JsonPropertyName("ChatInterval")] public float ChatInterval { get; set; } = 60;
}
[MinimumApiVersion(80)]
public class WithConfigPlugin : BasePlugin, IPluginConfig<SampleConfig>
{
public override string ModuleName => "Example: With Config";
public override string ModuleVersion => "1.0.0";
public SampleConfig Config { get; set; }
public void OnConfigParsed(SampleConfig config)
{
// Do manual verification of the config and override any invalid values
if (config.ChatInterval > 60)
{
config.ChatInterval = 60;
}
if (config.ChatPrefix.Length > 25)
{
throw new Exception($"Invalid value has been set to config value 'ChatPrefix': {config.ChatPrefix}");
}
// Once we've validated the config, we can set it to the instance
Config = config;
}
[ConsoleCommand("css_reload_config", "Reloads the plugin config")]
public void OnReloadConfig(CCSPlayerController? player, CommandInfo commandInfo)
{
commandInfo.ReplyToCommand("Chat Interval before reload: " + Config.ChatInterval);
Config.Reload();
commandInfo.ReplyToCommand("Chat Interval after reload: " + Config.ChatInterval);
}
[ConsoleCommand("css_reset_config", "Resets the plugin config")]
public void OnResetConfig(CCSPlayerController? player, CommandInfo commandInfo)
{
commandInfo.ReplyToCommand("Chat Interval before reset: " + Config.ChatInterval);
Config.ChatInterval = 60;
Config.Update();
commandInfo.ReplyToCommand("Chat Interval after reset: " + Config.ChatInterval);
}
}

View File

@@ -11,7 +11,7 @@ set(CMAKE_CONFIGURATION_TYPES "Debug;Release" CACHE STRING
FORCE
)
set(CMAKE_CXX_STANDARD 17)
set(CMAKE_CXX_STANDARD 20)
if(LINUX)
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fPIC")
@@ -35,10 +35,10 @@ else()
add_definitions(-DGITHUB_SHA="Local")
endif()
if(DEFINED ENV{BUILD_NUMBER})
add_definitions(-DBUILD_NUMBER="$ENV{BUILD_NUMBER}")
if(DEFINED ENV{SEMVER})
add_definitions(-DSEMVER="$ENV{SEMVER}")
else()
add_definitions(-DBUILD_NUMBER="0")
add_definitions(-DSEMVER="Local")
endif()
if(CMAKE_CXX_COMPILER_ID STREQUAL "GNU")

File diff suppressed because it is too large Load Diff

View File

@@ -206,6 +206,18 @@ namespace CounterStrikeSharp.API.Core
}
}
public static void ReplicateConvar(int clientslot, string convarname, string convarvalue){
lock (ScriptContext.GlobalScriptContext.Lock) {
ScriptContext.GlobalScriptContext.Reset();
ScriptContext.GlobalScriptContext.Push(clientslot);
ScriptContext.GlobalScriptContext.Push(convarname);
ScriptContext.GlobalScriptContext.Push(convarvalue);
ScriptContext.GlobalScriptContext.SetIdentifier(0xC8728BEC);
ScriptContext.GlobalScriptContext.Invoke();
ScriptContext.GlobalScriptContext.CheckErrors();
}
}
public static T DynamicHookGetReturn<T>(IntPtr hook, int datatype){
lock (ScriptContext.GlobalScriptContext.Lock) {
ScriptContext.GlobalScriptContext.Reset();
@@ -337,6 +349,16 @@ 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 void IssueServerCommand(string command){
lock (ScriptContext.GlobalScriptContext.Lock) {
ScriptContext.GlobalScriptContext.Reset();
@@ -758,6 +780,21 @@ namespace CounterStrikeSharp.API.Core
}
}
public static uint EmitSoundFilter(ulong filtermask, uint ent, string sound, float volume, float pitch){
lock (ScriptContext.GlobalScriptContext.Lock) {
ScriptContext.GlobalScriptContext.Reset();
ScriptContext.GlobalScriptContext.Push(filtermask);
ScriptContext.GlobalScriptContext.Push(ent);
ScriptContext.GlobalScriptContext.Push(sound);
ScriptContext.GlobalScriptContext.Push(volume);
ScriptContext.GlobalScriptContext.Push(pitch);
ScriptContext.GlobalScriptContext.SetIdentifier(0x43C4A2B3);
ScriptContext.GlobalScriptContext.Invoke();
ScriptContext.GlobalScriptContext.CheckErrors();
return (uint)ScriptContext.GlobalScriptContext.GetResult(typeof(uint));
}
}
public static void HookEvent(string name, InputArgument callback, bool ispost){
lock (ScriptContext.GlobalScriptContext.Lock) {
ScriptContext.GlobalScriptContext.Reset();
@@ -1150,6 +1187,17 @@ namespace CounterStrikeSharp.API.Core
}
}
public static IntPtr MetaFactory(string interfacename){
lock (ScriptContext.GlobalScriptContext.Lock) {
ScriptContext.GlobalScriptContext.Reset();
ScriptContext.GlobalScriptContext.Push(interfacename);
ScriptContext.GlobalScriptContext.SetIdentifier(0x61521EF3);
ScriptContext.GlobalScriptContext.Invoke();
ScriptContext.GlobalScriptContext.CheckErrors();
return (IntPtr)ScriptContext.GlobalScriptContext.GetResult(typeof(IntPtr));
}
}
public static short GetSchemaOffset(string classname, string propname){
lock (ScriptContext.GlobalScriptContext.Lock) {
ScriptContext.GlobalScriptContext.Reset();

View File

@@ -0,0 +1,9 @@
using System;
namespace CounterStrikeSharp.API.Core.Attributes.Registration;
[AttributeUsage(AttributeTargets.Method)]
public class ListenerHandlerAttribute<T> : Attribute
where T: Delegate
{
}

View File

@@ -116,9 +116,6 @@ namespace CounterStrikeSharp.API.Core
public readonly Dictionary<Delegate, CallbackSubscriber> Handlers =
new Dictionary<Delegate, CallbackSubscriber>();
public readonly Dictionary<Delegate, CallbackSubscriber> CommandHandlers =
new Dictionary<Delegate, CallbackSubscriber>();
public readonly Dictionary<Delegate, CallbackSubscriber> CommandListeners =
new Dictionary<Delegate, CallbackSubscriber>();
@@ -132,6 +129,8 @@ namespace CounterStrikeSharp.API.Core
internal readonly Dictionary<Delegate, EntityIO.EntityOutputCallback> EntitySingleOutputHooks =
new Dictionary<Delegate, EntityIO.EntityOutputCallback>();
public readonly List<CommandDefinition> CommandDefinitions = new List<CommandDefinition>();
public readonly List<Timer> Timers = new List<Timer>();
public delegate HookResult GameEventHandler<T>(T @event, GameEventInfo info) where T : GameEvent;
@@ -193,11 +192,13 @@ namespace CounterStrikeSharp.API.Core
public void AddCommand(string name, string description, CommandInfo.CommandCallback handler)
{
var definition = new CommandDefinition(name, description, handler);
CommandDefinitions.Add(definition);
CommandManager.RegisterCommand(definition);
}
private void AddCommand(CommandDefinition definition)
{
CommandDefinitions.Add(definition);
CommandManager.RegisterCommand(definition);
}
@@ -229,14 +230,13 @@ namespace CounterStrikeSharp.API.Core
/// <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))
var definition = CommandDefinitions.FirstOrDefault(
definition => definition.Name == name && definition.Callback == handler);
if (definition != null)
{
var subscriber = CommandHandlers[handler];
NativeAPI.RemoveCommand(name, subscriber.GetInputArgument());
FunctionReference.Remove(subscriber.GetReferenceIdentifier());
CommandHandlers.Remove(handler);
CommandDefinitions.Remove(definition);
CommandManager.RemoveCommand(definition);
}
}
@@ -396,20 +396,26 @@ namespace CounterStrikeSharp.API.Core
}
/// <summary>
/// Registers all game event handlers that are decorated with the <see cref="GameEventHandlerAttribute"/> attribute.
/// Registers all game event handlers that are decorated with the <see cref="GameEventHandlerAttribute"/> and <see cref="ListenerHandlerAttribute{T}"/> attribute.
/// </summary>
/// <param name="instance">The instance of the object where the event handlers are defined.</param>
public void RegisterAttributeHandlers(object instance)
{
var eventHandlers = instance.GetType()
.GetMethods()
var methods = instance.GetType().GetMethods();
var eventHandlers = methods
.Where(method => method.GetCustomAttribute<GameEventHandlerAttribute>() != null)
.Where(method =>
method.GetParameters().FirstOrDefault()?.ParameterType.IsSubclassOf(typeof(GameEvent)) == true)
.ToArray();
var listenerHandlers = methods
.Where(method => method.GetCustomAttribute(typeof(ListenerHandlerAttribute<>)) != null)
.ToArray();
var method = typeof(BasePlugin).GetMethod("RegisterEventHandlerInternal", BindingFlags.NonPublic |
var registerEvent = typeof(BasePlugin).GetMethod(nameof(RegisterEventHandlerInternal), BindingFlags.NonPublic |
BindingFlags.Instance)!;
var registerListener = GetType().GetMethod(nameof(RegisterListener))!;
foreach (var eventHandler in eventHandlers)
{
@@ -421,8 +427,22 @@ namespace CounterStrikeSharp.API.Core
var actionType = typeof(GameEventHandler<>).MakeGenericType(parameterType);
var action = Delegate.CreateDelegate(actionType, instance, eventHandler);
var generic = method.MakeGenericMethod(parameterType);
generic.Invoke(this, new object[] { eventName, action, hookMode == HookMode.Post });
var registerEventGeneric = registerEvent.MakeGenericMethod(parameterType);
registerEventGeneric.Invoke(this, [eventName, action, hookMode == HookMode.Post]);
}
foreach (var listnerHandler in listenerHandlers)
{
var attribute = listnerHandler.GetCustomAttribute(typeof(ListenerHandlerAttribute<>))!;
var listenerType = attribute.GetType().GetGenericArguments().First();
if (listenerType.GetCustomAttribute<ListenerNameAttribute>() == null)
throw new ArgumentException("Listener of type T is invalid and does not have a name attribute",
listenerType.Name);
var listenerDelegate = Delegate.CreateDelegate(listenerType, instance, listnerHandler);
registerListener.MakeGenericMethod(listenerType).Invoke(this, [listenerDelegate]);
}
}
@@ -621,11 +641,6 @@ namespace CounterStrikeSharp.API.Core
{
subscriber.Dispose();
}
foreach (var subscriber in CommandHandlers.Values)
{
subscriber.Dispose();
}
foreach (var subscriber in CommandListeners.Values)
{
@@ -642,6 +657,11 @@ namespace CounterStrikeSharp.API.Core
subscriber.Dispose();
}
foreach (var definition in CommandDefinitions)
{
CommandManager.RemoveCommand(definition);
}
foreach (var timer in Timers)
{
timer.Kill();
@@ -650,4 +670,4 @@ namespace CounterStrikeSharp.API.Core
_disposed = true;
}
}
}
}

View File

@@ -70,8 +70,13 @@ public class CommandManager : ICommandManager
if (_commandDefinitions.TryGetValue(name, out var handler))
{
foreach (var command in handler)
foreach (var command in handler.ToList())
{
if (!handler.Contains(command))
{
continue;
}
var methodInfo = command.Callback?.GetMethodInfo();
// We do not need to do permission checks on commands executed from the server console.

View File

@@ -682,6 +682,30 @@ namespace CounterStrikeSharp.API.Core
get => GetPlayer("userid");
set => SetPlayer("userid", value);
}
public bool PlayerHeld
{
get => Get<bool>("player_held");
set => Set<bool>("player_held", value);
}
public bool PlayerThrown
{
get => Get<bool>("player_thrown");
set => Set<bool>("player_thrown", value);
}
public bool PlayerDropped
{
get => Get<bool>("player_dropped");
set => Set<bool>("player_dropped", value);
}
}
[EventName("broken_breakable")]
@@ -2053,10 +2077,10 @@ namespace CounterStrikeSharp.API.Core
// Entindex of the entity they see
public int Subject
public long Subject
{
get => Get<int>("subject");
set => Set<int>("subject", value);
get => Get<long>("subject");
set => Set<long>("subject", value);
}
@@ -2334,6 +2358,14 @@ namespace CounterStrikeSharp.API.Core
get => Get<string>("mapname");
set => Set<string>("mapname", value);
}
// true if this is a transition from one map to another
public bool Transition
{
get => Get<bool>("transition");
set => Set<bool>("transition", value);
}
}
[EventName("game_phase_changed")]
@@ -3318,6 +3350,14 @@ namespace CounterStrikeSharp.API.Core
}
// entity id of the env_instructor_hint that fired the event
public long HintEntindex
{
get => Get<long>("hint_entindex");
set => Set<long>("hint_entindex", value);
}
// what to name the hint. For referencing it again later (e.g. a kill command for the hint instead of a timeout)
public string HintName
{
@@ -3342,7 +3382,7 @@ namespace CounterStrikeSharp.API.Core
}
// userid id of the activator
// playerslot of the activator
public CCSPlayerController? HintActivatorUserid
{
get => GetPlayer("hint_activator_userid");
@@ -3430,14 +3470,6 @@ namespace CounterStrikeSharp.API.Core
}
// gamepad bindings to use when use_binding is the onscreen icon
public string HintGamepadBinding
{
get => Get<string>("hint_gamepad_binding");
set => Set<string>("hint_gamepad_binding", value);
}
// if false, the hint will dissappear if the target entity is invisible
public bool HintAllowNodrawTarget
{
@@ -3468,6 +3500,62 @@ namespace CounterStrikeSharp.API.Core
get => Get<bool>("hint_local_player_only");
set => Set<bool>("hint_local_player_only", value);
}
// Game sound to play
public string HintStartSound
{
get => Get<string>("hint_start_sound");
set => Set<string>("hint_start_sound", value);
}
// Path for Panorama layout file
public string HintLayoutfile
{
get => Get<string>("hint_layoutfile");
set => Set<string>("hint_layoutfile", value);
}
// Attachment type for the Panorama panel
public int HintVrPanelType
{
get => Get<int>("hint_vr_panel_type");
set => Set<int>("hint_vr_panel_type", value);
}
// Height offset for attached panels
public float HintVrHeightOffset
{
get => Get<float>("hint_vr_height_offset");
set => Set<float>("hint_vr_height_offset", value);
}
// offset for attached panels
public float HintVrOffsetX
{
get => Get<float>("hint_vr_offset_x");
set => Set<float>("hint_vr_offset_x", value);
}
// offset for attached panels
public float HintVrOffsetY
{
get => Get<float>("hint_vr_offset_y");
set => Set<float>("hint_vr_offset_y", value);
}
// offset for attached panels
public float HintVrOffsetZ
{
get => Get<float>("hint_vr_offset_z");
set => Set<float>("hint_vr_offset_z", value);
}
}
[EventName("instructor_server_hint_stop")]
@@ -3484,6 +3572,14 @@ namespace CounterStrikeSharp.API.Core
get => Get<string>("hint_name");
set => Set<string>("hint_name", value);
}
// entity id of the env_instructor_hint that fired the event
public long HintEntindex
{
get => Get<long>("hint_entindex");
set => Set<long>("hint_entindex", value);
}
}
[EventName("instructor_start_lesson")]
@@ -3549,6 +3645,21 @@ namespace CounterStrikeSharp.API.Core
public EventInventoryUpdated(bool force) : base("inventory_updated", force){}
public int Itemdef
{
get => Get<int>("itemdef");
set => Set<int>("itemdef", value);
}
public long Itemid
{
get => Get<long>("itemid");
set => Set<long>("itemid", value);
}
}
[EventName("item_equip")]
@@ -4489,14 +4600,6 @@ namespace CounterStrikeSharp.API.Core
}
// ip:port
public string Address
{
get => Get<string>("address");
set => Set<string>("address", value);
}
public bool Bot
{
@@ -5297,7 +5400,7 @@ namespace CounterStrikeSharp.API.Core
// player
public CCSPlayerController? Userid
{
get => GetPlayer("userid");
@@ -5337,7 +5440,15 @@ namespace CounterStrikeSharp.API.Core
}
// true if player is a bot
public string Name
{
get => Get<string>("name");
set => Set<string>("name", value);
}
public bool Isbot
{
get => Get<bool>("isbot");
@@ -6885,42 +6996,18 @@ namespace CounterStrikeSharp.API.Core
public int VoteOption1
public int Yesvotes
{
get => Get<int>("vote_option1");
set => Set<int>("vote_option1", value);
get => Get<int>("yesVotes");
set => Set<int>("yesVotes", value);
}
public int VoteOption2
public int Novotes
{
get => Get<int>("vote_option2");
set => Set<int>("vote_option2", value);
}
public int VoteOption3
{
get => Get<int>("vote_option3");
set => Set<int>("vote_option3", value);
}
public int VoteOption4
{
get => Get<int>("vote_option4");
set => Set<int>("vote_option4", value);
}
public int VoteOption5
{
get => Get<int>("vote_option5");
set => Set<int>("vote_option5", value);
get => Get<int>("noVotes");
set => Set<int>("noVotes", value);
}
@@ -7086,6 +7173,14 @@ namespace CounterStrikeSharp.API.Core
public string Votedata
{
get => Get<string>("votedata");
set => Set<string>("votedata", value);
}
public int Team
{
get => Get<int>("team");
@@ -7099,6 +7194,14 @@ namespace CounterStrikeSharp.API.Core
get => Get<long>("initiator");
set => Set<long>("initiator", value);
}
// this event is reliable
public int Reliable
{
get => Get<int>("reliable");
set => Set<int>("reliable", value);
}
}
[EventName("warmup_end")]

View File

@@ -163,5 +163,18 @@ namespace CounterStrikeSharp.API.Core
/// <param name="manifest">Resource Manifest</param>
[ListenerName("OnServerPrecacheResources")]
public delegate void OnServerPrecacheResources(ResourceManifest manifest);
/// <summary>
/// Called when checking transmit on entities.
/// </summary>
/// <param name="infoList">Transmit info list</param>
[ListenerName("CheckTransmit")]
public delegate void CheckTransmit([CastFrom(typeof(nint))]CCheckTransmitInfoList infoList);
/// <summary>
/// Called when all metamod plugins are loaded.
/// </summary>
[ListenerName("OnMetamodAllPluginsLoaded")]
public delegate void OnMetamodAllPluginsLoaded();
}
}
}

View File

@@ -12,15 +12,17 @@ public partial class CBaseEntity
public void Teleport(Vector? position = null, QAngle? angles = null, Vector? velocity = null)
{
Guard.IsValidEntity(this);
if (position == null && angles == null && velocity == null)
throw new ArgumentNullException("No valid argument");
nint _position = position?.Handle ?? 0;
nint _angles = angles?.Handle ?? 0;
nint _velocity = velocity?.Handle ?? 0;
VirtualFunction.CreateVoid<IntPtr, IntPtr, IntPtr, IntPtr>(Handle, GameData.GetOffset("CBaseEntity_Teleport"))(Handle, _position, _angles, _velocity);
nint _handle = Handle;
VirtualFunction.CreateVoid<IntPtr, IntPtr, IntPtr, IntPtr>(_handle, GameData.GetOffset("CBaseEntity_Teleport"))(_handle, _position,
_angles, _velocity);
}
/// <exception cref="InvalidOperationException">Entity is not valid</exception>
@@ -48,4 +50,25 @@ public partial class CBaseEntity
return (T)Activator.CreateInstance(typeof(T), Marshal.ReadIntPtr(SubclassID.Handle + 4));
}
/// <summary>
/// Emit a soundevent to all players.
/// </summary>
/// <param name="soundEventName">The name of the soundevent to emit.</param>
/// <param name="recipients">The recipients of the soundevent.</param>
/// <param name="volume">The volume of the soundevent.</param>
/// <param name="pitch">The pitch of the soundevent.</param>
/// <returns>The sound event guid.</returns>
public uint EmitSound(string soundEventName, RecipientFilter? recipients = null, float volume = 1f, float pitch = 0)
{
Guard.IsValidEntity(this);
if (recipients == null)
{
recipients = new RecipientFilter();
recipients.AddAllPlayers();
}
return NativeAPI.EmitSoundFilter(recipients.GetRecipientMask(), this.Index, soundEventName, volume, pitch);
}
}

View File

@@ -16,6 +16,7 @@
using CounterStrikeSharp.API.Modules.Entities.Constants;
using CounterStrikeSharp.API.Modules.Memory;
using CounterStrikeSharp.API.Modules.Utils;
namespace CounterStrikeSharp.API.Core;
@@ -28,4 +29,33 @@ public partial class CCSGameRules
{
VirtualFunctions.TerminateRound(Handle, roundEndReason, delay, 0, 0);
}
}
public T? FindPickerEntity<T>(CBasePlayerController player)
where T : CBaseEntity
{
VirtualFunctionWithReturn<CCSGameRules, CBasePlayerController, CBaseEntity?> CCSGameRules_FindPickerEntity = new (Handle, GameData.GetOffset("CCSGameRules_FindPickerEntity"));
CBaseEntity? entity = CCSGameRules_FindPickerEntity.Invoke(this, player);
if (entity == null || !entity.IsValid)
{
return null;
}
return entity.As<T>();
}
public CCSPlayerController? GetClientAimTarget(CCSPlayerController player)
{
CCSPlayerPawn? pawn = FindPickerEntity<CCSPlayerPawn>(player);
if (pawn == null || !pawn.IsValid)
return null;
if (pawn.DesignerName == "player")
{
return pawn.OriginalController.Value;
}
return null;
}
}

View File

@@ -340,4 +340,16 @@ public partial class CCSPlayerController
NativeAPI.SetClientVoiceFlags(Handle, (Byte)value);
}
}
[Obsolete(
"You are trying to call Teleport on a non-physical player. Maybe you mean Pawn? (See: https://docs.cssharp.dev/docs/guides/referencing-players.html#controllers--pawns)")]
public new void Teleport(Vector? position = null, QAngle? angles = null, Vector? velocity = null)
{
base.Teleport(position, angles, velocity);
}
public void ReplicateConVar(string conVar, string value)
{
NativeAPI.ReplicateConvar(Slot, conVar, value);
}
}

View File

@@ -15,6 +15,8 @@
*/
using CounterStrikeSharp.API.Modules.Memory;
using CounterStrikeSharp.API.Modules.Memory.DynamicFunctions;
using CounterStrikeSharp.API.Modules.Utils;
namespace CounterStrikeSharp.API.Core;
@@ -54,4 +56,9 @@ public partial class CCSPlayer_ItemServices
return (T)Activator.CreateInstance(typeof(T), pointer)!;
}
public AcquireResult CanAcquire(CEconItemView itemView, AcquireMethod method, IntPtr unknown = 0)
{
return VirtualFunctions.CCSPlayer_ItemServices_CanAcquireFunc.Invoke(this, itemView, method, unknown);
}
}

View File

@@ -0,0 +1,106 @@
/*
* This file is part of CounterStrikeSharp.
* CounterStrikeSharp is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* CounterStrikeSharp is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with CounterStrikeSharp. If not, see <https://www.gnu.org/licenses/>. *
*/
using System.Collections;
using System.Runtime.InteropServices;
namespace CounterStrikeSharp.API.Core
{
[StructLayout(LayoutKind.Explicit)]
public struct CCheckTransmitInfo
{
/// <summary>
/// Entity n is already marked for transmission
/// </summary>
[FieldOffset(0x0)]
public CFixedBitVecBase TransmitEntities;
/// <summary>
/// Entity n is always send even if not in PVS (HLTV and Replay only)
/// </summary>
[FieldOffset(0x8)]
public CFixedBitVecBase TransmitAlways;
};
public sealed class CCheckTransmitInfoList : NativeObject, IReadOnlyList<(CCheckTransmitInfo info, CCSPlayerController? player)>
{
private int CheckTransmitPlayerSlotOffset = GameData.GetOffset("CheckTransmitPlayerSlot");
private unsafe nint* Inner => (nint*)base.Handle;
public unsafe int Count { get => (int)(*(this.Inner + 1)); }
public unsafe CCheckTransmitInfoList(IntPtr pointer) : base(pointer)
{ }
/// <summary>
/// Get transmit info for the given index.
/// </summary>
/// <param name="index">Index of the info you want to retrieve from the list, should be between 0 and '<see cref="Count"/>' - 1</param>
/// <returns></returns>
public (CCheckTransmitInfo info, CCSPlayerController? player) this[int index]
{
get
{
var (transmit, slot) = this.Get(index);
CCSPlayerController? player = Utilities.GetPlayerFromSlot(slot);
return (transmit, player);
}
}
/// <summary>
/// Get transmit info for the given index.
/// </summary>
/// <param name="index">Index of the info you want to retrieve from the list, should be between 0 and '<see cref="Count"/>' - 1</param>
/// <returns></returns>
private unsafe (CCheckTransmitInfo, int) Get(int index)
{
if (index < 0 || index >= this.Count)
{
throw new ArgumentOutOfRangeException("index");
}
// 'base.Handle' holds the pointer for our 'CCheckTransmitInfoList' wrapper class
// Get the pointer to the array of 'CCheckTransmitInfo'
nint* infoListPtr = *(nint**)this.Inner; // Dereference 'Inner' to get the pointer to the array
// Access the specific 'CCheckTransmitInfo*'
nint infoPtr = *(infoListPtr + index);
// Retrieve the 'CCheckTransmitInfo' from the pointer
CCheckTransmitInfo info = Marshal.PtrToStructure<CCheckTransmitInfo>(infoPtr);
// Get player slot from the 'infoPtr' using the 'CheckTransmitPlayerSlotOffset' offset
int playerSlot = *(int*)((byte*)infoPtr + CheckTransmitPlayerSlotOffset);
return (info, playerSlot);
}
public IEnumerator<(CCheckTransmitInfo, CCSPlayerController?)> GetEnumerator()
{
for (int i = 0; i < this.Count; i++)
{
yield return this[i];
}
}
IEnumerator IEnumerable.GetEnumerator()
{
return this.GetEnumerator();
}
}
}

View File

@@ -0,0 +1,81 @@
/*
* This file is part of CounterStrikeSharp.
* CounterStrikeSharp is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* CounterStrikeSharp is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with CounterStrikeSharp. If not, see <https://www.gnu.org/licenses/>. *
*/
using System.Runtime.InteropServices;
namespace CounterStrikeSharp.API.Core
{
// credits: qstage
[StructLayout(LayoutKind.Sequential)]
public unsafe struct CFixedBitVecBase
{
private const int LOG2_BITS_PER_INT = 5;
private const int BITS_PER_INT = 32;
private readonly uint* m_Ints;
public void Add(CEntityInstance entityInstance) => Write(entityInstance.Index);
public void Add(int bitNum) => Write(bitNum);
public void Add(uint bitNum) => Write(bitNum);
public void Remove(CEntityInstance entityInstance) => Clear(entityInstance.Index);
public void Remove(int bitNum) => Clear(bitNum);
public void Remove(uint bitNum) => Clear(bitNum);
public bool Contains(CEntityInstance entityInstance) => Contains(entityInstance.Index);
public bool Contains(uint bitNum) => Contains((int)bitNum);
private void Clear(uint bitNum) => Clear((int)bitNum);
private void Write(uint bitNum) => Write((int)bitNum);
private void Clear(int bitNum)
{
if (!(bitNum >= 0 && bitNum < Utilities.MaxEdicts))
return;
uint* pInt = m_Ints + BitVec_Int(bitNum);
*pInt &= ~(uint)BitVec_Bit(bitNum);
}
private void Write(int bitNum)
{
if (!(bitNum >= 0 && bitNum < Utilities.MaxEdicts))
return;
uint* pInt = m_Ints + BitVec_Int(bitNum);
*pInt |= (uint)BitVec_Bit(bitNum);
}
public bool Contains(int bitNum)
{
if (!(bitNum >= 0 && bitNum < Utilities.MaxEdicts))
return false;
uint* pInt = m_Ints + BitVec_Int(bitNum);
return (*pInt & (uint)BitVec_Bit(bitNum)) != 0;
}
private int BitVec_Int(int bitNum) => bitNum >> LOG2_BITS_PER_INT;
private int BitVec_Bit(int bitNum) => 1 << (bitNum & (BITS_PER_INT - 1));
}
}

View File

@@ -0,0 +1,32 @@
using System.Runtime.InteropServices;
namespace CounterStrikeSharp.API.Core;
public partial class CTakeDamageInfo
{
/// <summary>
/// Retrieves the hitgroup
/// </summary>
/// <returns>
/// Returns a <see cref="HitGroup_t"/> enumeration representing the player's current hit group,
/// or <see cref="HitGroup_t.HITGROUP_INVALID"/> if the hit group cannot be determined.
/// </returns>
public HitGroup_t GetHitGroup()
{
IntPtr v4 = Marshal.ReadIntPtr(Handle, 0x78);
if (v4 == nint.Zero)
{
return HitGroup_t.HITGROUP_INVALID;
}
IntPtr v1 = Marshal.ReadIntPtr(v4, 16);
if (v1 == nint.Zero)
{
return HitGroup_t.HITGROUP_GENERIC;
}
return (HitGroup_t)Marshal.ReadInt32(v1, 56);
}
}

View File

@@ -17,7 +17,7 @@ public partial class NetworkedVector<T> : NativeObject, IReadOnlyCollection<T>
}
public unsafe uint Size => Unsafe.Read<uint>((void*)Handle);
public unsafe int Count => NativeAPI.GetNetworkVectorSize(Handle);
public T this[int index]
@@ -28,7 +28,7 @@ public partial class NetworkedVector<T> : NativeObject, IReadOnlyCollection<T>
{
throw new NotSupportedException("Networked vectors currently only support CHandle<T>");
}
return (T)Activator.CreateInstance(typeof(T), NativeAPI.GetNetworkVectorElementAt(Handle, index));
}
}
@@ -50,4 +50,4 @@ public partial class NetworkedVector<T> : NativeObject, IReadOnlyCollection<T>
{
return GetEnumerator();
}
}
}

View File

@@ -58,4 +58,8 @@ public partial class CBaseAnimGraph : CBaseModelEntity
[SchemaMember("CBaseAnimGraph", "m_bRagdollClientSide")]
public ref bool RagdollClientSide => ref Schema.GetRef<bool>(this.Handle, "CBaseAnimGraph", "m_bRagdollClientSide");
// m_nLastDestructiblePartDestroyedAnimgraphSetTick
[SchemaMember("CBaseAnimGraph", "m_nLastDestructiblePartDestroyedAnimgraphSetTick")]
public ref Int32 LastDestructiblePartDestroyedAnimgraphSetTick => ref Schema.GetRef<Int32>(this.Handle, "CBaseAnimGraph", "m_nLastDestructiblePartDestroyedAnimgraphSetTick");
}

View File

@@ -78,12 +78,8 @@ public partial class CBaseCSGrenadeProjectile : CBaseGrenade
[SchemaMember("CBaseCSGrenadeProjectile", "m_nTicksAtZeroVelocity")]
public ref Int32 TicksAtZeroVelocity => ref Schema.GetRef<Int32>(this.Handle, "CBaseCSGrenadeProjectile", "m_nTicksAtZeroVelocity");
// m_bHasEverHitPlayer
[SchemaMember("CBaseCSGrenadeProjectile", "m_bHasEverHitPlayer")]
public ref bool HasEverHitPlayer => ref Schema.GetRef<bool>(this.Handle, "CBaseCSGrenadeProjectile", "m_bHasEverHitPlayer");
// m_bClearFromPlayers
[SchemaMember("CBaseCSGrenadeProjectile", "m_bClearFromPlayers")]
public ref bool ClearFromPlayers => ref Schema.GetRef<bool>(this.Handle, "CBaseCSGrenadeProjectile", "m_bClearFromPlayers");
// m_bHasEverHitEnemy
[SchemaMember("CBaseCSGrenadeProjectile", "m_bHasEverHitEnemy")]
public ref bool HasEverHitEnemy => ref Schema.GetRef<bool>(this.Handle, "CBaseCSGrenadeProjectile", "m_bHasEverHitEnemy");
}

View File

@@ -30,10 +30,6 @@ public partial class CBaseCombatCharacter : CBaseFlex
[SchemaMember("CBaseCombatCharacter", "m_impactEnergyScale")]
public ref float ImpactEnergyScale => ref Schema.GetRef<float>(this.Handle, "CBaseCombatCharacter", "m_impactEnergyScale");
// m_LastHitGroup
[SchemaMember("CBaseCombatCharacter", "m_LastHitGroup")]
public ref HitGroup_t LastHitGroup => ref Schema.GetRef<HitGroup_t>(this.Handle, "CBaseCombatCharacter", "m_LastHitGroup");
// m_bApplyStressDamage
[SchemaMember("CBaseCombatCharacter", "m_bApplyStressDamage")]
public ref bool ApplyStressDamage => ref Schema.GetRef<bool>(this.Handle, "CBaseCombatCharacter", "m_bApplyStressDamage");

View File

@@ -26,6 +26,34 @@ public partial class CBaseModelEntity : CBaseEntity
[SchemaMember("CBaseModelEntity", "m_CHitboxComponent")]
public CHitboxComponent CHitboxComponent => Schema.GetDeclaredClass<CHitboxComponent>(this.Handle, "CBaseModelEntity", "m_CHitboxComponent");
// m_nDestructiblePartInitialStateDestructed0
[SchemaMember("CBaseModelEntity", "m_nDestructiblePartInitialStateDestructed0")]
public ref HitGroup_t DestructiblePartInitialStateDestructed0 => ref Schema.GetRef<HitGroup_t>(this.Handle, "CBaseModelEntity", "m_nDestructiblePartInitialStateDestructed0");
// m_nDestructiblePartInitialStateDestructed1
[SchemaMember("CBaseModelEntity", "m_nDestructiblePartInitialStateDestructed1")]
public ref HitGroup_t DestructiblePartInitialStateDestructed1 => ref Schema.GetRef<HitGroup_t>(this.Handle, "CBaseModelEntity", "m_nDestructiblePartInitialStateDestructed1");
// m_nDestructiblePartInitialStateDestructed2
[SchemaMember("CBaseModelEntity", "m_nDestructiblePartInitialStateDestructed2")]
public ref HitGroup_t DestructiblePartInitialStateDestructed2 => ref Schema.GetRef<HitGroup_t>(this.Handle, "CBaseModelEntity", "m_nDestructiblePartInitialStateDestructed2");
// m_nDestructiblePartInitialStateDestructed3
[SchemaMember("CBaseModelEntity", "m_nDestructiblePartInitialStateDestructed3")]
public ref HitGroup_t DestructiblePartInitialStateDestructed3 => ref Schema.GetRef<HitGroup_t>(this.Handle, "CBaseModelEntity", "m_nDestructiblePartInitialStateDestructed3");
// m_nDestructiblePartInitialStateDestructed4
[SchemaMember("CBaseModelEntity", "m_nDestructiblePartInitialStateDestructed4")]
public ref HitGroup_t DestructiblePartInitialStateDestructed4 => ref Schema.GetRef<HitGroup_t>(this.Handle, "CBaseModelEntity", "m_nDestructiblePartInitialStateDestructed4");
// m_nLastHitDestructiblePartIndex
[SchemaMember("CBaseModelEntity", "m_nLastHitDestructiblePartIndex")]
public ref Int32 LastHitDestructiblePartIndex => ref Schema.GetRef<Int32>(this.Handle, "CBaseModelEntity", "m_nLastHitDestructiblePartIndex");
// m_LastHitGroup
[SchemaMember("CBaseModelEntity", "m_LastHitGroup")]
public ref HitGroup_t LastHitGroup => ref Schema.GetRef<HitGroup_t>(this.Handle, "CBaseModelEntity", "m_LastHitGroup");
// m_flDissolveStartTime
[SchemaMember("CBaseModelEntity", "m_flDissolveStartTime")]
public ref float DissolveStartTime => ref Schema.GetRef<float>(this.Handle, "CBaseModelEntity", "m_flDissolveStartTime");
@@ -68,7 +96,7 @@ public partial class CBaseModelEntity : CBaseEntity
// m_Collision
[SchemaMember("CBaseModelEntity", "m_Collision")]
public CCollisionProperty Collision => Schema.GetDeclaredClass<CCollisionProperty>(this.Handle, "CBaseModelEntity", "m_Collision");
public new CCollisionProperty Collision => Schema.GetDeclaredClass<CCollisionProperty>(this.Handle, "CBaseModelEntity", "m_Collision");
// m_Glow
[SchemaMember("CBaseModelEntity", "m_Glow")]

View File

@@ -82,10 +82,6 @@ public partial class CBasePlayerController : CBaseEntity
[SchemaMember("CBasePlayerController", "m_bPredict")]
public ref bool Predict => ref Schema.GetRef<bool>(this.Handle, "CBasePlayerController", "m_bPredict");
// m_bAutoKickDisabled
[SchemaMember("CBasePlayerController", "m_bAutoKickDisabled")]
public ref bool AutoKickDisabled => ref Schema.GetRef<bool>(this.Handle, "CBasePlayerController", "m_bAutoKickDisabled");
// m_bIsLowViolence
[SchemaMember("CBasePlayerController", "m_bIsLowViolence")]
public ref bool IsLowViolence => ref Schema.GetRef<bool>(this.Handle, "CBasePlayerController", "m_bIsLowViolence");

View File

@@ -52,7 +52,7 @@ public partial class CBasePropDoor : CDynamicProp
// m_hBlocker
[SchemaMember("CBasePropDoor", "m_hBlocker")]
public CHandle<CBaseEntity> Blocker => Schema.GetDeclaredClass<CHandle<CBaseEntity>>(this.Handle, "CBasePropDoor", "m_hBlocker");
public new CHandle<CBaseEntity> Blocker => Schema.GetDeclaredClass<CHandle<CBaseEntity>>(this.Handle, "CBasePropDoor", "m_hBlocker");
// m_bFirstBlocked
[SchemaMember("CBasePropDoor", "m_bFirstBlocked")]

View File

@@ -88,7 +88,7 @@ public partial class CBeam : CBaseModelEntity
// m_fSpeed
[SchemaMember("CBeam", "m_fSpeed")]
public ref float Speed => ref Schema.GetRef<float>(this.Handle, "CBeam", "m_fSpeed");
public new ref float Speed => ref Schema.GetRef<float>(this.Handle, "CBeam", "m_fSpeed");
// m_flFrame
[SchemaMember("CBeam", "m_flFrame")]

View File

@@ -20,6 +20,6 @@ public partial class CBodyComponentPoint : CBodyComponent
// m_sceneNode
[SchemaMember("CBodyComponentPoint", "m_sceneNode")]
public CGameSceneNode SceneNode => Schema.GetDeclaredClass<CGameSceneNode>(this.Handle, "CBodyComponentPoint", "m_sceneNode");
public new CGameSceneNode SceneNode => Schema.GetDeclaredClass<CGameSceneNode>(this.Handle, "CBodyComponentPoint", "m_sceneNode");
}

View File

@@ -306,6 +306,10 @@ public partial class CCSGameRules : CTeamplayRules
[SchemaMember("CCSGameRules", "m_bSpawnedTerrorHuntHeavy")]
public ref bool SpawnedTerrorHuntHeavy => ref Schema.GetRef<bool>(this.Handle, "CCSGameRules", "m_bSpawnedTerrorHuntHeavy");
// m_ullLocalMatchID
[SchemaMember("CCSGameRules", "m_ullLocalMatchID")]
public ref UInt64 UllLocalMatchID => ref Schema.GetRef<UInt64>(this.Handle, "CCSGameRules", "m_ullLocalMatchID");
// m_nEndMatchMapGroupVoteTypes
[SchemaMember("CCSGameRules", "m_nEndMatchMapGroupVoteTypes")]
public Span<Int32> EndMatchMapGroupVoteTypes => Schema.GetFixedArray<Int32>(this.Handle, "CCSGameRules", "m_nEndMatchMapGroupVoteTypes", 10);

View File

@@ -98,6 +98,10 @@ public partial class CCSPlayerController : CBasePlayerController
[SchemaMember("CCSPlayerController", "m_bRemoveAllItemsOnNextRoundReset")]
public ref bool RemoveAllItemsOnNextRoundReset => ref Schema.GetRef<bool>(this.Handle, "CCSPlayerController", "m_bRemoveAllItemsOnNextRoundReset");
// m_flLastJoinTeamTime
[SchemaMember("CCSPlayerController", "m_flLastJoinTeamTime")]
public ref float LastJoinTeamTime => ref Schema.GetRef<float>(this.Handle, "CCSPlayerController", "m_flLastJoinTeamTime");
// m_szClan
[SchemaMember("CCSPlayerController", "m_szClan")]
public string Clan
@@ -174,6 +178,10 @@ public partial class CCSPlayerController : CBasePlayerController
[SchemaMember("CCSPlayerController", "m_uiAbandonRecordedReason")]
public ref UInt32 UiAbandonRecordedReason => ref Schema.GetRef<UInt32>(this.Handle, "CCSPlayerController", "m_uiAbandonRecordedReason");
// m_eNetworkDisconnectionReason
[SchemaMember("CCSPlayerController", "m_eNetworkDisconnectionReason")]
public ref UInt32 NetworkDisconnectionReason => ref Schema.GetRef<UInt32>(this.Handle, "CCSPlayerController", "m_eNetworkDisconnectionReason");
// m_bCannotBeKicked
[SchemaMember("CCSPlayerController", "m_bCannotBeKicked")]
public ref bool CannotBeKicked => ref Schema.GetRef<bool>(this.Handle, "CCSPlayerController", "m_bCannotBeKicked");
@@ -290,9 +298,17 @@ public partial class CCSPlayerController : CBasePlayerController
[SchemaMember("CCSPlayerController", "m_iRoundsWon")]
public ref Int32 RoundsWon => ref Schema.GetRef<Int32>(this.Handle, "CCSPlayerController", "m_iRoundsWon");
// m_vecKills
[SchemaMember("CCSPlayerController", "m_vecKills")]
public NetworkedVector<EKillTypes_t> Kills => Schema.GetDeclaredClass<NetworkedVector<EKillTypes_t>>(this.Handle, "CCSPlayerController", "m_vecKills");
// m_recentKillQueue
[SchemaMember("CCSPlayerController", "m_recentKillQueue")]
public Span<byte> RecentKillQueue => Schema.GetFixedArray<byte>(this.Handle, "CCSPlayerController", "m_recentKillQueue", 8);
// m_nFirstKill
[SchemaMember("CCSPlayerController", "m_nFirstKill")]
public ref byte FirstKill => ref Schema.GetRef<byte>(this.Handle, "CCSPlayerController", "m_nFirstKill");
// m_nKillCount
[SchemaMember("CCSPlayerController", "m_nKillCount")]
public ref byte KillCount => ref Schema.GetRef<byte>(this.Handle, "CCSPlayerController", "m_nKillCount");
// m_bMvpNoMusic
[SchemaMember("CCSPlayerController", "m_bMvpNoMusic")]
@@ -370,4 +386,8 @@ public partial class CCSPlayerController : CBasePlayerController
[SchemaMember("CCSPlayerController", "m_nNonSuspiciousHitStreak")]
public ref UInt32 NonSuspiciousHitStreak => ref Schema.GetRef<UInt32>(this.Handle, "CCSPlayerController", "m_nNonSuspiciousHitStreak");
// m_bFireBulletsSeedSynchronized
[SchemaMember("CCSPlayerController", "m_bFireBulletsSeedSynchronized")]
public ref bool FireBulletsSeedSynchronized => ref Schema.GetRef<bool>(this.Handle, "CCSPlayerController", "m_bFireBulletsSeedSynchronized");
}

View File

@@ -18,10 +18,6 @@ public partial class CCSPlayer_MovementServices : CPlayer_MovementServices_Human
{
public CCSPlayer_MovementServices (IntPtr pointer) : base(pointer) {}
// m_flMaxFallVelocity
[SchemaMember("CCSPlayer_MovementServices", "m_flMaxFallVelocity")]
public ref float MaxFallVelocity => ref Schema.GetRef<float>(this.Handle, "CCSPlayer_MovementServices", "m_flMaxFallVelocity");
// m_vecLadderNormal
[SchemaMember("CCSPlayer_MovementServices", "m_vecLadderNormal")]
public Vector LadderNormal => Schema.GetDeclaredClass<Vector>(this.Handle, "CCSPlayer_MovementServices", "m_vecLadderNormal");
@@ -142,14 +138,6 @@ public partial class CCSPlayer_MovementServices : CPlayer_MovementServices_Human
[SchemaMember("CCSPlayer_MovementServices", "m_flJumpPressedTime")]
public ref float JumpPressedTime => ref Schema.GetRef<float>(this.Handle, "CCSPlayer_MovementServices", "m_flJumpPressedTime");
// m_flJumpUntil
[SchemaMember("CCSPlayer_MovementServices", "m_flJumpUntil")]
public ref float JumpUntil => ref Schema.GetRef<float>(this.Handle, "CCSPlayer_MovementServices", "m_flJumpUntil");
// m_flJumpVel
[SchemaMember("CCSPlayer_MovementServices", "m_flJumpVel")]
public ref float JumpVel => ref Schema.GetRef<float>(this.Handle, "CCSPlayer_MovementServices", "m_flJumpVel");
// m_fStashGrenadeParameterWhen
[SchemaMember("CCSPlayer_MovementServices", "m_fStashGrenadeParameterWhen")]
public ref float StashGrenadeParameterWhen => ref Schema.GetRef<float>(this.Handle, "CCSPlayer_MovementServices", "m_fStashGrenadeParameterWhen");
@@ -182,4 +170,12 @@ public partial class CCSPlayer_MovementServices : CPlayer_MovementServices_Human
[SchemaMember("CCSPlayer_MovementServices", "m_flMaxJumpHeightLastJump")]
public ref float MaxJumpHeightLastJump => ref Schema.GetRef<float>(this.Handle, "CCSPlayer_MovementServices", "m_flMaxJumpHeightLastJump");
// m_flStaminaAtJumpStart
[SchemaMember("CCSPlayer_MovementServices", "m_flStaminaAtJumpStart")]
public ref float StaminaAtJumpStart => ref Schema.GetRef<float>(this.Handle, "CCSPlayer_MovementServices", "m_flStaminaAtJumpStart");
// m_flAccumulatedJumpError
[SchemaMember("CCSPlayer_MovementServices", "m_flAccumulatedJumpError")]
public ref float AccumulatedJumpError => ref Schema.GetRef<float>(this.Handle, "CCSPlayer_MovementServices", "m_flAccumulatedJumpError");
}

View File

@@ -222,6 +222,10 @@ public partial class CCSWeaponBase : CBasePlayerWeapon
[SchemaMember("CCSWeaponBase", "m_nextPrevOwnerTouchTime")]
public ref float NextPrevOwnerTouchTime => ref Schema.GetRef<float>(this.Handle, "CCSWeaponBase", "m_nextPrevOwnerTouchTime");
// m_nextPrevOwnerUseTime
[SchemaMember("CCSWeaponBase", "m_nextPrevOwnerUseTime")]
public ref float NextPrevOwnerUseTime => ref Schema.GetRef<float>(this.Handle, "CCSWeaponBase", "m_nextPrevOwnerUseTime");
// m_hPrevOwner
[SchemaMember("CCSWeaponBase", "m_hPrevOwner")]
public CHandle<CCSPlayerPawn> PrevOwner => Schema.GetDeclaredClass<CHandle<CCSPlayerPawn>>(this.Handle, "CCSWeaponBase", "m_hPrevOwner");

View File

@@ -58,6 +58,10 @@ public partial class CDamageRecord : NativeObject
[SchemaMember("CDamageRecord", "m_RecipientXuid")]
public ref UInt64 RecipientXuid => ref Schema.GetRef<UInt64>(this.Handle, "CDamageRecord", "m_RecipientXuid");
// m_iBulletsDamage
[SchemaMember("CDamageRecord", "m_iBulletsDamage")]
public ref Int32 BulletsDamage => ref Schema.GetRef<Int32>(this.Handle, "CDamageRecord", "m_iBulletsDamage");
// m_iDamage
[SchemaMember("CDamageRecord", "m_iDamage")]
public ref Int32 Damage => ref Schema.GetRef<Int32>(this.Handle, "CDamageRecord", "m_iDamage");

View File

@@ -36,7 +36,7 @@ public partial class CEnvBeam : CBeam
// m_iszEndEntity
[SchemaMember("CEnvBeam", "m_iszEndEntity")]
public string EndEntity
public new string EndEntity
{
get { return Schema.GetUtf8String(this.Handle, "CEnvBeam", "m_iszEndEntity"); }
set { Schema.SetString(this.Handle, "CEnvBeam", "m_iszEndEntity", value); }
@@ -56,7 +56,7 @@ public partial class CEnvBeam : CBeam
// m_speed
[SchemaMember("CEnvBeam", "m_speed")]
public ref Int32 Speed => ref Schema.GetRef<Int32>(this.Handle, "CEnvBeam", "m_speed");
public new ref Int32 Speed => ref Schema.GetRef<Int32>(this.Handle, "CEnvBeam", "m_speed");
// m_restrike
[SchemaMember("CEnvBeam", "m_restrike")]

View File

@@ -44,6 +44,6 @@ public partial class CEnvLaser : CBeam
// m_flStartFrame
[SchemaMember("CEnvLaser", "m_flStartFrame")]
public ref float StartFrame => ref Schema.GetRef<float>(this.Handle, "CEnvLaser", "m_flStartFrame");
public new ref float StartFrame => ref Schema.GetRef<float>(this.Handle, "CEnvLaser", "m_flStartFrame");
}

View File

@@ -14,7 +14,7 @@ using CounterStrikeSharp.API.Core.Attributes;
namespace CounterStrikeSharp.API.Core;
public partial class CEnvSoundscape : CServerOnlyEntity
public partial class CEnvSoundscape : CBaseEntity
{
public CEnvSoundscape (IntPtr pointer) : base(pointer) {}
@@ -26,14 +26,6 @@ public partial class CEnvSoundscape : CServerOnlyEntity
[SchemaMember("CEnvSoundscape", "m_flRadius")]
public ref float Radius => ref Schema.GetRef<float>(this.Handle, "CEnvSoundscape", "m_flRadius");
// m_soundscapeName
[SchemaMember("CEnvSoundscape", "m_soundscapeName")]
public string SoundscapeName
{
get { return Schema.GetUtf8String(this.Handle, "CEnvSoundscape", "m_soundscapeName"); }
set { Schema.SetString(this.Handle, "CEnvSoundscape", "m_soundscapeName", value); }
}
// m_soundEventName
[SchemaMember("CEnvSoundscape", "m_soundEventName")]
public string SoundEventName
@@ -54,10 +46,6 @@ public partial class CEnvSoundscape : CServerOnlyEntity
[SchemaMember("CEnvSoundscape", "m_soundscapeEntityListId")]
public ref Int32 SoundscapeEntityListId => ref Schema.GetRef<Int32>(this.Handle, "CEnvSoundscape", "m_soundscapeEntityListId");
// m_soundEventHash
[SchemaMember("CEnvSoundscape", "m_soundEventHash")]
public ref UInt32 SoundEventHash => ref Schema.GetRef<UInt32>(this.Handle, "CEnvSoundscape", "m_soundEventHash");
// m_positionNames
[SchemaMember("CEnvSoundscape", "m_positionNames")]
public Span<string> PositionNames => Schema.GetFixedArray<string>(this.Handle, "CEnvSoundscape", "m_positionNames", 8);
@@ -70,4 +58,16 @@ public partial class CEnvSoundscape : CServerOnlyEntity
[SchemaMember("CEnvSoundscape", "m_bDisabled")]
public ref bool Disabled => ref Schema.GetRef<bool>(this.Handle, "CEnvSoundscape", "m_bDisabled");
// m_soundscapeName
[SchemaMember("CEnvSoundscape", "m_soundscapeName")]
public string SoundscapeName
{
get { return Schema.GetUtf8String(this.Handle, "CEnvSoundscape", "m_soundscapeName"); }
set { Schema.SetString(this.Handle, "CEnvSoundscape", "m_soundscapeName", value); }
}
// m_soundEventHash
[SchemaMember("CEnvSoundscape", "m_soundEventHash")]
public ref UInt32 SoundEventHash => ref Schema.GetRef<UInt32>(this.Handle, "CEnvSoundscape", "m_soundEventHash");
}

View File

@@ -64,7 +64,7 @@ public partial class CFish : CBaseAnimGraph
// m_speed
[SchemaMember("CFish", "m_speed")]
public ref float Speed => ref Schema.GetRef<float>(this.Handle, "CFish", "m_speed");
public new ref float Speed => ref Schema.GetRef<float>(this.Handle, "CFish", "m_speed");
// m_desiredSpeed
[SchemaMember("CFish", "m_desiredSpeed")]

View File

@@ -32,7 +32,7 @@ public partial class CFishPool : CBaseEntity
// m_waterLevel
[SchemaMember("CFishPool", "m_waterLevel")]
public ref float WaterLevel => ref Schema.GetRef<float>(this.Handle, "CFishPool", "m_waterLevel");
public new ref float WaterLevel => ref Schema.GetRef<float>(this.Handle, "CFishPool", "m_waterLevel");
// m_isDormant
[SchemaMember("CFishPool", "m_isDormant")]

View File

@@ -44,7 +44,7 @@ public partial class CFuncMover : CBaseModelEntity
// m_eMoveType
[SchemaMember("CFuncMover", "m_eMoveType")]
public ref CFuncMoverMove_t MoveType => ref Schema.GetRef<CFuncMoverMove_t>(this.Handle, "CFuncMover", "m_eMoveType");
public new ref CFuncMoverMove_t MoveType => ref Schema.GetRef<CFuncMoverMove_t>(this.Handle, "CFuncMover", "m_eMoveType");
// m_bIsReversing
[SchemaMember("CFuncMover", "m_bIsReversing")]
@@ -52,7 +52,7 @@ public partial class CFuncMover : CBaseModelEntity
// m_vTarget
[SchemaMember("CFuncMover", "m_vTarget")]
public Vector Target => Schema.GetDeclaredClass<Vector>(this.Handle, "CFuncMover", "m_vTarget");
public new Vector Target => Schema.GetDeclaredClass<Vector>(this.Handle, "CFuncMover", "m_vTarget");
// m_flStartSpeed
[SchemaMember("CFuncMover", "m_flStartSpeed")]

View File

@@ -44,6 +44,6 @@ public partial class CInstancedSceneEntity : CSceneEntity
// m_hTarget
[SchemaMember("CInstancedSceneEntity", "m_hTarget")]
public CHandle<CBaseEntity> Target => Schema.GetDeclaredClass<CHandle<CBaseEntity>>(this.Handle, "CInstancedSceneEntity", "m_hTarget");
public new CHandle<CBaseEntity> Target => Schema.GetDeclaredClass<CHandle<CBaseEntity>>(this.Handle, "CInstancedSceneEntity", "m_hTarget");
}

View File

@@ -52,7 +52,7 @@ public partial class CLogicMeasureMovement : CLogicalEntity
// m_hTarget
[SchemaMember("CLogicMeasureMovement", "m_hTarget")]
public CHandle<CBaseEntity> Target => Schema.GetDeclaredClass<CHandle<CBaseEntity>>(this.Handle, "CLogicMeasureMovement", "m_hTarget");
public new CHandle<CBaseEntity> Target => Schema.GetDeclaredClass<CHandle<CBaseEntity>>(this.Handle, "CLogicMeasureMovement", "m_hTarget");
// m_hTargetReference
[SchemaMember("CLogicMeasureMovement", "m_hTargetReference")]

View File

@@ -50,4 +50,8 @@ public partial class CMapInfo : CPointEntity
[SchemaMember("CMapInfo", "m_bFadePlayerVisibilityFarZ")]
public ref bool FadePlayerVisibilityFarZ => ref Schema.GetRef<bool>(this.Handle, "CMapInfo", "m_bFadePlayerVisibilityFarZ");
// m_bRainTraceToSkyEnabled
[SchemaMember("CMapInfo", "m_bRainTraceToSkyEnabled")]
public ref bool RainTraceToSkyEnabled => ref Schema.GetRef<bool>(this.Handle, "CMapInfo", "m_bRainTraceToSkyEnabled");
}

View File

@@ -20,7 +20,7 @@ public partial class CPointEntityFinder : CBaseEntity
// m_hEntity
[SchemaMember("CPointEntityFinder", "m_hEntity")]
public CHandle<CBaseEntity> Entity => Schema.GetDeclaredClass<CHandle<CBaseEntity>>(this.Handle, "CPointEntityFinder", "m_hEntity");
public new CHandle<CBaseEntity> Entity => Schema.GetDeclaredClass<CHandle<CBaseEntity>>(this.Handle, "CPointEntityFinder", "m_hEntity");
// m_iFilterName
[SchemaMember("CPointEntityFinder", "m_iFilterName")]

View File

@@ -34,6 +34,14 @@ public partial class CPointWorldText : CModelPointEntity
set { Schema.SetStringBytes(this.Handle, "CPointWorldText", "m_FontName", value, 64); }
}
// m_BackgroundMaterialName
[SchemaMember("CPointWorldText", "m_BackgroundMaterialName")]
public string BackgroundMaterialName
{
get { return Schema.GetString(this.Handle, "CPointWorldText", "m_BackgroundMaterialName"); }
set { Schema.SetStringBytes(this.Handle, "CPointWorldText", "m_BackgroundMaterialName", value, 64); }
}
// m_bEnabled
[SchemaMember("CPointWorldText", "m_bEnabled")]
public ref bool Enabled => ref Schema.GetRef<bool>(this.Handle, "CPointWorldText", "m_bEnabled");
@@ -54,6 +62,22 @@ public partial class CPointWorldText : CModelPointEntity
[SchemaMember("CPointWorldText", "m_flDepthOffset")]
public ref float DepthOffset => ref Schema.GetRef<float>(this.Handle, "CPointWorldText", "m_flDepthOffset");
// m_bDrawBackground
[SchemaMember("CPointWorldText", "m_bDrawBackground")]
public ref bool DrawBackground => ref Schema.GetRef<bool>(this.Handle, "CPointWorldText", "m_bDrawBackground");
// m_flBackgroundBorderWidth
[SchemaMember("CPointWorldText", "m_flBackgroundBorderWidth")]
public ref float BackgroundBorderWidth => ref Schema.GetRef<float>(this.Handle, "CPointWorldText", "m_flBackgroundBorderWidth");
// m_flBackgroundBorderHeight
[SchemaMember("CPointWorldText", "m_flBackgroundBorderHeight")]
public ref float BackgroundBorderHeight => ref Schema.GetRef<float>(this.Handle, "CPointWorldText", "m_flBackgroundBorderHeight");
// m_flBackgroundWorldToUV
[SchemaMember("CPointWorldText", "m_flBackgroundWorldToUV")]
public ref float BackgroundWorldToUV => ref Schema.GetRef<float>(this.Handle, "CPointWorldText", "m_flBackgroundWorldToUV");
// m_Color
[SchemaMember("CPointWorldText", "m_Color")]
public Color Color

View File

@@ -60,7 +60,7 @@ public partial class CPostProcessingVolume : CBaseTrigger
// m_bMaster
[SchemaMember("CPostProcessingVolume", "m_bMaster")]
public ref bool Master => ref Schema.GetRef<bool>(this.Handle, "CPostProcessingVolume", "m_bMaster");
public new ref bool Master => ref Schema.GetRef<bool>(this.Handle, "CPostProcessingVolume", "m_bMaster");
// m_bExposureControl
[SchemaMember("CPostProcessingVolume", "m_bExposureControl")]

View File

@@ -30,4 +30,8 @@ public partial class CRagdollManager : CBaseEntity
[SchemaMember("CRagdollManager", "m_bSaveImportant")]
public ref bool SaveImportant => ref Schema.GetRef<bool>(this.Handle, "CRagdollManager", "m_bSaveImportant");
// m_bCanTakeDamage
[SchemaMember("CRagdollManager", "m_bCanTakeDamage")]
public ref bool CanTakeDamage => ref Schema.GetRef<bool>(this.Handle, "CRagdollManager", "m_bCanTakeDamage");
}

View File

@@ -68,7 +68,7 @@ public partial class CScriptedSequence : CBaseEntity
// m_iszEntity
[SchemaMember("CScriptedSequence", "m_iszEntity")]
public string Entity
public new string Entity
{
get { return Schema.GetUtf8String(this.Handle, "CScriptedSequence", "m_iszEntity"); }
set { Schema.SetString(this.Handle, "CScriptedSequence", "m_iszEntity", value); }

View File

@@ -42,6 +42,14 @@ public partial class CSmokeGrenadeProjectile : CBaseCSGrenadeProjectile
[SchemaMember("CSmokeGrenadeProjectile", "m_VoxelFrameData")]
public NetworkedVector<byte> VoxelFrameData => Schema.GetDeclaredClass<NetworkedVector<byte>>(this.Handle, "CSmokeGrenadeProjectile", "m_VoxelFrameData");
// m_nVoxelFrameDataSize
[SchemaMember("CSmokeGrenadeProjectile", "m_nVoxelFrameDataSize")]
public ref Int32 VoxelFrameDataSize => ref Schema.GetRef<Int32>(this.Handle, "CSmokeGrenadeProjectile", "m_nVoxelFrameDataSize");
// m_nVoxelUpdate
[SchemaMember("CSmokeGrenadeProjectile", "m_nVoxelUpdate")]
public ref Int32 VoxelUpdate => ref Schema.GetRef<Int32>(this.Handle, "CSmokeGrenadeProjectile", "m_nVoxelUpdate");
// m_flLastBounce
[SchemaMember("CSmokeGrenadeProjectile", "m_flLastBounce")]
public ref float LastBounce => ref Schema.GetRef<float>(this.Handle, "CSmokeGrenadeProjectile", "m_flLastBounce");

View File

@@ -20,7 +20,7 @@ public partial class CTriggerPhysics : CBaseTrigger
// m_gravityScale
[SchemaMember("CTriggerPhysics", "m_gravityScale")]
public ref float GravityScale => ref Schema.GetRef<float>(this.Handle, "CTriggerPhysics", "m_gravityScale");
public new ref float GravityScale => ref Schema.GetRef<float>(this.Handle, "CTriggerPhysics", "m_gravityScale");
// m_linearLimit
[SchemaMember("CTriggerPhysics", "m_linearLimit")]

View File

@@ -0,0 +1,14 @@
// <auto-generated />
#nullable enable
#pragma warning disable CS1591
using System;
namespace CounterStrikeSharp.API.Core;
public enum EContributionScoreFlag_t : byte
{
k_EContributionScoreFlag_Default = 0x0,
k_EContributionScoreFlag_Objective = 0x1,
k_EContributionScoreFlag_Bullets = 0x2,
}

View File

@@ -0,0 +1,13 @@
// <auto-generated />
#nullable enable
#pragma warning disable CS1591
using System;
namespace CounterStrikeSharp.API.Core;
public enum EDestructiblePartDamagePassThroughType : uint
{
Normal = 0x0,
Absorb = 0x1,
}

View File

@@ -0,0 +1,16 @@
// <auto-generated />
#nullable enable
#pragma warning disable CS1591
using System;
namespace CounterStrikeSharp.API.Core;
public enum EIKEndEffectorRotationFixUpMode : uint
{
None = 0x0,
MatchTargetOrientation = 0x1,
LookAtTargetForward = 0x2,
MaintainParentOrientation = 0x3,
Count = 0x4,
}

View File

@@ -39,6 +39,7 @@
<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"/>
<PackageReference Include="Tomlyn" Version="0.19.0"/>
</ItemGroup>
<ItemGroup>
<Folder Include="Core\Schema\"/>
@@ -59,9 +60,9 @@
</PropertyGroup>
<Target Name="SetSourceRevisionId" BeforeTargets="InitializeSourceControlInformation">
<Exec
Command="git describe --long --always --exclude=* --abbrev=7"
ConsoleToMSBuild="True"
IgnoreExitCode="False"
Command="git describe --long --always --exclude=* --abbrev=7"
ConsoleToMSBuild="True"
IgnoreExitCode="False"
>
<Output PropertyName="SourceRevisionId" TaskParameter="ConsoleOutput"/>
</Exec>

View File

@@ -2,7 +2,9 @@
using System.Collections.Generic;
using System.Diagnostics.CodeAnalysis;
using System.Linq;
using CounterStrikeSharp.API.Core;
using CounterStrikeSharp.API.Modules.Entities;
using CounterStrikeSharp.API.Modules.Memory;
using CounterStrikeSharp.API.Modules.Utils;
namespace CounterStrikeSharp.API.Modules.Commands.Targeting;
@@ -12,7 +14,9 @@ public class Target
private TargetType Type { get; }
private string Raw { get; }
private string Slug { get; }
internal CCSGameRulesProxy? _gameRulesEntity = null;
public static readonly IReadOnlyDictionary<string, TargetType> TargetTypeMap = new Dictionary<string, TargetType>(StringComparer.OrdinalIgnoreCase)
{
{ "@all", TargetType.GroupAll },
@@ -22,6 +26,7 @@ public class Target
{ "@dead", TargetType.GroupDead },
{ "@!me", TargetType.GroupNotMe },
{ "@me", TargetType.PlayerMe },
{ "@aim", TargetType.PlayerAim },
{ "@ct", TargetType.TeamCt },
{ "@t", TargetType.TeamT },
{ "@spec", TargetType.TeamSpec }
@@ -31,7 +36,7 @@ public class Target
private static bool ConstTargetType(string target, out TargetType targetType)
{
targetType = TargetType.Invalid;
if (!target.StartsWith("@"))
if (!target.StartsWith('@'))
{
return false;
}
@@ -45,13 +50,13 @@ public class Target
{
targetType = TargetType.Invalid;
slug = null!;
if (!target.StartsWith("#"))
if (!target.StartsWith('#'))
{
return false;
}
slug = target.TrimStart('#');
if (slug.StartsWith("STEAM")) targetType = TargetType.IdSteamEscaped;
if (slug.StartsWith("STEAM") && slug.Contains(':')) targetType = TargetType.IdSteamEscaped;
else if (!ulong.TryParse(slug, out _)) targetType = TargetType.ExplicitName;
else if (slug.Length == 17) targetType = TargetType.IdSteam64;
else targetType = TargetType.IdUserid;
@@ -80,48 +85,39 @@ public class Target
}
}
private bool TargetPredicate(CCSPlayerController player, CCSPlayerController? caller)
private bool TargetPredicate(CCSPlayerController player, CCSPlayerController? caller, CCSGameRules? gameRules = null)
{
switch (Type)
return Type switch
{
case TargetType.TeamCt:
return player.TeamNum == (byte)CsTeam.CounterTerrorist;
case TargetType.TeamT:
return player.TeamNum == (byte)CsTeam.Terrorist;
case TargetType.TeamSpec:
return player.TeamNum == (byte)CsTeam.Spectator;
case TargetType.GroupAll:
return !player.IsHLTV;
case TargetType.GroupBots:
return player.IsBot;
case TargetType.GroupHumans:
return !player.IsBot && !player.IsHLTV;
case TargetType.GroupAlive:
return player.PlayerPawn is { IsValid: true, Value.LifeState: (byte)LifeState_t.LIFE_ALIVE };
case TargetType.GroupDead:
return player.PlayerPawn is { IsValid: true, Value.LifeState: (byte)LifeState_t.LIFE_DEAD or (byte)LifeState_t.LIFE_DYING };
case TargetType.GroupNotMe:
return player.SteamID != caller?.SteamID;
case TargetType.PlayerMe:
return player.SteamID == caller?.SteamID;
case TargetType.IdUserid:
return player.UserId.ToString() == Slug;
case TargetType.IdSteamEscaped:
return ((SteamID)player.SteamID).SteamId2 == Slug;
case TargetType.IdSteam64:
return ((SteamID)player.SteamID).SteamId64.ToString() == Slug;
case TargetType.ExplicitName:
case TargetType.ImplicitName:
return player.PlayerName.Contains(Slug, StringComparison.OrdinalIgnoreCase);
default:
return false;
}
TargetType.PlayerAim => caller != null && player == gameRules!.GetClientAimTarget(caller),
TargetType.TeamCt => player.Team == CsTeam.CounterTerrorist,
TargetType.TeamT => player.Team == CsTeam.Terrorist,
TargetType.TeamSpec => player.Team == CsTeam.Spectator,
TargetType.GroupAll => !player.IsHLTV,
TargetType.GroupBots => player.IsBot,
TargetType.GroupHumans => !player.IsBot && !player.IsHLTV,
TargetType.GroupAlive => player.PlayerPawn is { IsValid: true, Value.LifeState: (byte)LifeState_t.LIFE_ALIVE },
TargetType.GroupDead => player.PlayerPawn is { IsValid: true, Value.LifeState: (byte)LifeState_t.LIFE_DEAD or (byte)LifeState_t.LIFE_DYING },
TargetType.GroupNotMe => player.SteamID != caller?.SteamID,
TargetType.PlayerMe => player.SteamID == caller?.SteamID,
TargetType.IdUserid => player.UserId.ToString() == Slug,
TargetType.IdSteamEscaped when player.SteamID != 0 => (SteamID)player.SteamID == (SteamID)Slug,
TargetType.IdSteam64 => player.SteamID.ToString() == Slug,
TargetType.ExplicitName or TargetType.ImplicitName => player.PlayerName.Contains(Slug, StringComparison.OrdinalIgnoreCase),
_ => false
};
}
public TargetResult GetTarget(CCSPlayerController? caller)
{
var players = Utilities.GetPlayers().Where(player => TargetPredicate(player, caller)).ToList();
return new TargetResult() { Players = players };
if (Type == TargetType.PlayerAim)
{
if (_gameRulesEntity == null || !_gameRulesEntity.IsValid)
{
_gameRulesEntity = Utilities.FindAllEntitiesByDesignerName<CCSGameRulesProxy>("cs_gamerules").FirstOrDefault();
}
}
return new TargetResult() { Players = Utilities.GetPlayers().Where(player => TargetPredicate(player, caller, _gameRulesEntity?.GameRules)).ToList() };
}
}

View File

@@ -14,6 +14,7 @@ public enum TargetType
GroupNotMe, // @!me
PlayerMe, // @me
PlayerAim, // @aim
IdUserid, // #4
IdSteamEscaped, // "#STEAM_0:1:8614"
@@ -22,4 +23,4 @@ public enum TargetType
ExplicitName, // #name
ImplicitName, // name
Invalid
}
}

View File

@@ -14,18 +14,21 @@
* along with CounterStrikeSharp. If not, see <https://www.gnu.org/licenses/>. *
*/
using System;
using System.IO;
using System.Reflection;
using System.Text;
using System.Text.Json;
using CounterStrikeSharp.API.Core;
using CounterStrikeSharp.API.Core.Logging;
using Microsoft.Extensions.Logging;
using Tomlyn;
namespace CounterStrikeSharp.API.Modules.Config
{
enum ConfigType
{
Json,
Toml
}
public static class ConfigManager
{
private static readonly DirectoryInfo? _rootDir;
@@ -33,47 +36,59 @@ namespace CounterStrikeSharp.API.Modules.Config
private static readonly string _pluginConfigsFolderPath;
private static ILogger _logger = CoreLogging.Factory.CreateLogger("ConfigManager");
internal static JsonSerializerOptions JsonSerializerOptions { get; } = new()
{
WriteIndented = true,
ReadCommentHandling = JsonCommentHandling.Skip
};
internal static TomlModelOptions TomlModelOptions { get; } = new()
{
ConvertPropertyName = name => name
};
static ConfigManager()
{
_rootDir = new FileInfo(Assembly.GetExecutingAssembly().Location).Directory.Parent;
_pluginConfigsFolderPath = Path.Combine(_rootDir.FullName, "configs", "plugins");
}
public static T Load<T>(string pluginName) where T : IBasePluginConfig, new()
public static T Load<T>(string pluginName) where T : class, IBasePluginConfig, new()
{
string directoryPath = Path.Combine(_pluginConfigsFolderPath, pluginName);
string configPath = Path.Combine(directoryPath, $"{pluginName}.json");
string exampleConfigPath = Path.Combine(directoryPath, $"{pluginName}.example.json");
string configPath = Path.Combine(directoryPath, $"{pluginName}");
string exampleConfigPath = Path.Combine(directoryPath, $"{pluginName}.example");
T config = (T)Activator.CreateInstance(typeof(T))!;
string[] configFilePaths =
[
$"{configPath}.toml",
$"{configPath}.json",
];
if (!File.Exists(configPath) && !File.Exists(exampleConfigPath))
foreach (var path in configFilePaths)
{
try
if (File.Exists(path))
{
if (!Directory.Exists(directoryPath))
{
Directory.CreateDirectory(directoryPath);
}
return Deserialize<T>(path);
}
}
StringBuilder builder = new StringBuilder();
builder.Append(
$"// This configuration was automatically generated by CounterStrikeSharp for plugin '{pluginName}', at {DateTimeOffset.Now:yyyy/MM/dd hh:mm:ss}\n");
builder.Append(JsonSerializer.Serialize<T>(config,
new JsonSerializerOptions { WriteIndented = true }));
File.WriteAllText(configPath, builder.ToString());
return config;
}
catch (Exception ex)
{
_logger.LogError(ex, "Failed to generate configuration file for {PluginName}", pluginName);
}
} else if (File.Exists(exampleConfigPath) && !File.Exists(configPath))
string[] exampleFilePaths =
[
$"{exampleConfigPath}.toml",
$"{exampleConfigPath}.json"
];
foreach (var path in exampleFilePaths)
{
if (!File.Exists(path)) continue;
try
{
_logger.LogInformation("Copying example configuration file for {PluginName}", pluginName);
File.Copy(exampleConfigPath, configPath);
var destPath = Path.Combine(directoryPath, Path.GetFileName(path).Replace(".example", ""));
File.Copy(path, destPath);
return Deserialize<T>(destPath);
}
catch (Exception ex)
{
@@ -83,14 +98,58 @@ namespace CounterStrikeSharp.API.Modules.Config
try
{
config = JsonSerializer.Deserialize<T>(File.ReadAllText(configPath), new JsonSerializerOptions() { ReadCommentHandling = JsonCommentHandling.Skip })!;
if (!Directory.Exists(directoryPath))
{
Directory.CreateDirectory(directoryPath);
}
var config = new T();
var output = Serialize(config, ConfigType.Json, pluginName);
File.WriteAllText(Path.Combine(directoryPath, $"{pluginName}.json"), output);
return config;
}
catch (Exception ex)
{
_logger.LogError(ex, "Failed to parse configuration file for {PluginName}", pluginName);
_logger.LogError(ex, "Failed to generate configuration file for {PluginName}", pluginName);
return new T();
}
}
private static T Deserialize<T>(string path) where T : class, IBasePluginConfig, new()
{
switch (Path.GetExtension(path))
{
case ".toml":
return Toml.ToModel<T>(File.ReadAllText(path), options: TomlModelOptions);
case ".json":
return JsonSerializer.Deserialize<T>(File.ReadAllText(path), JsonSerializerOptions)!;
}
return config;
throw new NotSupportedException("Unsupported configuration file format");
}
private static string Serialize<T>(T config, ConfigType configType, string pluginName) where T : class, IBasePluginConfig, new()
{
StringBuilder builder = new StringBuilder();
string comment =
$"This configuration was automatically generated by CounterStrikeSharp for plugin '{pluginName}', at {DateTimeOffset.Now:yyyy/MM/dd hh:mm:ss}\n";
switch (configType)
{
case ConfigType.Json:
builder.Append($"// {comment}");
builder.Append(JsonSerializer.Serialize<T>(config, JsonSerializerOptions));
break;
case ConfigType.Toml:
builder.Append($"# {comment}");
builder.Append(Toml.FromModel(config, options: TomlModelOptions));
break;
default:
throw new NotSupportedException("Unsupported configuration file format");
}
return builder.ToString();
}
}
}
}

View File

@@ -72,6 +72,16 @@ public class FakeConVar<T> where T : IComparable<T>
try
{
var argString = args.ArgString;
if (typeof(T) == typeof(string))
{
if (argString.Length >= 2 && argString.StartsWith('"') && argString.EndsWith('"'))
{
argString = argString.Substring(1, argString.Length - 2);
}
}
// TODO(dotnet8): Replace with IParsable<T>
bool success = true;
T parsedValue = default(T);
@@ -80,11 +90,11 @@ public class FakeConVar<T> where T : IComparable<T>
{
try
{
parsedValue = (T)converter.ConvertFromString(args.ArgString);
parsedValue = (T)converter.ConvertFromString(argString);
}
catch
{
success = typeof(T) == typeof(bool) && TryConvertCustomBoolean(args.ArgString, out parsedValue);
success = typeof(T) == typeof(bool) && TryConvertCustomBoolean(argString, out parsedValue);
}
}
@@ -137,4 +147,4 @@ public class FakeConVar<T> where T : IComparable<T>
_value = value;
ValueChanged?.Invoke(this, _value);
}
}
}

View File

@@ -0,0 +1,125 @@
using System.Text.Json;
using System.Reflection;
using System.Runtime.Serialization;
using CounterStrikeSharp.API.Modules.Config;
using Tomlyn;
namespace CounterStrikeSharp.API.Modules.Extensions;
public static class PluginConfigExtensions
{
public static JsonSerializerOptions JsonSerializerOptions => ConfigManager.JsonSerializerOptions;
/// <summary>
/// Gets the configuration file path
/// </summary>
/// <typeparam name="T">Type of the plugin configuration.</typeparam>
/// <param name="_">Current configuration instance</param>
public static string GetConfigPath<T>(this T _) where T : BasePluginConfig, new()
{
string assemblyName = typeof(T).Assembly.GetName().Name ?? string.Empty;
string[] configFilePaths =
[
Path.Combine(Server.GameDirectory, "csgo", "addons", "counterstrikesharp", "configs", "plugins", assemblyName,
$"{assemblyName}.json"),
Path.Combine(Server.GameDirectory, "csgo", "addons", "counterstrikesharp", "configs", "plugins", assemblyName,
$"{assemblyName}.toml"),
];
foreach (var path in configFilePaths)
{
if (File.Exists(path))
{
return path;
}
}
return configFilePaths[0];
}
/// <summary>
/// Updates the configuration file
/// </summary>
/// <typeparam name="T">Type of the plugin configuration.</typeparam>
/// <param name="config">Current configuration instance</param>
public static void Update<T>(this T config) where T : BasePluginConfig, new()
{
var configPath = config.GetConfigPath();
try
{
using var stream = new FileStream(configPath, FileMode.Create, FileAccess.Write, FileShare.None);
using var writer = new StreamWriter(stream);
switch (Path.GetExtension(configPath))
{
case ".json":
{
writer.Write(JsonSerializer.Serialize(config, ConfigManager.JsonSerializerOptions));
break;
}
case ".toml":
writer.Write(Toml.FromModel(config, ConfigManager.TomlModelOptions));
break;
default:
throw new NotSupportedException($"Configuration file type '{Path.GetExtension(configPath)}' is not supported.");
}
}
catch (Exception ex)
{
throw new Exception($"Failed to update configuration file at '{configPath}'.", ex);
}
}
/// <summary>
/// Reloads the configuration file and updates current configuration instance.
/// </summary>
/// <typeparam name="T">Type of the plugin configuration.</typeparam>
/// <param name="config">Current configuration instance</param>
public static void Reload<T>(this T config) where T : BasePluginConfig, new()
{
var configPath = config.GetConfigPath();
try
{
if (!File.Exists(configPath))
{
throw new FileNotFoundException($"Configuration file '{configPath} not found.");
}
var configContent = File.ReadAllText(configPath);
T? newConfig = null;
switch (Path.GetExtension(configPath))
{
case ".json":
newConfig = JsonSerializer.Deserialize<T>(configContent, ConfigManager.JsonSerializerOptions)
?? throw new JsonException($"Deserialization failed for configuration file '{configPath}'.");
break;
case ".toml":
newConfig = Toml.ToModel<T>(configContent, options: ConfigManager.TomlModelOptions);
break;
}
if (newConfig is null)
{
throw new SerializationException($"Deserialization failed for configuration file '{configPath}'.");
}
foreach (var property in typeof(T).GetProperties(BindingFlags.Instance | BindingFlags.Public))
{
if (property.CanWrite)
{
property.SetValue(config, property.GetValue(newConfig));
}
}
}
catch (Exception ex)
{
throw new Exception($"Failed to reload configuration file at '{configPath}'.", ex);
}
}
}

View File

@@ -11,8 +11,7 @@ namespace CounterStrikeSharp.API.Modules.Memory;
public static class VirtualFunctions
{
public static MemoryFunctionVoid<IntPtr, HudDestination, string, IntPtr, IntPtr, IntPtr, IntPtr> ClientPrintFunc =
new(
GameData.GetSignature("ClientPrint"));
new(GameData.GetSignature("ClientPrint"));
public static Action<IntPtr, HudDestination, string, IntPtr, IntPtr, IntPtr, IntPtr> ClientPrint =
ClientPrintFunc.Invoke;
@@ -68,7 +67,13 @@ public static class VirtualFunctions
public static MemoryFunctionWithReturn<CCSPlayer_WeaponServices, CBasePlayerWeapon, bool> CCSPlayer_WeaponServices_CanUseFunc = new(GameData.GetSignature("CCSPlayer_WeaponServices_CanUse"));
public static Func<CCSPlayer_WeaponServices, CBasePlayerWeapon, bool> CCSPlayer_WeaponServices_CanUse = CCSPlayer_WeaponServices_CanUseFunc.Invoke;
public static MemoryFunctionWithReturn<int, string, CCSWeaponBaseVData> GetCSWeaponDataFromKeyFunc = new(GameData.GetSignature("GetCSWeaponDataFromKey"));
public static Func<int, string, CCSWeaponBaseVData> GetCSWeaponDataFromKey = GetCSWeaponDataFromKeyFunc.Invoke;
public static MemoryFunctionWithReturn<CCSPlayer_ItemServices, CEconItemView, AcquireMethod, IntPtr, AcquireResult> CCSPlayer_ItemServices_CanAcquireFunc = new(GameData.GetSignature("CCSPlayer_ItemServices_CanAcquire"));
public static Func<CCSPlayer_ItemServices, CEconItemView, AcquireMethod, IntPtr, AcquireResult> CCSPlayer_ItemServices_CanAcquire = CCSPlayer_ItemServices_CanAcquireFunc.Invoke;
public static MemoryFunctionVoid<CCSPlayerPawnBase> CCSPlayerPawnBase_PostThinkFunc = new (GameData.GetSignature("CCSPlayerPawnBase_PostThink"));
public static Action<CCSPlayerPawnBase> CCSPlayerPawnBase_PostThink = CCSPlayerPawnBase_PostThinkFunc.Invoke;

View File

@@ -90,6 +90,7 @@ public abstract class BaseMenuInstance : IMenuInstance
protected bool HasPrevButton => Page > 0;
protected bool HasNextButton => Menu.MenuOptions.Count > NumPerPage && CurrentOffset + NumPerPage < Menu.MenuOptions.Count;
protected bool HasExitButton => Menu.ExitButton;
protected virtual int MenuItemsPerPage => NumPerPage;
public virtual void Display()
@@ -113,7 +114,7 @@ public abstract class BaseMenuInstance : IMenuInstance
return;
}
if (key == 9)
if (key == 9 && HasExitButton)
{
Close();
return;
@@ -174,4 +175,4 @@ public abstract class BaseMenuInstance : IMenuInstance
CurrentOffset = PrevPageOffsets.Pop();
Display();
}
}
}

View File

@@ -29,13 +29,13 @@ public class CenterHtmlMenu : BaseMenu
public string NextPageColor { get; set; } = "yellow";
public string CloseColor { get; set; } = "red";
public CenterHtmlMenu(string title, BasePlugin plugin) : base(ModifyTitle(title))
public CenterHtmlMenu(string title, BasePlugin plugin) : base(title)
{
_plugin = plugin;
}
[Obsolete("Use the constructor that takes a BasePlugin")]
public CenterHtmlMenu(string title) : base(ModifyTitle(title))
public CenterHtmlMenu(string title) : base(title)
{
}
@@ -45,40 +45,18 @@ public class CenterHtmlMenu : BaseMenu
{
throw new InvalidOperationException("This method is unsupported with the CenterHtmlMenu constructor used." +
"Please provide a BasePlugin in the constructor.");
};
};
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);
var option = new ChatMenuOption(display, disabled, onSelect);
MenuOptions.Add(option);
return option;
}
private static string ModifyTitle(string title)
{
if (title.Length > 32)
{
Application.Instance.Logger.LogWarning("Title should not be longer than 32 characters for a CenterHtmlMenu");
return title[..32];
}
return title;
}
private static string ModifyOptionDisplay(string display)
{
if (display.Length > 26)
{
Application.Instance.Logger.LogWarning("Display should not be longer than 26 characters for a CenterHtmlMenu item");
return display[..26];
}
return display;
}
}
public class CenterHtmlMenuInstance : BaseMenuInstance

View File

@@ -0,0 +1,23 @@
/*
* This file is part of CounterStrikeSharp.
* CounterStrikeSharp is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* CounterStrikeSharp is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with CounterStrikeSharp. If not, see <https://www.gnu.org/licenses/>. *
*/
namespace CounterStrikeSharp.API.Modules.Utils;
public enum AcquireMethod : int
{
PickUp = 0,
Buy,
};

View File

@@ -0,0 +1,32 @@
/*
* This file is part of CounterStrikeSharp.
* CounterStrikeSharp is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* CounterStrikeSharp is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with CounterStrikeSharp. If not, see <https://www.gnu.org/licenses/>. *
*/
namespace CounterStrikeSharp.API.Modules.Utils;
public enum AcquireResult : int
{
Allowed = 0,
InvalidItem,
AlreadyOwned,
AlreadyPurchased,
ReachedGrenadeTypeLimit,
ReachedGrenadeTotalLimit,
NotAllowedByTeam,
NotAllowedByMap,
NotAllowedByMode,
NotAllowedForPurchase,
NotAllowedByProhibition,
};

View File

@@ -60,7 +60,7 @@ public class ChatColors
case CsTeam.CounterTerrorist:
return LightBlue;
case CsTeam.Terrorist:
return Yellow;
return Orange;
default:
throw new ArgumentException($"Invalid team: ${team}");
}

View File

@@ -101,13 +101,11 @@ public class RecipientFilter : IList<CCSPlayerController>, IMarshalToNative
public void Add(int slot)
{
var player = Utilities.GetPlayerFromSlot(slot);
if (player == null)
if (player != null)
{
throw new ArgumentException($"Player with slot {slot} not found");
_recipients.Add(player);
CollectionChanged?.Invoke();
}
_recipients.Add(player);
CollectionChanged?.Invoke();
}
public void AddAllPlayers()

View File

@@ -46,28 +46,33 @@ namespace CounterStrikeSharp.API
/// </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();
/// <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();
/// <summary>
/// Returns the time spent on last server or client frame
/// </summary>
public static float FrameTime => NativeAPI.GetGameFrameTime();
public static void PrecacheModel(string name) => NativeAPI.PrecacheModel(name);
/// <summary>
/// <inheritdoc cref="RunOnTick"/>
/// Returns Task that completes once the synchronous task has been completed.
@@ -78,7 +83,7 @@ namespace CounterStrikeSharp.API
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.
@@ -108,7 +113,7 @@ namespace CounterStrikeSharp.API
{
NextFrameAsync(task);
}
/// <summary>
/// <inheritdoc cref="NextWorldUpdate"/>
/// Returns Task that completes once the synchronous task has been completed.
@@ -119,7 +124,7 @@ namespace CounterStrikeSharp.API
NativeAPI.QueueTaskForNextWorldUpdate(functionReference);
return functionReference.CompletionTask;
}
/// <summary>
/// Queue a task to be executed on the next pre world update.
/// <remarks>Executes if the server is hibernating.</remarks>
@@ -157,4 +162,4 @@ namespace CounterStrikeSharp.API
public static void PrintToConsole(string s) => NativeAPI.PrintToServerConsole($"{s}\n\0");
}
}
}

View File

@@ -247,5 +247,20 @@ namespace CounterStrikeSharp.API
entity.LastNetworkChange = Server.CurrentTime;
entity.IsSteadyState.Clear();
}
/// <summary>
/// metamod method 'MetaFactory' to get the pointer of api interface exposed by metamod plugins.
/// Returns null when the interface cannot be found.
/// </summary>
/// <param name="interfaceName">The interface name of metamod api, can be found in their api header file</param>
public static IntPtr? MetaFactory(string interfaceName)
{
IntPtr ptr = NativeAPI.MetaFactory(interfaceName);
if (ptr == 0)
{
return null;
}
return ptr;
}
}
}

View File

@@ -122,5 +122,7 @@ public enum NetworkDisconnectionReason
NETWORK_DISCONNECT_KICKED_IDLE = 158,
NETWORK_DISCONNECT_KICKED_SUICIDE = 159,
NETWORK_DISCONNECT_KICKED_NOSTEAMLOGIN = 160,
NETWORK_DISCONNECT_KICKED_NOSTEAMTICKET = 161
NETWORK_DISCONNECT_KICKED_NOSTEAMTICKET = 161,
NETWORK_DISCONNECT_KICKED_INPUTAUTOMATION = 162,
NETWORK_DISCONNECT_KICKED_VACNETABNORMALBEHAVIOR = 163
}

View File

@@ -104,7 +104,7 @@ internal static partial class Program
if (IgnoreClasses.Contains(className))
continue;
allClasses[className] = schemaClass;
allClasses[className] = schemaClass with { Name = className };
}
}
@@ -174,7 +174,7 @@ internal static partial class Program
{
search.Compute(networkClassName);
}
// Clear output directory
if (Directory.Exists(outputPath))
{
@@ -194,7 +194,7 @@ internal static partial class Program
var newBuilder = new StringBuilder(enumBuilder.ToString());
WriteEnum(newBuilder, enumName, schemaEnum);
File.WriteAllText(Path.Combine(outputPath, "Enums", $"{SanitiseTypeName(enumName)}.g.cs"),
newBuilder.ToString());
newBuilder.ToString().ReplaceLineEndings("\r\n"));
}
// Manually whitelist some classes
@@ -217,20 +217,39 @@ internal static partial class Program
var isPointeeType = pointeeTypes.Contains(className);
var newBuilder = new StringBuilder(classBuilder.ToString());
WriteClass(newBuilder, className, schemaClass, parentToChildMap, isPointeeType);
WriteClass(newBuilder, className, schemaClass, allClasses, isPointeeType);
visitedClassNames.Add(className);
File.WriteAllText(Path.Combine(outputPath, "Classes", $"{SanitiseTypeName(className)}.g.cs"),
newBuilder.ToString());
newBuilder.ToString().ReplaceLineEndings("\r\n"));
}
}
}
private static IEnumerable<(SchemaClass clazz, SchemaField field)> GetAllParentFields(
SchemaClass schemaClass,
SortedDictionary<string, SchemaClass> allClasses)
{
while (schemaClass.Parent != null)
{
allClasses.TryGetValue(schemaClass.Parent, out var parentClass);
if (parentClass == null)
break;
foreach (var field in parentClass.Fields)
{
yield return (parentClass, field);
}
schemaClass = parentClass;
}
}
private static void WriteClass(
StringBuilder builder,
string schemaClassName,
SchemaClass schemaClass,
IReadOnlyDictionary<string, ImmutableList<KeyValuePair<string, SchemaClass>>> parentToChildMap,
SortedDictionary<string, SchemaClass> allClasses,
bool isPointeeType)
{
var isEntityClass =
@@ -242,8 +261,12 @@ internal static partial class Program
builder.AppendLine();
builder.Append($"public partial class {classNameCs}");
(SchemaClass clazz, SchemaField field)[] parentFields = [];
if (schemaClass.Parent != null)
{
builder.Append($" : {schemaClass.Parent}");
parentFields = GetAllParentFields(schemaClass, allClasses).ToArray();
}
if (schemaClass.Parent == null)
{
@@ -276,6 +299,8 @@ internal static partial class Program
if (IgnoreClasses.Contains(field.Type.Inner!.Name)) continue;
}
var requiresNewKeyword = parentFields.Any(x => x.clazz.CsPropertyNameForField(x.clazz.Name, x.field) == schemaClass.CsPropertyNameForField(schemaClassName, field));
var handleParams = $"this.Handle, \"{schemaClassName}\", \"{field.Name}\"";
builder.AppendLine($"\t// {field.Name}");
@@ -286,7 +311,7 @@ internal static partial class Program
var getter = $"return Schema.GetString({handleParams});";
var setter = $"Schema.SetString({handleParams}, value{(field.Type.ArraySize != null ? ", " + field.Type.ArraySize : "")});";
builder.AppendLine(
$"\tpublic {SanitiseTypeName(field.Type.CsTypeName)} {schemaClass.CsPropertyNameForField(schemaClassName, field)}");
$"\tpublic {(requiresNewKeyword ? "new ": "")}{SanitiseTypeName(field.Type.CsTypeName)} {schemaClass.CsPropertyNameForField(schemaClassName, field)}");
builder.AppendLine($"\t{{");
builder.AppendLine(
$"\t\tget {{ {getter} }}");
@@ -301,7 +326,7 @@ internal static partial class Program
var getter = $"return Schema.GetString({handleParams});";
var setter = $"Schema.SetStringBytes({handleParams}, value, {field.Type.ArraySize});";
builder.AppendLine(
$"\tpublic {SanitiseTypeName(field.Type.CsTypeName)} {schemaClass.CsPropertyNameForField(schemaClassName, field)}");
$"\tpublic {(requiresNewKeyword ? "new ": "")}{SanitiseTypeName(field.Type.CsTypeName)} {schemaClass.CsPropertyNameForField(schemaClassName, field)}");
builder.AppendLine($"\t{{");
builder.AppendLine(
$"\t\tget {{ {getter} }}");
@@ -316,7 +341,7 @@ internal static partial class Program
var getter = $"return Schema.GetUtf8String({handleParams});";
var setter = $"Schema.SetString({handleParams}, value);";
builder.AppendLine(
$"\tpublic {SanitiseTypeName(field.Type.CsTypeName)} {schemaClass.CsPropertyNameForField(schemaClassName, field)}");
$"\tpublic {(requiresNewKeyword ? "new ": "")}{SanitiseTypeName(field.Type.CsTypeName)} {schemaClass.CsPropertyNameForField(schemaClassName, field)}");
builder.AppendLine($"\t{{");
builder.AppendLine(
$"\t\tget {{ {getter} }}");
@@ -330,7 +355,7 @@ internal static partial class Program
var getter =
$"Schema.GetFixedArray<{SanitiseTypeName(field.Type.Inner!.CsTypeName)}>({handleParams}, {field.Type.ArraySize});";
builder.AppendLine(
$"\tpublic Span<{SanitiseTypeName(field.Type.Inner!.CsTypeName)}> {schemaClass.CsPropertyNameForField(schemaClassName, field)} => {getter}");
$"\tpublic {(requiresNewKeyword ? "new ": "")}Span<{SanitiseTypeName(field.Type.Inner!.CsTypeName)}> {schemaClass.CsPropertyNameForField(schemaClassName, field)} => {getter}");
builder.AppendLine();
}
else if (field.Type.Category == SchemaTypeCategory.DeclaredClass &&
@@ -338,7 +363,7 @@ internal static partial class Program
{
var getter = $"Schema.GetDeclaredClass<{SanitiseTypeName(field.Type.CsTypeName)}>({handleParams});";
builder.AppendLine(
$"\tpublic {SanitiseTypeName(field.Type.CsTypeName)} {schemaClass.CsPropertyNameForField(schemaClassName, field)} => {getter}");
$"\tpublic {(requiresNewKeyword ? "new ": "")}{SanitiseTypeName(field.Type.CsTypeName)} {schemaClass.CsPropertyNameForField(schemaClassName, field)} => {getter}");
builder.AppendLine();
}
else if ((field.Type.Category == SchemaTypeCategory.Builtin ||
@@ -347,7 +372,7 @@ internal static partial class Program
{
var getter = $"ref Schema.GetRef<{SanitiseTypeName(field.Type.CsTypeName)}>({handleParams});";
builder.AppendLine(
$"\tpublic ref {SanitiseTypeName(field.Type.CsTypeName)} {schemaClass.CsPropertyNameForField(schemaClassName, field)} => {getter}");
$"\tpublic {(requiresNewKeyword ? "new ": "")}ref {SanitiseTypeName(field.Type.CsTypeName)} {schemaClass.CsPropertyNameForField(schemaClassName, field)} => {getter}");
builder.AppendLine();
}
else if (field.Type.Category == SchemaTypeCategory.Ptr)
@@ -356,7 +381,7 @@ internal static partial class Program
if (inner.Category != SchemaTypeCategory.DeclaredClass) continue;
builder.AppendLine(
$"\tpublic {SanitiseTypeName(field.Type.CsTypeName)} {schemaClass.CsPropertyNameForField(schemaClassName, field)} => Schema.GetPointer<{SanitiseTypeName(inner.CsTypeName)}>({handleParams});");
$"\tpublic {(requiresNewKeyword ? "new ": "")}{SanitiseTypeName(field.Type.CsTypeName)} {schemaClass.CsPropertyNameForField(schemaClassName, field)} => Schema.GetPointer<{SanitiseTypeName(inner.CsTypeName)}>({handleParams});");
builder.AppendLine();
}
else if (field.Type is { Category: SchemaTypeCategory.Atomic, Name: "Color" })
@@ -364,7 +389,7 @@ internal static partial class Program
var getter = $"return Schema.GetCustomMarshalledType<{field.Type.CsTypeName}>({handleParams});";
var setter = $"Schema.SetCustomMarshalledType<{field.Type.CsTypeName}>({handleParams}, value);";
builder.AppendLine(
$"\tpublic {SanitiseTypeName(field.Type.CsTypeName)} {schemaClass.CsPropertyNameForField(schemaClassName, field)}");
$"\tpublic {(requiresNewKeyword ? "new ": "")}{SanitiseTypeName(field.Type.CsTypeName)} {schemaClass.CsPropertyNameForField(schemaClassName, field)}");
builder.AppendLine($"\t{{");
builder.AppendLine(
$"\t\tget {{ {getter} }}");
@@ -377,7 +402,7 @@ internal static partial class Program
{
var getter = $"Schema.GetDeclaredClass<{SanitiseTypeName(field.Type.CsTypeName)}>({handleParams});";
builder.AppendLine(
$"\tpublic {SanitiseTypeName(field.Type.CsTypeName)} {schemaClass.CsPropertyNameForField(schemaClassName, field)} => {getter}");
$"\tpublic {(requiresNewKeyword ? "new ": "")}{SanitiseTypeName(field.Type.CsTypeName)} {schemaClass.CsPropertyNameForField(schemaClassName, field)} => {getter}");
builder.AppendLine();
}
}
@@ -425,4 +450,4 @@ internal static partial class Program
builder.AppendLine("}");
}
}
}

View File

@@ -2497,7 +2497,36 @@
]
},
"CAnimGraphControllerBase": {
"fields": []
"fields": [
{
"name": "m_sDestructiblePartDestroyedHitGroup",
"type": {
"atomic": 1,
"category": 4,
"inner": {
"category": 1,
"inner": {
"category": 0,
"name": "char"
},
"name": "char*"
},
"name": "CAnimGraphParamOptionalRef< char* >"
}
},
{
"name": "m_nDestructiblePartDestroyedPartIndex",
"type": {
"atomic": 1,
"category": 4,
"inner": {
"category": 0,
"name": "int32"
},
"name": "CAnimGraphParamOptionalRef< int32 >"
}
}
]
},
"CAnimGraphDebugReplay": {
"fields": [
@@ -5153,6 +5182,13 @@
"category": 0,
"name": "bool"
}
},
{
"name": "m_nLastDestructiblePartDestroyedAnimgraphSetTick",
"type": {
"category": 0,
"name": "int32"
}
}
],
"parent": "CBaseModelEntity"
@@ -5685,14 +5721,7 @@
}
},
{
"name": "m_bHasEverHitPlayer",
"type": {
"category": 0,
"name": "bool"
}
},
{
"name": "m_bClearFromPlayers",
"name": "m_bHasEverHitEnemy",
"type": {
"category": 0,
"name": "bool"
@@ -5840,13 +5869,6 @@
"name": "float32"
}
},
{
"name": "m_LastHitGroup",
"type": {
"category": 6,
"name": "HitGroup_t"
}
},
{
"name": "m_bApplyStressDamage",
"type": {
@@ -7084,6 +7106,55 @@
"name": "CHitboxComponent"
}
},
{
"name": "m_nDestructiblePartInitialStateDestructed0",
"type": {
"category": 6,
"name": "HitGroup_t"
}
},
{
"name": "m_nDestructiblePartInitialStateDestructed1",
"type": {
"category": 6,
"name": "HitGroup_t"
}
},
{
"name": "m_nDestructiblePartInitialStateDestructed2",
"type": {
"category": 6,
"name": "HitGroup_t"
}
},
{
"name": "m_nDestructiblePartInitialStateDestructed3",
"type": {
"category": 6,
"name": "HitGroup_t"
}
},
{
"name": "m_nDestructiblePartInitialStateDestructed4",
"type": {
"category": 6,
"name": "HitGroup_t"
}
},
{
"name": "m_nLastHitDestructiblePartIndex",
"type": {
"category": 0,
"name": "int32"
}
},
{
"name": "m_LastHitGroup",
"type": {
"category": 6,
"name": "HitGroup_t"
}
},
{
"name": "m_flDissolveStartTime",
"type": {
@@ -7543,13 +7614,6 @@
"name": "bool"
}
},
{
"name": "m_bAutoKickDisabled",
"type": {
"category": 0,
"name": "bool"
}
},
{
"name": "m_bIsLowViolence",
"type": {
@@ -13229,6 +13293,13 @@
"name": "bool"
}
},
{
"name": "m_ullLocalMatchID",
"type": {
"category": 0,
"name": "uint64"
}
},
{
"name": "m_nEndMatchMapGroupVoteTypes",
"type": {
@@ -14451,6 +14522,13 @@
"name": "bool"
}
},
{
"name": "m_flLastJoinTeamTime",
"type": {
"category": 5,
"name": "GameTime_t"
}
},
{
"name": "m_szClan",
"type": {
@@ -14582,6 +14660,13 @@
"name": "uint32"
}
},
{
"name": "m_eNetworkDisconnectionReason",
"type": {
"category": 0,
"name": "uint32"
}
},
{
"name": "m_bCannotBeKicked",
"type": {
@@ -14805,15 +14890,28 @@
}
},
{
"name": "m_vecKills",
"name": "m_recentKillQueue",
"type": {
"atomic": 2,
"category": 4,
"category": 3,
"inner": {
"category": 6,
"name": "EKillTypes_t"
"category": 0,
"name": "uint8"
},
"name": "CNetworkUtlVectorBase< EKillTypes_t >"
"name": "uint8[8]"
}
},
{
"name": "m_nFirstKill",
"type": {
"category": 0,
"name": "uint8"
}
},
{
"name": "m_nKillCount",
"type": {
"category": 0,
"name": "uint8"
}
},
{
@@ -14948,6 +15046,13 @@
"category": 0,
"name": "uint32"
}
},
{
"name": "m_bFireBulletsSeedSynchronized",
"type": {
"category": 0,
"name": "bool"
}
}
],
"parent": "CBasePlayerController"
@@ -16486,13 +16591,6 @@
},
"CCSPlayer_MovementServices": {
"fields": [
{
"name": "m_flMaxFallVelocity",
"type": {
"category": 0,
"name": "float32"
}
},
{
"name": "m_vecLadderNormal",
"type": {
@@ -16716,20 +16814,6 @@
"name": "float32"
}
},
{
"name": "m_flJumpUntil",
"type": {
"category": 0,
"name": "float32"
}
},
{
"name": "m_flJumpVel",
"type": {
"category": 0,
"name": "float32"
}
},
{
"name": "m_fStashGrenadeParameterWhen",
"type": {
@@ -16785,6 +16869,20 @@
"category": 0,
"name": "float32"
}
},
{
"name": "m_flStaminaAtJumpStart",
"type": {
"category": 0,
"name": "float32"
}
},
{
"name": "m_flAccumulatedJumpError",
"type": {
"category": 0,
"name": "float32"
}
}
],
"parent": "CPlayer_MovementServices_Humanoid"
@@ -17616,6 +17714,13 @@
"name": "GameTime_t"
}
},
{
"name": "m_nextPrevOwnerUseTime",
"type": {
"category": 5,
"name": "GameTime_t"
}
},
{
"name": "m_hPrevOwner",
"type": {
@@ -20347,6 +20452,13 @@
"name": "uint64"
}
},
{
"name": "m_iBulletsDamage",
"type": {
"category": 0,
"name": "int32"
}
},
{
"name": "m_iDamage",
"type": {
@@ -20548,6 +20660,156 @@
],
"parent": "CAnimComponentUpdater"
},
"CDestructiblePartRuntimeData": {
"fields": [
{
"name": "m_nHealthRemaining",
"type": {
"category": 0,
"name": "int32"
}
}
]
},
"CDestructiblePartRuntimeDataVector": {
"fields": [
{
"name": "m_DestructiblePartsRuntimeData",
"type": {
"atomic": 2,
"category": 4,
"inner": {
"category": 5,
"name": "CDestructiblePartRuntimeData"
},
"name": "CUtlVector< CDestructiblePartRuntimeData >"
}
}
]
},
"CDestructiblePartsSystemData": {
"fields": [
{
"name": "m_DestructiblePartsDataByHitGroup",
"type": {
"atomic": 3,
"category": 4,
"name": "CUtlOrderedMap< HitGroup_t, CDestructiblePartsSystemData_HitGroupInfoAndPartData >"
}
}
]
},
"CDestructiblePartsSystemData_HitGroupInfoAndPartData": {
"fields": [
{
"name": "m_sName",
"type": {
"atomic": 0,
"category": 4,
"name": "CUtlString"
}
},
{
"name": "m_DestructiblePartsData",
"type": {
"atomic": 2,
"category": 4,
"inner": {
"category": 5,
"name": "CDestructiblePartsSystemData_PartData"
},
"name": "CUtlVector< CDestructiblePartsSystemData_PartData >"
}
},
{
"name": "m_bDisableHitGroupWhenDestroyed",
"type": {
"category": 0,
"name": "bool"
}
}
]
},
"CDestructiblePartsSystemData_PartData": {
"fields": [
{
"name": "m_sName",
"type": {
"atomic": 0,
"category": 4,
"name": "CUtlString"
}
},
{
"name": "m_sBreakablePieceName",
"type": {
"atomic": 0,
"category": 4,
"name": "CGlobalSymbol"
}
},
{
"name": "m_sBodyGroupName",
"type": {
"atomic": 0,
"category": 4,
"name": "CGlobalSymbol"
}
},
{
"name": "m_nBodyGroupValue",
"type": {
"category": 0,
"name": "int32"
}
},
{
"name": "m_sAnimGraphParamName_PartDestroyed",
"type": {
"atomic": 0,
"category": 4,
"name": "CGlobalSymbol"
}
},
{
"name": "m_sAnimGraphParamName_PartNormalizedHealth",
"type": {
"atomic": 0,
"category": 4,
"name": "CGlobalSymbol"
}
},
{
"name": "m_nHealth",
"type": {
"category": 5,
"name": "CSkillInt"
}
},
{
"name": "m_nDamagePassthroughType",
"type": {
"category": 6,
"name": "EDestructiblePartDamagePassThroughType"
}
},
{
"name": "m_bKillNPCOnDestruction",
"type": {
"category": 0,
"name": "bool"
}
},
{
"name": "m_sCustomDeathHandshake",
"type": {
"atomic": 0,
"category": 4,
"name": "CGlobalSymbol"
}
}
]
},
"CDirectPlaybackTagData": {
"fields": [
{
@@ -24209,14 +24471,6 @@
"name": "float32"
}
},
{
"name": "m_soundscapeName",
"type": {
"atomic": 0,
"category": 4,
"name": "CUtlSymbolLarge"
}
},
{
"name": "m_soundEventName",
"type": {
@@ -24246,13 +24500,6 @@
"name": "int32"
}
},
{
"name": "m_soundEventHash",
"type": {
"category": 0,
"name": "uint32"
}
},
{
"name": "m_positionNames",
"type": {
@@ -24283,9 +24530,24 @@
"category": 0,
"name": "bool"
}
},
{
"name": "m_soundscapeName",
"type": {
"atomic": 0,
"category": 4,
"name": "CUtlSymbolLarge"
}
},
{
"name": "m_soundEventHash",
"type": {
"category": 0,
"name": "uint32"
}
}
],
"parent": "CServerOnlyEntity"
"parent": "CBaseEntity"
},
"CEnvSoundscapeAlias_snd_soundscape": {
"fields": [],
@@ -34850,6 +35112,13 @@
"category": 0,
"name": "bool"
}
},
{
"name": "m_bRainTraceToSkyEnabled",
"type": {
"category": 0,
"name": "bool"
}
}
],
"parent": "CPointEntity"
@@ -48678,6 +48947,17 @@
"name": "char[64]"
}
},
{
"name": "m_BackgroundMaterialName",
"type": {
"category": 3,
"inner": {
"category": 0,
"name": "char"
},
"name": "char[64]"
}
},
{
"name": "m_bEnabled",
"type": {
@@ -48713,6 +48993,34 @@
"name": "float32"
}
},
{
"name": "m_bDrawBackground",
"type": {
"category": 0,
"name": "bool"
}
},
{
"name": "m_flBackgroundBorderWidth",
"type": {
"category": 0,
"name": "float32"
}
},
{
"name": "m_flBackgroundBorderHeight",
"type": {
"category": 0,
"name": "float32"
}
},
{
"name": "m_flBackgroundWorldToUV",
"type": {
"category": 0,
"name": "float32"
}
},
{
"name": "m_Color",
"type": {
@@ -51818,6 +52126,13 @@
"category": 0,
"name": "bool"
}
},
{
"name": "m_bCanTakeDamage",
"type": {
"category": 0,
"name": "bool"
}
}
],
"parent": "CBaseEntity"
@@ -57267,7 +57582,21 @@
"category": 0,
"name": "uint8"
},
"name": "CUtlVector< uint8 >"
"name": "CNetworkUtlVectorBase< uint8 >"
}
},
{
"name": "m_nVoxelFrameDataSize",
"type": {
"category": 0,
"name": "int32"
}
},
{
"name": "m_nVoxelUpdate",
"type": {
"category": 0,
"name": "int32"
}
},
{
@@ -87420,6 +87749,13 @@
"category": 0,
"name": "int32"
}
},
{
"name": "m_EndEffectorRotationFixUpMode",
"type": {
"category": 6,
"name": "EIKEndEffectorRotationFixUpMode"
}
}
]
},
@@ -92093,6 +92429,13 @@
"category": 0,
"name": "bool"
}
},
{
"name": "m_nHealthToGrant",
"type": {
"category": 0,
"name": "int32"
}
}
]
},
@@ -94126,13 +94469,6 @@
},
"name": "CUtlVector< ChainToSolveData_t >"
}
},
{
"name": "m_bMatchTargetOrientation",
"type": {
"category": 0,
"name": "bool"
}
}
]
},
@@ -101062,6 +101398,23 @@
}
]
},
"EContributionScoreFlag_t": {
"align": 1,
"items": [
{
"name": "k_EContributionScoreFlag_Default",
"value": 0
},
{
"name": "k_EContributionScoreFlag_Objective",
"value": 1
},
{
"name": "k_EContributionScoreFlag_Bullets",
"value": 2
}
]
},
"EDemoBoneSelectionMode": {
"align": 4,
"items": [
@@ -101075,6 +101428,44 @@
}
]
},
"EDestructiblePartDamagePassThroughType": {
"align": 4,
"items": [
{
"name": "Normal",
"value": 0
},
{
"name": "Absorb",
"value": 1
}
]
},
"EIKEndEffectorRotationFixUpMode": {
"align": 4,
"items": [
{
"name": "None",
"value": 0
},
{
"name": "MatchTargetOrientation",
"value": 1
},
{
"name": "LookAtTargetForward",
"value": 2
},
{
"name": "MaintainParentOrientation",
"value": 3
},
{
"name": "Count",
"value": 4
}
]
},
"EInButtonState": {
"align": 4,
"items": [
@@ -110245,4 +110636,4 @@
]
}
}
}
}

View File

@@ -4,6 +4,7 @@ namespace CounterStrikeSharp.SchemaGen;
public partial record SchemaClass(
int Index,
string Name,
string? Parent,
IReadOnlyList<SchemaField> Fields)
{

View File

@@ -1,5 +1,8 @@

Microsoft Visual Studio Solution File, Format Version 12.00
# Visual Studio Version 17
VisualStudioVersion = 17.12.35309.182
MinimumVisualStudioVersion = 10.0.40219.1
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "TestPlugin", "TestPlugin\TestPlugin.csproj", "{57E64289-5D69-4AA1-BEF0-D0D96A55EE8F}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "CounterStrikeSharp.API", "CounterStrikeSharp.API\CounterStrikeSharp.API.csproj", "{55B47E41-61AA-4D75-9069-CB14328107B7}"
@@ -42,6 +45,8 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "WithSharedTypesConsumer", "
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "WithUserMessages", "..\examples\WithUserMessages\WithUserMessages.csproj", "{A14029BA-CADE-4F25-ADC5-48CF14332F61}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "WithCheckTransmit", "..\examples\WithCheckTransmit\WithCheckTransmit.csproj", "{854B06B5-0E7B-438A-BA51-3F299557F884}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU
@@ -108,14 +113,14 @@ Global
{6FA3107D-42AF-42A0-BF51-2230D13268B5}.Debug|Any CPU.Build.0 = Debug|Any CPU
{6FA3107D-42AF-42A0-BF51-2230D13268B5}.Release|Any CPU.ActiveCfg = Release|Any CPU
{6FA3107D-42AF-42A0-BF51-2230D13268B5}.Release|Any CPU.Build.0 = Release|Any CPU
{4E5289B5-E81D-421C-B340-B98B6FFE09D1}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{4E5289B5-E81D-421C-B340-B98B6FFE09D1}.Debug|Any CPU.Build.0 = Debug|Any CPU
{4E5289B5-E81D-421C-B340-B98B6FFE09D1}.Release|Any CPU.ActiveCfg = Release|Any CPU
{4E5289B5-E81D-421C-B340-B98B6FFE09D1}.Release|Any CPU.Build.0 = Release|Any CPU
{1309954E-FAF7-47A5-9FF9-C7263B33E4E3}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{1309954E-FAF7-47A5-9FF9-C7263B33E4E3}.Debug|Any CPU.Build.0 = Debug|Any CPU
{1309954E-FAF7-47A5-9FF9-C7263B33E4E3}.Release|Any CPU.ActiveCfg = Release|Any CPU
{1309954E-FAF7-47A5-9FF9-C7263B33E4E3}.Release|Any CPU.Build.0 = Release|Any CPU
{4E5289B5-E81D-421C-B340-B98B6FFE09D1}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{4E5289B5-E81D-421C-B340-B98B6FFE09D1}.Debug|Any CPU.Build.0 = Debug|Any CPU
{4E5289B5-E81D-421C-B340-B98B6FFE09D1}.Release|Any CPU.ActiveCfg = Release|Any CPU
{4E5289B5-E81D-421C-B340-B98B6FFE09D1}.Release|Any CPU.Build.0 = Release|Any CPU
{A37676EA-CF2F-424D-85A1-C359D07A679D}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{A37676EA-CF2F-424D-85A1-C359D07A679D}.Debug|Any CPU.Build.0 = Debug|Any CPU
{A37676EA-CF2F-424D-85A1-C359D07A679D}.Release|Any CPU.ActiveCfg = Release|Any CPU
@@ -128,6 +133,13 @@ Global
{A14029BA-CADE-4F25-ADC5-48CF14332F61}.Debug|Any CPU.Build.0 = Debug|Any CPU
{A14029BA-CADE-4F25-ADC5-48CF14332F61}.Release|Any CPU.ActiveCfg = Release|Any CPU
{A14029BA-CADE-4F25-ADC5-48CF14332F61}.Release|Any CPU.Build.0 = Release|Any CPU
{854B06B5-0E7B-438A-BA51-3F299557F884}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{854B06B5-0E7B-438A-BA51-3F299557F884}.Debug|Any CPU.Build.0 = Debug|Any CPU
{854B06B5-0E7B-438A-BA51-3F299557F884}.Release|Any CPU.ActiveCfg = Release|Any CPU
{854B06B5-0E7B-438A-BA51-3F299557F884}.Release|Any CPU.Build.0 = Release|Any CPU
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
EndGlobalSection
GlobalSection(NestedProjects) = preSolution
{57E64289-5D69-4AA1-BEF0-D0D96A55EE8F} = {7DF99C35-881D-4FF2-B1C9-246BD3DECB9A}
@@ -141,10 +153,14 @@ Global
{31EABE0B-871F-497B-BF36-37FFC6FAD15F} = {7DF99C35-881D-4FF2-B1C9-246BD3DECB9A}
{BB44E08E-CCA8-4E22-A132-11B2F69D1890} = {7DF99C35-881D-4FF2-B1C9-246BD3DECB9A}
{6FA3107D-42AF-42A0-BF51-2230D13268B5} = {7DF99C35-881D-4FF2-B1C9-246BD3DECB9A}
{4E5289B5-E81D-421C-B340-B98B6FFE09D1} = {7DF99C35-881D-4FF2-B1C9-246BD3DECB9A}
{1309954E-FAF7-47A5-9FF9-C7263B33E4E3} = {7DF99C35-881D-4FF2-B1C9-246BD3DECB9A}
{4E5289B5-E81D-421C-B340-B98B6FFE09D1} = {7DF99C35-881D-4FF2-B1C9-246BD3DECB9A}
{A37676EA-CF2F-424D-85A1-C359D07A679D} = {7DF99C35-881D-4FF2-B1C9-246BD3DECB9A}
{76AD7BB0-A096-4336-83E2-B32CAE4E9933} = {7DF99C35-881D-4FF2-B1C9-246BD3DECB9A}
{A14029BA-CADE-4F25-ADC5-48CF14332F61} = {7DF99C35-881D-4FF2-B1C9-246BD3DECB9A}
{854B06B5-0E7B-438A-BA51-3F299557F884} = {7DF99C35-881D-4FF2-B1C9-246BD3DECB9A}
EndGlobalSection
GlobalSection(ExtensibilityGlobals) = postSolution
SolutionGuid = {069C4CD4-BACA-446A-A6B8-0194E4F75355}
EndGlobalSection
EndGlobal

View File

@@ -15,6 +15,7 @@
*/
using System;
using System.Collections.Generic;
using System.Drawing;
using System.Globalization;
using System.IO;
@@ -145,7 +146,7 @@ namespace TestPlugin
// Mirrors a chat message back to the player
RegisterEventHandler<EventPlayerChat>(((@event, _) =>
{
var player = Utilities.GetPlayerFromIndex(@event.Userid);
var player = @event.Userid;
if (player == null) return HookResult.Continue;
player.PrintToChat($"You said {@event.Text}");
@@ -301,6 +302,26 @@ namespace TestPlugin
return;
}
});
// Hide every door (prop_door_rotating) for everyone as a test
RegisterListener<Listeners.CheckTransmit>((CCheckTransmitInfoList infoList) =>
{
IEnumerable<CPropDoorRotating> doors = Utilities.FindAllEntitiesByDesignerName<CPropDoorRotating>("prop_door_rotating");
if (!doors.Any())
return;
foreach ((CCheckTransmitInfo info, CCSPlayerController? player) in infoList)
{
if (player == null)
continue;
foreach (CPropDoorRotating door in doors)
{
info.TransmitEntities.Remove(door);
}
}
});
}
private void SetupCommands()
@@ -371,6 +392,16 @@ namespace TestPlugin
return HookResult.Continue;
}
[ListenerHandler<Listeners.OnClientPutInServer>]
public void OnClientPutInServer(int playerSlot)
{
var player = Utilities.GetPlayerFromSlot(playerSlot);
if (player == null || player.IsBot) return;
player.PrintToChat("Welcome to the server!");
}
[ConsoleCommand("css_testinput", "Test AcceptInput and AddEntityIOEvent")]
public void OnTestInput(CCSPlayerController? player, CommandInfo command)
{

View File

@@ -78,6 +78,7 @@ ISmmAPI* ismm = nullptr;
CGameEntitySystem* entitySystem = nullptr;
CCoreConfig* coreConfig = nullptr;
CGameConfig* gameConfig = nullptr;
ISource2GameEntities* gameEntities = nullptr;
// Custom Managers
CallbackManager callbackManager;
@@ -142,9 +143,9 @@ void DetourGameEventManagerInit(IGameEventManager2* pGameEventManager)
int source_hook_pluginid = 0;
CGlobalVars* getGlobalVars() {
INetworkGameServer *server = networkServerService->GetIGameServer();
if(!server) return nullptr;
return networkServerService->GetIGameServer()->GetGlobals();
INetworkGameServer* server = networkServerService->GetIGameServer();
if (!server) return nullptr;
return networkServerService->GetIGameServer()->GetGlobals();
}
} // namespace globals
} // namespace counterstrikesharp

View File

@@ -94,6 +94,7 @@ extern ISource2Server* server;
extern CGlobalEntityList* globalEntityList;
extern EntityListener entityListener;
extern CGameEntitySystem* entitySystem;
extern ISource2GameEntities* gameEntities;
extern EventManager eventManager;
extern UserMessageManager userMessageManager;

View File

@@ -216,7 +216,7 @@ void ConCommandManager::OnAllInitialized()
}
}
static uint64 flagsToRemove = (FCVAR_HIDDEN | FCVAR_DEVELOPMENTONLY | FCVAR_MISSING0 | FCVAR_MISSING1 | FCVAR_MISSING2 | FCVAR_MISSING3);
static uint64 flagsToRemove = (FCVAR_HIDDEN | FCVAR_DEVELOPMENTONLY);
void UnlockConVars()
{

View File

@@ -17,6 +17,7 @@
#include "core/managers/entity_manager.h"
#include "core/gameconfig.h"
#include "core/log.h"
#include "core/recipientfilters.h"
#include <funchook.h>
#include <vector>
@@ -24,14 +25,24 @@
#include <public/eiface.h>
#include "scripting/callback_manager.h"
SH_DECL_HOOK7_void(ISource2GameEntities, CheckTransmit, SH_NOATTRIB, 0, CCheckTransmitInfo**, int, CBitVec<16384>&, const Entity2Networkable_t**, const uint16*, int, bool);
namespace counterstrikesharp {
EntityManager::EntityManager() {}
EntityManager::EntityManager()
{
m_profile_name = "EntityManager";
}
EntityManager::~EntityManager() {}
CCheckTransmitInfoList::CCheckTransmitInfoList(CCheckTransmitInfo** pInfoInfoList, int nInfoCount) : infoList(pInfoInfoList), infoCount(nInfoCount) {}
void EntityManager::OnAllInitialized()
{
SH_ADD_HOOK_MEMFUNC(ISource2GameEntities, CheckTransmit, globals::gameEntities, this, &EntityManager::CheckTransmit, true);
check_transmit = globals::callbackManager.CreateCallback("CheckTransmit");
on_entity_spawned_callback = globals::callbackManager.CreateCallback("OnEntitySpawned");
on_entity_created_callback = globals::callbackManager.CreateCallback("OnEntityCreated");
on_entity_deleted_callback = globals::callbackManager.CreateCallback("OnEntityDeleted");
@@ -62,6 +73,14 @@ void EntityManager::OnAllInitialized()
CSSHARP_CORE_CRITICAL("Failed to find signature for \'CEntitySystem_AddEntityIOEvent\'");
}
CBaseEntity_EmitSoundFilter = decltype(CBaseEntity_EmitSoundFilter) (
modules::server->FindSignature(globals::gameConfig->GetSignature("CBaseEntity_EmitSoundFilter")));
if (!CBaseEntity_EmitSoundFilter)
{
CSSHARP_CORE_CRITICAL("Failed to find signature for \'CBaseEntity_EmitSoundFilter\'");
}
auto m_hook = funchook_create();
funchook_prepare(m_hook, (void**)&m_pFireOutputInternal, (void*)&DetourFireOutputInternal);
funchook_install(m_hook, 0);
@@ -75,7 +94,10 @@ void EntityManager::OnShutdown()
globals::callbackManager.ReleaseCallback(on_entity_created_callback);
globals::callbackManager.ReleaseCallback(on_entity_deleted_callback);
globals::callbackManager.ReleaseCallback(on_entity_parent_changed_callback);
globals::callbackManager.ReleaseCallback(check_transmit);
globals::entitySystem->RemoveListenerEntity(&entityListener);
SH_REMOVE_HOOK_MEMFUNC(ISource2GameEntities, CheckTransmit, globals::gameEntities, this, &EntityManager::CheckTransmit, true);
}
void CEntityListener::OnEntitySpawned(CEntityInstance* pEntity)
@@ -156,6 +178,23 @@ void EntityManager::UnhookEntityOutput(const char* szClassname, const char* szOu
}
}
void EntityManager::CheckTransmit(CCheckTransmitInfo** pInfoInfoList, int nInfoCount, CBitVec<16384>& unionTransmitEdicts, const Entity2Networkable_t** pNetworkables, const uint16* pEntityIndicies, int nEntityIndices, bool bEnablePVSBits)
{
VPROF_BUDGET(m_profile_name.c_str(), "CS# CheckTransmit");
auto callback = globals::entityManager.check_transmit;
if (callback && callback->GetFunctionCount()) {
CCheckTransmitInfoList* infoList = new CCheckTransmitInfoList(pInfoInfoList, nInfoCount);
callback->ScriptContext().Reset();
callback->ScriptContext().Push(infoList);
callback->Execute();
delete infoList;
}
}
void DetourFireOutputInternal(CEntityIOOutput* const pThis, CEntityInstance* pActivator,
CEntityInstance* pCaller, const CVariant* const value, float flDelay)
{
@@ -235,4 +274,19 @@ void DetourFireOutputInternal(CEntityIOOutput* const pThis, CEntityInstance* pAc
}
}
SndOpEventGuid_t EntityEmitSoundFilter(IRecipientFilter& filter, uint32 ent, const char* pszSound, float flVolume, float flPitch)
{
if (!CBaseEntity_EmitSoundFilter) {
CSSHARP_CORE_ERROR("[EntityManager][EmitSoundFilter] - Failed to emit a sound. Signature for \'CBaseEntity_EmitSoundFilter\' is not found. The latest update may have broken it.");
return SndOpEventGuid_t{};
}
EmitSound_t params;
params.m_pSoundName = pszSound;
params.m_flVolume = flVolume;
params.m_nPitch = flPitch;
return CBaseEntity_EmitSoundFilter(filter, ent, params);
}
} // namespace counterstrikesharp

View File

@@ -27,6 +27,8 @@
#include <variant.h>
#include "vprof.h"
namespace counterstrikesharp {
class ScriptCallback;
@@ -39,6 +41,14 @@ class CEntityListener : public IEntityListener {
void OnEntityParentChanged(CEntityInstance *pEntity, CEntityInstance *pNewParent) override;
};
class CCheckTransmitInfoList {
public:
CCheckTransmitInfoList(CCheckTransmitInfo** pInfoInfoList, int nInfoCount);
private:
CCheckTransmitInfo** infoList;
int infoCount;
};
class EntityManager : public GlobalClass {
friend CEntityListener;
public:
@@ -51,10 +61,15 @@ public:
CEntityListener entityListener;
std::map<OutputKey_t, CallbackPair*> m_pHookMap;
private:
void CheckTransmit(CCheckTransmitInfo** pInfoInfoList, int nInfoCount, CBitVec<16384>& unionTransmitEdicts, const Entity2Networkable_t** pNetworkables, const uint16* pEntityIndicies, int nEntityIndices, bool bEnablePVSBits);
ScriptCallback *on_entity_spawned_callback;
ScriptCallback *on_entity_created_callback;
ScriptCallback *on_entity_deleted_callback;
ScriptCallback *on_entity_parent_changed_callback;
ScriptCallback *check_transmit;
std::string m_profile_name;
};
@@ -122,4 +137,80 @@ inline void (*CEntitySystem_AddEntityIOEvent)(CEntitySystem* pEntitySystem,
variant_t* value,
float delay,
int nOutputID);
typedef uint32 SoundEventGuid_t;
enum gender_t : uint8
{
GENDER_NONE = 0x0,
GENDER_MALE = 0x1,
GENDER_FEMALE = 0x2,
GENDER_NAMVET = 0x3,
GENDER_TEENGIRL = 0x4,
GENDER_BIKER = 0x5,
GENDER_MANAGER = 0x6,
GENDER_GAMBLER = 0x7,
GENDER_PRODUCER = 0x8,
GENDER_COACH = 0x9,
GENDER_MECHANIC = 0xA,
GENDER_CEDA = 0xB,
GENDER_CRAWLER = 0xC,
GENDER_UNDISTRACTABLE = 0xD,
GENDER_FALLEN = 0xE,
GENDER_RIOT_CONTROL = 0xF,
GENDER_CLOWN = 0x10,
GENDER_JIMMY = 0x11,
GENDER_HOSPITAL_PATIENT = 0x12,
GENDER_BRIDE = 0x13,
GENDER_LAST = 0x14,
};
struct EmitSound_t
{
EmitSound_t() :
m_nChannel(0),
m_pSoundName(0),
m_flVolume(VOL_NORM),
m_SoundLevel(SNDLVL_NONE),
m_nFlags(0),
m_nPitch(PITCH_NORM),
m_pOrigin(0),
m_flSoundTime(0.0f),
m_pflSoundDuration(0),
m_bEmitCloseCaption(true),
m_bWarnOnMissingCloseCaption(false),
m_bWarnOnDirectWaveReference(false),
m_nSpeakerEntity(-1),
m_UtlVecSoundOrigin(),
m_nForceGuid(0),
m_SpeakerGender(GENDER_NONE)
{
}
int m_nChannel;
const char* m_pSoundName;
float m_flVolume;
soundlevel_t m_SoundLevel;
int m_nFlags;
int m_nPitch;
const Vector* m_pOrigin;
float m_flSoundTime;
float* m_pflSoundDuration;
bool m_bEmitCloseCaption;
bool m_bWarnOnMissingCloseCaption;
bool m_bWarnOnDirectWaveReference;
CEntityIndex m_nSpeakerEntity;
CUtlVector<Vector, CUtlMemory<Vector, int> > m_UtlVecSoundOrigin;
SoundEventGuid_t m_nForceGuid;
gender_t m_SpeakerGender;
};
struct SndOpEventGuid_t
{
SoundEventGuid_t m_nGuid;
uint64 m_hStackHash;
};
inline SndOpEventGuid_t(FASTCALL* CBaseEntity_EmitSoundFilter)(IRecipientFilter& filter, CEntityIndex ent, const EmitSound_t& params);
SndOpEventGuid_t EntityEmitSoundFilter(IRecipientFilter& filter, uint32 ent, const char* pszSound, float flVolume = 1.0f, float flPitch = 1.0f);
} // namespace counterstrikesharp

View File

@@ -30,14 +30,15 @@
*/
#include "core/timer_system.h"
#include <algorithm>
#include <public/eiface.h>
#include <algorithm>
#include "core/globals.h"
#include "core/log.h"
#include "scripting/callback_manager.h"
#include "core/managers/player_manager.h"
#include "scripting/callback_manager.h"
namespace counterstrikesharp {
namespace timers {
@@ -46,8 +47,7 @@ double timer_next_think = 0.0f;
} // namespace timers
timers::Timer::Timer(float interval, float exec_time, CallbackT callback, int flags)
: m_interval(interval), m_exec_time(exec_time), m_flags(flags), m_kill_me(false),
m_in_exec(false)
: m_interval(interval), m_exec_time(exec_time), m_flags(flags), m_kill_me(false), m_in_exec(false)
{
m_callback = globals::callbackManager.CreateCallback("Timer");
m_callback->AddListener(callback);
@@ -76,7 +76,8 @@ void TimerSystem::OnShutdown()
void TimerSystem::OnLevelEnd()
{
if (on_map_end_callback && on_map_end_callback->GetFunctionCount()) {
if (on_map_end_callback && on_map_end_callback->GetFunctionCount())
{
on_map_end_callback->ScriptContext().Reset();
on_map_end_callback->Execute();
}
@@ -89,7 +90,8 @@ void TimerSystem::OnLevelEnd()
void TimerSystem::OnStartupServer()
{
if (m_has_map_ticked) {
if (m_has_map_ticked)
{
CALL_GLOBAL_LISTENER(OnLevelEnd());
CSSHARP_CORE_TRACE("name={0}", "LevelShutdown");
@@ -101,12 +103,16 @@ void TimerSystem::OnStartupServer()
void TimerSystem::OnGameFrame(bool simulating)
{
if (simulating && m_has_map_ticked) {
if (simulating && m_has_map_ticked)
{
timers::universal_time += globals::getGlobalVars()->curtime - m_last_ticked_time;
if (!m_has_map_simulated) {
if (!m_has_map_simulated)
{
m_has_map_simulated = true;
}
} else {
}
else
{
timers::universal_time += globals::engine_fixed_tick_interval;
}
@@ -114,13 +120,15 @@ void TimerSystem::OnGameFrame(bool simulating)
m_has_map_ticked = true;
// Handle timer tick
if (timers::universal_time >= timers::timer_next_think) {
if (timers::universal_time >= timers::timer_next_think)
{
RunFrame();
timers::timer_next_think = CalculateNextThink(timers::timer_next_think, 0.1f);
}
if (m_on_tick_callback_->GetFunctionCount()) {
if (m_on_tick_callback_->GetFunctionCount())
{
m_on_tick_callback_->ScriptContext().Reset();
m_on_tick_callback_->Execute();
}
@@ -130,18 +138,23 @@ void TimerSystem::OnGameFrame(bool simulating)
double TimerSystem::CalculateNextThink(double last_think_time, float interval)
{
if (timers::universal_time - last_think_time - interval <= 0.1) {
if (timers::universal_time - last_think_time - interval <= 0.1)
{
return last_think_time + interval;
} else {
}
else
{
return timers::universal_time + interval;
}
}
void TimerSystem::RunFrame()
{
for (int i = m_once_off_timers.size() - 1; i >= 0; i--) {
for (int i = m_once_off_timers.size() - 1; i >= 0; i--)
{
auto timer = m_once_off_timers[i];
if (timers::universal_time >= timer->m_exec_time) {
if (timers::universal_time >= timer->m_exec_time)
{
timer->m_in_exec = true;
timer->m_callback->ScriptContext().Reset();
timer->m_callback->Execute();
@@ -151,14 +164,17 @@ void TimerSystem::RunFrame()
}
}
for (int i = m_repeat_timers.size() - 1; i >= 0; i--) {
for (int i = m_repeat_timers.size() - 1; i >= 0; i--)
{
auto timer = m_repeat_timers[i];
if (timers::universal_time >= timer->m_exec_time) {
if (timers::universal_time >= timer->m_exec_time)
{
timer->m_in_exec = true;
timer->m_callback->ScriptContext().Reset();
timer->m_callback->Execute();
if (timer->m_kill_me) {
if (timer->m_kill_me)
{
m_repeat_timers.erase(m_repeat_timers.begin() + i);
delete timer;
continue;
@@ -172,17 +188,17 @@ void TimerSystem::RunFrame()
void TimerSystem::RemoveMapChangeTimers()
{
for (auto timer : m_once_off_timers) {
if (timer->m_flags & TIMER_FLAG_NO_MAPCHANGE) {
KillTimer(timer);
auto isMapChangeTimer = [](timers::Timer* timer) {
bool shouldRemove = timer->m_flags & TIMER_FLAG_NO_MAPCHANGE;
if (shouldRemove)
{
delete timer;
}
}
return shouldRemove;
};
for (auto timer : m_repeat_timers) {
if (timer->m_flags & TIMER_FLAG_NO_MAPCHANGE) {
KillTimer(timer);
}
}
std::erase_if(m_once_off_timers, isMapChangeTimer);
std::erase_if(m_repeat_timers, isMapChangeTimer);
}
timers::Timer* TimerSystem::CreateTimer(float interval, CallbackT callback, int flags)
@@ -191,7 +207,8 @@ timers::Timer* TimerSystem::CreateTimer(float interval, CallbackT callback, int
auto timer = new timers::Timer(interval, exec_time, callback, flags);
if (flags & TIMER_FLAG_REPEAT) {
if (flags & TIMER_FLAG_REPEAT)
{
m_repeat_timers.push_back(timer);
return timer;
}
@@ -202,39 +219,41 @@ timers::Timer* TimerSystem::CreateTimer(float interval, CallbackT callback, int
void TimerSystem::KillTimer(timers::Timer* timer)
{
if (!timer)
return;
if (!timer) return;
if (std::find(m_repeat_timers.begin(), m_repeat_timers.end(), timer) == m_repeat_timers.end() &&
std::find(m_once_off_timers.begin(), m_once_off_timers.end(), timer) ==
m_once_off_timers.end()) {
std::find(m_once_off_timers.begin(), m_once_off_timers.end(), timer) == m_once_off_timers.end())
{
return;
}
if (timer->m_kill_me)
return;
if (timer->m_kill_me) return;
// If were executing, make sure it doesn't run again next time.
if (timer->m_in_exec) {
if (timer->m_in_exec)
{
timer->m_kill_me = true;
return;
}
if (timer->m_flags & TIMER_FLAG_REPEAT) {
auto it = std::remove_if(m_repeat_timers.begin(), m_repeat_timers.end(),
[timer](timers::Timer* i) { return timer == i; });
if (timer->m_flags & TIMER_FLAG_REPEAT)
{
auto it = std::remove_if(m_repeat_timers.begin(), m_repeat_timers.end(), [timer](timers::Timer* i) {
return timer == i;
});
bool success;
if ((success = it != m_repeat_timers.end()))
m_repeat_timers.erase(it, m_repeat_timers.end());
if ((success = it != m_repeat_timers.end())) m_repeat_timers.erase(it, m_repeat_timers.end());
delete timer;
} else {
auto it = std::remove_if(m_once_off_timers.begin(), m_once_off_timers.end(),
[timer](timers::Timer* i) { return timer == i; });
}
else
{
auto it = std::remove_if(m_once_off_timers.begin(), m_once_off_timers.end(), [timer](timers::Timer* i) {
return timer == i;
});
bool success;
if ((success = it != m_once_off_timers.end()))
m_once_off_timers.erase(it, m_once_off_timers.end());
if ((success = it != m_once_off_timers.end())) m_once_off_timers.erase(it, m_once_off_timers.end());
delete timer;
}
}

View File

@@ -34,7 +34,7 @@
#include "scripting/script_engine.h"
#include "tier0/vprof.h"
#define VERSION_STRING "v" BUILD_NUMBER " @ " GITHUB_SHA
#define VERSION_STRING "v" SEMVER " @ " GITHUB_SHA
#define BUILD_TIMESTAMP __DATE__ " " __TIME__
counterstrikesharp::GlobalClass* counterstrikesharp::GlobalClass::head = nullptr;
@@ -102,6 +102,7 @@ bool CounterStrikeSharpMMPlugin::Load(PluginId id, ISmmAPI* ismm, char* error, s
GET_V_IFACE_ANY(GetEngineFactory, globals::gameEventSystem, IGameEventSystem, GAMEEVENTSYSTEM_INTERFACE_VERSION);
GET_V_IFACE_ANY(GetEngineFactory, globals::engineServiceManager, IEngineServiceMgr, ENGINESERVICEMGR_INTERFACE_VERSION);
GET_V_IFACE_ANY(GetEngineFactory, globals::networkMessages, INetworkMessages, NETWORKMESSAGES_INTERFACE_VERSION);
GET_V_IFACE_ANY(GetServerFactory, globals::gameEntities, ISource2GameEntities, SOURCE2GAMEENTITIES_INTERFACE_VERSION);
auto coreconfig_path = std::string(utils::ConfigsDirectory() + "/core");
globals::coreConfig = new CCoreConfig(coreconfig_path);
@@ -133,6 +134,7 @@ bool CounterStrikeSharpMMPlugin::Load(PluginId id, ISmmAPI* ismm, char* error, s
CALL_GLOBAL_LISTENER(OnAllInitialized());
on_activate_callback = globals::callbackManager.CreateCallback("OnMapStart");
on_metamod_all_plugins_loaded_callback = globals::callbackManager.CreateCallback("OnMetamodAllPluginsLoaded");
SH_ADD_HOOK_MEMFUNC(IServerGameDLL, GameFrame, globals::server, this, &CounterStrikeSharpMMPlugin::Hook_GameFrame, true);
SH_ADD_HOOK_MEMFUNC(INetworkServerService, StartupServer, globals::networkServerService, this,
@@ -181,6 +183,7 @@ bool CounterStrikeSharpMMPlugin::Unload(char* error, size_t maxlen)
&CounterStrikeSharpMMPlugin::Hook_StartupServer, true);
globals::callbackManager.ReleaseCallback(on_activate_callback);
globals::callbackManager.ReleaseCallback(on_metamod_all_plugins_loaded_callback);
return true;
}
@@ -190,6 +193,8 @@ void CounterStrikeSharpMMPlugin::AllPluginsLoaded()
/* This is where we'd do stuff that relies on the mod or other plugins
* being initialized (for example, cvars added and events registered).
*/
on_metamod_all_plugins_loaded_callback->ScriptContext().Reset();
on_metamod_all_plugins_loaded_callback->Execute();
}
void CounterStrikeSharpMMPlugin::AddTaskForNextFrame(std::function<void()>&& task)

View File

@@ -71,6 +71,7 @@ class CounterStrikeSharpMMPlugin : public ISmmPlugin, public IMetamodListener
};
static ScriptCallback* on_activate_callback;
static ScriptCallback* on_metamod_all_plugins_loaded_callback;
extern CounterStrikeSharpMMPlugin gPlugin;
PLUGIN_GLOBALVARS();

View File

@@ -1,4 +1,5 @@
OnEntitySpawned: entity:pointer
OnEntityCreated: entity:pointer
OnEntityDeleted: entity:pointer
OnEntityParentChanged: entity:pointer, newParent:pointer
OnEntityParentChanged: entity:pointer, newParent:pointer
CheckTransmit: infoList:pointer

View File

@@ -0,0 +1 @@
OnMetamodAllPluginsLoaded:

View File

@@ -15,13 +15,17 @@
*/
#include <eiface.h>
#include <networksystem/inetworkmessages.h>
#include "scripting/autonative.h"
#include "scripting/callback_manager.h"
#include "core/managers/con_command_manager.h"
#include "core/managers/player_manager.h"
#include "core/recipientfilters.h"
#include "igameeventsystem.h"
#include "scripting/script_engine.h"
#include "core/log.h"
#include <networkbasetypes.pb.h>
namespace counterstrikesharp {
@@ -191,6 +195,25 @@ void SetConVarStringValue(ScriptContext& script_context)
pCvar->values = reinterpret_cast<CVValue_t**>((char*)value);
}
void ReplicateConVar(ScriptContext& script_context)
{
auto slot = script_context.GetArgument<int>(0);
auto name = script_context.GetArgument<const char*>(1);
auto value = script_context.GetArgument<const char*>(2);
INetworkMessageInternal* pNetMsg = globals::networkMessages->FindNetworkMessagePartial("SetConVar");
auto msg = pNetMsg->AllocateMessage()->ToPB<CNETMsg_SetConVar>();
CMsg_CVars_CVar* cvarMsg = msg->mutable_convars()->add_cvars();
cvarMsg->set_name(name);
cvarMsg->set_value(value);
CSingleRecipientFilter filter(slot);
globals::gameEventSystem->PostEventAbstract(-1, false, &filter, pNetMsg, msg, 0);
delete msg;
}
REGISTER_NATIVES(commands, {
ScriptEngine::RegisterNativeHandler("ADD_COMMAND", AddCommand);
ScriptEngine::RegisterNativeHandler("REMOVE_COMMAND", RemoveCommand);
@@ -211,5 +234,6 @@ REGISTER_NATIVES(commands, {
IssueClientCommandFromServer);
ScriptEngine::RegisterNativeHandler("GET_CLIENT_CONVAR_VALUE", GetClientConVarValue);
ScriptEngine::RegisterNativeHandler("SET_FAKE_CLIENT_CONVAR_VALUE", SetFakeClientConVarValue);
ScriptEngine::RegisterNativeHandler("REPLICATE_CONVAR", ReplicateConVar);
})
} // namespace counterstrikesharp

Some files were not shown because too many files have changed in this diff Show More