mirror of
https://github.com/roflmuffin/CounterStrikeSharp.git
synced 2025-12-06 16:06:37 -08:00
Compare commits
38 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
c9f8e477d3 | ||
|
|
2398ba0a5d | ||
|
|
e45c20481d | ||
|
|
fe321ee93d | ||
|
|
be19103556 | ||
|
|
64cb26b86d | ||
|
|
637224dc55 | ||
|
|
3aca7c37f1 | ||
|
|
87f38d72ee | ||
|
|
5daf94791f | ||
|
|
c50213c442 | ||
|
|
c02d31cb2e | ||
|
|
98cbca44d4 | ||
|
|
4cf88fc03e | ||
|
|
f1dff6d4d3 | ||
|
|
414a59a36d | ||
|
|
f1c108087b | ||
|
|
47ddf42c11 | ||
|
|
ded133f1db | ||
|
|
bbc621acdc | ||
|
|
f7784c26c6 | ||
|
|
2da5448c8e | ||
|
|
e406b78044 | ||
|
|
3839831ea9 | ||
|
|
54ad6c0b79 | ||
|
|
7c2cc8a7f6 | ||
|
|
e99d27ca30 | ||
|
|
44d3c51bc7 | ||
|
|
f72e6d5daf | ||
|
|
c8bccb07e0 | ||
|
|
2c0640700a | ||
|
|
0f71e1aebe | ||
|
|
ac38ec249b | ||
|
|
cff24f4321 | ||
|
|
f05cc5e043 | ||
|
|
bd1105d752 | ||
|
|
9b4ee727c7 | ||
|
|
38d248defe |
270
.github/workflows/build-and-publish.yml
vendored
Normal file
270
.github/workflows/build-and-publish.yml
vendored
Normal 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.
|
||||
248
.github/workflows/cmake-single-platform.yml
vendored
248
.github/workflows/cmake-single-platform.yml
vendored
@@ -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 }}"
|
||||
10
.github/workflows/publish-docs.yml
vendored
10
.github/workflows/publish-docs.yml
vendored
@@ -23,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
|
||||
|
||||
@@ -35,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
1343
CHANGELOG.md
Normal file
File diff suppressed because it is too large
Load Diff
@@ -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
1
GitVersion.yml
Normal file
@@ -0,0 +1 @@
|
||||
workflow: GitHubFlow/v1
|
||||
84
cliff.toml
Normal file
84
cliff.toml
Normal 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]+"
|
||||
@@ -153,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",
|
||||
@@ -266,4 +273,4 @@
|
||||
"linux": 584
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
Submodule libraries/Protobufs updated: b46090af9c...3d85413bf7
Submodule libraries/hl2sdk-cs2 updated: a658a0f7ef...a26ca82e87
@@ -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
@@ -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();
|
||||
@@ -768,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();
|
||||
@@ -1160,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();
|
||||
|
||||
@@ -0,0 +1,9 @@
|
||||
using System;
|
||||
|
||||
namespace CounterStrikeSharp.API.Core.Attributes.Registration;
|
||||
|
||||
[AttributeUsage(AttributeTargets.Method)]
|
||||
public class ListenerHandlerAttribute<T> : Attribute
|
||||
where T: Delegate
|
||||
{
|
||||
}
|
||||
@@ -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]);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -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")]
|
||||
|
||||
@@ -170,5 +170,11 @@ namespace CounterStrikeSharp.API.Core
|
||||
/// <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();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -50,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);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -347,4 +347,9 @@ public partial class CCSPlayerController
|
||||
{
|
||||
base.Teleport(position, angles, velocity);
|
||||
}
|
||||
|
||||
public void ReplicateConVar(string conVar, string value)
|
||||
{
|
||||
NativeAPI.ReplicateConvar(Slot, conVar, value);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -96,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")]
|
||||
|
||||
@@ -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");
|
||||
|
||||
@@ -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")]
|
||||
|
||||
@@ -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")]
|
||||
|
||||
@@ -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");
|
||||
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -178,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");
|
||||
|
||||
@@ -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")]
|
||||
|
||||
@@ -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");
|
||||
|
||||
}
|
||||
|
||||
@@ -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")]
|
||||
|
||||
@@ -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")]
|
||||
|
||||
@@ -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")]
|
||||
|
||||
@@ -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");
|
||||
|
||||
}
|
||||
|
||||
@@ -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")]
|
||||
|
||||
@@ -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")]
|
||||
|
||||
@@ -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")]
|
||||
|
||||
@@ -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); }
|
||||
|
||||
@@ -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")]
|
||||
|
||||
@@ -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>
|
||||
|
||||
@@ -36,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;
|
||||
}
|
||||
@@ -50,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;
|
||||
@@ -101,10 +101,9 @@ public class Target
|
||||
TargetType.GroupNotMe => player.SteamID != caller?.SteamID,
|
||||
TargetType.PlayerMe => player.SteamID == caller?.SteamID,
|
||||
TargetType.IdUserid => player.UserId.ToString() == Slug,
|
||||
TargetType.IdSteamEscaped => ((SteamID)player.SteamID).SteamId2 == Slug,
|
||||
TargetType.IdSteam64 => ((SteamID)player.SteamID).SteamId64.ToString() == Slug,
|
||||
TargetType.ExplicitName => player.PlayerName.Contains(Slug, StringComparison.OrdinalIgnoreCase),
|
||||
TargetType.ImplicitName => player.PlayerName.Contains(Slug, StringComparison.OrdinalIgnoreCase),
|
||||
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
|
||||
};
|
||||
}
|
||||
|
||||
@@ -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();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,16 +1,14 @@
|
||||
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
|
||||
{
|
||||
private static readonly JsonSerializerOptions _jsonSerializerOptions = new()
|
||||
{
|
||||
WriteIndented = true
|
||||
};
|
||||
|
||||
public static JsonSerializerOptions JsonSerializerOptions => _jsonSerializerOptions;
|
||||
public static JsonSerializerOptions JsonSerializerOptions => ConfigManager.JsonSerializerOptions;
|
||||
|
||||
/// <summary>
|
||||
/// Gets the configuration file path
|
||||
@@ -20,7 +18,24 @@ public static class PluginConfigExtensions
|
||||
public static string GetConfigPath<T>(this T _) where T : BasePluginConfig, new()
|
||||
{
|
||||
string assemblyName = typeof(T).Assembly.GetName().Name ?? string.Empty;
|
||||
return Path.Combine(Server.GameDirectory, "csgo", "addons", "counterstrikesharp", "configs", "plugins", assemblyName, $"{assemblyName}.json");
|
||||
|
||||
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>
|
||||
@@ -36,7 +51,22 @@ public static class PluginConfigExtensions
|
||||
{
|
||||
using var stream = new FileStream(configPath, FileMode.Create, FileAccess.Write, FileShare.None);
|
||||
using var writer = new StreamWriter(stream);
|
||||
writer.Write(JsonSerializer.Serialize(config, JsonSerializerOptions));
|
||||
|
||||
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)
|
||||
{
|
||||
@@ -62,8 +92,22 @@ public static class PluginConfigExtensions
|
||||
|
||||
var configContent = File.ReadAllText(configPath);
|
||||
|
||||
var newConfig = JsonSerializer.Deserialize<T>(configContent)
|
||||
?? throw new JsonException($"Deserialization failed for configuration file '{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))
|
||||
{
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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}");
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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("}");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -7614,13 +7614,6 @@
|
||||
"name": "bool"
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "m_bAutoKickDisabled",
|
||||
"type": {
|
||||
"category": 0,
|
||||
"name": "bool"
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "m_bIsLowViolence",
|
||||
"type": {
|
||||
@@ -13300,6 +13293,13 @@
|
||||
"name": "bool"
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "m_ullLocalMatchID",
|
||||
"type": {
|
||||
"category": 0,
|
||||
"name": "uint64"
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "m_nEndMatchMapGroupVoteTypes",
|
||||
"type": {
|
||||
@@ -14660,6 +14660,13 @@
|
||||
"name": "uint32"
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "m_eNetworkDisconnectionReason",
|
||||
"type": {
|
||||
"category": 0,
|
||||
"name": "uint32"
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "m_bCannotBeKicked",
|
||||
"type": {
|
||||
@@ -110629,4 +110636,4 @@
|
||||
]
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -4,6 +4,7 @@ namespace CounterStrikeSharp.SchemaGen;
|
||||
|
||||
public partial record SchemaClass(
|
||||
int Index,
|
||||
string Name,
|
||||
string? Parent,
|
||||
IReadOnlyList<SchemaField> Fields)
|
||||
{
|
||||
|
||||
@@ -146,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}");
|
||||
@@ -392,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)
|
||||
{
|
||||
|
||||
@@ -143,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
|
||||
|
||||
@@ -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()
|
||||
{
|
||||
|
||||
@@ -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>
|
||||
@@ -72,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);
|
||||
@@ -265,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
|
||||
|
||||
@@ -137,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
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
@@ -134,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,
|
||||
@@ -182,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;
|
||||
}
|
||||
@@ -191,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)
|
||||
|
||||
@@ -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();
|
||||
|
||||
1
src/scripting/listeners/metamod.yaml
Normal file
1
src/scripting/listeners/metamod.yaml
Normal file
@@ -0,0 +1 @@
|
||||
OnMetamodAllPluginsLoaded:
|
||||
@@ -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
|
||||
|
||||
@@ -12,4 +12,5 @@ ISSUE_CLIENT_COMMAND_FROM_SERVER: slot:int,command:string -> void
|
||||
FIND_CONVAR: name:string -> pointer
|
||||
SET_CONVAR_STRING_VALUE: convar:pointer,value:string -> void
|
||||
GET_CLIENT_CONVAR_VALUE: clientIndex:int,convarName:string -> string
|
||||
SET_FAKE_CLIENT_CONVAR_VALUE: clientIndex:int,convarName:string,convarValue:string -> void
|
||||
SET_FAKE_CLIENT_CONVAR_VALUE: clientIndex:int,convarName:string,convarValue:string -> void
|
||||
REPLICATE_CONVAR: clientSlot:int,convarName:string,convarValue:string -> void
|
||||
|
||||
@@ -23,6 +23,7 @@
|
||||
#include "core/managers/entity_manager.h"
|
||||
#include "core/managers/player_manager.h"
|
||||
#include "core/memory.h"
|
||||
#include "core/recipientfilters.h"
|
||||
#include "scripting/autonative.h"
|
||||
#include "scripting/script_engine.h"
|
||||
|
||||
@@ -256,6 +257,21 @@ void AddEntityIOEvent(ScriptContext& script_context)
|
||||
CEntitySystem_AddEntityIOEvent(GameEntitySystem(), pTarget, pInputName, pActivator, pCaller, &_value, delay, outputID);
|
||||
}
|
||||
|
||||
SoundEventGuid_t EmitSoundFilter(ScriptContext& script_context)
|
||||
{
|
||||
auto filtermask = script_context.GetArgument<uint64>(0);
|
||||
auto ent = script_context.GetArgument<uint32>(1);
|
||||
auto sound = script_context.GetArgument<const char*>(2);
|
||||
auto volume = script_context.GetArgument<float>(3);
|
||||
auto pitch = script_context.GetArgument<float>(4);
|
||||
|
||||
CRecipientFilter filter{};
|
||||
filter.AddRecipientsFromMask(filtermask);
|
||||
|
||||
SndOpEventGuid_t ret = EntityEmitSoundFilter(filter, ent, sound, volume, pitch);
|
||||
return ret.m_nGuid;
|
||||
}
|
||||
|
||||
REGISTER_NATIVES(entities, {
|
||||
ScriptEngine::RegisterNativeHandler("GET_ENTITY_FROM_INDEX", GetEntityFromIndex);
|
||||
ScriptEngine::RegisterNativeHandler("GET_USERID_FROM_INDEX", GetUserIdFromIndex);
|
||||
@@ -273,5 +289,6 @@ REGISTER_NATIVES(entities, {
|
||||
ScriptEngine::RegisterNativeHandler("UNHOOK_ENTITY_OUTPUT", UnhookEntityOutput);
|
||||
ScriptEngine::RegisterNativeHandler("ACCEPT_INPUT", AcceptInput);
|
||||
ScriptEngine::RegisterNativeHandler("ADD_ENTITY_IO_EVENT", AddEntityIOEvent);
|
||||
ScriptEngine::RegisterNativeHandler("EMIT_SOUND_FILTER", EmitSoundFilter);
|
||||
})
|
||||
} // namespace counterstrikesharp
|
||||
|
||||
@@ -14,3 +14,4 @@ HOOK_ENTITY_OUTPUT: classname:string, outputName:string, callback:func, mode:Hoo
|
||||
UNHOOK_ENTITY_OUTPUT: classname:string, outputName:string, callback:func, mode:HookMode -> void
|
||||
ACCEPT_INPUT: pThis:pointer, inputName:string, activator:pointer, caller:pointer, value:string, outputID:int -> void
|
||||
ADD_ENTITY_IO_EVENT: pTarget:pointer, inputName:string, activator:pointer, caller:pointer, value:string, delay:float, outputID:int -> void
|
||||
EMIT_SOUND_FILTER: filtermask:uint64, ent:uint, sound:string, volume:float, pitch:float -> uint
|
||||
|
||||
@@ -17,11 +17,11 @@
|
||||
#include <ios>
|
||||
#include <sstream>
|
||||
|
||||
#include "scripting/autonative.h"
|
||||
#include "core/function.h"
|
||||
#include "scripting/script_engine.h"
|
||||
#include "core/memory.h"
|
||||
#include "core/log.h"
|
||||
#include "core/memory.h"
|
||||
#include "scripting/autonative.h"
|
||||
#include "scripting/script_engine.h"
|
||||
|
||||
namespace counterstrikesharp {
|
||||
std::vector<ValveFunction*> m_managed_ptrs;
|
||||
@@ -44,21 +44,22 @@ ValveFunction* CreateVirtualFunctionBySignature(ScriptContext& script_context)
|
||||
|
||||
auto* function_addr = FindSignature(binary_name, signature_hex_string);
|
||||
|
||||
if (function_addr == nullptr) {
|
||||
if (function_addr == nullptr)
|
||||
{
|
||||
script_context.ThrowNativeError("Could not find signature %s", signature_hex_string);
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
auto args = std::vector<DataType_t>();
|
||||
for (int i = 0; i < num_arguments; i++) {
|
||||
for (int i = 0; i < num_arguments; i++)
|
||||
{
|
||||
args.push_back(script_context.GetArgument<DataType_t>(5 + i));
|
||||
}
|
||||
|
||||
auto function = new ValveFunction(function_addr, CONV_CDECL, args, return_type);
|
||||
function->SetSignature(signature_hex_string);
|
||||
|
||||
CSSHARP_CORE_TRACE("Created virtual function, pointer found at {}, signature {}", function_addr,
|
||||
signature_hex_string);
|
||||
CSSHARP_CORE_TRACE("Created virtual function, pointer found at {}, signature {}", function_addr, signature_hex_string);
|
||||
|
||||
m_managed_ptrs.push_back(function);
|
||||
return function;
|
||||
@@ -72,7 +73,8 @@ ValveFunction* CreateVirtualFunction(ScriptContext& script_context)
|
||||
auto return_type = script_context.GetArgument<DataType_t>(3);
|
||||
|
||||
void** vtable = *(void***)ptr;
|
||||
if (!vtable) {
|
||||
if (!vtable)
|
||||
{
|
||||
script_context.ThrowNativeError("Failed to get the virtual function table.");
|
||||
return nullptr;
|
||||
}
|
||||
@@ -80,7 +82,8 @@ ValveFunction* CreateVirtualFunction(ScriptContext& script_context)
|
||||
auto function_addr = (void*)vtable[vtable_offset];
|
||||
|
||||
auto args = std::vector<DataType_t>();
|
||||
for (int i = 0; i < num_arguments; i++) {
|
||||
for (int i = 0; i < num_arguments; i++)
|
||||
{
|
||||
args.push_back(script_context.GetArgument<DataType_t>(4 + i));
|
||||
}
|
||||
|
||||
@@ -97,7 +100,8 @@ void HookFunction(ScriptContext& script_context)
|
||||
auto callback = script_context.GetArgument<CallbackT>(1);
|
||||
auto post = script_context.GetArgument<bool>(2);
|
||||
|
||||
if (!function) {
|
||||
if (!function)
|
||||
{
|
||||
script_context.ThrowNativeError("Invalid function pointer");
|
||||
return;
|
||||
}
|
||||
@@ -111,7 +115,8 @@ void UnhookFunction(ScriptContext& script_context)
|
||||
auto callback = script_context.GetArgument<CallbackT>(1);
|
||||
auto post = script_context.GetArgument<bool>(2);
|
||||
|
||||
if (!function) {
|
||||
if (!function)
|
||||
{
|
||||
script_context.ThrowNativeError("Invalid function pointer");
|
||||
return;
|
||||
}
|
||||
@@ -123,7 +128,8 @@ void ExecuteVirtualFunction(ScriptContext& script_context)
|
||||
{
|
||||
auto function = script_context.GetArgument<ValveFunction*>(0);
|
||||
|
||||
if (!function) {
|
||||
if (!function)
|
||||
{
|
||||
script_context.ThrowNativeError("Invalid function pointer");
|
||||
return;
|
||||
}
|
||||
@@ -155,8 +161,7 @@ void RemoveAllNetworkVectorElements(ScriptContext& script_context)
|
||||
|
||||
REGISTER_NATIVES(memory, {
|
||||
ScriptEngine::RegisterNativeHandler("CREATE_VIRTUAL_FUNCTION", CreateVirtualFunction);
|
||||
ScriptEngine::RegisterNativeHandler("CREATE_VIRTUAL_FUNCTION_BY_SIGNATURE",
|
||||
CreateVirtualFunctionBySignature);
|
||||
ScriptEngine::RegisterNativeHandler("CREATE_VIRTUAL_FUNCTION_BY_SIGNATURE", CreateVirtualFunctionBySignature);
|
||||
ScriptEngine::RegisterNativeHandler("EXECUTE_VIRTUAL_FUNCTION", ExecuteVirtualFunction);
|
||||
ScriptEngine::RegisterNativeHandler("HOOK_FUNCTION", HookFunction);
|
||||
ScriptEngine::RegisterNativeHandler("UNHOOK_FUNCTION", UnhookFunction);
|
||||
|
||||
32
src/scripting/natives/natives_metamod.cpp
Normal file
32
src/scripting/natives/natives_metamod.cpp
Normal 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/>. *
|
||||
*/
|
||||
|
||||
#include <scripting/autonative.h>
|
||||
#include <scripting/script_engine.h>
|
||||
|
||||
namespace counterstrikesharp {
|
||||
|
||||
static void* MetaFactory(ScriptContext& script_context)
|
||||
{
|
||||
auto interfaceName = script_context.GetArgument<const char*>(0);
|
||||
void* ptr = globals::ismm->MetaFactory(interfaceName, nullptr, nullptr);
|
||||
return ptr;
|
||||
}
|
||||
|
||||
REGISTER_NATIVES(metamod, {
|
||||
ScriptEngine::RegisterNativeHandler("META_FACTORY", MetaFactory);
|
||||
})
|
||||
} // namespace counterstrikesharp
|
||||
1
src/scripting/natives/natives_metamod.yaml
Normal file
1
src/scripting/natives/natives_metamod.yaml
Normal file
@@ -0,0 +1 @@
|
||||
META_FACTORY: interfaceName:string -> pointer
|
||||
@@ -61,8 +61,8 @@ public partial class Generators
|
||||
|
||||
private static List<string> GameEventFiles = new List<string>()
|
||||
{
|
||||
"game/core/pak01_dir/resource/core.gameevents",
|
||||
"game/csgo/pak01_dir/resource/game.gameevents",
|
||||
"game/core/pak01_dir/resource/core.gameevents",
|
||||
"game/csgo/pak01_dir/resource/mod.gameevents"
|
||||
};
|
||||
|
||||
|
||||
Reference in New Issue
Block a user