Compare commits

...

80 Commits

Author SHA1 Message Date
Yarukon
a87bd25b48 Improve Teleport Function (#513) 2024-06-27 23:51:57 +10:00
Michael Wilson
9c5468e5ba fix: bad vector natives (closes #512) 2024-06-27 03:58:21 +00:00
Michael Wilson
f826be664f [no ci] Add Linux Dev Container (#448) 2024-06-27 13:52:14 +10:00
Michael Wilson
7f5103d9ee Add Basic VPROF Budgets, Add Con Command Unlocker to Core (#505) 2024-06-17 21:08:05 +10:00
dependabot[bot]
877b7c5a4a chore(deps): bump libraries/hl2sdk-cs2 from 4202f1c to 4b31db7 (#496)
Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
Co-authored-by: Michael Wilson <roflmuffin@users.noreply.github.com>
2024-06-17 08:35:54 +00:00
WidovV
24363d6352 [no ci] Change example command prefix to follow "best practice" (#503) 2024-06-17 18:25:13 +10:00
Yarukon
2eaf7c2d8c Fix AddResource offset for Linux (#479) 2024-06-13 22:27:34 +10:00
dependabot[bot]
8b486ecf7e chore(deps): bump libraries/hl2sdk-cs2 from 739c88f to 4202f1c (#494)
Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
Co-authored-by: Roflmuffin <shortguy014@gmail.com>
2024-06-13 22:26:50 +10:00
StefanX
54cc93e0f8 fix: CBasePlayerController_SetPawn signature (#493) 2024-06-13 21:55:33 +10:00
Michael Wilson
a695eec4fa Revert "fix: improve error handling if globals are accessed before ready"
This reverts commit e207be2fbf.
2024-05-31 20:06:26 +10:00
Roflmuffin
e207be2fbf fix: improve error handling if globals are accessed before ready 2024-05-31 12:51:48 +10:00
Nukoooo
eea64519a6 Update `GiveNamedItem` signature for linux (#470) 2024-05-31 08:49:03 +10:00
Ian Lucas
13ec19e412 Update GiveNamedItem signature on Linux (#467) 2024-05-30 14:19:50 +10:00
Ian Lucas
3240a5e582 Update GiveNamedItem signature on Linux (#463) 2024-05-26 10:29:41 +10:00
Michael Wilson
cafc4e237f Initial update after 2024-05-23 CS2 update (#461) 2024-05-25 18:50:09 +10:00
dependabot[bot]
02d5191e74 chore(deps): bump libraries/hl2sdk-cs2 from f7ed6a0 to 36dd2db (#452)
Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
Co-authored-by: roflmuffin <shortguy014@gmail.com>
2024-05-10 11:50:41 +10:00
dependabot[bot]
aec696abc0 chore(deps): bump libraries/hl2sdk-cs2 from 9ddef9a to f7ed6a0 (#451)
Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2024-05-09 00:43:54 +10:00
Roflmuffin
c01aeec14b [no ci] chore: fix dependabot prefix 2024-05-08 20:13:19 +10:00
dependabot[bot]
41e7bee85a chore(deps): update hl2sdk: bump libraries/metamod-source from e857fbe to 607301a (#450)
Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2024-05-08 20:10:01 +10:00
Roflmuffin
9834271956 [no ci] chore: add metamod source dependabot config 2024-05-08 19:59:53 +10:00
Michael Wilson
fb5967d102 Back to C++17 (#447) 2024-05-08 16:34:51 +10:00
dependabot[bot]
928bc3f74d chore(deps): update hl2sdk: bump libraries/hl2sdk-cs2 from 3fc8d0f to 9ddef9a (#446)
Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2024-05-08 15:27:48 +10:00
Roflmuffin
6a7d7dba4f [no ci] feat: add hl2sdk-cs2 dependabot 2024-05-08 14:30:51 +10:00
Roflmuffin
11e5e9972d fix: concommand crash when no description 2024-05-01 14:44:57 +10:00
Michael Wilson
9a221b4ebb chore: bump hl2sdk after update (#434) 2024-05-01 09:38:54 +10:00
Yarukon
e270bdfd44 AcceptInput changes (#433) 2024-05-01 01:12:25 +10:00
Michael Wilson
f591fe58d0 fix: add memoverride on windows, use correct MT flag (#431) 2024-04-30 17:40:25 +10:00
Roflmuffin
052cb4e14e chore: improve ccsplayercontroller helpers validity checks 2024-04-30 11:39:49 +10:00
Michael Wilson
bc3bec4aa8 feat: improve docs and add more null checking for handle accesses (#417) 2024-04-30 11:20:47 +10:00
Roflmuffin
20bab7f4a8 feat: add PrintToCenterAlert player helper 2024-04-29 20:14:58 +10:00
Roflmuffin
c7eac71109 feat: add generic math operators to Vector 2024-04-29 00:56:00 +10:00
Roflmuffin
e3d2370e2e chore: use IDA style sigs for gamedata 2024-04-28 13:57:07 +10:00
Roflmuffin
142242744c chore: update give named item sig for linux 2024-04-28 09:44:51 +10:00
Nukoooo
0eebffd860 Copy bytes of a module to prevent signature scanning failures and some minor changes (#414)
Co-authored-by: Michael Wilson <roflmuffin@users.noreply.github.com>
2024-04-27 10:44:42 +00:00
Michael Wilson
25ca5dbe0c chore: use offsets for give named item (#427) 2024-04-27 19:56:07 +10:00
Nexd
7cae4be96d Fix: new game update broke signatures (#425)
Co-authored-by: KillStr3aK <KillStr3aK@users.noreply.github.com>
Co-authored-by: Roflmuffin <shortguy014@gmail.com>
2024-04-26 16:29:38 +10:00
Nexd
83bc1a95fb Make shared type loader less strict (#424)
Co-authored-by: KillStr3aK <KillStr3aK@users.noreply.github.com>
2024-04-26 10:26:39 +10:00
roflmuffin
71c694b52e [no ci] add windows install script 2024-04-14 13:25:43 +10:00
Michael Wilson
a452d79ba3 [no ci] feat: add install script 2024-04-14 12:58:24 +10:00
Nukoooo
dfc9859806 Make signature support IDA/x64Dbg style (#407)
Co-authored-by: Michael Wilson <roflmuffin@users.noreply.github.com>
2024-04-13 12:11:26 +10:00
Nukoooo
f99f58402a Add mising `GameData.GetSignature to NetworkStateChangedFunc` (#415) 2024-04-13 11:00:51 +10:00
Michael Wilson
6317559bd2 [no ci] Update .clang-format & add formatting tool install scripts (#410) 2024-04-12 12:36:39 +10:00
Michael Wilson
ad6e1ca2e2 chore: bump hl2sdk (#408) 2024-04-11 18:15:50 +10:00
Michael Wilson
2564ef9f39 fix: fix startup server listener 2024-04-11 16:14:16 +10:00
Michael Wilson
83a341d3cf feat: expose TargetTypeMap 2024-04-11 15:34:01 +10:00
Michael Wilson
534fc42444 fix: bad commit 2024-04-11 14:26:21 +10:00
Michael Wilson
41355d05fa docs: add more comments to base plugin 2024-04-11 14:20:24 +10:00
luxury fabka
d9da15be83 Add teleport overloads (#399)
Co-authored-by: Michael Wilson <roflmuffin@users.noreply.github.com>
2024-04-11 00:48:55 +00:00
B3none
75e2f6e8aa [no ci] Rename ACKNOWLEDGEMENTS to ACKNOWLEDGEMENTS.md (#401) 2024-04-10 16:34:15 +10:00
Michael Wilson
37b34e1d41 [no ci] add basic contributing guide 2024-04-08 10:02:18 +10:00
WidovV
5ce04649fd Add CenterHtmlMenu button colors (#398) 2024-04-06 21:43:38 +10:00
Michael Wilson
7b7202fe8a [no ci] Update README.md 2024-04-05 11:54:53 +10:00
Michael Wilson
cadb817ed2 fix: mark center html menu constructor as obsolete, throw error (#396) 2024-04-04 09:33:22 +10:00
luxury fabka
211516cce5 added Open method to each menu type (#385)
Co-authored-by: Michael Wilson <roflmuffin@users.noreply.github.com>
Co-authored-by: Roflmuffin <shortguy014@gmail.com>
2024-04-01 18:04:12 +10:00
Roflmuffin
ab211a42e6 [skip ci] chore: update ApiCompat to v202, disable suppression file 2024-03-26 12:46:42 +10:00
Roflmuffin
696ecadee4 fix: bad vector math 2024-03-26 12:16:53 +10:00
Roflmuffin
e4d598dba8 fix: main version number 2024-03-25 17:15:31 +10:00
Michael Wilson
5c67d88844 feat: improve version stamping (#389) 2024-03-25 17:11:16 +10:00
Michael Wilson
9d8b6beae6 .NET8 Upgrade (#261)
Co-authored-by: Frederik St-Onge <frederik.stonge@gmail.com>
Co-authored-by: B3none <24966460+B3none@users.noreply.github.com>
2024-03-25 14:16:32 +10:00
ipsvn
39604b7ad7 Fix backwards compatibility in DynamicHook (#388) 2024-03-22 23:04:09 +10:00
luxury fabka
1b1f1d04dd minor menu changes (#373)
Co-authored-by: Michael Wilson <roflmuffin@users.noreply.github.com>
Co-authored-by: Roflmuffin <shortguy014@gmail.com>
2024-03-18 05:00:31 +00:00
Ian Lucas
dbc348c1bf Add RemoveAll method to NetworkedVector class (#380) 2024-03-18 14:56:29 +10:00
Michael Wilson
d295589c44 fix: update collision groups (#376) 2024-03-13 16:10:42 +10:00
Michael Wilson
16767fd494 feat: add Server.RunOnTick method which allows tick scheduling (#374) 2024-03-11 23:08:54 +10:00
roflmuffin
36a97bfffd fix: disable autoload plugin but allow shared library loading 2024-03-09 15:29:45 +10:00
roflmuffin
178f7472c6 feat: add PluginAutoLoadEnabled config option
closes #370
2024-03-09 14:29:43 +10:00
luxury fabka
cba5144bbf remove unused arguments (#334)
Co-authored-by: Michael Wilson <roflmuffin@users.noreply.github.com>
2024-03-08 05:08:33 +00:00
roflmuffin
0de951cb6f fix: allows game events to be freed, frees event in print to center html
closes #346
2024-03-08 10:39:59 +10:00
Michael Wilson
c3d44a87bc feat: use concurrent queue for next frame & world update tasks (#365) 2024-03-06 21:08:22 +10:00
B3none
bd3c0c76e3 [no ci] Update minimum api version for shared api docs (#364) 2024-03-06 15:42:34 +10:00
Yarukon
656c0e3a84 Fix TerminateRound params (#363) 2024-03-04 10:59:02 +00:00
Michael Wilson
40c842149c fix: add error handling to OnAllPluginsLoaded 2024-03-04 17:21:50 +10:00
roflmuffin
64d1c0a9f4 chore: remove erroneous log 2024-03-04 16:56:49 +10:00
roflmuffin
a6de51c444 fix: use concurrent dictionary for function reference 2024-03-04 13:41:18 +10:00
roflmuffin
2535ac0575 feat: add assembly name lazy loading of shared libraries 2024-03-04 12:15:37 +10:00
Michael Wilson
bc61323315 chore: migrate to protobufs submodule (#362) 2024-03-04 10:48:52 +10:00
roflmuffin
241817b7f2 feat: update game events dump from Feb 14 update 2024-03-04 10:34:58 +10:00
BuSheeZy
fbcdce34fc fix: allow empty overrides to skip checks (#357)
Co-authored-by: Michael Wilson <roflmuffin@users.noreply.github.com>
2024-03-04 00:13:17 +00:00
Michael Wilson
daf0d25f36 Shared Plugin APIs/Capabilities (#253)
Co-authored-by: B3none <ablackham2000@gmail.com>
Co-authored-by: B3none <24966460+B3none@users.noreply.github.com>
2024-03-04 09:45:34 +10:00
Yarukon
12485be29f Adding the proper way to do resource precache (#358) 2024-03-02 15:10:37 +10:00
261 changed files with 112109 additions and 107835 deletions

View File

@@ -1,21 +1,72 @@
BasedOnStyle: LLVM
# Spacing
IndentWidth: 4
ColumnLimit: 100
UseTab: Never
ColumnLimit: 140
# Line Endings
LineEnding: LF
InsertNewlineAtEOF: true
DerivePointerAlignment: false
PointerAlignment: Left
AlignAfterOpenBracket: Align
KeepEmptyLinesAtTheStartOfBlocks: false
SortIncludes: false
SpaceBeforeParens: ControlStatements
AllowAllArgumentsOnNextLine: true
AllowShortIfStatementsOnASingleLine: false
IndentCaseLabels: false
IndentCaseLabels: true
# Line Breaks
BreakBeforeBraces: Custom
BraceWrapping:
AfterCaseLabel: true
AfterClass: true
AfterStruct: true
AfterControlStatement: Always
AfterEnum: true
AfterUnion: true
AfterNamespace: false
AfterFunction: true
AfterNamespace: false
AfterStruct: true
AfterUnion: true
AfterExternBlock: true
BeforeCatch: true
BeforeElse: true
BeforeLambdaBody: false
BeforeWhile: false
IndentBraces: false
SplitEmptyFunction: true
SplitEmptyRecord: true
SplitEmptyNamespace: true
PointerAlignment: Left
SortIncludes: CaseSensitive
IncludeBlocks: Regroup
IncludeCategories:
# External headers in <> with extension or /
- Regex: '<[-\w\/-_]+[\.\/][-\w\/-_]+>'
Priority: 2
# Standard headers in <>
- Regex: '<[-\w\/-_]+>'
Priority: 3
# Local headers in ""
- Regex: '"[-\w\/-_]*"'
Priority: 4
ReflowComments: true
CompactNamespaces: false
Cpp11BracedListStyle: false
AlignConsecutiveMacros:
Enabled: true
AcrossEmptyLines: false
AcrossComments: false
AlignEscapedNewlines: Left
AlignTrailingComments: Never
AllowShortBlocksOnASingleLine: Empty
AllowShortIfStatementsOnASingleLine: OnlyFirstIf
AllowShortLambdasOnASingleLine: Empty
BinPackArguments: true
BinPackParameters: false
LambdaBodyIndentation: OuterScope

View File

@@ -0,0 +1,11 @@
{
"name": "SteamRT Sniper SDK",
"image": "registry.gitlab.steamos.cloud/steamrt/sniper/sdk:latest",
"customizations": {
"vscode": {
"extensions": [
"ms-vscode.cpptools"
]
}
}
}

14
.editorconfig Normal file
View File

@@ -0,0 +1,14 @@
# top-most EditorConfig file
root = true
# Unix-style newlines with a newline ending every file
[*]
end_of_line = lf
insert_final_newline = true
indent_style = space
indent_size = 4
max_line_length = 140
trim_trailing_whitespace = true
[{*.json,*.yaml,*.yml}]
indent_size = 2

12
.github/dependabot.yaml vendored Normal file
View File

@@ -0,0 +1,12 @@
version: 2
updates:
# Update the submodule in libraries/hl2sdk-cs2 every day
- package-ecosystem: "gitsubmodule"
directory: "/"
allow:
- dependency-name: "libraries/hl2sdk-cs2"
- dependency-name: "libraries/metamod-source"
schedule:
interval: "daily"
commit-message:
prefix: "chore(deps)"

View File

@@ -3,22 +3,46 @@ name: Build & Publish
on:
push:
paths-ignore:
- 'docfx/**'
branches: [ "main", "dev" ]
- "docfx/**"
branches: ["main", "dev"]
pull_request:
branches: [ "main", "dev" ]
branches: ["main", "dev"]
env:
BUILD_TYPE: Release
jobs:
setup:
permissions:
contents: write
runs-on: ubuntu-latest
outputs:
buildnumber: ${{ steps.buildnumber.outputs.build_number }}
steps:
- name: Generate build number
if: ${{ github.event_name == 'push' && github.ref == 'refs/heads/main' }}
id: buildnumber
uses: onyxmueller/build-tag-number@v1
with:
token: ${{secrets.github_token}}
build_windows:
needs: setup
runs-on: windows-latest
steps:
- name: Prepare env
shell: bash
run: echo "GITHUB_SHA_SHORT=${GITHUB_SHA::7}" >> $GITHUB_ENV
- name: Fallback build number
if: ${{ github.event_name == 'pull_request' || github.ref != 'refs/heads/main' }}
shell: bash
run: echo "BUILD_NUMBER=0" >> $GITHUB_ENV
- name: Main build number
if: ${{ github.event_name == 'push' && github.ref == 'refs/heads/main' }}
run: echo "BUILD_NUMBER=${{ needs.setup.outputs.buildnumber }}" >> $GITHUB_ENV
- name: Visual Studio environment
shell: cmd
run: |
@@ -34,7 +58,7 @@ jobs:
- uses: actions/checkout@v3
with:
submodules: 'recursive'
submodules: "recursive"
- name: Build
run: |
@@ -56,6 +80,7 @@ jobs:
path: build/output/
build_linux:
needs: setup
runs-on: ubuntu-latest
# Could not figure out how to run in a container only on some matrix paths, so I've split it out into its own build.
container:
@@ -65,9 +90,18 @@ jobs:
shell: bash
run: echo "GITHUB_SHA_SHORT=${GITHUB_SHA::7}" >> $GITHUB_ENV
- name: Fallback build number
if: ${{ github.event_name == 'pull_request' || github.ref != 'refs/heads/main' }}
shell: bash
run: echo "BUILD_NUMBER=0" >> $GITHUB_ENV
- name: Main build number
if: ${{ github.event_name == 'push' && github.ref == 'refs/heads/main' }}
run: echo "BUILD_NUMBER=${{ needs.setup.outputs.buildnumber }}" >> $GITHUB_ENV
- uses: actions/checkout@v3
with:
submodules: 'recursive'
submodules: "recursive"
- name: Build
run: |
@@ -87,11 +121,10 @@ jobs:
path: build/output/
build_managed:
needs: setup
permissions:
contents: write
runs-on: ubuntu-latest
outputs:
buildnumber: ${{ steps.buildnumber.outputs.build_number }}
steps:
- name: Prepare env
shell: bash
@@ -102,20 +135,17 @@ jobs:
shell: bash
run: echo "BUILD_NUMBER=0" >> $GITHUB_ENV
- name: Main build number
if: ${{ github.event_name == 'push' && github.ref == 'refs/heads/main' }}
run: echo "BUILD_NUMBER=${{ needs.setup.outputs.buildnumber }}" >> $GITHUB_ENV
# We don't need expensive submodules for the managed side.
- uses: actions/checkout@v3
- name: Generate build number
if: ${{ github.event_name == 'push' && github.ref == 'refs/heads/main' }}
id: buildnumber
uses: onyxmueller/build-tag-number@v1
with:
token: ${{secrets.github_token}}
- name: Build runtime v${{ env.BUILD_NUMBER }}
uses: actions/setup-dotnet@v3
with:
dotnet-version: '7.0.x'
dotnet-version: "8.0.x"
- name: Install dependencies
run: dotnet restore managed/CounterStrikeSharp.sln
@@ -133,7 +163,7 @@ jobs:
- name: Publish artifacts
run: |
dotnet publish -c Release /p:Version=1.0.${{ env.BUILD_NUMBER }} managed/CounterStrikeSharp.API
dotnet pack -c Release /p:Version=1.0.${{ env.BUILD_NUMBER }} managed/CounterStrikeSharp.API
dotnet pack -c Release /p:Version=1.0.${{ env.BUILD_NUMBER }} managed/CounterStrikeSharp.API
- uses: actions/upload-artifact@v3
with:
@@ -144,7 +174,7 @@ jobs:
if: ${{ github.event_name == 'push' && github.ref == 'refs/heads/main' }}
permissions:
contents: write
needs: [ "build_linux", "build_windows", "build_managed" ]
needs: ["setup", "build_linux", "build_windows", "build_managed"]
runs-on: ubuntu-latest
steps:
- name: Prepare env
@@ -171,49 +201,48 @@ jobs:
run: |
mkdir -p build/linux/addons/counterstrikesharp/api
mkdir -p build/windows/addons/counterstrikesharp/api
cp -r build/api/net7.0/publish/* build/linux/addons/counterstrikesharp/api
cp -r build/api/net7.0/publish/* build/windows/addons/counterstrikesharp/api
cp -r build/api/net8.0/publish/* build/linux/addons/counterstrikesharp/api
cp -r build/api/net8.0/publish/* build/windows/addons/counterstrikesharp/api
- name: Zip Builds
run: |
(cd build/linux && zip -qq -r ../../counterstrikesharp-build-${{ needs.build_managed.outputs.buildnumber }}-linux-${{ env.GITHUB_SHA_SHORT }}.zip *)
(cd build/windows && zip -qq -r ../../counterstrikesharp-build-${{ needs.build_managed.outputs.buildnumber }}-windows-${{ env.GITHUB_SHA_SHORT }}.zip *)
(cd build/linux && zip -qq -r ../../counterstrikesharp-build-${{ needs.setup.outputs.buildnumber }}-linux-${{ env.GITHUB_SHA_SHORT }}.zip *)
(cd build/windows && zip -qq -r ../../counterstrikesharp-build-${{ needs.setup.outputs.buildnumber }}-windows-${{ env.GITHUB_SHA_SHORT }}.zip *)
- name: Add dotnet runtime
run: |
mkdir -p build/linux/addons/counterstrikesharp/dotnet
curl -s -L https://download.visualstudio.microsoft.com/download/pr/dc2c0a53-85a8-4fda-a283-fa28adb5fbe2/8ccade5bc400a5bb40cd9240f003b45c/aspnetcore-runtime-7.0.11-linux-x64.tar.gz \
curl -s -L https://download.visualstudio.microsoft.com/download/pr/c1371dc2-eed2-47be-9af3-ae060dbe3c7d/bd509e0a87629764ed47608466d183e6/aspnetcore-runtime-8.0.3-linux-x64.tar.gz \
| tar xvz -C build/linux/addons/counterstrikesharp/dotnet
mv build/linux/addons/counterstrikesharp/dotnet/shared/Microsoft.NETCore.App/7.0.11/* build/linux/addons/counterstrikesharp/dotnet/shared/Microsoft.NETCore.App/
mkdir -p build/windows/addons/counterstrikesharp/dotnet
curl -s -L https://download.visualstudio.microsoft.com/download/pr/a99861c8-2e00-4587-aaef-60366ca77307/a44ceec2c5d34165ae881600f52edc43/aspnetcore-runtime-7.0.11-win-x64.zip -o dotnet.zip
curl -s -L https://download.visualstudio.microsoft.com/download/pr/086d1dd6-57a5-437a-a1ef-549cf702fb48/dd4a8fe6c53a1016a414d6f2925c1323/aspnetcore-runtime-8.0.3-win-x64.zip -o dotnet.zip
unzip -qq dotnet.zip -d build/windows/addons/counterstrikesharp/dotnet
- name: Zip Builds
run: |
(cd build/linux && zip -qq -r ../../counterstrikesharp-with-runtime-build-${{ needs.build_managed.outputs.buildnumber }}-linux-${{ env.GITHUB_SHA_SHORT }}.zip *)
(cd build/windows && zip -qq -r ../../counterstrikesharp-with-runtime-build-${{ needs.build_managed.outputs.buildnumber }}-windows-${{ env.GITHUB_SHA_SHORT }}.zip *)
(cd build/linux && zip -qq -r ../../counterstrikesharp-with-runtime-build-${{ needs.setup.outputs.buildnumber }}-linux-${{ env.GITHUB_SHA_SHORT }}.zip *)
(cd build/windows && zip -qq -r ../../counterstrikesharp-with-runtime-build-${{ needs.setup.outputs.buildnumber }}-windows-${{ env.GITHUB_SHA_SHORT }}.zip *)
- name: Release
id: release
uses: softprops/action-gh-release@v1
with:
tag_name: v${{ needs.build_managed.outputs.buildnumber }}
tag_name: v${{ needs.setup.outputs.buildnumber }}
files: |
counterstrikesharp-build-${{ needs.build_managed.outputs.buildnumber }}-windows-${{ env.GITHUB_SHA_SHORT }}.zip
counterstrikesharp-with-runtime-build-${{ needs.build_managed.outputs.buildnumber }}-windows-${{ env.GITHUB_SHA_SHORT }}.zip
counterstrikesharp-build-${{ needs.build_managed.outputs.buildnumber }}-linux-${{ env.GITHUB_SHA_SHORT }}.zip
counterstrikesharp-with-runtime-build-${{ needs.build_managed.outputs.buildnumber }}-linux-${{ env.GITHUB_SHA_SHORT }}.zip
counterstrikesharp-build-${{ needs.setup.outputs.buildnumber }}-windows-${{ env.GITHUB_SHA_SHORT }}.zip
counterstrikesharp-with-runtime-build-${{ needs.setup.outputs.buildnumber }}-windows-${{ env.GITHUB_SHA_SHORT }}.zip
counterstrikesharp-build-${{ needs.setup.outputs.buildnumber }}-linux-${{ env.GITHUB_SHA_SHORT }}.zip
counterstrikesharp-with-runtime-build-${{ needs.setup.outputs.buildnumber }}-linux-${{ env.GITHUB_SHA_SHORT }}.zip
- name: Publish NuGet package
run: |
dotnet nuget push build/api/CounterStrikeSharp.API.1.0.${{ needs.build_managed.outputs.buildnumber }}.nupkg --api-key ${{ secrets.NUGET_API_KEY }} --source https://api.nuget.org/v3/index.json --skip-duplicate
dotnet nuget push build/api/CounterStrikeSharp.API.1.0.${{ needs.build_managed.outputs.buildnumber }}.snupkg --api-key ${{ secrets.NUGET_API_KEY }} --source https://api.nuget.org/v3/index.json --skip-duplicate
dotnet nuget push build/api/CounterStrikeSharp.API.1.0.${{ needs.setup.outputs.buildnumber }}.nupkg --api-key ${{ secrets.NUGET_API_KEY }} --source https://api.nuget.org/v3/index.json --skip-duplicate
dotnet nuget push build/api/CounterStrikeSharp.API.1.0.${{ needs.setup.outputs.buildnumber }}.snupkg --api-key ${{ secrets.NUGET_API_KEY }} --source https://api.nuget.org/v3/index.json --skip-duplicate
- name: Send Notification to Discord
env:
DISCORD_WEBHOOK: ${{ secrets.DISCORD_WEBHOOK }}
uses: Ilshidur/action-discord@0.3.2
with:
args: "A new release of CS# has been tagged (v${{ needs.build_managed.outputs.buildnumber }}) at ${{ steps.release.outputs.url }}"
args: "A new release of CS# has been tagged (v${{ needs.setup.outputs.buildnumber }}) at ${{ steps.release.outputs.url }}"

3
.gitignore vendored
View File

@@ -1,8 +1,7 @@
.ccls-cache/
.cmake/
cmake-build-debug*/
cmake-build-*/
.kdev4/
.vscode/
generated/
# configure_file auto generated.

6
.gitmodules vendored
View File

@@ -14,12 +14,12 @@
[submodule "libraries/dyncall"]
path = libraries/dyncall
url = https://github.com/LWJGL-CI/dyncall
[submodule "libraries/GameTracking-CS2"]
path = libraries/GameTracking-CS2
url = https://github.com/SteamDatabase/GameTracking-CS2
[submodule "libraries/DynoHook"]
path = libraries/DynoHook
url = https://github.com/qubka/DynoHook
[submodule "libraries/asmjit"]
path = libraries/asmjit
url = https://github.com/asmjit/asmjit
[submodule "libraries/Protobufs"]
path = libraries/Protobufs
url = https://github.com/SteamDatabase/Protobufs

4
.vscode/settings.json vendored Normal file
View File

@@ -0,0 +1,4 @@
{
"editor.defaultFormatter": null,
"editor.formatOnSave": true
}

View File

@@ -5,6 +5,8 @@ project(counterstrikesharp C CXX ASM)
include("makefiles/shared.cmake")
set(CMAKE_MSVC_RUNTIME_LIBRARY "MultiThreaded$<$<CONFIG:Debug>:Debug>")
add_subdirectory(libraries/spdlog)
add_subdirectory(libraries/dyncall)
add_subdirectory(libraries/funchook)
@@ -13,7 +15,8 @@ add_subdirectory(libraries/DynoHook)
set_property(TARGET dynohook PROPERTY DYNO_ARCH_X86 64)
set_property(TARGET funchook-static PROPERTY POSITION_INDEPENDENT_CODE ON)
SET(SOURCE_FILES
set(SOURCE_FILES
libraries/hl2sdk-cs2/public/tier0/memoverride.cpp
src/mm_plugin.cpp
src/mm_plugin.h
libraries/hl2sdk-cs2/tier1/convar.cpp
@@ -49,10 +52,10 @@ SET(SOURCE_FILES
src/core/managers/event_manager.cpp
src/core/timer_system.h
src/core/timer_system.cpp
src/core/tick_scheduler.h
src/core/tick_scheduler.cpp
src/scripting/autonative.h
src/scripting/natives/natives_engine.cpp
src/core/engine_trace.h
src/core/engine_trace.cpp
src/scripting/natives/natives_callbacks.cpp
src/core/managers/player_manager.h
src/core/managers/player_manager.cpp
@@ -68,7 +71,6 @@ SET(SOURCE_FILES
src/core/memory_module.h
src/core/memory_module.cpp
src/core/cs2_sdk/interfaces/cgameresourceserviceserver.h
src/core/cs2_sdk/interfaces/cschemasystem.h
src/core/cs2_sdk/interfaces/cs2_interfaces.h
src/core/cs2_sdk/interfaces/cs2_interfaces.cpp
src/core/cs2_sdk/schema.h
@@ -90,68 +92,59 @@ SET(SOURCE_FILES
src/core/managers/voice_manager.cpp
src/core/managers/voice_manager.h
src/scripting/natives/natives_dynamichooks.cpp
src/core/game_system.h
src/core/game_system.cpp
)
if (LINUX)
# memoverride.cpp is not usable on CMake Windows, cuz CMake default link libraries (seems) always link ucrt.lib
set(SOURCE_FILES
${SOURCE_FILES}
libraries/hl2sdk-cs2/public/tier0/memoverride.cpp
)
endif()
set(PROTO_DIRS -I${CMAKE_CURRENT_SOURCE_DIR}/libraries/GameTracking-CS2/Protobufs)
file(GLOB PROTOS "${CMAKE_CURRENT_SOURCE_DIR}/libraries/GameTracking-CS2/Protobufs/*.proto")
set(PROTO_DIRS -I${CMAKE_CURRENT_SOURCE_DIR}/libraries/Protobufs/csgo)
file(GLOB PROTOS "${CMAKE_CURRENT_SOURCE_DIR}/libraries/Protobufs/csgo/*.proto")
## Generate protobuf source & headers
if (LINUX)
if(LINUX)
set(PROTOC_EXECUTABLE ${CMAKE_CURRENT_SOURCE_DIR}/libraries/hl2sdk-cs2/devtools/bin/linux/protoc)
elseif(WIN32)
set(PROTOC_EXECUTABLE ${CMAKE_CURRENT_SOURCE_DIR}/libraries/hl2sdk-cs2/devtools/bin/protoc.exe)
endif()
add_custom_command(
OUTPUT protobuf_output_stamp
COMMAND ${PROTOC_EXECUTABLE} --proto_path=thirdparty/protobuf-3.21.8/src --proto_path=common --cpp_out=common common/network_connection.proto
COMMENT "Generating protobuf file"
WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}/libraries/hl2sdk-cs2
VERBATIM
OUTPUT protobuf_output_stamp
COMMAND ${PROTOC_EXECUTABLE} --proto_path=thirdparty/protobuf-3.21.8/src --proto_path=common --cpp_out=common common/network_connection.proto
COMMENT "Generating protobuf file"
WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}/libraries/hl2sdk-cs2
VERBATIM
)
SET(SOURCE_FILES ${SOURCE_FILES} protobuf_output_stamp)
set(SOURCE_FILES ${SOURCE_FILES} protobuf_output_stamp)
# Sources
add_library(${PROJECT_NAME} SHARED ${SOURCE_FILES} ${NATIVES_SOURCES} ${CONVERSIONS_SOURCES} ${CONVERSIONS_HEADERS})
target_include_directories(
${PROJECT_NAME}
PUBLIC
${CMAKE_CURRENT_SOURCE_DIR}/src
${CMAKE_CURRENT_SOURCE_DIR}/src/core/cs2_sdk
${PROJECT_NAME}
PUBLIC
${CMAKE_CURRENT_SOURCE_DIR}/src
${CMAKE_CURRENT_SOURCE_DIR}/src/core/cs2_sdk
)
if (LINUX)
if(LINUX)
include("makefiles/linux.base.cmake")
set_target_properties(${PROJECT_NAME} PROPERTIES
PREFIX ""
LIBRARY_OUTPUT_DIRECTORY "${CMAKE_BINARY_DIR}/addons/counterstrikesharp/bin/linuxsteamrt64"
PREFIX ""
LIBRARY_OUTPUT_DIRECTORY "${CMAKE_BINARY_DIR}/addons/counterstrikesharp/bin/linuxsteamrt64"
)
elseif(WIN32)
include("makefiles/windows.base.cmake")
set_target_properties(${PROJECT_NAME} PROPERTIES
PREFIX ""
LIBRARY_OUTPUT_DIRECTORY "${CMAKE_BINARY_DIR}/addons/counterstrikesharp/bin/win64"
PREFIX ""
LIBRARY_OUTPUT_DIRECTORY "${CMAKE_BINARY_DIR}/addons/counterstrikesharp/bin/win64"
)
endif()
# Libraries
target_link_libraries(${PROJECT_NAME} ${COUNTER_STRIKE_SHARP_LINK_LIBRARIES})
add_custom_command(
TARGET ${PROJECT_NAME} PRE_BUILD
COMMAND ${CMAKE_COMMAND} -E copy_directory
${CMAKE_SOURCE_DIR}/configs ${CMAKE_BINARY_DIR}
)
TARGET ${PROJECT_NAME} PRE_BUILD
COMMAND ${CMAKE_COMMAND} -E copy_directory
${CMAKE_SOURCE_DIR}/configs ${CMAKE_BINARY_DIR}
)

103
CONTRIBUTING.md Normal file
View File

@@ -0,0 +1,103 @@
# Contributing to CounterStrikeSharp
We'd love for you to contribute to CS# to make it better than it is today!
Here are the guidelines we'd like you to follow:
- [Question or Problem?](#question)
- [Issues and Bugs](#issue)
- [Submission Guidelines](#submit)
- [Coding Format](#format)
## <a name="question"></a> Got a Question or Problem?
If you have questions about how to contribute to CounterStrikeSharp, please join our [Discord][discord] server.
## <a name="issue"></a> Found an Issue?
If you find a bug in the source code or a mistake in the documentation, you can help us by
submitting an issue to our [GitHub Repository][github]. Even better you can submit a Pull Request
with a fix.
**Please see the [Submission Guidelines](#submit) below.**
## <a name="submit"></a> Submission Guidelines
### Submitting an Issue
Before you submit your issue please search the archive, maybe your question was already answered.
If your issue appears to be a bug and hasn't been reported, open a new issue. Help us to maximize
the effort we can spend fixing issues and adding new features, by not reporting duplicate issues.
Providing the following information will increase the chances of your issue being dealt with
quickly:
* **Overview of the Issue** - if an error is being thrown a stack trace helps
* **Operating System** - is this a problem with a specific OS (Windows or Linux)?
* **Reproduce the Error** - provide details, if possible, on how to reproduce the error
* **Related Issues** - has a similar issue been reported before?
* **Suggest a Fix** - if you can't fix the bug yourself, perhaps you can point to what might be causing the problem (line of code or commit)
### Submitting a Pull Request
Before you submit your pull request consider the following guidelines:
* Search [GitHub](https://github.com/roflmuffin/CounterStrikeSharp/pulls) for an open or closed Pull Request
that relates to your submission. You don't want to duplicate effort.
* If adding a feature or enhancement, we recommend you first [start a discussion for
it](https://github.com/roflmuffin/CounterStrikeSharp/discussions) before submitting a Pull Request.
* [Fork](https://help.github.com/articles/fork-a-repo/) this repo.
* [Clone](https://help.github.com/articles/cloning-a-repository/) your copy.
```shell
git clone https://github.com/YOUR_USERNAME/CounterStrikeSharp.git
cd CounterStrikeSharp/
```
* After cloning, set a new remote [upstream](https://help.github.com/articles/configuring-a-remote-for-a-fork/) (this helps to keep your fork up to date)
```shell
git remote add upstream https://github.com/roflmuffin/CounterStrikeSharp.git
```
* Make your changes in a new git branch:
```shell
git checkout -b my-fix-branch master
```
* Create your patch and run appropriate tests.
* Commit your changes using a descriptive commit message that uses the imperative, present tense: "change" not "changed" nor "changes".
```shell
git commit -a
```
Note: the optional commit `-a` command line option will automatically "add" and "rm" edited files.
* Push your branch to GitHub:
```shell
git push origin my-fix-branch
```
In GitHub, send a pull request to `CounterStrikeSharp:master`.
If we suggest changes, then:
* Make the required updates.
* Re-run CounterStrikeSharp to ensure everything is still working & tests are passing.
* Commit your changes to your branch (e.g. `my-fix-branch`).
* Push the changes to your GitHub repository (this will update your Pull Request).
If the PR gets too outdated we may ask you to rebase and force push to update the PR:
```shell
git fetch upstream
git rebase upstream/master
git push origin my-fix-branch -f
```
That's it! Thank you for your contribution!
#### After your pull request is merged
After your pull request is merged, you can safely delete your branch and pull the changes
from the main (upstream) repository.
[github]: https://github.com/roflmuffin/CounterStrikeSharp
[discord]: https://discord.gg/eAZU3guKWU

View File

@@ -1,6 +1,6 @@
# CounterStrikeSharp
CounterStrikeSharp is a server side modding framework for Counter-Strike: Global Offensive. This project attempts to implement a .NET Core scripting layer on top of a Metamod Source Plugin, allowing developers to create plugins that interact with the game server in a modern language (C#) to facilitate the creation of maintainable and testable code.
CounterStrikeSharp is a server side modding framework for Counter-Strike 2. This project implements a .NET 8 scripting layer on top of a Metamod Source Plugin, allowing developers to create plugins that interact with the game server in a modern language (C#) to facilitate the creation of maintainable and testable code.
[Come and join our Discord](https://discord.gg/eAZU3guKWU)
@@ -18,14 +18,12 @@ Detailed installation instructions can be found in the [docs](https://docs.cssha
## What works?
_(Note, these were features in the previous VSP.NET project, but have not been implemented yet in this project)_
These features are the core of the platform and work pretty well/have a low risk of causing issues.
- [x] Console Commands, Server Commands (e.g. css_mycommand)
- [x] Chat Commands with `!` and `/` prefixes (e.g. !mycommand)
- [ ] **(In Progress)** Console Variables
- [x] Game Event Handlers & Custom Events (e.g. player_death)
- [x] Fake Console Variables (commands which mimic ConVar behaviour as these have not been fully reverse engineered)
- [x] Game Event Handlers & Firing of Events (e.g. player_death)
- [x] Basic event value get/set (string, bool, int32, float)
- [x] Complex event values get/set (ehandle, pawn, player controller)
- [x] Game Tick Based Timers (e.g. repeating map timers)
@@ -34,7 +32,7 @@ These features are the core of the platform and work pretty well/have a low risk
- [x] Client Listeners (e.g. connect, disconnect, put in server)
- [x] OnMapStart
- [x] OnTick
- [x] Server Information (current map, game time, tick rate, model precaching)
- [x] Server Information (current map, game time)
- [x] Schema System Access (access player values like current weapon, money, location etc.)
## Links
@@ -81,7 +79,7 @@ public class HelloWorldPlugin : BasePlugin
return HookResult.Continue;
}
[ConsoleCommand("issue_warning", "Issue warning to player")]
[ConsoleCommand("css_issue_warning", "Issue warning to player")]
public void OnCommand(CCSPlayerController? player, CommandInfo command)
{
Logger.LogWarning("Player shouldn't be doing that");

View File

@@ -3,5 +3,8 @@
"SilentChatTrigger": [ "/" ],
"FollowCS2ServerGuidelines": true,
"PluginHotReloadEnabled": true,
"ServerLanguage": "en"
"PluginAutoLoadEnabled": true,
"ServerLanguage": "en",
"UnlockConCommands": true,
"UnlockConVars": true
}

View File

@@ -2,190 +2,210 @@
"UTIL_ClientPrintAll": {
"signatures": {
"library": "server",
"windows": "\\x48\\x89\\x5C\\x24\\x08\\x48\\x89\\x6C\\x24\\x10\\x48\\x89\\x74\\x24\\x18\\x57\\x48\\x81\\xEC\\x70\\x01\\x2A\\x2A\\x8B\\xE9",
"linux": "\\x55\\x48\\x89\\xE5\\x41\\x57\\x49\\x89\\xD7\\x41\\x56\\x49\\x89\\xF6\\x41\\x55\\x41\\x89\\xFD"
"windows": "48 89 5C 24 08 48 89 6C 24 10 48 89 74 24 18 57 48 81 EC 70 01 ? ? 8B E9",
"linux": "55 48 89 E5 41 57 49 89 D7 41 56 49 89 F6 41 55 41 89 FD"
}
},
"ClientPrint": {
"signatures": {
"library": "server",
"windows": "\\x48\\x85\\xC9\\x0F\\x84\\x2A\\x2A\\x2A\\x2A\\x48\\x8B\\xC4\\x48\\x89\\x58\\x18",
"linux": "\\x55\\x48\\x89\\xE5\\x41\\x57\\x49\\x89\\xCF\\x41\\x56\\x49\\x89\\xD6\\x41\\x55\\x41\\x89\\xF5\\x41\\x54\\x4C\\x8D\\xA5\\xA0\\xFE\\xFF\\xFF"
"windows": "48 85 C9 0F 84 ? ? ? ? 48 8B C4 48 89 58 18",
"linux": "55 48 89 E5 41 57 49 89 CF 41 56 49 89 D6 41 55 41 89 F5 41 54 4C 8D A5 A0 FE FF FF"
}
},
"CCSPlayerController_SwitchTeam": {
"signatures": {
"library": "server",
"windows": "\\x40\\x56\\x57\\x48\\x81\\xEC\\x2A\\x2A\\x2A\\x2A\\x48\\x8B\\xF9\\x8B\\xF2\\x8B\\xCA",
"linux": "\\x55\\x48\\x89\\xE5\\x41\\x55\\x49\\x89\\xFD\\x89\\xF7"
"windows": "40 56 57 48 81 EC ? ? ? ? 48 8B F9 8B F2 8B CA",
"linux": "55 48 89 E5 41 55 49 89 FD 89 F7"
}
},
"CCSPlayerController_ChangeTeam": {
"offsets": {
"windows": 93,
"linux": 92
"windows": 98,
"linux": 97
}
},
"CCSPlayerController_Respawn": {
"offsets": {
"windows": 244,
"linux": 246
"windows": 254,
"linux": 256
}
},
"CBasePlayerController_SetPawn": {
"signatures": {
"library": "server",
"windows": "\\x44\\x88\\x4C\\x24\\x20\\x55\\x57\\x41\\x54\\x41\\x56\\x41\\x57\\x48\\x8D\\x6C\\x24\\x2A\\x48\\x81\\xEC\\x2A",
"linux": "\\x55\\x48\\x89\\xE5\\x41\\x57\\x41\\x56\\x41\\x55\\x41\\x54\\x49\\x89\\xFC\\x53\\x48\\x89\\xF3\\x48\\x81\\xEC\\xC8\\x00\\x00\\x00"
"windows": "44 88 4C 24 ? 55 56 57 41 54 41 56 48 8D 6C 24 ?",
"linux": "55 48 89 E5 41 57 41 56 41 55 49 89 FD 41 54 45 89 C4"
}
},
"CCSPlayerPawnBase_PostThink": {
"signatures": {
"library": "server",
"windows": "\\x48\\x8B\\xC4\\x48\\x89\\x48\\x08\\x55\\x53\\x56\\x57\\x41\\x56\\x48\\x8D\\xA8\\xD8\\xFE\\xFF\\xFF",
"linux": "\\x55\\x48\\x89\\xE5\\x41\\x57\\x41\\x56\\x41\\x55\\x41\\x54\\x53\\x48\\x89\\xFB\\x48\\x81\\xEC\\x2A\\x2A\\x2A\\x2A\\xE8\\x2A\\x2A\\x2A\\x2A\\x48\\x89\\xDF"
"windows": "48 ? ? 55 53 56 57 41 ? 48 ? ? ? 48 ? ? ? ? ? ? 4C 89 68",
"linux": "55 48 89 E5 41 56 41 55 41 54 53 48 89 FB 48 83 EC 30 E8 ? ? ? ?"
}
},
"CGameEventManager_Init": {
"signatures": {
"library": "server",
"windows": "40 53 48 83 EC 20 48 8B 01 48 8B D9 FF 50 10",
"linux": "55 48 89 E5 41 54 49 89 FC 48 83 EC 08 48 8B 07 FF 50 18"
}
},
"GiveNamedItem": {
"signatures": {
"library": "server",
"windows": "\\x48\\x89\\x5C\\x24\\x18\\x48\\x89\\x74\\x24\\x20\\x55\\x57\\x41\\x54\\x41\\x56\\x41\\x57\\x48\\x8D\\x6C\\x24\\xD9",
"linux": "\\x55\\x48\\x89\\xE5\\x41\\x57\\x41\\x56\\x49\\x89\\xCE\\x41\\x55\\x49\\x89\\xF5\\x41\\x54\\x49\\x89\\xD4"
"windows": "48 89 5C 24 ? 48 89 74 24 ? 55 57 41 ? 41 ? 41 ? 48 ? ? ? ? 48 ? ? ? ? ? ? 4D ? ? 48",
"linux": "55 48 89 E5 41 57 41 56 49 89 D6 41 55 49 89 CD 41 54 49 89 F4 53 48 89 FB 48 8D 3D"
}
},
"UTIL_Remove": {
"signatures": {
"library": "server",
"windows": "\\x48\\x85\\xC9\\x74\\x2A\\x48\\x8B\\xD1\\x48\\x8B\\x0D\\x2A\\x2A\\x2A\\x2A",
"linux": "\\x48\\x89\\xFE\\x48\\x85\\xFF\\x74\\x2A\\x48\\x8D\\x05\\x2A\\x2A\\x2A\\x2A\\x48"
"windows": "48 85 C9 74 ? 48 8B D1 48 8B 0D ? ? ? ?",
"linux": "48 89 FE 48 85 FF 74 ? 48 8D 05 ? ? ? ? 48"
}
},
"Host_Say": {
"signatures": {
"library": "server",
"windows": "\\x44\\x89\\x4C\\x24\\x20\\x44\\x88\\x44\\x24\\x18",
"linux": "\\x55\\x48\\x89\\xE5\\x41\\x57\\x49\\x89\\xFF\\x41\\x56\\x41\\x55\\x41\\x54\\x4D\\x89\\xC4"
"windows": "44 89 4C 24 20 44 88 44 24 18",
"linux": "55 48 89 E5 41 57 41 56 41 89 D6 41 55 4D 89 C5"
}
},
"CBaseModelEntity_SetModel": {
"signatures": {
"library": "server",
"windows": "\\x48\\x89\\x5C\\x24\\x2A\\x48\\x89\\x7C\\x24\\x2A\\x55\\x48\\x8B\\xEC\\x48\\x83\\xEC\\x50\\x48\\x8B\\xF9\\x4C\\x8B\\xC2",
"linux": "\\x55\\x48\\x89\\xF2\\x48\\x89\\xE5\\x41\\x54\\x49\\x89\\xFC\\x48\\x8D\\x7D\\xE0\\x48\\x83\\xEC\\x2A\\x48\\x8D\\x05\\x2A\\x2A\\x2A\\x2A\\x48\\x8B\\x30\\x48\\x8B\\x06"
"library": "server",
"windows": "48 89 5C 24 ? 48 89 7C 24 ? 55 48 8B EC 48 83 EC 50 48 8B F9 4C 8B C2",
"linux": "55 48 89 F2 48 89 E5 41 54 49 89 FC 48 8D 7D E0 48 83 EC ? 48 8D 05 ? ? ? ? 48 8B 30 48 8B 06"
}
},
"CCSPlayer_WeaponServices_CanUse": {
"signatures": {
"library": "server",
"windows": "\\x48\\x89\\x5C\\x24\\x10\\x48\\x89\\x6C\\x24\\x18\\x56\\x57\\x41\\x56\\x48\\x83\\xEC\\x30\\x80\\xB9\\xA0\\x00\\x00\\x00\\x00",
"linux": "\\x48\\x85\\xF6\\x0F\\x84\\x2A\\x2A\\x2A\\x2A\\x55\\x31\\xC9\\x48\\x89\\xE5\\x41\\x55\\x49\\x89\\xFD"
"windows": "48 89 5C 24 10 48 89 6C 24 18 56 57 41 56 48 83 EC 30 80 B9 A0 00 00 00 00",
"linux": "48 85 F6 0F 84 ? ? ? ? 55 31 C9 48 89 E5 41 55 49 89 FD"
}
},
"CCSPlayer_ItemServices_GiveNamedItem": {
"offsets": {
"windows": 17,
"linux": 18
}
},
"CCSPlayer_ItemServices_DropActivePlayerWeapon": {
"offsets": {
"windows": 18,
"linux": 19
"windows": 18,
"linux": 19
}
},
"CCSPlayer_ItemServices_RemoveWeapons": {
"offsets": {
"windows": 19,
"linux": 20
}
"offsets": {
"windows": 19,
"linux": 20
}
},
"CGameSceneNode_GetSkeletonInstance": {
"offsets": {
"windows": 8,
"linux": 8
"windows": 8,
"linux": 8
}
},
"CCSGameRules_TerminateRound": {
"signatures": {
"library": "server",
"windows": "\\x48\\x8B\\xC4\\x4C\\x89\\x48\\x20\\x55\\x57",
"linux": "\\x55\\x48\\x89\\xE5\\x41\\x57\\x41\\x56\\x41\\x55\\x41\\x54\\x49\\x89\\xFC\\x53\\x48\\x81\\xEC\\xE8\\x01\\x00\\x00\\x48\\x8D\\x05\\x2A\\x2A\\x2A\\x2A"
}
"library": "server",
"windows": "48 8B C4 4C 89 48 ? 48 89 48 ? 55 56",
"linux": "55 48 89 E5 41 57 41 56 41 55 41 54 49 89 FC 53 48 81 EC 88 00 00 00 48 8D 05 ? ? ? ?"
}
},
"UTIL_CreateEntityByName": {
"signatures": {
"library": "server",
"windows": "\\x48\\x83\\xEC\\x48\\xC6\\x44\\x24\\x30\\x00",
"linux": "\\x48\\x8D\\x05\\x2A\\x2A\\x2A\\x2A\\x55\\x48\\x89\\xFA"
}
"library": "server",
"windows": "48 83 EC 48 C6 44 24 30 00",
"linux": "48 8D 05 ? ? ? ? 55 48 89 FA"
}
},
"CBaseEntity_DispatchSpawn": {
"signatures": {
"library": "server",
"windows": "\\x48\\x89\\x5C\\x24\\x10\\x57\\x48\\x83\\xEC\\x30\\x48\\x8B\\xDA\\x48\\x8B\\xF9\\x48\\x85\\xC9",
"linux": "\\x48\\x85\\xFF\\x74\\x2A\\x55\\x48\\x89\\xE5\\x41\\x56"
}
"library": "server",
"windows": "48 89 5C 24 10 57 48 83 EC 30 48 8B DA 48 8B F9 48 85 C9",
"linux": "48 85 FF 74 ? 55 48 89 E5 41 56"
}
},
"CEntityInstance_AcceptInput": {
"signatures": {
"library": "server",
"windows": "\\x48\\x89\\x5C\\x24\\x10\\x48\\x89\\x74\\x24\\x18\\x57\\x48\\x83\\xEC\\x40\\x49\\x8B\\xF0",
"linux": "\\x55\\x48\\x89\\xE5\\x41\\x57\\x49\\x89\\xFF\\x41\\x56\\x48\\x8D\\x7D\\xC0"
"windows": "48 89 5C 24 10 48 89 74 24 18 57 48 83 EC 40 49 8B F0",
"linux": "55 48 89 E5 41 57 49 89 FF 41 56 48 8D 7D C0"
}
},
"CEntitySystem_AddEntityIOEvent": {
"signatures": {
"library": "server",
"windows": "48 89 5C 24 ? 48 89 74 24 ? 57 48 ? ? ? 49 ? ? 48 ? ? 48 ? ? 74",
"linux": "55 41 BA FF FF FF FF"
}
},
"LegacyGameEventListener": {
"signatures": {
"library": "server",
"windows": "\\x48\\x8B\\x15\\x2A\\x2A\\x2A\\x2A\\x48\\x85\\xD2\\x74\\x2A\\x85\\xC9\\x74",
"linux": "\\x48\\x8B\\x05\\x2A\\x2A\\x2A\\x2A\\x48\\x85\\xC0\\x74\\x2A\\x83\\xFF\\x3F\\x76\\x2A\\x31\\xC0"
"windows": "48 8B 15 ? ? ? ? 48 85 D2 74 ? 85 C9 74",
"linux": "48 8B 05 ? ? ? ? 48 85 C0 74 ? 85 FF"
}
},
"CBasePlayerPawn_CommitSuicide": {
"offsets": {
"windows": 360,
"linux": 360
"windows": 372,
"linux": 372
}
},
"CBasePlayerPawn_RemovePlayerItem": {
"signatures": {
"library": "server",
"linux": "\\x55\\x48\\x89\\x2A\\x41\\x2A\\x49\\x89\\x2A\\x41\\x2A\\x49\\x89\\x2A\\xE8\\x2A\\x2A\\x2A\\x2A\\x49\\x39",
"windows": "\\x48\\x85\\xD2\\x0F\\x84\\x2A\\x2A\\x2A\\x2A\\x48\\x89\\x5C\\x24\\x08\\x57\\x48\\x83\\xEC\\x30\\x48\\x8B\\xDA"
"windows": "48 ? ? 0F 84 ? ? ? ? 48 89 5C 24 ? 57 48 ? ? ? 48 ? ? 48 ? ? E8",
"linux": "55 48 89 ? 41 ? 49 89 ? 41 ? 49 89 ? E8 ? ? ? ? 49 39"
}
},
"CBaseEntity_Teleport": {
"offsets": {
"windows": 149,
"linux": 148
"windows": 155,
"linux": 154
}
},
"CBaseEntity_TakeDamageOld": {
"signatures": {
"library": "server",
"windows": "\\x40\\x56\\x57\\x48\\x83\\xEC\\x58\\x48\\x8B\\x41\\x10",
"linux": "\\x55\\x48\\x89\\xE5\\x41\\x57\\x41\\x56\\x41\\x55\\x41\\x54\\x49\\x89\\xFC\\x53\\x48\\x83\\xEC\\x38\\x4C\\x8D\\x2D\\x2A\\x2A\\x2A\\x2A\\x49\\x8B\\x7D\\x00\\x48\\x85\\xFF\\x0F\\x84\\x2A\\x2A\\x2A\\x2A"
"windows": "48 89 74 24 20 57 48 83 EC 60 48 8B 41 10",
"linux": "55 48 89 E5 41 57 41 56 41 55 41 54 49 89 FC 53 48 83 EC 48 4C 8D 2D ? ? ? ? 49 8B 7D 00 48 85 FF 0F 84 ? ? ? ?"
}
},
"CBaseTrigger_StartTouch": {
"signatures": {
"library": "server",
"windows": "\\x41\\x56\\x41\\x57\\x48\\x83\\xEC\\x58\\x48\\x8B\\x01",
"linux": "\\x55\\x48\\x89\\xE5\\x41\\x56\\x49\\x89\\xF6\\x41\\x55\\x49\\x89\\xFD\\x41\\x54\\x53\\xBB"
"windows": "41 56 41 57 48 83 EC 58 48 8B 01",
"linux": "55 48 89 E5 41 56 49 89 F6 41 55 49 89 FD 41 54 53 BB"
}
},
"CBaseTrigger_EndTouch": {
"signatures": {
"library": "server",
"windows": "\\x40\\x53\\x57\\x41\\x55\\x48\\x83\\xEC\\x40",
"linux": "\\x55\\xBA\\xFF\\xFF\\xFF\\xFF\\x48\\x89\\xE5\\x41\\x57\\x41\\x56\\x41\\x55\\x49\\x89\\xF5\\x41"
"windows": "40 53 57 41 55 48 83 EC 40",
"linux": "55 BA FF FF FF FF 48 89 E5 41 57 41 56 41 55 49 89 F5 41"
}
},
"StateChanged": {
"signatures": {
"library": "server",
"windows": "\\x40\\x55\\x53\\x56\\x41\\x55\\x41\\x57\\x48\\x8D\\x6C\\x24\\xB0",
"linux": "\\x55\\x48\\x89\\xE5\\x41\\x57\\x41\\x56\\x41\\x55\\x41\\x54\\x53\\x89\\xD3"
"windows": "40 55 53 56 41 55 41 57 48 8D 6C 24 B0",
"linux": "55 48 89 E5 41 57 41 56 41 55 41 54 53 89 D3"
}
},
"NetworkStateChanged": {
"signatures": {
"library": "server",
"windows": "\\x4C\\x8B\\xC9\\x48\\x8B\\x09\\x48\\x85\\xC9\\x74\\x2A\\x48\\x8B\\x41\\x10",
"linux": "\\x4C\\x8B\\x07\\x4D\\x85\\xC0\\x74\\x2A\\x49\\x8B\\x40\\x10"
"windows": "4C 8B C9 48 8B 09 48 85 C9 74 ? 48 8B 41 10",
"linux": "4C 8B 07 4D 85 C0 74 ? 49 8B 40 10"
}
},
"GameEntitySystem": {
@@ -203,8 +223,21 @@
"CEntityIOOutput_FireOutputInternal": {
"signatures": {
"library": "server",
"windows": "\\x4C\\x89\\x4C\\x24\\x20\\x53\\x55\\x57\\x41\\x54\\x41\\x56\\x48\\x81\\xEC",
"linux": "\\x55\\x48\\x89\\xE5\\x41\\x57\\x41\\x56\\x41\\x55\\x41\\x54\\x49\\x89\\xD4\\x53\\x48\\x89\\xF3\\x48\\x83\\xEC\\x58"
"windows": "4C 89 4C 24 20 53 55 57 41 54 41 56 48 81 EC",
"linux": "55 48 89 E5 41 57 41 56 41 55 41 54 49 89 D4 53 48 89 F3 48 83 EC 58"
}
},
"IGameSystem_InitAllSystems_pFirst": {
"signatures": {
"library": "server",
"windows": "48 8B 1D ? ? ? ? 48 85 DB 0F 84 ? ? ? ? BE ? ? ? ? 0F 1F 00 48 8B 7B 10",
"linux": "4C 8B 35 ? ? ? ? 4D 85 F6 75 2D E9 ? ? ? ? 0F 1F 40 00 48 8B 05"
}
},
"CEntityResourceManifest_AddResource": {
"offsets": {
"windows": 2,
"linux": 0
}
}
}

View File

@@ -0,0 +1 @@
This folder should contain any shared APIs, in the same DLL structure as the plugins folder (MySharedApi/MySharedApi.dll)

View File

@@ -0,0 +1,67 @@
---
title: Shared Plugin API (Capabilities)
description: How to add inter-plugin communication to CounterStrikeSharp plugins.
---
# Shared Plugin API
How to expose and use shared plugin APIs between multiple plugins.
## Creating a Contract Library
Inter-plugin communication requires a contract/shared library that simply exposes the shape of the API, using simple interfaces. e.g.
```csharp
public interface IBalanceHandler
{
decimal Balance { get; }
// These are just here to show that you can have methods on your shared types.
// You could also add a Setter to the Balance property.
public decimal Add(decimal amount);
public decimal Subtract(decimal amount);
}
```
This library ideally should not contain any business logic, and simply define the schema for callers.
This library should be placed in the `shared` subfolder, in the same folder layout as the plugins folder. So if a contract DLL is named `MySharedApi.dll` its file path should be: `shared/MySharedApi/MySharedApi.dll`.
## Creating a Capability
A capability can be declared with a simple static variable in your plugin class. A `PlayerCapability` is a player specific capability, and a `PluginCapability` is generic functionality that a plugin can expose.
```csharp
public static PlayerCapability<IBalanceHandler> BalanceCapability { get; } = new("myplugin:balance");
public static PluginCapability<IBalanceService> BalanceServiceCapability { get; } = new("myplugin:balance_service");
```
For every plugin that wishes to use this new "Balance API", they must ensure they create a capability using the shared API interface (`IBalanceHandler`), as well as use the same name (`myplugin:balance`).
## Registering a Capability
If you are the plugin that is expected to provide the basis of the API (i.e. you are providing a currency/balance plugin which does nothing except store users balances), then you will need to provide the implementation that other callers will use. This is done through the use of static members on the `Capabilities` class:
```csharp
// Player capabilities are given the calling player context
Capabilities.RegisterPlayerCapability(BalanceCapability, player => new BalanceHandler(player));
// Plugin capabilities can simply return an instance of the interface
Capabilities.RegisterPluginCapability(BalanceServiceCapability, () => new BalanceService());
```
### Using Capabilities
To utilise a capability, simply call the `.Get()` method provided on the static capability you declared earlier, i.e.
```csharp
var balance = BalanceCapability.Get(player);
var balanceService = BalanceServiceCapability.Get();
if (balance == null) return;
balance.Add(500);
```
This value _MUST_ be checked for null, as if there are no plugins providing implementations for a given capability, this method will return null, and you must handle this flow in your plugin.

View File

@@ -9,3 +9,6 @@
- name: Global Listeners
href: global-listeners.md
- name: Shared Plugin API
href: shared-plugin-api.md

View File

@@ -9,7 +9,7 @@ How to write your first plugin for CounterStrikeSharp
## Creating a New Project
First, ensure you have the relevant .NET 7.0 SDK for your platform installed on your machine. You can find the links to the latest downloads on the <a href="https://dotnet.microsoft.com/en-us/download/dotnet/7.0" target="_blank"> official Microsoft download page</a>.
First, ensure you have the relevant .NET 8.0 SDK for your platform installed on your machine. You can find the links to the latest downloads on the <a href="https://dotnet.microsoft.com/en-us/download/dotnet/8.0" target="_blank"> official Microsoft download page</a>.
### Creating a Class Library
@@ -25,7 +25,7 @@ Use your IDE (Visual Studio/Rider) to add a reference to the `CounterStrikeSharp
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFramework>net7.0</TargetFramework>
<TargetFramework>net8.0</TargetFramework>
<ImplicitUsings>enable</ImplicitUsings>
<Nullable>enable</Nullable>
</PropertyGroup>
@@ -65,7 +65,7 @@ public class HelloWorldPlugin : BasePlugin
}
```
Now build your project using your ide or the `dotnet build` command. You should now have a built binary file in your `bin/Debug/net7.0` subdirectory in the project.
Now build your project using your ide or the `dotnet build` command. You should now have a built binary file in your `bin/Debug/net8.0` subdirectory in the project.
### Installing your Plugin

View File

@@ -28,11 +28,22 @@ receive a ban.
> [!NOTE]
> Disable this option at your own risk.
## PluginHotReloadEnabled
When enabled, plugins are automatically reloaded when their .dll file is updated.
## PluginAutoLoadEnabled
When enabled, plugins are automatically loaded from the plugins directory on server start.
## ServerLanguage
Configures the default language to use for server commands & messages. The format for the culture name based on RFC 4646 is `languagecode2-country`/`regioncode2`, where `languagecode2` is the two-letter language code and `country/regioncode2` is the two-letter subculture code. Examples include `ja-JP` for Japanese (Japan) and `en-US` for English (United States). Defaults to "en".
Configures the default language to use for server commands & messages. The format for the culture name based on RFC 4646 is `languagecode2-country`/`regioncode2`, where `languagecode2` is the two-letter language code and `country/regioncode2` is the two-letter subculture code. Examples include `ja-JP` for Japanese (Japan) and `en-US` for English (United States). Defaults to "en".
## UnlockConCommands
When enabled, will remove the `FCVAR_HIDDEN`,`FCVAR_DEVELOPMENTONLY`, `FCVAR_MISSING0`, `FCVAR_MISSING1`, `FCVAR_MISSING2`, `FCVAR_MISSING3` flags from all console commands.
## UnlockConVars
When enabled, will remove the `FCVAR_HIDDEN`,`FCVAR_DEVELOPMENTONLY`, `FCVAR_MISSING0`, `FCVAR_MISSING1`, `FCVAR_MISSING2`, `FCVAR_MISSING3` flags from all console variables.

View File

@@ -0,0 +1,11 @@
[!INCLUDE [WithSharedTypes](../../examples/WithSharedTypes/README.md)]
<a href="https://github.com/roflmuffin/CounterStrikeSharp/tree/main/examples/WithSharedTypes" class="btn btn-secondary">View project on Github <i class="bi bi-github"></i></a>
[!code-csharp[](../../examples/WithSharedTypes/WithSharedTypesPlugin.cs)]
[!INCLUDE [WithSharedTypesConsumer](../../examples/WithSharedTypesConsumer/README.md)]
<a href="https://github.com/roflmuffin/CounterStrikeSharp/tree/main/examples/WithSharedTypesConsumer" class="btn btn-secondary">View project on Github <i class="bi bi-github"></i></a>
[!code-csharp[](../../examples/WithSharedTypesConsumer/WithSharedTypesConsumerPlugin.cs)]

View File

@@ -15,6 +15,8 @@ items:
href: WithGameEventHandlers.md
- name: Database (Dapper)
href: WithDatabase.md
- name: Shared Plugin Types
href: WithSharedTypes.md
- name: Translations
href: WithTranslations.md
- name: Voice Overrides

View File

@@ -0,0 +1,37 @@
# Tool taken from dotnet/runtime
# https://github.com/dotnet/runtime/blob/a8158c170b694f8c1dbae114c63c346b38244901/eng/formatting/download-tools.ps1
function DownloadClangTool {
param (
[string]
$toolName,
[string]
$downloadOutputPath
)
$clangVersion = "17.0.6"
$clangToolsRootUrl = "https://clrjit2.blob.core.windows.net/clang-tools"
$clangPlatform = "windows-x64"
$toolUrl = "$clangToolsRootUrl/$clangVersion/$clangPlatform/$toolName.exe"
$targetPath = "$downloadOutputPath\$toolName.exe"
if (-not $(ls $downloadOutputPath | Where-Object { $_.Name -eq "$toolName.exe" })) {
Write-Output "Downloading '$toolUrl' to '$targetPath'"
# Pass -PassThru as otherwise Invoke-WebRequest leaves a corrupted file if the download fails. With -PassThru the download is buffered first.
# -UseBasicParsing is necessary for older PowerShells when Internet Explorer might not be installed/configured
$null = Invoke-WebRequest -Uri "$toolUrl" -OutFile $(Join-Path $downloadOutputPath -ChildPath "$toolName.exe") -PassThru -UseBasicParsing
}
else {
Write-Output "Found '$targetPath'"
}
}
$downloadPathFolder = Split-Path $PSScriptRoot -Parent | Split-Path -Parent | Join-Path -ChildPath "artifacts" | Join-Path -ChildPath "tools"
mkdir $downloadPathFolder -ErrorAction SilentlyContinue
DownloadClangTool "clang-format" "$downloadPathFolder"
# Add to path to enable scripts to skip additional downloading steps since the tools will already be on the path.
$env:PATH = "$downloadPathFolder;$env:PATH"

View File

@@ -0,0 +1,60 @@
# Tool taken from dotnet/runtime
# https://github.com/dotnet/runtime/blob/a8158c170b694f8c1dbae114c63c346b38244901/eng/formatting/download-tools.sh
#!/usr/bin/env bash
set -ue
source="${BASH_SOURCE[0]}"
# resolve $source until the file is no longer a symlink
while [[ -h "$source" ]]; do
scriptroot="$( cd -P "$( dirname "$source" )" && pwd )"
source="$(readlink "$source")"
# if $source was a relative symlink, we need to resolve it relative to the path where the
# symlink file was located
[[ $source != /* ]] && source="$scriptroot/$source"
done
scriptroot="$( cd -P "$( dirname "$source" )" && pwd )"
function DownloadClangTool {
clangVersion="17.0.6"
clangToolsRootUrl="https://clrjit2.blob.core.windows.net/clang-tools"
clangPlatform="$(dotnet --info | grep 'RID:')"
clangPlatform="${clangPlatform##*RID:* }"
echo "dotnet RID: ${clangPlatform}"
# override common RIDs with compatible version so we don't need to upload binaries for each RID
case $clangPlatform in
ubuntu.*-x64)
clangPlatform=linux-x64
;;
esac
toolUrl="${clangToolsRootUrl}/${clangVersion}/${clangPlatform}/$1"
toolOutput=$2/$1
echo "Downloading $1 from ${toolUrl} to ${toolOutput}"
if [[ ! -x "$toolOutput" ]]; then
curl --silent --retry 5 --fail -o "${toolOutput}" "$toolUrl"
chmod 751 $toolOutput
fi
if [[ ! -x "$toolOutput" ]]; then
echo "Failed to download $1"
exit 1
fi
}
engFolder="$(cd -P "$( dirname "$scriptroot" )" && pwd )"
downloadPathFolder="$(cd -P "$( dirname "$engFolder" )" && pwd )/artifacts/tools"
mkdir -p "$downloadPathFolder"
DownloadClangTool "clang-format" "$downloadPathFolder"
export PATH=$downloadPathFolder:$PATH

29
eng/formatting/format.sh Normal file
View File

@@ -0,0 +1,29 @@
# Tool taken from dotnet/runtime
# https://github.com/dotnet/runtime/blob/a8158c170b694f8c1dbae114c63c346b38244901/eng/formatting/format.sh
#!/bin/sh
LC_ALL=C
# Select files to format
NATIVE_FILES=$(git diff --cached --name-only --diff-filter=ACM "*.h" "*.hpp" "*.c" "*.cpp" "*.inl" | sed 's| |\\ |g')
MANAGED_FILES=$(git diff --cached --name-only --diff-filter=ACM "*.cs" "*.vb" | sed 's| |\\ |g')
exec 1>&2
if [ -n "$NATIVE_FILES" ]; then
# Format all selected files
echo "$NATIVE_FILES" | cat | xargs | sed -e 's/ /,/g' | xargs "./artifacts/tools/clang-format" -style=file -i
# Add back the modified files to staging
echo "$NATIVE_FILES" | xargs git add
fi
if [ -n "$MANAGED_FILES" ]; then
# Format all selected files
echo "$MANAGED_FILES" | cat | xargs | sed -e 's/ /,/g' | dotnet format whitespace --include - --folder
# Add back the modified files to staging
echo "$MANAGED_FILES" | xargs git add
fi
exit 0

71
eng/install/install.ps1 Normal file
View File

@@ -0,0 +1,71 @@
# Install script that downloads Metamod:Source and Counter-Strike Sharp (with runtime)
$MM_DOWNLOAD_URL = "https://mms.alliedmods.net/mmsdrop/2.0/mmsource-2.0.0-git1286-windows.zip"
$TARGET_DIR = "./game/csgo"
$GAMEINFO_FILE = Join-Path $TARGET_DIR "gameinfo.gi"
$ProgressPreference = 'SilentlyContinue'
# Verification
if (-not (Test-Path $GAMEINFO_FILE)) {
Write-Error "Error: $GAMEINFO_FILE does not exist in the specified directory."
exit 1
}
# GitHub API for Counter-Strike Sharp Releases
$RELEASE_INFO = (Invoke-WebRequest -Uri "https://api.github.com/repos/roflmuffin/CounterStrikeSharp/releases/latest").Content | ConvertFrom-Json
# Filtering download URLs
$CSSHARP_DOWNLOAD_URL = $RELEASE_INFO.assets |
Where-Object { $_.browser_download_url -like '*windows*.zip*' -and $_.browser_download_url -notlike '*with-runtime*' } |
Select-Object -First 1 -ExpandProperty browser_download_url
$CSSHARP_RUNTIME_DOWNLOAD_URL = $RELEASE_INFO.assets |
Where-Object { $_.browser_download_url -like '*windows*.zip*' -and $_.browser_download_url -like '*with-runtime*' } |
Select-Object -First 1 -ExpandProperty browser_download_url
### METAMOD:SOURCE ###
Write-Output "Downloading Metamod:Source..."
Invoke-WebRequest -Uri $MM_DOWNLOAD_URL -OutFile metamod.zip
Write-Output "Extracting Metamod:Source to $TARGET_DIR..."
Expand-Archive -Force -Path metamod.zip -DestinationPath $TARGET_DIR
Remove-Item metamod.zip
### GAMEINFO.GI UPDATE ###
$NEW_ENTRY = " Game csgo/addons/metamod"
$FILE_CONTENT = Get-Content $GAMEINFO_FILE
Write-Output "Updating $GAMEINFO_FILE..."
if ($FILE_CONTENT -contains $NEW_ENTRY) {
Write-Output "The entry '$NEW_ENTRY' already exists in $GAMEINFO_FILE. No changes were made."
} else {
$Pattern = "Game_LowViolence"
$Modified = $false
$NewContent = @()
foreach ($line in $FILE_CONTENT) {
if ($line -match $Pattern -and -not $Modified) {
$NewContent += $line
$NewContent += $NEW_ENTRY
$Modified = $true
} else {
$NewContent += $line
}
}
$NewContent | Set-Content $GAMEINFO_FILE
Write-Host "The file $GAMEINFO_FILE has been modified successfully. '$NEW_ENTRY' has been added."
}
### COUNTER-STRIKE SHARP ###
Write-Output "Downloading Counter-Strike Sharp (with runtime)..."
# Determine if runtime needs to be downloaded
if (-not (Test-Path "./game/csgo/addons/CounterStrikeSharp/dotnet/dotnet.exe")) {
$CSSHARP_DOWNLOAD_URL = $CSSHARP_RUNTIME_DOWNLOAD_URL
}
Invoke-WebRequest -Uri $CSSHARP_DOWNLOAD_URL -OutFile cssharp.zip
Write-Output "Extracting Counter-Strike Sharp to $TARGET_DIR..."
Expand-Archive -Force -Path cssharp.zip -DestinationPath $TARGET_DIR
Remove-Item cssharp.zip

72
eng/install/install.sh Executable file
View File

@@ -0,0 +1,72 @@
#!/bin/bash
# Install script that downloads Metamod:Source and Counter-Strike Sharp (with runtime)
MM_DOWNLOAD_URL="https://mms.alliedmods.net/mmsdrop/2.0/mmsource-2.0.0-git1286-linux.tar.gz"
TARGET_DIR="./game/csgo"
GAMEINFO_FILE="${TARGET_DIR}/gameinfo.gi"
if [ ! -f "${GAMEINFO_FILE}" ]; then
printf "Error: %s does not exist in the specified directory.\n" "$GAMEINFO_FILE"
exit 1
fi
RELEASE_INFO=$(curl -s https://api.github.com/repos/roflmuffin/CounterStrikeSharp/releases/latest)
# Filter and store download URLs
CSSHARP_DOWNLOAD_URL=$(echo "$RELEASE_INFO" | grep -o "browser_download_url.*linux.*\.zip" | cut -d '"' -f 3 | grep -v "with-runtime")
CSSHARP_RUNTIME_DOWNLOAD_URL=$(echo "$RELEASE_INFO" | grep -o "browser_download_url.*linux.*\.zip" | cut -d '"' -f 3 | grep "with-runtime")
### METAMOD:SOURCE ###
printf "Downloading Metamod:Source...\n"
curl -s -L -o metamod.tar.gz "$MM_DOWNLOAD_URL"
if [ $? -eq 0 ]; then
printf "Extracting Metamod:Source to %s...\n" "$TARGET_DIR"
tar -xzf metamod.tar.gz -C "$TARGET_DIR"
rm metamod.tar.gz
else
echo "Download failed. Please check the URL and your connection."
fi
### GAMEINFO.GI UPDATE ###
NEW_ENTRY=" Game csgo/addons/metamod"
printf "Updating %s...\n" "$GAMEINFO_FILE"
if grep -Fxq "$NEW_ENTRY" "$GAMEINFO_FILE"; then
echo "The entry '$(echo $NEW_ENTRY | xargs)' already exists in ${GAMEINFO_FILE}. No changes were made."
else
awk -v new_entry="$NEW_ENTRY" '
BEGIN { found=0; }
// {
if (found) {
print new_entry;
found=0;
}
print;
}
/Game_LowViolence/ { found=1; }
' "$GAMEINFO_FILE" > "$GAMEINFO_FILE.tmp" && mv "$GAMEINFO_FILE.tmp" "$GAMEINFO_FILE"
printf "The file %s has been modified successfully. '%s' has been added.\n" "$GAMEINFO_FILE" "$(echo $NEW_ENTRY | xargs)"
fi
printf "Downloading Counter-Strike Sharp (with runtime)...\n"
# If ./game/csgo/addons/CounterStrikeSharp/dotnet/dotnet does not exist, use the runtime download url
if [ ! -f "./game/csgo/addons/CounterStrikeSharp/dotnet/dotnet" ]; then
CSSHARP_DOWNLOAD_URL="$CSSHARP_RUNTIME_DOWNLOAD_URL"
fi
curl -s -L -o cssharp.zip "$CSSHARP_DOWNLOAD_URL"
if [ $? -eq 0 ]; then
printf "Extracting Counter-Strike Sharp to %s...\n" "$TARGET_DIR"
unzip -q -o cssharp.zip -d "$TARGET_DIR"
rm cssharp.zip
else
echo "Download failed. Please check the URL and your connection."
fi

View File

@@ -1,6 +1,6 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFramework>net7.0</TargetFramework>
<TargetFramework>net8.0</TargetFramework>
<ImplicitUsings>enable</ImplicitUsings>
<Nullable>enable</Nullable>
<GenerateAssemblyInfo>false</GenerateAssemblyInfo>

View File

@@ -0,0 +1,11 @@
namespace MySharedTypes.Contracts;
public interface IBalanceHandler
{
decimal Balance { get; }
// These are just here to show that you can have methods on your shared types.
// You could also add a Setter to the Balance property.
public decimal Add(decimal amount);
public decimal Subtract(decimal amount);
}

View File

@@ -0,0 +1,6 @@
namespace MySharedTypes.Contracts;
public interface IBalanceService
{
public void ClearAllBalances();
}

View File

@@ -0,0 +1,7 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFramework>net8.0</TargetFramework>
<ImplicitUsings>enable</ImplicitUsings>
<Nullable>enable</Nullable>
</PropertyGroup>
</Project>

View File

@@ -1,6 +1,6 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFramework>net7.0</TargetFramework>
<TargetFramework>net8.0</TargetFramework>
<OutputType>Library</OutputType>
<GenerateAssemblyInfo>false</GenerateAssemblyInfo>
<CopyLocalLockFileAssemblies>true</CopyLocalLockFileAssemblies>

View File

@@ -1,6 +1,6 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFramework>net7.0</TargetFramework>
<TargetFramework>net8.0</TargetFramework>
<ImplicitUsings>enable</ImplicitUsings>
<Nullable>enable</Nullable>
<GenerateAssemblyInfo>false</GenerateAssemblyInfo>

View File

@@ -1,6 +1,6 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFramework>net7.0</TargetFramework>
<TargetFramework>net8.0</TargetFramework>
<ImplicitUsings>enable</ImplicitUsings>
<Nullable>enable</Nullable>
<GenerateAssemblyInfo>false</GenerateAssemblyInfo>

View File

@@ -1,6 +1,6 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFramework>net7.0</TargetFramework>
<TargetFramework>net8.0</TargetFramework>
<ImplicitUsings>enable</ImplicitUsings>
<Nullable>enable</Nullable>
<GenerateAssemblyInfo>false</GenerateAssemblyInfo>

View File

@@ -1,6 +1,6 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFramework>net7.0</TargetFramework>
<TargetFramework>net8.0</TargetFramework>
<ImplicitUsings>enable</ImplicitUsings>
<Nullable>enable</Nullable>
<GenerateAssemblyInfo>false</GenerateAssemblyInfo>

View File

@@ -1,6 +1,6 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFramework>net7.0</TargetFramework>
<TargetFramework>net8.0</TargetFramework>
<ImplicitUsings>enable</ImplicitUsings>
<Nullable>enable</Nullable>
<GenerateAssemblyInfo>false</GenerateAssemblyInfo>

View File

@@ -1,6 +1,6 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFramework>net7.0</TargetFramework>
<TargetFramework>net8.0</TargetFramework>
<ImplicitUsings>enable</ImplicitUsings>
<Nullable>enable</Nullable>
<GenerateAssemblyInfo>false</GenerateAssemblyInfo>

View File

@@ -1,6 +1,6 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFramework>net7.0</TargetFramework>
<TargetFramework>net8.0</TargetFramework>
<ImplicitUsings>enable</ImplicitUsings>
<Nullable>enable</Nullable>
<GenerateAssemblyInfo>false</GenerateAssemblyInfo>

View File

@@ -0,0 +1,33 @@
using CounterStrikeSharp.API.Core;
using MySharedTypes.Contracts;
namespace WithSharedTypes;
public class BalanceHandler : IBalanceHandler
{
private readonly CCSPlayerController _player;
// This could be a database, a file, or a dictionary like this.
internal static readonly Dictionary<CCSPlayerController, decimal> Balances = new();
public BalanceHandler(CCSPlayerController player)
{
_player = player;
}
public decimal Balance
{
get => Balances.TryGetValue(_player, out var balance) ? balance : 0;
set => Balances[_player] = value;
}
public decimal Add(decimal amount)
{
return Balance += amount;
}
public decimal Subtract(decimal amount)
{
return Balance -= amount;
}
}

View File

@@ -0,0 +1,11 @@
using MySharedTypes.Contracts;
namespace WithSharedTypes;
public class BalanceService : IBalanceService
{
public void ClearAllBalances()
{
BalanceHandler.Balances.Clear();
}
}

View File

@@ -0,0 +1,5 @@
# With Shared Types (Capabilities)
An example plugin that exposes a balance contract library, to use as a shared library between multiple plugins.
This allows one plugin to expose a capability for a player or plugin, and other plugins to use the exposed API.

View File

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

View File

@@ -0,0 +1,57 @@
using CounterStrikeSharp.API.Core;
using CounterStrikeSharp.API.Core.Attributes;
using CounterStrikeSharp.API.Core.Capabilities;
using MySharedTypes.Contracts;
namespace WithSharedTypes;
[MinimumApiVersion(184)]
public class WithSharedTypesPlugin : BasePlugin
{
public override string ModuleName => "Example: Shared Types";
public override string ModuleVersion => "1.0.0";
public override string ModuleAuthor => "CounterStrikeSharp & Contributors";
public override string ModuleDescription => "A simple plugin that shares types between multiple plugins";
// Declares a player capability, that stores some sort of functionality for a player.
// In this case, it's a balance handler, which is used to store a player's balance.
// Note that we use the same name for the capability as the one in the other plugin.
// IBalanceHandler is defined in MySharedTypes.Contracts, which is a shared library and placed in the `shared/` subfolder.
public static PlayerCapability<IBalanceHandler> BalanceCapability { get; } = new("myplugin:balance");
// Declares a player capability of a primitive type, in this case, a decimal.
public static PlayerCapability<Decimal> BalanceCapabilityDecimal { get; } = new("myplugin:balance_decimal");
// Plugin capabilities are similar to player capabilities, but they are not tied to a player, and are just generic APIs
// that are exposed by a plugin. In this case, we expose a balance service, which is used to clear all balances.
public static PluginCapability<IBalanceService> BalanceServiceCapability { get; } = new("myplugin:balance_service");
public override void Load(bool hotReload)
{
// Register the capability implementations here. Note that plugins don't need to register an implementation if it is already implemented in another plugin.
Capabilities.RegisterPlayerCapability(BalanceCapability, player => new BalanceHandler(player));
Capabilities.RegisterPluginCapability(BalanceServiceCapability, () => new BalanceService());
Capabilities.RegisterPlayerCapability(BalanceCapabilityDecimal, (player) => new BalanceHandler(player).Balance);
AddCommand("css_balance", "Gets your current balance", (player, info) =>
{
if (player == null) return;
player.PrintToChat($"Your balance is {BalanceCapability.Get(player)?.Balance}");
});
AddCommand("css_give", "Gives you money", (player, info) =>
{
if (player == null) return;
var balance = BalanceCapability.Get(player);
if (balance == null) return;
balance.Add(100);
player.PrintToChat($"Your balance is now {balance.Balance}");
});
}
public override void Unload(bool hotReload)
{
}
}

View File

@@ -0,0 +1,2 @@
# With Shared Types (Consumer Plugin)
Uses the decimal balance shared library.

View File

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

View File

@@ -0,0 +1,56 @@
using CounterStrikeSharp.API.Core;
using CounterStrikeSharp.API.Core.Attributes;
using CounterStrikeSharp.API.Core.Capabilities;
using CounterStrikeSharp.API.Core.Plugin;
using MySharedTypes.Contracts;
namespace WithSharedTypesConsumer;
[MinimumApiVersion(184)]
public class WithSharedTypesConsumerPlugin : BasePlugin
{
public override string ModuleName => "Example: Shared Types (Consumer)";
public override string ModuleVersion => "1.0.0";
public override string ModuleAuthor => "CounterStrikeSharp & Contributors";
public override string ModuleDescription => "A simple plugin that utilises the balance api from another plugin";
public static PlayerCapability<IBalanceHandler> BalanceCapability { get; } = new("myplugin:balance");
public static PlayerCapability<Decimal> BalanceCapabilityDecimal { get; } = new("myplugin:balance_decimal");
public static PluginCapability<IBalanceService> BalanceServiceCapability { get; } = new("myplugin:balance_service");
public override void Load(bool hotReload)
{
AddCommand("css_subtract", "Subtracts 50 from your balance", (player, info) =>
{
if (player == null) return;
var balance = BalanceCapability.Get(player);
if (balance == null) return;
balance.Subtract(50);
player.PrintToChat($"Your balance is now {balance.Balance}");
});
AddCommand("css_clearbalances", "Clears all balances", (player, info) =>
{
if (player == null) return;
var service = BalanceServiceCapability.Get();
if (service == null) return;
service.ClearAllBalances();
var balance = BalanceCapability.Get(player);
if (balance == null) return;
player.PrintToChat($"Your balance is now {balance.Balance}");
});
AddCommand("css_decimalbalance", "Gets your current balance", (player, info) =>
{
if (player == null) return;
player.PrintToChat($"Your balance is {BalanceCapabilityDecimal.Get(player)}");
});
}
public override void Unload(bool hotReload)
{
}
}

View File

@@ -1,6 +1,6 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFramework>net7.0</TargetFramework>
<TargetFramework>net8.0</TargetFramework>
<ImplicitUsings>enable</ImplicitUsings>
<Nullable>enable</Nullable>
<GenerateAssemblyInfo>false</GenerateAssemblyInfo>

View File

@@ -1,6 +1,6 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFramework>net7.0</TargetFramework>
<TargetFramework>net8.0</TargetFramework>
<ImplicitUsings>enable</ImplicitUsings>
<Nullable>enable</Nullable>
<GenerateAssemblyInfo>false</GenerateAssemblyInfo>

1
libraries/Protobufs Submodule

Submodule libraries/Protobufs added at 686a0628e6

File diff suppressed because it is too large Load Diff

View File

@@ -1,6 +1,5 @@
#set(_ITERATOR_DEBUG_LEVEL 2)
add_definitions(-D_LINUX -DPOSIX -DLINUX -DGNUC -DCOMPILER_GCC -DPLATFORM_64BITS)
add_definitions(-D_LINUX -DPOSIX -DLINUX -DGNUC -DCOMPILER_GCC -DPLATFORM_64BITS -D_FILE_OFFSET_BITS=64)
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Dstricmp=strcasecmp -D_stricmp=strcasecmp -D_strnicmp=strncasecmp")
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Dstrnicmp=strncasecmp -D_snprintf=snprintf")
@@ -16,16 +15,18 @@ set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wno-invalid-offsetof -Wno-reorder")
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -mfpmath=sse -msse -fno-strict-aliasing")
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fno-threadsafe-statics -v -fvisibility=default")
SET(
COUNTER_STRIKE_SHARP_LINK_LIBRARIES
${SOURCESDK_LIB}/linux64/libtier0.so
${SOURCESDK_LIB}/linux64/tier1.a
${SOURCESDK_LIB}/linux64/interfaces.a
${SOURCESDK_LIB}/linux64/mathlib.a
spdlog
dynload_s
dyncall_s
distorm
funchook-static
dynohook
)
set(CMAKE_SHARED_LINKER_FLAGS "${CMAKE_SHARED_LINKER_FLAGS} -static-libgcc -static-libstdc++")
set(
COUNTER_STRIKE_SHARP_LINK_LIBRARIES
${SOURCESDK_LIB}/linux64/libtier0.so
${SOURCESDK_LIB}/linux64/tier1.a
${SOURCESDK_LIB}/linux64/interfaces.a
${SOURCESDK_LIB}/linux64/mathlib.a
spdlog
dynload_s
dyncall_s
distorm
funchook-static
dynohook
)

View File

@@ -1,8 +1,8 @@
if (UNIX AND NOT APPLE)
if(UNIX AND NOT APPLE)
set(LINUX TRUE)
endif()
if (WIN32 AND NOT MSVC)
if(WIN32 AND NOT MSVC)
message(FATAL "MSVC restricted.")
endif()
@@ -11,10 +11,9 @@ set(CMAKE_CONFIGURATION_TYPES "Debug;Release" CACHE STRING
FORCE
)
# TODO: Use C++20 instead.
set(CMAKE_CXX_STANDARD 17)
if (LINUX)
if(LINUX)
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fPIC")
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -fPIC")
endif()
@@ -29,6 +28,18 @@ set(SOURCESDK_LIB ${SOURCESDK}/lib)
add_definitions(-DMETA_IS_SOURCE2)
if(DEFINED ENV{GITHUB_SHA_SHORT})
add_definitions(-DGITHUB_SHA="$ENV{GITHUB_SHA_SHORT}")
else()
add_definitions(-DGITHUB_SHA="Local")
endif()
if(DEFINED ENV{BUILD_NUMBER})
add_definitions(-DBUILD_NUMBER="$ENV{BUILD_NUMBER}")
else()
add_definitions(-DBUILD_NUMBER="0")
endif()
include_directories(
${SOURCESDK}
${SOURCESDK}/thirdparty/protobuf-3.21.8/src
@@ -43,6 +54,7 @@ include_directories(
${SOURCESDK}/public/entity2
${SOURCESDK}/public/game/server
${SOURCESDK}/public/entity2
${SOURCESDK}/public/schemasystem
${METAMOD_DIR}/core
${METAMOD_DIR}/core/sourcehook
libraries/dyncall/dynload
@@ -51,7 +63,8 @@ include_directories(
libraries/tl
libraries/funchook/include
libraries/DynoHook/src
libraries/moodycamel
libraries
)
include(${CMAKE_CURRENT_LIST_DIR}/metamod/configure_metamod.cmake)
include(${CMAKE_CURRENT_LIST_DIR}/metamod/configure_metamod.cmake)

View File

@@ -6,6 +6,7 @@ add_definitions(
set(CMAKE_CXX_FLAGS_RELEASE "${CMAKE_CXX_FLAGS_RELEASE} /Zi")
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} /wd4819 /wd4828 /wd5033 /permissive- /utf-8 /wd4005 /MP")
set(CMAKE_SHARED_LINKER_FLAGS_RELEASE "${CMAKE_SHARED_LINKER_FLAGS_RELEASE} /OPT:REF /OPT:ICF")
set(CMAKE_SHARED_LINKER_FLAGS_DEBUG "${CMAKE_SHARED_LINKER_FLAGS_DEBUG} /NODEFAULTLIB:libcmt")
set(COUNTER_STRIKE_SHARP_LINK_LIBRARIES
${SOURCESDK_LIB}/public/win64/tier0.lib
@@ -18,4 +19,4 @@ set(COUNTER_STRIKE_SHARP_LINK_LIBRARIES
distorm
funchook-static
dynohook
)
)

View File

@@ -1,7 +1,7 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFramework>net7.0</TargetFramework>
<TargetFramework>net8.0</TargetFramework>
<ImplicitUsings>enable</ImplicitUsings>
<Nullable>enable</Nullable>

View File

@@ -13,4 +13,14 @@ public class Api
{
return Assembly.GetAssembly(typeof(BasePlugin))!.GetName().Version!.Build;
}
/// <summary>
/// Returns the assembly version of CounterStrikeSharp running on the server as a string including git commit hash
/// </summary>
/// <example>1.0.0+9d8b6be</example>
public static string GetVersionString()
{
return Assembly.GetAssembly(typeof(BasePlugin))!.GetCustomAttribute<AssemblyInformationalVersionAttribute>()!
.InformationalVersion;
}
}

Binary file not shown.

File diff suppressed because it is too large Load Diff

View File

@@ -315,16 +315,6 @@ namespace CounterStrikeSharp.API.Core
}
}
public static float GetGameFrameTime(){
lock (ScriptContext.GlobalScriptContext.Lock) {
ScriptContext.GlobalScriptContext.Reset();
ScriptContext.GlobalScriptContext.SetIdentifier(0x97E331CA);
ScriptContext.GlobalScriptContext.Invoke();
ScriptContext.GlobalScriptContext.CheckErrors();
return (float)ScriptContext.GlobalScriptContext.GetResult(typeof(float));
}
}
public static double GetEngineTime(){
lock (ScriptContext.GlobalScriptContext.Lock) {
ScriptContext.GlobalScriptContext.Reset();
@@ -512,6 +502,17 @@ namespace CounterStrikeSharp.API.Core
}
}
public static void QueueTaskForFrame(int tick, InputArgument callback){
lock (ScriptContext.GlobalScriptContext.Lock) {
ScriptContext.GlobalScriptContext.Reset();
ScriptContext.GlobalScriptContext.Push(tick);
ScriptContext.GlobalScriptContext.Push((InputArgument)callback);
ScriptContext.GlobalScriptContext.SetIdentifier(0x2F92C340);
ScriptContext.GlobalScriptContext.Invoke();
ScriptContext.GlobalScriptContext.CheckErrors();
}
}
public static void QueueTaskForNextWorldUpdate(InputArgument callback){
lock (ScriptContext.GlobalScriptContext.Lock) {
ScriptContext.GlobalScriptContext.Reset();
@@ -713,6 +714,37 @@ namespace CounterStrikeSharp.API.Core
}
}
public static void AcceptInput(IntPtr pthis, string inputname, IntPtr activator, IntPtr caller, string value, int outputid){
lock (ScriptContext.GlobalScriptContext.Lock) {
ScriptContext.GlobalScriptContext.Reset();
ScriptContext.GlobalScriptContext.Push(pthis);
ScriptContext.GlobalScriptContext.Push(inputname);
ScriptContext.GlobalScriptContext.Push(activator);
ScriptContext.GlobalScriptContext.Push(caller);
ScriptContext.GlobalScriptContext.Push(value);
ScriptContext.GlobalScriptContext.Push(outputid);
ScriptContext.GlobalScriptContext.SetIdentifier(0x259E084C);
ScriptContext.GlobalScriptContext.Invoke();
ScriptContext.GlobalScriptContext.CheckErrors();
}
}
public static void AddEntityIoEvent(IntPtr ptarget, string inputname, IntPtr activator, IntPtr caller, string value, float delay, int outputid){
lock (ScriptContext.GlobalScriptContext.Lock) {
ScriptContext.GlobalScriptContext.Reset();
ScriptContext.GlobalScriptContext.Push(ptarget);
ScriptContext.GlobalScriptContext.Push(inputname);
ScriptContext.GlobalScriptContext.Push(activator);
ScriptContext.GlobalScriptContext.Push(caller);
ScriptContext.GlobalScriptContext.Push(value);
ScriptContext.GlobalScriptContext.Push(delay);
ScriptContext.GlobalScriptContext.Push(outputid);
ScriptContext.GlobalScriptContext.SetIdentifier(0x4CFDE98A);
ScriptContext.GlobalScriptContext.Invoke();
ScriptContext.GlobalScriptContext.CheckErrors();
}
}
public static void HookEvent(string name, InputArgument callback, bool ispost){
lock (ScriptContext.GlobalScriptContext.Lock) {
ScriptContext.GlobalScriptContext.Reset();
@@ -749,6 +781,16 @@ namespace CounterStrikeSharp.API.Core
}
}
public static void FreeEvent(IntPtr gameevent){
lock (ScriptContext.GlobalScriptContext.Lock) {
ScriptContext.GlobalScriptContext.Reset();
ScriptContext.GlobalScriptContext.Push(gameevent);
ScriptContext.GlobalScriptContext.SetIdentifier(0x7E8B60C2);
ScriptContext.GlobalScriptContext.Invoke();
ScriptContext.GlobalScriptContext.CheckErrors();
}
}
public static void FireEvent(IntPtr gameevent, bool dontbroadcast){
lock (ScriptContext.GlobalScriptContext.Lock) {
ScriptContext.GlobalScriptContext.Reset();
@@ -1085,6 +1127,16 @@ namespace CounterStrikeSharp.API.Core
}
}
public static void RemoveAllNetworkVectorElements(IntPtr vec){
lock (ScriptContext.GlobalScriptContext.Lock) {
ScriptContext.GlobalScriptContext.Reset();
ScriptContext.GlobalScriptContext.Push(vec);
ScriptContext.GlobalScriptContext.SetIdentifier(0x67206C08);
ScriptContext.GlobalScriptContext.Invoke();
ScriptContext.GlobalScriptContext.CheckErrors();
}
}
public static short GetSchemaOffset(string classname, string propname){
lock (ScriptContext.GlobalScriptContext.Lock) {
ScriptContext.GlobalScriptContext.Reset();

View File

@@ -106,13 +106,13 @@ namespace CounterStrikeSharp.API.Core
[RequiresPermissions("@css/generic")]
private void OnCSSCommand(CCSPlayerController? caller, CommandInfo info)
{
var currentVersion = Api.GetVersion();
var versionString = $"v{Api.GetVersion()} ({Api.GetVersionString()})";
info.ReplyToCommand(
" CounterStrikeSharp was created and is maintained by Michael \"roflmuffin\" Wilson.\n" +
" Counter-Strike Sharp uses code borrowed from SourceMod, Source.Python, FiveM, Saul Rennison, source2gen and CS2Fixes.\n" +
" See ACKNOWLEDGEMENTS.md for more information.\n" +
" Current API Version: " + currentVersion);
" Current API Version: " + versionString);
return;
}
@@ -130,11 +130,11 @@ namespace CounterStrikeSharp.API.Core
{
var sb = new StringBuilder();
sb.AppendFormat(" [#{0}:{1}]: \"{2}\" ({3})", plugin.PluginId,
plugin.State.ToString().ToUpper(), plugin.Plugin.ModuleName,
plugin.Plugin.ModuleVersion);
if (!string.IsNullOrEmpty(plugin.Plugin.ModuleAuthor))
plugin.State.ToString().ToUpper(), plugin.Plugin?.ModuleName ?? "Unknown",
plugin.Plugin?.ModuleVersion ?? "Unknown");
if (!string.IsNullOrEmpty(plugin.Plugin?.ModuleAuthor))
sb.AppendFormat(" by {0}", plugin.Plugin.ModuleAuthor);
if (!string.IsNullOrEmpty(plugin.Plugin.ModuleDescription))
if (!string.IsNullOrEmpty(plugin.Plugin?.ModuleDescription))
{
sb.Append("\n");
sb.Append(" ");
@@ -175,6 +175,8 @@ namespace CounterStrikeSharp.API.Core
try
{
_pluginManager.LoadPlugin(path);
plugin = _pluginContextQueryHandler.FindPluginByModulePath(path);
plugin.Plugin.OnAllPluginsLoaded(false);
}
catch (Exception e)
{
@@ -185,6 +187,7 @@ namespace CounterStrikeSharp.API.Core
else
{
plugin.Load(false);
plugin.Plugin.OnAllPluginsLoaded(false);
}
break;
@@ -233,6 +236,7 @@ namespace CounterStrikeSharp.API.Core
plugin.Unload(true);
plugin.Load(true);
plugin.Plugin.OnAllPluginsLoaded(true);
break;
}

View File

@@ -73,6 +73,10 @@ namespace CounterStrikeSharp.API.Core
public virtual void Unload(bool hotReload)
{
}
public virtual void OnAllPluginsLoaded(bool hotReload)
{
}
public class CallbackSubscriber : IDisposable
{
@@ -118,9 +122,6 @@ namespace CounterStrikeSharp.API.Core
public readonly Dictionary<Delegate, CallbackSubscriber> CommandListeners =
new Dictionary<Delegate, CallbackSubscriber>();
public readonly Dictionary<Delegate, CallbackSubscriber> ConvarChangeHandlers =
new Dictionary<Delegate, CallbackSubscriber>();
public readonly Dictionary<Delegate, CallbackSubscriber> Listeners =
new Dictionary<Delegate, CallbackSubscriber>();
@@ -155,7 +156,23 @@ namespace CounterStrikeSharp.API.Core
var name = typeof(T).GetCustomAttribute<EventNameAttribute>()?.Name;
RegisterEventHandlerInternal(name, handler, hookMode == HookMode.Post);
}
/// <summary>
/// De-registers a game event handler.
/// </summary>
/// <inheritdoc cref="RegisterEventHandler{T}"/>
public void DeregisterEventHandler<T>(GameEventHandler<T> handler, HookMode hookMode = HookMode.Post) where T : GameEvent
{
var name = typeof(T).GetCustomAttribute<EventNameAttribute>()!.Name;
if (!Handlers.TryGetValue(handler, out var subscriber)) return;
NativeAPI.UnhookEvent(name, subscriber.GetInputArgument(), hookMode == HookMode.Post);
FunctionReference.Remove(subscriber.GetReferenceIdentifier());
Handlers.Remove(handler);
}
[Obsolete("Use the generic version of this method")]
public void DeregisterEventHandler(string name, Delegate handler, bool post)
{
if (!Handlers.TryGetValue(handler, out var subscriber)) return;
@@ -183,6 +200,12 @@ namespace CounterStrikeSharp.API.Core
CommandManager.RegisterCommand(definition);
}
/// <summary>
/// Adds a command listener which will be called before or after the command is executed on the server by a player.
/// </summary>
/// <param name="name">Name of the command, e.g. `jointeam`</param>
/// <param name="handler">Code to run when command is executed. Return <see cref="HookResult.Handled"/> or higher to prevent command execution.</param>
/// <param name="mode">Whether to hook before or after the command is executed.</param>
public void AddCommandListener(string? name, CommandInfo.CommandListenerCallback handler, HookMode mode = HookMode.Pre)
{
var wrappedHandler = new Func<int, IntPtr, HookResult>((i, ptr) =>
@@ -198,6 +221,11 @@ namespace CounterStrikeSharp.API.Core
CommandListeners[handler] = subscriber;
}
/// <summary>
/// Removes a server command.
/// </summary>
/// <param name="name">The name of the command.</param>
/// <param name="handler">The callback function to be invoked when the command is executed.</param>
public void RemoveCommand(string name, CommandInfo.CommandCallback handler)
{
if (CommandHandlers.ContainsKey(handler))
@@ -211,6 +239,10 @@ namespace CounterStrikeSharp.API.Core
}
}
/// <summary>
/// Remove a command listener.
/// </summary>
/// <inheritdoc cref="AddCommandListener"/>
public void RemoveCommandListener(string name, CommandInfo.CommandListenerCallback handler, HookMode mode)
{
if (CommandListeners.ContainsKey(handler))
@@ -224,39 +256,24 @@ namespace CounterStrikeSharp.API.Core
}
}
/*
public void HookConVarChange(ConVar convar, ConVar.ConVarChangedCallback handler)
{
var wrappedHandler = new Action<IntPtr, string, string>((ptr, oldVal, newVal) =>
{
handler?.Invoke(new ConVar(ptr), oldVal, newVal);
});
var subscriber = new CallbackSubscriber(convar, handler, wrappedHandler);
NativeAPI.HookConvarChange(convar.Handle, subscriber.GetInputArgument());
ConvarChangeHandlers[handler] = subscriber;
}
public void UnhookConVarChange(ConVar convar, ConVar.ConVarChangedCallback handler)
{
if (ConvarChangeHandlers.ContainsKey(handler))
{
var subscriber = ConvarChangeHandlers[handler];
NativeAPI.UnhookConvarChange(convar.Handle, subscriber.GetInputArgument());
FunctionReference.Remove(subscriber.GetReferenceIdentifier());
CommandHandlers.Remove(handler);
}
}*/
// Adds global listener, e.g. OnTick, OnClientConnect
/// <summary>
/// Registers a global listener, e.g. <see cref="Listeners.OnTick"/>, <see cref="Listeners.OnClientConnect"/>.
/// </summary>
/// <param name="handler"></param>
/// <typeparam name="T">Listener delegate type</typeparam>
/// <exception cref="ArgumentException">Invalid listener <see cref="T"/> provided</exception>
/// <example>
/// <code lang="C#">
/// RegisterListener&lt;Listeners.OnTick&gt;(OnTick);
/// </code>
/// </example>
public void RegisterListener<T>(T handler) where T : Delegate
{
var listenerName = typeof(T).GetCustomAttribute<ListenerNameAttribute>()?.Name;
if (string.IsNullOrEmpty(listenerName))
{
throw new Exception("Listener of type T is invalid and does not have a name attribute");
throw new ArgumentException("Listener of type T is invalid and does not have a name attribute",
nameof(T));
}
var parameterTypes = typeof(T).GetMethod("Invoke").GetParameters().Select(p => p.ParameterType).ToArray();
@@ -287,6 +304,34 @@ namespace CounterStrikeSharp.API.Core
Listeners[handler] = subscriber;
}
/// <summary>
/// Removes a global listener.
/// </summary>
/// <param name="handler"></param>
/// <typeparam name="T"></typeparam>
/// <exception cref="ArgumentException">Invalid listener <see cref="T"/> provided</exception>
public void RemoveListener<T>(T handler) where T : Delegate
{
var listenerName = typeof(T).GetCustomAttribute<ListenerNameAttribute>()?.Name;
if (string.IsNullOrEmpty(listenerName))
{
throw new ArgumentException("Listener of type T is invalid and does not have a name attribute",
nameof(T));
}
if (!Listeners.TryGetValue(handler, out var subscriber)) return;
NativeAPI.RemoveListener(listenerName, subscriber.GetInputArgument());
FunctionReference.Remove(subscriber.GetReferenceIdentifier());
Listeners.Remove(handler);
}
/// <summary>
/// Removes a global listener.
/// </summary>
/// <param name="name"></param>
/// <param name="handler"></param>
[Obsolete("Use the generic version of this method")]
public void RemoveListener(string name, Delegate handler)
{
if (!Listeners.TryGetValue(handler, out var subscriber)) return;
@@ -296,6 +341,14 @@ namespace CounterStrikeSharp.API.Core
Listeners.Remove(handler);
}
/// <summary>
/// Adds a timer that will call the given callback after the specified amount of seconds.
/// By default will only run once unless the <see cref="TimerFlags.REPEAT"/> flag is set.
/// </summary>
/// <param name="interval">Interval/Delay in seconds</param>
/// <param name="callback">Code to run when timer elapses</param>
/// <param name="flags">Controls if the timer is a one-off, repeat or stops on map change etc.</param>
/// <returns>An instance of the <see cref="Timer"/></returns>
public Timer AddTimer(float interval, Action callback, TimerFlags? flags = null)
{
var timer = new Timer(interval, callback, flags ?? 0);
@@ -303,7 +356,11 @@ namespace CounterStrikeSharp.API.Core
return timer;
}
/// <summary>
/// Registers all attribute handlers on the given instance.
/// Can be used to register event handlers, console commands, entity outputs etc. from classes that are not derived from `BasePlugin`.
/// </summary>
/// <param name="instance"></param>
public void RegisterAllAttributes(object instance)
{
this.RegisterAttributeHandlers(instance);
@@ -338,7 +395,7 @@ namespace CounterStrikeSharp.API.Core
}
/// <summary>
/// Registers all game event handlers that are decorated with the `[GameEventHandler]` attribute.
/// Registers all game event handlers that are decorated with the <see cref="GameEventHandlerAttribute"/> attribute.
/// </summary>
/// <param name="instance">The instance of the object where the event handlers are defined.</param>
public void RegisterAttributeHandlers(object instance)
@@ -368,6 +425,10 @@ namespace CounterStrikeSharp.API.Core
}
}
/// <summary>
/// Registers all console command handlers that are decorated with the <see cref="ConsoleCommandAttribute"/> attribute.
/// </summary>
/// <param name="instance">The instance of the object where the console command handlers are defined.</param>
public void RegisterConsoleCommandAttributeHandlers(object instance)
{
var eventHandlers = instance.GetType()
@@ -395,6 +456,10 @@ namespace CounterStrikeSharp.API.Core
}
}
/// <summary>
/// Registers all entity output handlers that are decorated with the <see cref="EntityOutputHookAttribute"/> attribute.
/// </summary>
/// <param name="instance">The instance of the object where entity output hook handlers are defined.</param>
public void RegisterEntityOutputAttributeHandlers(object instance)
{
var handlers = instance.GetType()
@@ -449,6 +514,12 @@ namespace CounterStrikeSharp.API.Core
RegisterFakeConVars(instance.GetType(), instance);
}
/// <summary>
/// Hooks an <a href="https://developer.valvesoftware.com/wiki/Inputs_and_Outputs">entity output</a>.
/// </summary>
/// <param name="classname">Classname to hook, or `*` for wildcard</param>
/// <param name="outputName">Output name to hook, or `*` for wildcard</param>
/// <param name="handler">Handler to call</param>
public void HookEntityOutput(string classname, string outputName, EntityIO.EntityOutputHandler handler, HookMode mode = HookMode.Pre)
{
var subscriber = new CallbackSubscriber(handler, handler,
@@ -458,6 +529,10 @@ namespace CounterStrikeSharp.API.Core
EntityOutputHooks[handler] = subscriber;
}
/// <summary>
/// Unhooks an entity output.
/// </summary>
/// <inheritdoc cref="HookEntityOutput"/>
public void UnhookEntityOutput(string classname, string outputName, EntityIO.EntityOutputHandler handler, HookMode mode = HookMode.Pre)
{
if (!EntityOutputHooks.TryGetValue(handler, out var subscriber)) return;
@@ -467,6 +542,12 @@ namespace CounterStrikeSharp.API.Core
EntityOutputHooks.Remove(handler);
}
/// <summary>
/// Hooks an entity output for a single entity instance.
/// </summary>
/// <param name="entityInstance">Entity instance to hook</param>
/// <param name="outputName">Output name to hook, or `*` for wildcard</param>
/// <param name="handler">Handler to call</param>
public void HookSingleEntityOutput(CEntityInstance entityInstance, string outputName, EntityIO.EntityOutputHandler handler)
{
// since we wrap around the plugin handler we need to do this to ensure that the plugin callback is only called
@@ -490,6 +571,10 @@ namespace CounterStrikeSharp.API.Core
EntitySingleOutputHooks[handler] = new EntityIO.EntityOutputCallback(entityInstance.DesignerName, outputName, internalHandler);
}
/// <summary>
/// Unhooks an entity output for a single entity instance.
/// </summary>
/// <inheritdoc cref="HookSingleEntityOutput"/>
public void UnhookSingleEntityOutput(CEntityInstance entityInstance, string outputName, EntityIO.EntityOutputHandler handler)
{
UnhookSingleEntityOutputInternal(entityInstance.DesignerName, outputName, handler);
@@ -528,10 +613,6 @@ namespace CounterStrikeSharp.API.Core
subscriber.Dispose();
}
foreach (var kv in ConvarChangeHandlers)
{
}
foreach (var subscriber in Listeners.Values)
{
subscriber.Dispose();

View File

@@ -0,0 +1,25 @@
namespace CounterStrikeSharp.API.Core.Capabilities;
public static class Capabilities
{
public static void RegisterPluginCapability<T>(PluginCapability<T> capability, Func<T> supplier)
{
if (!PluginCapability<T>.Providers.ContainsKey(capability.Name))
{
PluginCapability<T>.Providers.Add(capability.Name, new());
}
PluginCapability<T>.Providers[capability.Name].Add(supplier);
}
public static void RegisterPlayerCapability<T>(PlayerCapability<T> capability,
Func<CCSPlayerController, T> supplier)
{
if (!PlayerCapability<T>.Providers.ContainsKey(capability.Name))
{
PlayerCapability<T>.Providers.Add(capability.Name, new());
}
PlayerCapability<T>.Providers[capability.Name].Add(supplier);
}
}

View File

@@ -0,0 +1,24 @@
using System.Collections.Generic;
namespace CounterStrikeSharp.API.Core.Capabilities;
public sealed class PlayerCapability<T>
{
public string Name { get; }
internal static readonly Dictionary<string, List<Func<CCSPlayerController, T>>> Providers = new();
public PlayerCapability(string name)
{
Name = name;
}
public T? Get(CCSPlayerController entity)
{
foreach (var provider in Providers[Name])
{
return provider(entity);
}
return default;
}
}

View File

@@ -0,0 +1,24 @@
using System.Collections.Generic;
namespace CounterStrikeSharp.API.Core.Capabilities;
public sealed class PluginCapability<T>
{
public string Name { get; }
internal static readonly Dictionary<string, List<Func<T>>> Providers = new();
public PluginCapability(string name)
{
Name = name;
}
public T? Get()
{
foreach (var provider in Providers[Name])
{
return provider();
}
return default;
}
}

View File

@@ -106,6 +106,11 @@ public class CommandManager : ICommandManager
foreach (var attr in permissionsToCheck)
{
if (attr.Permissions.Count == 0)
{
continue;
}
attr.Command = name;
if (!attr.CanExecuteCommand(caller))
{

View File

@@ -46,12 +46,21 @@ namespace CounterStrikeSharp.API.Core
[JsonPropertyName("FollowCS2ServerGuidelines")]
public bool FollowCS2ServerGuidelines { get; set; } = true;
[JsonPropertyName("PluginHotReloadEnabled")]
public bool PluginHotReloadEnabled { get; set; } = true;
[JsonPropertyName("PluginAutoLoadEnabled")]
public bool PluginAutoLoadEnabled { get; set; } = true;
[JsonPropertyName("ServerLanguage")]
public string ServerLanguage { get; set; } = "en";
[JsonPropertyName("UnlockConCommands")]
public bool UnlockConCommands { get; set; } = true;
[JsonPropertyName("UnlockConVars")]
public bool UnlockConVars { get; set; } = true;
}
/// <summary>
@@ -94,8 +103,18 @@ namespace CounterStrikeSharp.API.Core
/// When enabled, plugins are automatically reloaded when their .dll file is updated.
/// </summary>
public static bool PluginHotReloadEnabled => _coreConfig.PluginHotReloadEnabled;
/// <summary>
/// When enabled, plugins are automatically loaded from the plugins directory on server start.
/// </summary>
public static bool PluginAutoLoadEnabled => _coreConfig.PluginAutoLoadEnabled;
public static string ServerLanguage => _coreConfig.ServerLanguage;
public static bool UnlockConCommands => _coreConfig.UnlockConCommands;
public static bool UnlockConVars => _coreConfig.UnlockConVars;
}
public partial class CoreConfig : IStartupService
@@ -131,7 +150,7 @@ namespace CounterStrikeSharp.API.Core
ReloadCoreConfigCommand));
_commandsRegistered = true;
}
if (!File.Exists(_coreConfigPath))
{
_logger.LogWarning(
@@ -172,13 +191,13 @@ namespace CounterStrikeSharp.API.Core
serverCulture = CultureInfo.InvariantCulture;
}
}
CultureInfo.DefaultThreadCurrentUICulture = serverCulture;
CultureInfo.DefaultThreadCurrentCulture = serverCulture;
CultureInfo.CurrentUICulture = serverCulture;
CultureInfo.CurrentCulture = serverCulture;
_logger.LogInformation("Successfully loaded core configuration");
}
}
}
}

View File

@@ -14,10 +14,9 @@
* along with CounterStrikeSharp. If not, see <https://www.gnu.org/licenses/>. *
*/
using System;
using System.Collections.Generic;
using System.Linq;
using System.Collections.Concurrent;
using System.Runtime.InteropServices;
using System.Threading.Tasks;
using Microsoft.Extensions.Logging;
namespace CounterStrikeSharp.API.Core
@@ -29,140 +28,149 @@ namespace CounterStrikeSharp.API.Core
{
/// <summary>Delegate will be removed after the first invocation.</summary>
SingleUse,
/// <summary>Delegate will remain in memory for the lifetime of the application.</summary>
/// <summary>Delegate will remain in memory for the lifetime of the application (or until <see cref="FunctionReference.Remove"/> is called).</summary>
Permanent
}
/// <summary>
/// Represents a reference to a function that can be called from native code.
/// </summary>
public class FunctionReference
{
private readonly Delegate m_method;
public FunctionLifetime Lifetime { get; set; } = FunctionLifetime.Permanent;
public unsafe delegate void CallbackDelegate(fxScriptContext* context);
private CallbackDelegate s_callback;
private FunctionReference(Delegate method)
private static readonly ConcurrentDictionary<int, FunctionReference> IdToFunctionReferencesMap = new();
private static readonly ConcurrentDictionary<Delegate, FunctionReference> TargetMethodToFunctionReferencesMap = new();
private static readonly object ReferenceCounterLock = new();
private static int _referenceCounter;
private readonly Delegate _targetMethod;
private readonly CallbackDelegate _nativeCallback;
private readonly TaskCompletionSource _taskCompletionSource = new();
private FunctionReference(Delegate method, FunctionLifetime lifetime)
{
m_method = method;
unsafe
{
var dg = new CallbackDelegate((fxScriptContext* context) =>
{
try
{
var scriptContext = new ScriptContext(context);
if (method.Method.GetParameters().FirstOrDefault()?.ParameterType == typeof(ScriptContext))
{
var returnO = m_method.DynamicInvoke(scriptContext);
if (returnO != null)
{
scriptContext.SetResult(returnO, context);
}
return;
}
var paramsList = method.Method.GetParameters().Select((x, i) =>
{
var param = method.Method.GetParameters()[i];
object obj = null;
if (typeof(NativeObject).IsAssignableFrom(param.ParameterType))
{
obj = Activator.CreateInstance(param.ParameterType,
new[] { scriptContext.GetArgument(typeof(IntPtr), i) });
}
else
{
obj = scriptContext.GetArgument(param.ParameterType, i);
}
return obj;
}).ToArray();
var returnObj = m_method.DynamicInvoke(paramsList);
if (returnObj != null)
{
scriptContext.SetResult(returnObj, context);
}
}
catch (Exception e)
{
Application.Instance.Logger.LogError(e, "Error invoking callback");
}
finally
{
if (Lifetime == FunctionLifetime.SingleUse)
{
Remove(Identifier);
if (references.ContainsKey(m_method))
references.Remove(m_method);
}
}
});
s_callback = dg;
}
Lifetime = lifetime;
_targetMethod = method;
_nativeCallback = CreateWrappedCallback();
}
/// <summary>
/// <inheritdoc cref="FunctionLifetime"/>
/// </summary>
public FunctionLifetime Lifetime { get; }
/// <summary>
/// For <see cref="FunctionLifetime.SingleUse"/> function references, this task will complete when
/// the function has finished invoking.
/// </summary>
public Task CompletionTask => _taskCompletionSource.Task;
public int Identifier { get; private set; }
public static FunctionReference Create(Delegate method)
private unsafe CallbackDelegate CreateWrappedCallback()
{
if (references.ContainsKey(method))
return context =>
{
return references[method];
try
{
var scriptContext = new ScriptContext(context);
// Allow for manual handling of the script context
if (_targetMethod.Method.GetParameters().FirstOrDefault()?.ParameterType == typeof(ScriptContext))
{
var returnValue = _targetMethod.DynamicInvoke(scriptContext);
if (returnValue != null)
{
scriptContext.SetResult(returnValue, context);
}
return;
}
var parameterList = _targetMethod.Method.GetParameters().Select((_, i) =>
{
var parameter = _targetMethod.Method.GetParameters()[i];
return scriptContext.GetArgument(parameter.ParameterType, i);
}).ToArray();
var returnObj = _targetMethod.DynamicInvoke(parameterList);
if (returnObj != null)
{
scriptContext.SetResult(returnObj, context);
}
}
catch (Exception e)
{
Application.Instance.Logger.LogError(e, "Error invoking callback");
}
finally
{
if (Lifetime == FunctionLifetime.SingleUse)
{
RemoveSelf();
}
_taskCompletionSource.TrySetResult();
}
};
}
public static FunctionReference Create(Delegate method, FunctionLifetime lifetime = FunctionLifetime.Permanent)
{
// We always want to create a new reference if the lifetime is single use.
if (lifetime == FunctionLifetime.Permanent && TargetMethodToFunctionReferencesMap.TryGetValue(method, out var existingReference))
{
return existingReference;
}
var reference = new FunctionReference(method);
var reference = new FunctionReference(method, lifetime);
var referenceId = Register(reference);
reference.Identifier = referenceId;
return reference;
}
private static Dictionary<int, FunctionReference> ms_references = new Dictionary<int, FunctionReference>();
private static int ms_referenceId;
private static Dictionary<Delegate, FunctionReference> references =
new Dictionary<Delegate, FunctionReference>();
private static int Register(FunctionReference reference)
{
var thisRefId = ms_referenceId;
ms_references[thisRefId] = reference;
references[reference.m_method] = reference;
unchecked { ms_referenceId++; }
return thisRefId;
}
public static FunctionReference Get(int reference)
{
if (ms_references.ContainsKey(reference))
lock (ReferenceCounterLock)
{
return ms_references[reference];
}
var thisRefId = _referenceCounter;
IdToFunctionReferencesMap[thisRefId] = reference;
TargetMethodToFunctionReferencesMap[reference._targetMethod] = reference;
return null;
unchecked
{
_referenceCounter++;
}
return thisRefId;
}
}
public IntPtr GetFunctionPointer()
public IntPtr GetFunctionPointer() => Marshal.GetFunctionPointerForDelegate(_nativeCallback);
private void RemoveSelf()
{
IntPtr cb = Marshal.GetFunctionPointerForDelegate(s_callback);
return cb;
Remove(Identifier);
}
public static void Remove(int reference)
{
if (ms_references.TryGetValue(reference, out var funcRef))
if (IdToFunctionReferencesMap.TryGetValue(reference, out var functionReference))
{
ms_references.Remove(reference);
if (TargetMethodToFunctionReferencesMap.ContainsKey(functionReference._targetMethod))
{
TargetMethodToFunctionReferencesMap.Remove(functionReference._targetMethod, out _);
}
IdToFunctionReferencesMap.Remove(reference, out _);
Application.Instance.Logger.LogDebug("Removing function/callback reference: {Reference}", reference);
}

File diff suppressed because it is too large Load Diff

View File

@@ -18,6 +18,12 @@ public interface IScriptHostConfiguration
/// </summary>
string PluginPath { get; }
/// <summary>
/// Gets the absolute path to the directory that contains CounterStrikeSharp plugin shared APIS.
/// e.g. /game/csgo/addons/counterstrikesharp/shared
/// </summary>
string SharedPath { get; }
/// <summary>
/// Gets the absolute path to the directory that contains CounterStrikeSharp configs.
/// e.g. /game/csgo/addons/counterstrikesharp/configs

View File

@@ -7,12 +7,14 @@ internal sealed class ScriptHostConfiguration : IScriptHostConfiguration
{
public string RootPath { get; }
public string PluginPath { get; }
public string SharedPath { get; }
public string ConfigsPath { get; }
public string GameDataPath { get; }
public ScriptHostConfiguration(IHostEnvironment hostEnvironment)
{
RootPath = Path.Join(new[] { hostEnvironment.ContentRootPath });
SharedPath = Path.Join(new[] { hostEnvironment.ContentRootPath, "shared" });
PluginPath = Path.Join(new[] { hostEnvironment.ContentRootPath, "plugins" });
ConfigsPath = Path.Join(new[] { hostEnvironment.ContentRootPath, "configs" });
GameDataPath = Path.Join(new[] { hostEnvironment.ContentRootPath, "gamedata" });

View File

@@ -28,17 +28,23 @@ namespace CounterStrikeSharp.API.Core
public interface IPlugin : IDisposable
{
/// <summary>
/// Name of the plugin.
/// Name of the plugin as it will appear in the plugin list.
/// </summary>
string ModuleName { get; }
/// <summary>
/// Module version.
/// Module version as it will appear in the plugin list.
/// </summary>
string ModuleVersion { get; }
/// <summary>
/// Author of the plugin as it will appear in the plugin list.
/// </summary>
string ModuleAuthor { get; }
/// <summary>
/// Brief description of the plugin as it will appear in the plugin list.
/// </summary>
string ModuleDescription { get; }
/// <summary>
@@ -53,12 +59,23 @@ namespace CounterStrikeSharp.API.Core
/// </summary>
void Unload(bool hotReload);
/// <summary>
/// Will be called by CounterStrikeSharp after all plugins have been loaded.
/// This will also be called for convenience after a reload or a late l oad, so that you don't have to handle
/// re-wiring everything.
/// </summary>
/// <param name="hotReload"></param>
void OnAllPluginsLoaded(bool hotReload);
/// <summary>
/// The path to the plugin's DLL file.
/// </summary>
string ModulePath { get; internal set; }
ILogger Logger { get; set; }
IStringLocalizer Localizer { get; set; }
ICommandManager CommandManager { get; set; }
void RegisterAllAttributes(object instance);

View File

@@ -2,6 +2,7 @@
using System;
using CounterStrikeSharp.API.Core.Attributes;
using CounterStrikeSharp.API.Modules.Entities;
using CounterStrikeSharp.API.Modules.Utils;
namespace CounterStrikeSharp.API.Core
{
@@ -154,5 +155,13 @@ namespace CounterStrikeSharp.API.Core
/// <param name="simulating"><see langword="true"/> if simulating, <see langword="false"/> otherwise</param>
[ListenerName("OnServerPreWorldUpdate")]
public delegate void OnServerPreWorldUpdate(bool simulating);
/// <summary>
/// Called when the server precaching resources (only when initial startup / changing map).
/// </summary>
/// <param name="manifest">Resource Manifest</param>
[ListenerName("OnServerPrecacheResources")]
public delegate void OnServerPrecacheResources(ResourceManifest manifest);
}
}
}

View File

@@ -8,12 +8,19 @@ namespace CounterStrikeSharp.API.Core;
public partial class CBaseEntity
{
/// <exception cref="InvalidOperationException">Entity is not valid</exception>
public void Teleport(Vector position, QAngle angles, Vector velocity)
/// <exception cref="ArgumentNullException">No valid argument</exception>
public void Teleport(Vector? position = null, QAngle? angles = null, Vector? velocity = null)
{
Guard.IsValidEntity(this);
VirtualFunction.CreateVoid<IntPtr, IntPtr, IntPtr, IntPtr>(Handle, GameData.GetOffset("CBaseEntity_Teleport"))(
Handle, position.Handle, angles.Handle, velocity.Handle);
if (position == null && angles == null && velocity == null)
throw new ArgumentNullException("No valid argument");
nint _position = position?.Handle ?? 0;
nint _angles = angles?.Handle ?? 0;
nint _velocity = velocity?.Handle ?? 0;
VirtualFunction.CreateVoid<IntPtr, IntPtr, IntPtr, IntPtr>(Handle, GameData.GetOffset("CBaseEntity_Teleport"))(Handle, _position, _angles, _velocity);
}
/// <exception cref="InvalidOperationException">Entity is not valid</exception>
@@ -39,6 +46,6 @@ public partial class CBaseEntity
{
Guard.IsValidEntity(this);
return (T) Activator.CreateInstance(typeof(T), Marshal.ReadIntPtr(SubclassID.Handle + 4));
return (T)Activator.CreateInstance(typeof(T), Marshal.ReadIntPtr(SubclassID.Handle + 4));
}
}
}

View File

@@ -26,6 +26,6 @@ public partial class CCSGameRules
/// </summary>
public void TerminateRound(float delay, RoundEndReason roundEndReason)
{
VirtualFunctions.TerminateRound(Handle, roundEndReason, delay);
VirtualFunctions.TerminateRound(Handle, roundEndReason, delay, 0, 0);
}
}

View File

@@ -16,17 +16,17 @@ public partial class CCSPlayerController
/// <exception cref="InvalidOperationException">Entity is not valid</exception>
public IntPtr GiveNamedItem(string item)
{
Guard.IsValidEntity(this);
if (!PlayerPawn.IsValid) return 0;
if (PlayerPawn.Value == null) return 0;
if (!PlayerPawn.Value.IsValid) return 0;
if (PlayerPawn.Value.ItemServices == null) return 0;
return VirtualFunctions.GiveNamedItem(PlayerPawn.Value.ItemServices.Handle, item, 0, 0, 0, 0);
return GiveNamedItem<CEntityInstance>(item)?.Handle ?? IntPtr.Zero;
}
public IntPtr GiveNamedItem(CsItem item)
public T? GiveNamedItem<T>(string item) where T : CEntityInstance
{
Guard.IsValidEntity(this);
return PlayerPawn.Value?.ItemServices?.As<CCSPlayer_ItemServices>().GiveNamedItem<T>(item);
}
public IntPtr GiveNamedItem(CsItem item)
{
string? itemString = EnumUtils.GetEnumMemberAttributeValue(item);
if (string.IsNullOrWhiteSpace(itemString))
@@ -61,6 +61,14 @@ public partial class CCSPlayerController
VirtualFunctions.ClientPrint(Handle, HudDestination.Center, message, 0, 0, 0, 0);
}
/// <exception cref="InvalidOperationException">Entity is not valid</exception>
public void PrintToCenterAlert(string message)
{
Guard.IsValidEntity(this);
VirtualFunctions.ClientPrint(Handle, HudDestination.Alert, message, 0, 0, 0, 0);
}
public void PrintToCenterHtml(string message) => PrintToCenterHtml(message, 5);
/// <exception cref="InvalidOperationException">Entity is not valid</exception>
@@ -75,6 +83,7 @@ public partial class CCSPlayerController
Userid = this
};
@event.FireEventToClient(this);
@event.Free();
}
/// <summary>
@@ -84,17 +93,13 @@ public partial class CCSPlayerController
public void DropActiveWeapon()
{
Guard.IsValidEntity(this);
if (!PlayerPawn.IsValid) return;
if (PlayerPawn.Value == null) return;
if (!PlayerPawn.Value.IsValid) return;
if (PlayerPawn.Value.ItemServices == null) return;
if (PlayerPawn.Value.WeaponServices == null) return;
if (!PlayerPawn.Value.WeaponServices.ActiveWeapon.IsValid) return;
CCSPlayer_ItemServices itemServices = new CCSPlayer_ItemServices(PlayerPawn.Value.ItemServices.Handle);
CCSPlayer_WeaponServices weaponServices = new CCSPlayer_WeaponServices(PlayerPawn.Value.WeaponServices.Handle);
itemServices.DropActivePlayerWeapon(weaponServices.ActiveWeapon.Value);
var itemServices = PlayerPawn.Value?.ItemServices?.As<CCSPlayer_ItemServices>();
var activeWeapon = PlayerPawn.Value?.WeaponServices?.ActiveWeapon.Value;
if (activeWeapon == null || itemServices == null) return;
itemServices.DropActivePlayerWeapon(activeWeapon);
}
/// <summary>
@@ -104,13 +109,8 @@ public partial class CCSPlayerController
public void RemoveWeapons()
{
Guard.IsValidEntity(this);
if (!PlayerPawn.IsValid) return;
if (PlayerPawn.Value == null) return;
if (!PlayerPawn.Value.IsValid) return;
if (PlayerPawn.Value.ItemServices == null) return;
CCSPlayer_ItemServices itemServices = new CCSPlayer_ItemServices(PlayerPawn.Value.ItemServices.Handle);
itemServices.RemoveWeapons();
PlayerPawn.Value?.ItemServices?.As<CCSPlayer_ItemServices>().RemoveWeapons();
}
/// <summary>
@@ -122,11 +122,8 @@ public partial class CCSPlayerController
public void CommitSuicide(bool explode, bool force)
{
Guard.IsValidEntity(this);
if (!PlayerPawn.IsValid) return;
if (PlayerPawn.Value == null) return;
if (!PlayerPawn.Value.IsValid) return;
PlayerPawn.Value.CommitSuicide(explode, force);
PlayerPawn.Value?.CommitSuicide(explode, force);
}
/// <summary>
@@ -136,9 +133,7 @@ public partial class CCSPlayerController
public void Respawn()
{
Guard.IsValidEntity(this);
if (!PlayerPawn.IsValid) return;
if (PlayerPawn.Value == null) return;
if (!PlayerPawn.Value.IsValid) return;
// The Call To Arms update appears to have invalidated the need for CCSPlayerPawn_Respawn.
SetPawn(PlayerPawn.Value);

View File

@@ -45,4 +45,13 @@ public partial class CCSPlayer_ItemServices
VirtualFunction.CreateVoid<nint>(Handle, GameData.GetOffset("CCSPlayer_ItemServices_RemoveWeapons"))(Handle);
}
}
public T? GiveNamedItem<T>(string item) where T : CEntityInstance
{
var pointer = VirtualFunction.Create<nint, string, nint>(Handle, GameData.GetOffset("CCSPlayer_ItemServices_GiveNamedItem"))(Handle, item);
if (pointer == IntPtr.Zero)
return null;
return (T)Activator.CreateInstance(typeof(T), pointer)!;
}
}

View File

@@ -65,7 +65,7 @@ public partial class CEntityInstance : IEquatable<CEntityInstance>
}
/// <summary>
/// Calls a named input method on an entity.
/// Calls a named input method on an entity, this will bypass the map IO event queue system.
/// <example>
/// <code>
/// entity.AcceptInput("Break");
@@ -82,7 +82,30 @@ public partial class CEntityInstance : IEquatable<CEntityInstance>
{
Guard.IsValidEntity(this);
VirtualFunctions.AcceptInput(Handle, inputName, activator?.Handle ?? IntPtr.Zero, caller?.Handle ?? IntPtr.Zero, value, 0);
NativeAPI.AcceptInput(Handle, inputName, activator?.Handle ?? IntPtr.Zero, caller?.Handle ?? IntPtr.Zero, value, outputId);
}
/// <summary>
/// Calls a named input method on an entity, conforming to the map IO event queue system.
/// <example>
/// <code>
/// entity.AddEntityIOEvent("Break");
/// </code>
/// </example>
/// </summary>
/// <param name="inputName">Input action name</param>
/// <param name="activator">Entity which initiated the action, <see langword="null"/> for no entity</param>
/// <param name="caller">Entity that is sending the event, <see langword="null"/> for no entity</param>
/// <param name="value">String variant value to send with the event</param>
/// <param name="delay">Delay in seconds before calling the input</param>
/// <param name="outputId">Unknown, defaults to 0</param>
/// <exception cref="InvalidOperationException">Entity is not valid</exception>
public void AddEntityIOEvent(string inputName, CEntityInstance? activator = null, CEntityInstance? caller = null, string value = "", float delay = 0, int outputId = 0)
{
Guard.IsValidEntity(this);
NativeAPI.AddEntityIoEvent(Handle, inputName, activator?.Handle ?? IntPtr.Zero, caller?.Handle ?? IntPtr.Zero, value, delay, outputId);
}
}
@@ -90,4 +113,4 @@ public partial class CEntityIdentity
{
public unsafe CEntityInstance EntityInstance => new(Unsafe.Read<IntPtr>((void*)Handle));
public unsafe CHandle<CEntityInstance> EntityHandle => new(this.Handle + 0x10);
}
}

View File

@@ -33,6 +33,11 @@ public partial class NetworkedVector<T> : NativeObject, IReadOnlyCollection<T>
}
}
public void RemoveAll()
{
NativeAPI.RemoveAllNetworkVectorElements(Handle);
}
public IEnumerator<T> GetEnumerator()
{
for (int i = 0; i < Count; i++)

View File

@@ -1,7 +1,11 @@
using System.Collections.Generic;
using System.Linq;
using System.Reflection;
using System.Runtime.Loader;
using CounterStrikeSharp.API.Core.Capabilities;
using CounterStrikeSharp.API.Core.Commands;
using CounterStrikeSharp.API.Core.Hosting;
using McMaster.NETCore.Plugins;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Logging;
@@ -14,8 +18,11 @@ public class PluginManager : IPluginManager
private readonly ICommandManager _commandManager;
private readonly IServiceProvider _serviceProvider;
private readonly ILogger<PluginManager> _logger;
private readonly Dictionary<string, Assembly> _sharedAssemblies = new();
private bool _loadedSharedLibs = false;
public PluginManager(IScriptHostConfiguration scriptHostConfiguration, ICommandManager commandManager, ILogger<PluginManager> logger, IServiceProvider serviceProvider, IServiceScopeFactory serviceScopeFactory)
public PluginManager(IScriptHostConfiguration scriptHostConfiguration, ICommandManager commandManager,
ILogger<PluginManager> logger, IServiceProvider serviceProvider, IServiceScopeFactory serviceScopeFactory)
{
_scriptHostConfiguration = scriptHostConfiguration;
_commandManager = commandManager;
@@ -23,6 +30,36 @@ public class PluginManager : IPluginManager
_serviceProvider = serviceProvider;
}
private void LoadLibrary(string path)
{
var loader = PluginLoader.CreateFromAssemblyFile(path, new[] { typeof(IPlugin), typeof(PluginCapability<>), typeof(PlayerCapability<>) },
config => { config.PreferSharedTypes = true; });
var assembly = loader.LoadDefaultAssembly();
_sharedAssemblies[assembly.GetName().Name] = assembly;
}
private void LoadSharedLibraries()
{
var sharedDirectory = Directory.GetDirectories(_scriptHostConfiguration.SharedPath);
var sharedAssemblyPaths = sharedDirectory
.Select(dir => Path.Combine(dir, Path.GetFileName(dir) + ".dll"))
.Where(File.Exists)
.ToArray();
foreach (var sharedAssemblyPath in sharedAssemblyPaths)
{
try
{
LoadLibrary(sharedAssemblyPath);
}
catch (Exception e)
{
_logger.LogError(e, "Failed to load shared assembly from {Path}", sharedAssemblyPath);
}
}
}
public void Load()
{
var pluginDirectories = Directory.GetDirectories(_scriptHostConfiguration.PluginPath);
@@ -31,15 +68,46 @@ public class PluginManager : IPluginManager
.Where(File.Exists)
.ToArray();
foreach (var path in pluginAssemblyPaths)
AssemblyLoadContext.Default.Resolving += (context, name) =>
{
if (!_loadedSharedLibs)
{
LoadSharedLibraries();
_loadedSharedLibs = true;
}
if (!_sharedAssemblies.TryGetValue(name.Name, out var assembly))
{
return null;
}
return assembly;
};
if (CoreConfig.PluginAutoLoadEnabled)
{
foreach (var path in pluginAssemblyPaths)
{
try
{
LoadPlugin(path);
}
catch (Exception e)
{
_logger.LogError(e, "Failed to load plugin from {Path}", path);
}
}
}
foreach (var plugin in _loadedPluginContexts)
{
try
{
LoadPlugin(path);
plugin.Plugin?.OnAllPluginsLoaded(false);
}
catch (Exception e)
{
_logger.LogError(e, "Failed to load plugin from {Path}", path);
_logger.LogError(e, "OnAllPluginsLoaded failed");
}
}
}
@@ -51,8 +119,9 @@ public class PluginManager : IPluginManager
public void LoadPlugin(string path)
{
var plugin = new PluginContext(_serviceProvider, _commandManager, _scriptHostConfiguration, path, _loadedPluginContexts.Select(x => x.PluginId).DefaultIfEmpty(0).Max() + 1);
var plugin = new PluginContext(_serviceProvider, _commandManager, _scriptHostConfiguration, path,
_loadedPluginContexts.Select(x => x.PluginId).DefaultIfEmpty(0).Max() + 1);
_loadedPluginContexts.Add(plugin);
plugin.Load();
}
}
}

View File

@@ -18,6 +18,7 @@ using System.Linq;
using System.Reflection;
using System.Threading.Tasks;
using CounterStrikeSharp.API.Core.Attributes;
using CounterStrikeSharp.API.Core.Capabilities;
using CounterStrikeSharp.API.Core.Commands;
using CounterStrikeSharp.API.Core.Hosting;
using CounterStrikeSharp.API.Core.Logging;
@@ -64,7 +65,7 @@ namespace CounterStrikeSharp.API.Core.Plugin
_hostConfiguration = hostConfiguration;
_path = path;
PluginId = id;
Loader = PluginLoader.CreateFromAssemblyFile(path,
new[]
{
@@ -76,7 +77,7 @@ namespace CounterStrikeSharp.API.Core.Plugin
config.IsUnloadable = true;
config.PreferSharedTypes = true;
});
if (CoreConfig.PluginHotReloadEnabled)
{
_fileWatcher = new FileSystemWatcher
@@ -110,6 +111,7 @@ namespace CounterStrikeSharp.API.Core.Plugin
Loader = eventargs.Loader;
Unload(hotReload: true);
Load(hotReload: true);
Plugin.OnAllPluginsLoaded(hotReload: true);
});
return Task.CompletedTask;
@@ -118,12 +120,12 @@ namespace CounterStrikeSharp.API.Core.Plugin
public void Load(bool hotReload = false)
{
if (State == PluginState.Loaded) return;
using (Loader.EnterContextualReflection())
{
var defaultAssembly = Loader.LoadDefaultAssembly();
Type pluginType = defaultAssembly.GetTypes()
Type pluginType = defaultAssembly.GetExportedTypes()
.FirstOrDefault(t => typeof(IPlugin).IsAssignableFrom(t));
if (pluginType == null) throw new Exception("Unable to find plugin in assembly");

View File

@@ -20,11 +20,11 @@ public partial class CAISound : CPointEntity
// m_iSoundType
[SchemaMember("CAISound", "m_iSoundType")]
public ref Int32 SoundType => ref Schema.GetRef<Int32>(this.Handle, "CAISound", "m_iSoundType");
public ref SoundTypes_t SoundType => ref Schema.GetRef<SoundTypes_t>(this.Handle, "CAISound", "m_iSoundType");
// m_iSoundContext
[SchemaMember("CAISound", "m_iSoundContext")]
public ref Int32 SoundContext => ref Schema.GetRef<Int32>(this.Handle, "CAISound", "m_iSoundContext");
// m_iSoundFlags
[SchemaMember("CAISound", "m_iSoundFlags")]
public ref SoundFlags_t SoundFlags => ref Schema.GetRef<SoundFlags_t>(this.Handle, "CAISound", "m_iSoundFlags");
// m_iVolume
[SchemaMember("CAISound", "m_iVolume")]

View File

@@ -46,6 +46,10 @@ public partial class CAI_Expresser : NativeObject
[SchemaMember("CAI_Expresser", "m_bConsiderSceneInvolvementAsSpeech")]
public ref bool ConsiderSceneInvolvementAsSpeech => ref Schema.GetRef<bool>(this.Handle, "CAI_Expresser", "m_bConsiderSceneInvolvementAsSpeech");
// m_bSceneEntityDisabled
[SchemaMember("CAI_Expresser", "m_bSceneEntityDisabled")]
public ref bool SceneEntityDisabled => ref Schema.GetRef<bool>(this.Handle, "CAI_Expresser", "m_bSceneEntityDisabled");
// m_nLastSpokenPriority
[SchemaMember("CAI_Expresser", "m_nLastSpokenPriority")]
public ref Int32 LastSpokenPriority => ref Schema.GetRef<Int32>(this.Handle, "CAI_Expresser", "m_nLastSpokenPriority");

View File

@@ -54,8 +54,8 @@ public partial class CBaseAnimGraph : CBaseModelEntity
[SchemaMember("CBaseAnimGraph", "m_pRagdollPose")]
public PhysicsRagdollPose_t? RagdollPose => Schema.GetPointer<PhysicsRagdollPose_t>(this.Handle, "CBaseAnimGraph", "m_pRagdollPose");
// m_bClientRagdoll
[SchemaMember("CBaseAnimGraph", "m_bClientRagdoll")]
public ref bool ClientRagdoll => ref Schema.GetRef<bool>(this.Handle, "CBaseAnimGraph", "m_bClientRagdoll");
// m_bRagdollClientSide
[SchemaMember("CBaseAnimGraph", "m_bRagdollClientSide")]
public ref bool RagdollClientSide => ref Schema.GetRef<bool>(this.Handle, "CBaseAnimGraph", "m_bRagdollClientSide");
}

View File

@@ -30,6 +30,10 @@ public partial class CBaseAnimGraphController : CSkeletonAnimationController
[SchemaMember("CBaseAnimGraphController", "m_flSoundSyncTime")]
public ref float SoundSyncTime => ref Schema.GetRef<float>(this.Handle, "CBaseAnimGraphController", "m_flSoundSyncTime");
// m_nActiveIKChainMask
[SchemaMember("CBaseAnimGraphController", "m_nActiveIKChainMask")]
public ref UInt32 ActiveIKChainMask => ref Schema.GetRef<UInt32>(this.Handle, "CBaseAnimGraphController", "m_nActiveIKChainMask");
// m_hSequence
[SchemaMember("CBaseAnimGraphController", "m_hSequence")]
public ref Int32 Sequence => ref Schema.GetRef<Int32>(this.Handle, "CBaseAnimGraphController", "m_hSequence");

View File

@@ -58,6 +58,14 @@ public partial class CBaseButton : CBaseToggle
set { Schema.SetString(this.Handle, "CBaseButton", "m_sUnlockedSound", value); }
}
// m_sOverrideAnticipationName
[SchemaMember("CBaseButton", "m_sOverrideAnticipationName")]
public string OverrideAnticipationName
{
get { return Schema.GetUtf8String(this.Handle, "CBaseButton", "m_sOverrideAnticipationName"); }
set { Schema.SetString(this.Handle, "CBaseButton", "m_sOverrideAnticipationName", value); }
}
// m_bLocked
[SchemaMember("CBaseButton", "m_bLocked")]
public ref bool Locked => ref Schema.GetRef<bool>(this.Handle, "CBaseButton", "m_bLocked");

View File

@@ -54,6 +54,10 @@ public partial class CBaseCSGrenade : CCSWeaponBase
[SchemaMember("CBaseCSGrenade", "m_fDropTime")]
public ref float DropTime => ref Schema.GetRef<float>(this.Handle, "CBaseCSGrenade", "m_fDropTime");
// m_fPinPullTime
[SchemaMember("CBaseCSGrenade", "m_fPinPullTime")]
public ref float PinPullTime => ref Schema.GetRef<float>(this.Handle, "CBaseCSGrenade", "m_fPinPullTime");
// m_bJustPulledPin
[SchemaMember("CBaseCSGrenade", "m_bJustPulledPin")]
public ref bool JustPulledPin => ref Schema.GetRef<bool>(this.Handle, "CBaseCSGrenade", "m_bJustPulledPin");

View File

@@ -54,10 +54,6 @@ public partial class CBaseCSGrenadeProjectile : CBaseGrenade
[SchemaMember("CBaseCSGrenadeProjectile", "m_bDetonationRecorded")]
public ref bool DetonationRecorded => ref Schema.GetRef<bool>(this.Handle, "CBaseCSGrenadeProjectile", "m_bDetonationRecorded");
// m_flDetonateTime
[SchemaMember("CBaseCSGrenadeProjectile", "m_flDetonateTime")]
public ref float DetonateTime => ref Schema.GetRef<float>(this.Handle, "CBaseCSGrenadeProjectile", "m_flDetonateTime");
// m_nItemIndex
[SchemaMember("CBaseCSGrenadeProjectile", "m_nItemIndex")]
public ref UInt16 ItemIndex => ref Schema.GetRef<UInt16>(this.Handle, "CBaseCSGrenadeProjectile", "m_nItemIndex");

View File

@@ -42,10 +42,6 @@ public partial class CBaseCombatCharacter : CBaseFlex
[SchemaMember("CBaseCombatCharacter", "m_bApplyStressDamage")]
public ref bool ApplyStressDamage => ref Schema.GetRef<bool>(this.Handle, "CBaseCombatCharacter", "m_bApplyStressDamage");
// m_bloodColor
[SchemaMember("CBaseCombatCharacter", "m_bloodColor")]
public ref Int32 BloodColor => ref Schema.GetRef<Int32>(this.Handle, "CBaseCombatCharacter", "m_bloodColor");
// m_iDamageCount
[SchemaMember("CBaseCombatCharacter", "m_iDamageCount")]
public ref Int32 DamageCount => ref Schema.GetRef<Int32>(this.Handle, "CBaseCombatCharacter", "m_iDamageCount");

View File

@@ -38,9 +38,9 @@ public partial class CBaseEntity : CEntityInstance
[SchemaMember("CBaseEntity", "m_nLastThinkTick")]
public ref Int32 LastThinkTick => ref Schema.GetRef<Int32>(this.Handle, "CBaseEntity", "m_nLastThinkTick");
// m_nDisableContextThinkStartTick
[SchemaMember("CBaseEntity", "m_nDisableContextThinkStartTick")]
public ref Int32 DisableContextThinkStartTick => ref Schema.GetRef<Int32>(this.Handle, "CBaseEntity", "m_nDisableContextThinkStartTick");
// m_bDisabledContextThinks
[SchemaMember("CBaseEntity", "m_bDisabledContextThinks")]
public ref bool DisabledContextThinks => ref Schema.GetRef<bool>(this.Handle, "CBaseEntity", "m_bDisabledContextThinks");
// m_isSteadyState
[SchemaMember("CBaseEntity", "m_isSteadyState")]
@@ -250,6 +250,10 @@ public partial class CBaseEntity : CEntityInstance
[SchemaMember("CBaseEntity", "m_hGroundEntity")]
public CHandle<CBaseEntity> GroundEntity => Schema.GetDeclaredClass<CHandle<CBaseEntity>>(this.Handle, "CBaseEntity", "m_hGroundEntity");
// m_nGroundBodyIndex
[SchemaMember("CBaseEntity", "m_nGroundBodyIndex")]
public ref Int32 GroundBodyIndex => ref Schema.GetRef<Int32>(this.Handle, "CBaseEntity", "m_nGroundBodyIndex");
// m_flFriction
[SchemaMember("CBaseEntity", "m_flFriction")]
public ref float Friction => ref Schema.GetRef<float>(this.Handle, "CBaseEntity", "m_flFriction");
@@ -338,4 +342,8 @@ public partial class CBaseEntity : CEntityInstance
[SchemaMember("CBaseEntity", "m_flVPhysicsUpdateLocalTime")]
public ref float VPhysicsUpdateLocalTime => ref Schema.GetRef<float>(this.Handle, "CBaseEntity", "m_flVPhysicsUpdateLocalTime");
// m_nBloodType
[SchemaMember("CBaseEntity", "m_nBloodType")]
public ref BloodType BloodType => ref Schema.GetRef<BloodType>(this.Handle, "CBaseEntity", "m_nBloodType");
}

View File

@@ -40,7 +40,7 @@ public partial class CBaseFlex : CBaseAnimGraph
// m_nNextSceneEventId
[SchemaMember("CBaseFlex", "m_nNextSceneEventId")]
public ref UInt32 NextSceneEventId => ref Schema.GetRef<UInt32>(this.Handle, "CBaseFlex", "m_nNextSceneEventId");
public SceneEventId_t NextSceneEventId => Schema.GetDeclaredClass<SceneEventId_t>(this.Handle, "CBaseFlex", "m_nNextSceneEventId");
// m_bUpdateLayerPriorities
[SchemaMember("CBaseFlex", "m_bUpdateLayerPriorities")]

View File

@@ -31,7 +31,7 @@ public partial class CBaseIssue : NativeObject
public string DetailsString
{
get { return Schema.GetString(this.Handle, "CBaseIssue", "m_szDetailsString"); }
set { Schema.SetStringBytes(this.Handle, "CBaseIssue", "m_szDetailsString", value, 260); }
set { Schema.SetStringBytes(this.Handle, "CBaseIssue", "m_szDetailsString", value, 4096); }
}
// m_iNumYesVotes

View File

@@ -30,6 +30,10 @@ public partial class CBasePlayerController : CBaseEntity
[SchemaMember("CBasePlayerController", "m_hPawn")]
public CHandle<CBasePlayerPawn> Pawn => Schema.GetDeclaredClass<CHandle<CBasePlayerPawn>>(this.Handle, "CBasePlayerController", "m_hPawn");
// m_bKnownTeamMismatch
[SchemaMember("CBasePlayerController", "m_bKnownTeamMismatch")]
public ref bool KnownTeamMismatch => ref Schema.GetRef<bool>(this.Handle, "CBasePlayerController", "m_bKnownTeamMismatch");
// m_nSplitScreenSlot
[SchemaMember("CBasePlayerController", "m_nSplitScreenSlot")]
public ref Int32 SplitScreenSlot => ref Schema.GetRef<Int32>(this.Handle, "CBasePlayerController", "m_nSplitScreenSlot");

View File

@@ -54,6 +54,10 @@ public partial class CBaseTrigger : CBaseToggle
[SchemaMember("CBaseTrigger", "m_OnTouching")]
public CEntityIOOutput OnTouching => Schema.GetDeclaredClass<CEntityIOOutput>(this.Handle, "CBaseTrigger", "m_OnTouching");
// m_OnTouchingEachEntity
[SchemaMember("CBaseTrigger", "m_OnTouchingEachEntity")]
public CEntityIOOutput OnTouchingEachEntity => Schema.GetDeclaredClass<CEntityIOOutput>(this.Handle, "CBaseTrigger", "m_OnTouchingEachEntity");
// m_OnNotTouching
[SchemaMember("CBaseTrigger", "m_OnNotTouching")]
public CEntityIOOutput OnNotTouching => Schema.GetDeclaredClass<CEntityIOOutput>(this.Handle, "CBaseTrigger", "m_OnNotTouching");

View File

@@ -32,6 +32,6 @@ public partial class CBlood : CPointEntity
// m_Color
[SchemaMember("CBlood", "m_Color")]
public ref Int32 Color => ref Schema.GetRef<Int32>(this.Handle, "CBlood", "m_Color");
public ref BloodType Color => ref Schema.GetRef<BloodType>(this.Handle, "CBlood", "m_Color");
}

View File

@@ -22,8 +22,4 @@ public partial class CBodyComponentBaseAnimGraph : CBodyComponentSkeletonInstanc
[SchemaMember("CBodyComponentBaseAnimGraph", "m_animationController")]
public CBaseAnimGraphController AnimationController => Schema.GetDeclaredClass<CBaseAnimGraphController>(this.Handle, "CBodyComponentBaseAnimGraph", "m_animationController");
// __m_pChainEntity
[SchemaMember("CBodyComponentBaseAnimGraph", "__m_pChainEntity")]
public CNetworkVarChainer __m_pChainEntity => Schema.GetDeclaredClass<CNetworkVarChainer>(this.Handle, "CBodyComponentBaseAnimGraph", "__m_pChainEntity");
}

View File

@@ -18,8 +18,4 @@ public partial class CBodyComponentBaseModelEntity : CBodyComponentSkeletonInsta
{
public CBodyComponentBaseModelEntity (IntPtr pointer) : base(pointer) {}
// __m_pChainEntity
[SchemaMember("CBodyComponentBaseModelEntity", "__m_pChainEntity")]
public CNetworkVarChainer __m_pChainEntity => Schema.GetDeclaredClass<CNetworkVarChainer>(this.Handle, "CBodyComponentBaseModelEntity", "__m_pChainEntity");
}

View File

@@ -22,8 +22,4 @@ public partial class CBodyComponentPoint : CBodyComponent
[SchemaMember("CBodyComponentPoint", "m_sceneNode")]
public CGameSceneNode SceneNode => Schema.GetDeclaredClass<CGameSceneNode>(this.Handle, "CBodyComponentPoint", "m_sceneNode");
// __m_pChainEntity
[SchemaMember("CBodyComponentPoint", "__m_pChainEntity")]
public CNetworkVarChainer __m_pChainEntity => Schema.GetDeclaredClass<CNetworkVarChainer>(this.Handle, "CBodyComponentPoint", "__m_pChainEntity");
}

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