mirror of
https://github.com/roflmuffin/CounterStrikeSharp.git
synced 2025-12-06 08:03:12 -08:00
Compare commits
19 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
9c8e9db56e | ||
|
|
e2e0eab87d | ||
|
|
43292bb1d2 | ||
|
|
12c54cd4fc | ||
|
|
e155a70873 | ||
|
|
69d9b5d2c8 | ||
|
|
933fdf9d81 | ||
|
|
18e9e37a98 | ||
|
|
fe236806e1 | ||
|
|
2c4e9bca42 | ||
|
|
8f3e0c226b | ||
|
|
5f6ccf2839 | ||
|
|
6c2f56793b | ||
|
|
cc7dd5ca96 | ||
|
|
ebc361b2f8 | ||
|
|
c72eff2546 | ||
|
|
4b432e9efc | ||
|
|
22bbf835c7 | ||
|
|
092a6077c3 |
203
.github/workflows/cmake-single-platform.yml
vendored
203
.github/workflows/cmake-single-platform.yml
vendored
@@ -5,86 +5,195 @@ on:
|
||||
paths-ignore:
|
||||
- 'docs/**'
|
||||
branches: [ "main" ]
|
||||
|
||||
pull_request:
|
||||
branches: [ "main" ]
|
||||
|
||||
env:
|
||||
BUILD_TYPE: Release
|
||||
|
||||
jobs:
|
||||
build:
|
||||
permissions:
|
||||
contents: write
|
||||
runs-on: ubuntu-latest
|
||||
container:
|
||||
image: registry.gitlab.steamos.cloud/steamrt/sniper/sdk:latest
|
||||
|
||||
build_windows:
|
||||
runs-on: windows-latest
|
||||
steps:
|
||||
- name: Prepare env
|
||||
shell: bash
|
||||
run: echo "GITHUB_SHA_SHORT=${GITHUB_SHA::7}" >> $GITHUB_ENV
|
||||
|
||||
- name: Setup protobuf
|
||||
shell: bash
|
||||
run: sudo apt-get update && sudo apt install -y protobuf-compiler
|
||||
- name: Visual Studio environment
|
||||
shell: cmd
|
||||
run: |
|
||||
:: See https://github.com/microsoft/vswhere/wiki/Find-VC
|
||||
for /f "usebackq delims=*" %%i in (`vswhere -latest -property installationPath`) do (
|
||||
call "%%i"\Common7\Tools\vsdevcmd.bat -arch=x64 -host_arch=x64
|
||||
)
|
||||
|
||||
:: Loop over all environment variables and make them global.
|
||||
for /f "delims== tokens=1,2" %%a in ('set') do (
|
||||
echo>>"%GITHUB_ENV%" %%a=%%b
|
||||
)
|
||||
|
||||
- uses: actions/checkout@v3
|
||||
with:
|
||||
submodules: 'recursive'
|
||||
|
||||
- name: Generate build number
|
||||
id: buildnumber
|
||||
uses: onyxmueller/build-tag-number@v1
|
||||
with:
|
||||
token: ${{secrets.github_token}}
|
||||
|
||||
- uses: actions/setup-dotnet@v3
|
||||
with:
|
||||
dotnet-version: '7.0.x'
|
||||
- run: dotnet publish -c Release /p:Version=1.0.${{ env.BUILD_NUMBER }} managed/CounterStrikeSharp.API
|
||||
|
||||
- name: Configure CMake
|
||||
run: cmake -B build -DCMAKE_BUILD_TYPE=${{env.BUILD_TYPE}}
|
||||
|
||||
- name: Build
|
||||
# Build your program with the given configuration
|
||||
run: cmake --build build --config ${{env.BUILD_TYPE}}
|
||||
run: |
|
||||
mkdir -p build
|
||||
cd build
|
||||
cmake -DCMAKE_BUILD_TYPE=${{env.BUILD_TYPE}} ..
|
||||
cmake --build . --config ${{env.BUILD_TYPE}} -- /m:16
|
||||
|
||||
- name: Clean build directory
|
||||
run: |
|
||||
mkdir -p build/addons/counterstrikesharp/bin/win64
|
||||
mv build/${{env.BUILD_TYPE}}/*.dll build/addons/counterstrikesharp/bin/win64
|
||||
mkdir build/output/
|
||||
mv build/addons build/output
|
||||
|
||||
- uses: actions/upload-artifact@v3
|
||||
with:
|
||||
name: counterstrikesharp-build-windows-${{ env.GITHUB_SHA_SHORT }}
|
||||
path: build/output/
|
||||
|
||||
build_linux:
|
||||
runs-on: ubuntu-latest
|
||||
# Could not figure out how to run in a container only on some matrix paths, so I've split it out into its own build.
|
||||
container:
|
||||
image: registry.gitlab.steamos.cloud/steamrt/sniper/sdk:latest
|
||||
steps:
|
||||
- name: Prepare env
|
||||
shell: bash
|
||||
run: echo "GITHUB_SHA_SHORT=${GITHUB_SHA::7}" >> $GITHUB_ENV
|
||||
|
||||
- uses: actions/checkout@v3
|
||||
with:
|
||||
submodules: 'recursive'
|
||||
|
||||
- name: Build
|
||||
run: |
|
||||
mkdir -p build
|
||||
cd build
|
||||
cmake -DCMAKE_BUILD_TYPE=${{env.BUILD_TYPE}} ..
|
||||
cmake --build . --config ${{env.BUILD_TYPE}} -- -j16
|
||||
|
||||
- name: Clean build directory
|
||||
run: |
|
||||
mkdir build/output/
|
||||
mv build/addons build/output
|
||||
|
||||
- name: Add API to Artifacts
|
||||
- uses: actions/upload-artifact@v3
|
||||
with:
|
||||
name: counterstrikesharp-build-linux-${{ env.GITHUB_SHA_SHORT }}
|
||||
path: build/output/
|
||||
|
||||
build_managed:
|
||||
permissions:
|
||||
contents: write
|
||||
runs-on: ubuntu-latest
|
||||
outputs:
|
||||
buildnumber: ${{ steps.buildnumber.outputs.build_number }}
|
||||
steps:
|
||||
- name: Prepare env
|
||||
shell: bash
|
||||
run: echo "GITHUB_SHA_SHORT=${GITHUB_SHA::7}" >> $GITHUB_ENV
|
||||
|
||||
- name: Set fallback build number
|
||||
if: github.event_name == 'pull_request'
|
||||
id: buildnumber
|
||||
run: |
|
||||
mkdir -p build/output/addons/counterstrikesharp/api
|
||||
cp -r managed/CounterStrikeSharp.API/bin/Release/net7.0/publish/* build/output/addons/counterstrikesharp/api
|
||||
echo "build_number=0" >> "$GITHUB_OUTPUT"
|
||||
echo "BUILD_NUMBER=0" >> $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'
|
||||
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'
|
||||
|
||||
- run: |
|
||||
dotnet publish -c Release /p:Version=1.0.${{ env.BUILD_NUMBER }} managed/CounterStrikeSharp.API
|
||||
dotnet pack -c Release /p:Version=1.0.${{ env.BUILD_NUMBER }} managed/CounterStrikeSharp.API
|
||||
|
||||
- uses: actions/upload-artifact@v3
|
||||
with:
|
||||
name: counterstrikesharp-build-${{ env.BUILD_NUMBER }}-${{ env.GITHUB_SHA_SHORT }}
|
||||
path: build/output/
|
||||
name: counterstrikesharp-build-api-${{ env.GITHUB_SHA_SHORT }}
|
||||
path: managed/CounterStrikeSharp.API/bin/Release
|
||||
|
||||
- name: Zip CounterStrikeSharp Build
|
||||
run: (cd build/output && zip -qq -r ../../counterstrikesharp-build-${{ env.BUILD_NUMBER }}-${{ env.GITHUB_SHA_SHORT }}.zip *)
|
||||
publish:
|
||||
if: github.event_name == 'push'
|
||||
permissions:
|
||||
contents: write
|
||||
needs: [ "build_linux", "build_windows", "build_managed" ]
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Prepare env
|
||||
shell: bash
|
||||
run: echo "GITHUB_SHA_SHORT=${GITHUB_SHA::7}" >> $GITHUB_ENV
|
||||
|
||||
- uses: actions/download-artifact@v3
|
||||
with:
|
||||
name: counterstrikesharp-build-windows-${{ env.GITHUB_SHA_SHORT }}
|
||||
path: build/windows
|
||||
|
||||
- uses: actions/download-artifact@v3
|
||||
with:
|
||||
name: counterstrikesharp-build-linux-${{ env.GITHUB_SHA_SHORT }}
|
||||
path: build/linux
|
||||
|
||||
- uses: actions/download-artifact@v3
|
||||
with:
|
||||
name: counterstrikesharp-build-api-${{ env.GITHUB_SHA_SHORT }}
|
||||
path: build/api
|
||||
|
||||
# TODO: This stuff should really be in a matrix
|
||||
- name: Add API to Artifacts
|
||||
run: |
|
||||
mkdir -p build/linux/addons/counterstrikesharp/api
|
||||
mkdir -p build/windows/addons/counterstrikesharp/api
|
||||
cp -r build/api/net7.0/publish/* build/linux/addons/counterstrikesharp/api
|
||||
cp -r build/api/net7.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 *)
|
||||
|
||||
- name: Add dotnet runtime
|
||||
run: |
|
||||
mkdir -p build/output/addons/counterstrikesharp/dotnet
|
||||
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 \
|
||||
| tar xvz -C build/output/addons/counterstrikesharp/dotnet
|
||||
mv build/output/addons/counterstrikesharp/dotnet/shared/Microsoft.NETCore.App/7.0.11/* build/output/addons/counterstrikesharp/dotnet/shared/Microsoft.NETCore.App/
|
||||
| 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
|
||||
unzip -qq dotnet.zip -d build/windows/addons/counterstrikesharp/dotnet
|
||||
|
||||
- name: Zip CounterStrikeSharp Runtime Build
|
||||
run: (cd build/output && zip -qq -r ../../counterstrikesharp-with-runtime-build-${{ env.BUILD_NUMBER }}-${{ env.GITHUB_SHA_SHORT }}.zip *)
|
||||
|
||||
- uses: actions/upload-artifact@v3
|
||||
with:
|
||||
name: counterstrikesharp-with-runtime-build-${{ env.BUILD_NUMBER }}-${{ env.GITHUB_SHA_SHORT }}
|
||||
path: build/output/
|
||||
- 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 *)
|
||||
|
||||
- name: Release
|
||||
uses: softprops/action-gh-release@v1
|
||||
with:
|
||||
tag_name: v${{ env.BUILD_NUMBER }}
|
||||
tag_name: v${{ needs.build_managed.outputs.buildnumber }}
|
||||
files: |
|
||||
counterstrikesharp-build-${{ env.BUILD_NUMBER }}-${{ env.GITHUB_SHA_SHORT }}.zip
|
||||
counterstrikesharp-with-runtime-build-${{ env.BUILD_NUMBER }}-${{ env.GITHUB_SHA_SHORT }}.zip
|
||||
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
|
||||
|
||||
- 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
|
||||
53
.github/workflows/pr-checks.yml
vendored
53
.github/workflows/pr-checks.yml
vendored
@@ -1,53 +0,0 @@
|
||||
name: Build
|
||||
|
||||
on:
|
||||
pull_request:
|
||||
branches: [ "main" ]
|
||||
|
||||
env:
|
||||
BUILD_TYPE: Release
|
||||
|
||||
jobs:
|
||||
build:
|
||||
runs-on: ubuntu-latest
|
||||
container:
|
||||
image: registry.gitlab.steamos.cloud/steamrt/sniper/sdk:latest
|
||||
permissions:
|
||||
pull-requests: read
|
||||
|
||||
steps:
|
||||
- uses: actions/checkout@v3
|
||||
with:
|
||||
submodules: 'recursive'
|
||||
|
||||
- uses: dorny/paths-filter@v2
|
||||
id: changes
|
||||
with:
|
||||
filters: |
|
||||
csharp:
|
||||
- managed/**/*
|
||||
- src/scripting/natives/**/*
|
||||
cpp:
|
||||
- src/**/*
|
||||
|
||||
- uses: actions/setup-dotnet@v3
|
||||
if: steps.changes.outputs.csharp == 'true'
|
||||
with:
|
||||
dotnet-version: '7.0.x'
|
||||
|
||||
- if: steps.changes.outputs.csharp == 'true'
|
||||
run: dotnet build -c Release managed/CounterStrikeSharp.API
|
||||
|
||||
- name: Setup protobuf
|
||||
shell: bash
|
||||
if: steps.changes.outputs.cpp == 'true'
|
||||
run: sudo apt-get update && sudo apt install -y protobuf-compiler
|
||||
|
||||
- name: Configure CMake
|
||||
if: steps.changes.outputs.cpp == 'true'
|
||||
run: cmake -B build -DCMAKE_BUILD_TYPE=${{env.BUILD_TYPE}}
|
||||
|
||||
- name: Build
|
||||
# Build your program with the given configuration
|
||||
if: steps.changes.outputs.cpp == 'true'
|
||||
run: cmake --build build --config ${{env.BUILD_TYPE}}
|
||||
5
.gitignore
vendored
5
.gitignore
vendored
@@ -5,8 +5,13 @@ cmake-build-debug/
|
||||
.vscode/
|
||||
generated/
|
||||
|
||||
# configure_file auto generated.
|
||||
configs/addons/metamod/counterstrikesharp.vdf
|
||||
|
||||
libraries/mono/
|
||||
|
||||
CMakeSettings.json
|
||||
|
||||
build/
|
||||
build_test/
|
||||
|
||||
|
||||
168
CMakeLists.txt
168
CMakeLists.txt
@@ -1,6 +1,7 @@
|
||||
cmake_minimum_required(VERSION 3.18)
|
||||
|
||||
Project(counterstrikesharp C CXX)
|
||||
# You must set ASM, otherwise CMAKE_ASM_COMPILE_OBJECT will not work on MSVC
|
||||
project(counterstrikesharp C CXX ASM)
|
||||
|
||||
include("makefiles/shared.cmake")
|
||||
|
||||
@@ -11,75 +12,86 @@ add_subdirectory(libraries/funchook)
|
||||
set_property(TARGET funchook-static PROPERTY POSITION_INDEPENDENT_CODE ON)
|
||||
|
||||
SET(SOURCE_FILES
|
||||
src/mm_plugin.cpp
|
||||
src/mm_plugin.h
|
||||
libraries/hl2sdk-cs2/tier1/convar.cpp
|
||||
libraries/hl2sdk-cs2/tier1/generichash.cpp
|
||||
libraries/hl2sdk-cs2/entity2/entitysystem.cpp
|
||||
libraries/hl2sdk-cs2/public/tier0/memoverride.cpp
|
||||
libraries/dotnet/hostfxr.h
|
||||
libraries/dotnet/coreclr_delegates.h
|
||||
"libraries/metamod-source/core/sourcehook/sourcehook.cpp"
|
||||
"libraries/metamod-source/core/sourcehook/sourcehook_impl_chookidman.cpp"
|
||||
"libraries/metamod-source/core/sourcehook/sourcehook_impl_chookmaninfo.cpp"
|
||||
"libraries/metamod-source/core/sourcehook/sourcehook_impl_cvfnptr.cpp"
|
||||
"libraries/metamod-source/core/sourcehook/sourcehook_impl_cproto.cpp"
|
||||
src/scripting/dotnet_host.h
|
||||
src/scripting/dotnet_host.cpp
|
||||
src/core/utils.h
|
||||
src/core/globals.h
|
||||
src/core/globals.cpp
|
||||
src/core/log.h
|
||||
src/core/log.cpp
|
||||
src/scripting/script_engine.h
|
||||
src/scripting/script_engine.cpp
|
||||
src/core/global_listener.h
|
||||
src/scripting/callback_manager.h
|
||||
src/scripting/callback_manager.cpp
|
||||
src/core/managers/event_manager.h
|
||||
src/core/managers/event_manager.cpp
|
||||
src/core/timer_system.h
|
||||
src/core/timer_system.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
|
||||
src/scripting/natives/natives_vector.cpp
|
||||
src/scripting/natives/natives_timers.cpp
|
||||
src/utils/virtual.h
|
||||
src/scripting/natives/natives_events.cpp
|
||||
src/core/memory.cpp
|
||||
src/core/memory.h
|
||||
src/core/managers/con_command_manager.cpp
|
||||
src/core/managers/con_command_manager.h
|
||||
src/scripting/natives/natives_commands.cpp
|
||||
src/core/memory_module.h
|
||||
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
|
||||
src/core/cs2_sdk/schema.cpp
|
||||
src/core/function.cpp
|
||||
src/core/function.h
|
||||
src/scripting/natives/natives_memory.cpp
|
||||
src/scripting/natives/natives_schema.cpp
|
||||
src/scripting/natives/natives_entities.cpp
|
||||
src/core/managers/entity_manager.cpp
|
||||
src/core/managers/entity_manager.h
|
||||
src/core/managers/chat_manager.cpp
|
||||
src/core/managers/chat_manager.h
|
||||
src/core/managers/client_command_manager.cpp
|
||||
src/core/managers/client_command_manager.h
|
||||
src/core/managers/server_manager.cpp
|
||||
src/core/managers/server_manager.h
|
||||
src/scripting/natives/natives_server.cpp
|
||||
libraries/nlohmann/json.hpp
|
||||
src/mm_plugin.cpp
|
||||
src/mm_plugin.h
|
||||
libraries/hl2sdk-cs2/tier1/convar.cpp
|
||||
libraries/hl2sdk-cs2/tier1/generichash.cpp
|
||||
libraries/hl2sdk-cs2/entity2/entitysystem.cpp
|
||||
libraries/dotnet/hostfxr.h
|
||||
libraries/dotnet/coreclr_delegates.h
|
||||
libraries/metamod-source/core/sourcehook/sourcehook.cpp
|
||||
libraries/metamod-source/core/sourcehook/sourcehook_impl_chookidman.cpp
|
||||
libraries/metamod-source/core/sourcehook/sourcehook_impl_chookmaninfo.cpp
|
||||
libraries/metamod-source/core/sourcehook/sourcehook_impl_cvfnptr.cpp
|
||||
libraries/metamod-source/core/sourcehook/sourcehook_impl_cproto.cpp
|
||||
src/scripting/dotnet_host.h
|
||||
src/scripting/dotnet_host.cpp
|
||||
src/core/utils.h
|
||||
src/core/globals.h
|
||||
src/core/globals.cpp
|
||||
src/core/gameconfig.h
|
||||
src/core/gameconfig.cpp
|
||||
src/core/log.h
|
||||
src/core/log.cpp
|
||||
src/scripting/script_engine.h
|
||||
src/scripting/script_engine.cpp
|
||||
src/core/global_listener.h
|
||||
src/scripting/callback_manager.h
|
||||
src/scripting/callback_manager.cpp
|
||||
src/core/managers/event_manager.h
|
||||
src/core/managers/event_manager.cpp
|
||||
src/core/timer_system.h
|
||||
src/core/timer_system.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
|
||||
src/scripting/natives/natives_vector.cpp
|
||||
src/scripting/natives/natives_timers.cpp
|
||||
src/utils/virtual.h
|
||||
src/scripting/natives/natives_events.cpp
|
||||
src/core/memory.cpp
|
||||
src/core/memory.h
|
||||
src/core/managers/con_command_manager.cpp
|
||||
src/core/managers/con_command_manager.h
|
||||
src/scripting/natives/natives_commands.cpp
|
||||
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
|
||||
src/core/cs2_sdk/schema.cpp
|
||||
src/core/function.cpp
|
||||
src/core/function.h
|
||||
src/scripting/natives/natives_memory.cpp
|
||||
src/scripting/natives/natives_schema.cpp
|
||||
src/scripting/natives/natives_entities.cpp
|
||||
src/core/managers/entity_manager.cpp
|
||||
src/core/managers/entity_manager.h
|
||||
src/core/managers/chat_manager.cpp
|
||||
src/core/managers/chat_manager.h
|
||||
src/core/managers/client_command_manager.cpp
|
||||
src/core/managers/client_command_manager.h
|
||||
src/core/managers/server_manager.cpp
|
||||
src/core/managers/server_manager.h
|
||||
src/scripting/natives/natives_server.cpp
|
||||
libraries/nlohmann/json.hpp
|
||||
)
|
||||
|
||||
|
||||
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")
|
||||
|
||||
@@ -105,15 +117,25 @@ target_include_directories(
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/src/core/cs2_sdk
|
||||
)
|
||||
|
||||
include("makefiles/linux.base.cmake")
|
||||
if (LINUX)
|
||||
include("makefiles/linux.base.cmake")
|
||||
set_target_properties(${PROJECT_NAME} PROPERTIES
|
||||
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"
|
||||
)
|
||||
endif()
|
||||
|
||||
|
||||
|
||||
# Libraries
|
||||
target_link_libraries(${PROJECT_NAME} ${COUNTER_STRIKE_SHARP_LINK_LIBRARIES})
|
||||
set_target_properties(${PROJECT_NAME} PROPERTIES
|
||||
PREFIX ""
|
||||
LIBRARY_OUTPUT_DIRECTORY "${CMAKE_BINARY_DIR}/addons/counterstrikesharp/bin/linuxsteamrt64"
|
||||
)
|
||||
|
||||
add_custom_command(
|
||||
TARGET ${PROJECT_NAME} PRE_BUILD
|
||||
COMMAND ${CMAKE_COMMAND} -E copy_directory
|
||||
|
||||
@@ -10,13 +10,6 @@ This project is an ongoing migration of a previous project (titled [VSP.NET](htt
|
||||
|
||||
Due to the architectural changes of CS2, the plugin is being rebuilt on the ground up, to support Linux 64-bit, something which was previously impossible.
|
||||
|
||||
## Philosophy
|
||||
|
||||
As a result, there are a few key philosophies and trade-offs that drive the project.
|
||||
- Only 64 bit is supported.
|
||||
- .NET only supports x64 on Linux; CSGO previously only supported 32 bit servers, but CS2 supports 64 bit on Linux.
|
||||
- Supporting both platforms is a lot of work for 1 person, so there are no real plans to support Windows.
|
||||
|
||||
## Install
|
||||
Download the latest build from [here](https://github.com/roflmuffin/CounterStrikeSharp/releases). (Download the with runtime version if this is your first time installing).
|
||||
|
||||
@@ -96,7 +89,7 @@ I've also used the scripting context & native system that is implemented in Five
|
||||
|
||||
## How to Build
|
||||
|
||||
Building requires CMake on Linux.
|
||||
Building requires CMake.
|
||||
|
||||
Clone the repository
|
||||
|
||||
|
||||
@@ -2,14 +2,26 @@
|
||||
"Erikj": {
|
||||
"identity": "76561197960265731",
|
||||
"flags": [
|
||||
"@css/reservation",
|
||||
"@css/generic",
|
||||
"@css/kick",
|
||||
"@css/ban"
|
||||
"@css/ban",
|
||||
"@css/unban",
|
||||
"@css/vip",
|
||||
"@css/slay",
|
||||
"@css/changemap",
|
||||
"@css/cvar",
|
||||
"@css/config",
|
||||
"@css/chat",
|
||||
"@css/vote",
|
||||
"@css/password",
|
||||
"@css/rcon",
|
||||
"@css/cheats",
|
||||
"@css/root"
|
||||
]
|
||||
},
|
||||
"Another erikj": {
|
||||
"identity": "STEAM_0:1:1",
|
||||
"flags": [
|
||||
"@anotherscope/foobar"
|
||||
]
|
||||
"flags": ["@mycustomplugin/admin"]
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
5
configs/addons/counterstrikesharp/configs/core.json
Normal file
5
configs/addons/counterstrikesharp/configs/core.json
Normal file
@@ -0,0 +1,5 @@
|
||||
{
|
||||
"PublicChatTrigger": "!",
|
||||
"SilentChatTrigger": "/",
|
||||
"FollowCS2ServerGuidelines": true
|
||||
}
|
||||
@@ -0,0 +1,4 @@
|
||||
Place your plugin configurations here.
|
||||
|
||||
TestPlugin/TestPlugin.json
|
||||
AnotherPlugin/AnotherPlugin.json
|
||||
@@ -2,46 +2,80 @@
|
||||
"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"
|
||||
}
|
||||
},
|
||||
"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"
|
||||
}
|
||||
},
|
||||
"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"
|
||||
}
|
||||
},
|
||||
"CCSPlayerController_ChangeTeam": {
|
||||
"offsets": {
|
||||
"windows": 90,
|
||||
"linux": 89
|
||||
}
|
||||
},
|
||||
"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"
|
||||
}
|
||||
},
|
||||
"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"
|
||||
}
|
||||
},
|
||||
"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"
|
||||
}
|
||||
},
|
||||
"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",
|
||||
"linux": "\\x55\\x48\\x89\\xF2\\x48\\x89\\xE5\\x41\\x54\\x49\\x89\\xFC\\x48\\x8D\\x7D\\xE0\\x48\\x83\\xEC\\x18\\x48\\x8D\\x05\\xE5\\xD1\\xBF\\x00"
|
||||
}
|
||||
},
|
||||
"CBasePlayerPawn_CommitSuicide": {
|
||||
"offsets": {
|
||||
"windows": 355,
|
||||
"linux": 355
|
||||
}
|
||||
},
|
||||
"CBaseEntity_Teleport": {
|
||||
"offsets": {
|
||||
"windows": 148,
|
||||
"linux": 147
|
||||
}
|
||||
},
|
||||
"GameEntitySystem": {
|
||||
"offsets": {
|
||||
"windows": 88,
|
||||
"linux": 80
|
||||
}
|
||||
},
|
||||
"GameEventManager": {
|
||||
"offsets": {
|
||||
"windows": 91,
|
||||
"linux": 91
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,5 +0,0 @@
|
||||
"Metamod Plugin"
|
||||
{
|
||||
"alias" "counterstrikesharp"
|
||||
"file" "addons/counterstrikesharp/bin/linuxsteamrt64/counterstrikesharp"
|
||||
}
|
||||
@@ -15,7 +15,7 @@ Adding an Admin is as simple as creating a new entry in the `configs/admins.json
|
||||
{
|
||||
"ZoNiCaL": {
|
||||
"identity": "76561198808392634",
|
||||
"flags": ["can_manipulate_players", "admin_messages"]
|
||||
"flags": ["@css/changemap", "@css/generic"]
|
||||
}
|
||||
}
|
||||
```
|
||||
@@ -27,7 +27,7 @@ You can also manually assign permissions to players in code with `AddPlayerPermi
|
||||
Assigning permissions to a Command is as easy as tagging the Command method (function callback) with a `RequiresPermissions` attribute.
|
||||
|
||||
```csharp
|
||||
[RequiresPermissions("can_execute_test_command", "other_permission")]
|
||||
[RequiresPermissions("@css/slay", "@custom/permission")]
|
||||
public void OnMyCommand(CCSPlayerController? caller, CommandInfo info)
|
||||
{
|
||||
...
|
||||
@@ -35,3 +35,28 @@ public void OnMyCommand(CCSPlayerController? caller, CommandInfo info)
|
||||
```
|
||||
|
||||
CounterStrikeSharp handles all of the permission checks behind the scenes for you.
|
||||
|
||||
### Standard Permissions
|
||||
|
||||
Because the flag system is just a list of strings associated with a user, there is no real list of letter based flags like there was previously in something like SourceMod. This means as a plugin author you can declare your own flags, scoped with an `@` symbol, like `@roflmuffin/guns`, which might be the permission to allow spawning of guns in a given command.
|
||||
|
||||
However there is a somewhat standardised list of flags that it is advised you use if you are adding functionality that aligns with their purpose, and these are based on the original SourceMod flags:
|
||||
|
||||
```shell
|
||||
@css/reservation # Reserved slot access.
|
||||
@css/generic # Generic admin.
|
||||
@css/kick # Kick other players.
|
||||
@css/ban # Ban other players.
|
||||
@css/unban # Remove bans.
|
||||
@css/vip # General vip status.
|
||||
@css/slay # Slay/harm other players.
|
||||
@css/changemap # Change the map or major gameplay features.
|
||||
@css/cvar # Change most cvars.
|
||||
@css/config # Execute config files.
|
||||
@css/chat # Special chat privileges.
|
||||
@css/vote # Start or create votes.
|
||||
@css/password # Set a password on the server.
|
||||
@css/rcon # Use RCON commands.
|
||||
@css/cheats # Change sv_cheats or use cheating commands.
|
||||
@css/root # Magically enables all flags and ignores immunity values.
|
||||
```
|
||||
|
||||
26
docs/src/content/docs/reference/core-configuration.md
Normal file
26
docs/src/content/docs/reference/core-configuration.md
Normal file
@@ -0,0 +1,26 @@
|
||||
---
|
||||
title: Core Configuration
|
||||
description: Summary for core configuration values
|
||||
---
|
||||
|
||||
## PublicChatTrigger
|
||||
|
||||
List of characters to use for public chat triggers.
|
||||
|
||||
## SilentChatTrigger
|
||||
|
||||
List of characters to use for silent chat triggers.
|
||||
|
||||
## FollowCS2ServerGuidelines
|
||||
|
||||
Per [CS2 Server Guidelines](https://blog.counter-strike.net/index.php/server_guidelines/), certain plugin
|
||||
functionality will trigger all of the game server owner's Game Server Login Tokens
|
||||
(GSLTs) to get banned when executed on a Counter-Strike 2 game server.
|
||||
|
||||
Enabling this option will block plugins from using functionality that is known to cause this.
|
||||
This option only has any effect on CS2. Note that this does NOT guarantee that you cannot
|
||||
receive a ban.
|
||||
|
||||
:::note
|
||||
Disable this option at your own risk.
|
||||
:::
|
||||
@@ -19,7 +19,9 @@
|
||||
<PackageReference Include="System.Data.DataSetExtensions" Version="4.5.0" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ProjectReference Include="..\..\managed\CounterStrikeSharp.API\CounterStrikeSharp.API.csproj" />
|
||||
<ProjectReference Include="..\..\managed\CounterStrikeSharp.API\CounterStrikeSharp.API.csproj">
|
||||
<Private>false</Private>
|
||||
</ProjectReference>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<PackageReference Include="Newtonsoft.Json" Version="12.0.3" />
|
||||
|
||||
@@ -1,34 +1,29 @@
|
||||
include("makefiles/shared.cmake")
|
||||
|
||||
#SET(_ITERATOR_DEBUG_LEVEL 2)
|
||||
#set(_ITERATOR_DEBUG_LEVEL 2)
|
||||
add_definitions(-D_LINUX -DPOSIX -DLINUX -DGNUC -DCOMPILER_GCC -DPLATFORM_64BITS)
|
||||
#Add_Definitions(-DCOMPILER_MSVC -DCOMPILER_MSVC32 -D_WIN32 -D_WINDOWS -D_ALLOW_KEYWORD_MACROS -D__STDC_LIMIT_MACROS)
|
||||
|
||||
# Set(CMAKE_CXX_FLAGS_RELEASE "/D_NDEBUG /MD /wd4005 /MP")
|
||||
|
||||
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")
|
||||
Set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -D_vsnprintf=vsnprintf -D_alloca=alloca -Dstrcmpi=strcasecmp")
|
||||
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")
|
||||
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -D_vsnprintf=vsnprintf -D_alloca=alloca -Dstrcmpi=strcasecmp")
|
||||
|
||||
# Warnings
|
||||
Set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wall -Wno-uninitialized -Wno-switch -Wno-unused")
|
||||
Set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wno-non-virtual-dtor -Wno-overloaded-virtual")
|
||||
Set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wno-conversion-null -Wno-write-strings")
|
||||
Set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wno-invalid-offsetof -Wno-reorder")
|
||||
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wall -Wno-uninitialized -Wno-switch -Wno-unused")
|
||||
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wno-non-virtual-dtor -Wno-overloaded-virtual")
|
||||
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wno-conversion-null -Wno-write-strings")
|
||||
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wno-invalid-offsetof -Wno-reorder")
|
||||
|
||||
# Others
|
||||
Set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -mfpmath=sse -msse -fno-strict-aliasing")
|
||||
Set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++17 -fno-threadsafe-statics -v -fvisibility=default")
|
||||
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
|
||||
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
|
||||
)
|
||||
10
makefiles/metamod/configure_metamod.cmake
Normal file
10
makefiles/metamod/configure_metamod.cmake
Normal file
@@ -0,0 +1,10 @@
|
||||
if (WIN32)
|
||||
set(COUNTERSTRIKESHARP_VDF_PLATFORM "win64")
|
||||
else()
|
||||
set(COUNTERSTRIKESHARP_VDF_PLATFORM "linuxsteamrt64")
|
||||
endif()
|
||||
|
||||
configure_file(
|
||||
${CMAKE_CURRENT_LIST_DIR}/counterstrikesharp.vdf.in
|
||||
${PROJECT_SOURCE_DIR}/configs/addons/metamod/counterstrikesharp.vdf
|
||||
)
|
||||
5
makefiles/metamod/counterstrikesharp.vdf.in
Normal file
5
makefiles/metamod/counterstrikesharp.vdf.in
Normal file
@@ -0,0 +1,5 @@
|
||||
"Metamod Plugin"
|
||||
{
|
||||
"alias" "counterstrikesharp"
|
||||
"file" "addons/counterstrikesharp/bin/${COUNTERSTRIKESHARP_VDF_PLATFORM}/counterstrikesharp"
|
||||
}
|
||||
@@ -1,40 +1,54 @@
|
||||
Set(CMAKE_CONFIGURATION_TYPES "Debug;Release" CACHE STRING
|
||||
"Only do Release and Debug"
|
||||
FORCE
|
||||
if (UNIX AND NOT APPLE)
|
||||
set(LINUX TRUE)
|
||||
endif()
|
||||
|
||||
if (WIN32 AND NOT MSVC)
|
||||
message(FATAL "MSVC restricted.")
|
||||
endif()
|
||||
|
||||
set(CMAKE_CONFIGURATION_TYPES "Debug;Release" CACHE STRING
|
||||
"Only do Release and Debug"
|
||||
FORCE
|
||||
)
|
||||
|
||||
Set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fPIC")
|
||||
# TODO: Use C++20 instead.
|
||||
set(CMAKE_CXX_STANDARD 17)
|
||||
|
||||
set(CMAKE_STATIC_LIBRARY_PREFIX "")
|
||||
|
||||
Set(SOURCESDK_DIR ${CMAKE_CURRENT_SOURCE_DIR}/libraries/hl2sdk-cs2)
|
||||
Set(METAMOD_DIR ${CMAKE_CURRENT_SOURCE_DIR}/libraries/metamod-source)
|
||||
set(SOURCESDK_DIR ${CMAKE_CURRENT_SOURCE_DIR}/libraries/hl2sdk-cs2)
|
||||
set(METAMOD_DIR ${CMAKE_CURRENT_SOURCE_DIR}/libraries/metamod-source)
|
||||
|
||||
Set(SOURCESDK ${SOURCESDK_DIR}/${BRANCH})
|
||||
Set(SOURCESDK_LIB ${SOURCESDK}/lib)
|
||||
set(SOURCESDK ${SOURCESDK_DIR}/${BRANCH})
|
||||
set(SOURCESDK_LIB ${SOURCESDK}/lib)
|
||||
|
||||
add_definitions(-DMETA_IS_SOURCE2)
|
||||
|
||||
include_directories(
|
||||
${SOURCESDK}
|
||||
${SOURCESDK}/common
|
||||
${SOURCESDK}/game/shared
|
||||
${SOURCESDK}/game/server
|
||||
${SOURCESDK}/public
|
||||
${SOURCESDK}/public/engine
|
||||
${SOURCESDK}/public/mathlib
|
||||
${SOURCESDK}/public/tier0
|
||||
${SOURCESDK}/public/tier1
|
||||
${SOURCESDK}/public/entity2
|
||||
${SOURCESDK}/public/game/server
|
||||
${SOURCESDK}/public/entity2
|
||||
${METAMOD_DIR}/core
|
||||
${METAMOD_DIR}/core/sourcehook
|
||||
libraries/dyncall/dynload
|
||||
libraries/dyncall/dyncall
|
||||
libraries/spdlog/include
|
||||
libraries/tl
|
||||
libraries/funchook/include
|
||||
libraries
|
||||
${SOURCESDK}
|
||||
${SOURCESDK}/common
|
||||
${SOURCESDK}/game/shared
|
||||
${SOURCESDK}/game/server
|
||||
${SOURCESDK}/public
|
||||
${SOURCESDK}/public/engine
|
||||
${SOURCESDK}/public/mathlib
|
||||
${SOURCESDK}/public/tier0
|
||||
${SOURCESDK}/public/tier1
|
||||
${SOURCESDK}/public/entity2
|
||||
${SOURCESDK}/public/game/server
|
||||
${SOURCESDK}/public/entity2
|
||||
${METAMOD_DIR}/core
|
||||
${METAMOD_DIR}/core/sourcehook
|
||||
libraries/dyncall/dynload
|
||||
libraries/dyncall/dyncall
|
||||
libraries/spdlog/include
|
||||
libraries/tl
|
||||
libraries/funchook/include
|
||||
libraries
|
||||
)
|
||||
|
||||
Project(counterstrikesharp C CXX)
|
||||
include(${CMAKE_CURRENT_LIST_DIR}/metamod/configure_metamod.cmake)
|
||||
|
||||
if (LINUX)
|
||||
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fPIC")
|
||||
endif()
|
||||
20
makefiles/windows.base.cmake
Normal file
20
makefiles/windows.base.cmake
Normal file
@@ -0,0 +1,20 @@
|
||||
add_definitions(
|
||||
-DCOMPILER_MSVC -DCOMPILER_MSVC64 -D_WIN32 -D_WINDOWS -D_ALLOW_KEYWORD_MACROS -D__STDC_LIMIT_MACROS
|
||||
-D_CRT_SECURE_NO_WARNINGS=1 -D_CRT_SECURE_NO_DEPRECATE=1 -D_CRT_NONSTDC_NO_DEPRECATE=1
|
||||
)
|
||||
|
||||
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(COUNTER_STRIKE_SHARP_LINK_LIBRARIES
|
||||
${SOURCESDK_LIB}/public/win64/tier0.lib
|
||||
${SOURCESDK_LIB}/public/win64/tier1.lib
|
||||
${SOURCESDK_LIB}/public/win64/interfaces.lib
|
||||
${SOURCESDK_LIB}/public/win64/mathlib.lib
|
||||
spdlog
|
||||
dynload_s
|
||||
dyncall_s
|
||||
distorm
|
||||
funchook-static
|
||||
)
|
||||
@@ -30,6 +30,8 @@ using CounterStrikeSharp.API.Modules.Events;
|
||||
using CounterStrikeSharp.API.Modules.Entities;
|
||||
using CounterStrikeSharp.API.Modules.Listeners;
|
||||
using CounterStrikeSharp.API.Modules.Timers;
|
||||
using McMaster.NETCore.Plugins;
|
||||
using CounterStrikeSharp.API.Modules.Config;
|
||||
|
||||
namespace CounterStrikeSharp.API.Core
|
||||
{
|
||||
@@ -333,6 +335,31 @@ namespace CounterStrikeSharp.API.Core
|
||||
this.RegisterConsoleCommandAttributeHandlers(instance);
|
||||
}
|
||||
|
||||
public void InitializeConfig(object instance, Type pluginType)
|
||||
{
|
||||
Type[] interfaces = pluginType.GetInterfaces();
|
||||
Func<Type, bool> predicate = (i => i.IsGenericType && i.GetGenericTypeDefinition() == typeof(IPluginConfig<>));
|
||||
|
||||
// if the plugin has set a configuration type (implements IPluginConfig<>)
|
||||
if (interfaces.Any(predicate))
|
||||
{
|
||||
// IPluginConfig<>
|
||||
Type @interface = interfaces.Where(predicate).FirstOrDefault()!;
|
||||
|
||||
// custom config type passed as generic
|
||||
Type genericType = @interface!.GetGenericArguments().First();
|
||||
|
||||
var config = typeof(ConfigManager)
|
||||
.GetMethod("Load")!
|
||||
.MakeGenericMethod(genericType)
|
||||
.Invoke(null, new object[] { Path.GetFileName(ModuleDirectory) }) as IBasePluginConfig;
|
||||
|
||||
// we KNOW that we can do this "safely"
|
||||
pluginType.GetRuntimeMethod("OnConfigParsed", new Type[] { genericType })
|
||||
.Invoke(instance, new object[] { config });
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Registers all game event handlers that are decorated with the `[GameEventHandler]` attribute.
|
||||
/// </summary>
|
||||
|
||||
32
managed/CounterStrikeSharp.API/Core/BasePluginConfig.cs
Normal file
32
managed/CounterStrikeSharp.API/Core/BasePluginConfig.cs
Normal file
@@ -0,0 +1,32 @@
|
||||
/*
|
||||
* This file is part of CounterStrikeSharp.
|
||||
* CounterStrikeSharp is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* CounterStrikeSharp is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with CounterStrikeSharp. If not, see <https://www.gnu.org/licenses/>. *
|
||||
*/
|
||||
|
||||
using System.Text.Json.Serialization;
|
||||
|
||||
namespace CounterStrikeSharp.API.Core
|
||||
{
|
||||
public interface IBasePluginConfig
|
||||
{
|
||||
[JsonPropertyName("ConfigVersion")]
|
||||
int Version { get; set; }
|
||||
}
|
||||
|
||||
public class BasePluginConfig : IBasePluginConfig
|
||||
{
|
||||
[JsonPropertyName("ConfigVersion")]
|
||||
public virtual int Version { get; set; } = 1;
|
||||
}
|
||||
}
|
||||
@@ -1,7 +1,37 @@
|
||||
using System;
|
||||
using System.Runtime.InteropServices;
|
||||
|
||||
namespace CounterStrikeSharp.API.Core;
|
||||
|
||||
public static class Constants
|
||||
{
|
||||
public const string ROOT_BINARY_PATH = "/bin/linuxsteamrt64/";
|
||||
public const string GAME_BINARY_PATH = "/csgo/bin/linuxsteamrt64/";
|
||||
public static string ModulePrefix { get; }
|
||||
|
||||
public static string ModuleSuffix { get; }
|
||||
|
||||
public static string RootBinaryPath { get; }
|
||||
|
||||
public static string GameBinaryPath { get; }
|
||||
|
||||
static Constants()
|
||||
{
|
||||
if (RuntimeInformation.IsOSPlatform(OSPlatform.Windows))
|
||||
{
|
||||
ModulePrefix = "";
|
||||
ModuleSuffix = ".dll";
|
||||
GameBinaryPath = "/csgo/bin/win64/";
|
||||
RootBinaryPath = "/bin/win64";
|
||||
}
|
||||
else if (RuntimeInformation.IsOSPlatform(OSPlatform.Linux))
|
||||
{
|
||||
ModulePrefix = "lib";
|
||||
ModuleSuffix = ".so";
|
||||
GameBinaryPath = "/csgo/bin/linuxsteamrt64/";
|
||||
RootBinaryPath = "/bin/linuxsteamrt64/";
|
||||
}
|
||||
else
|
||||
{
|
||||
throw new NotSupportedException($"""Current platform is "{RuntimeInformation.OSDescription}", but does not supported.""");
|
||||
}
|
||||
}
|
||||
}
|
||||
120
managed/CounterStrikeSharp.API/Core/CoreConfig.cs
Normal file
120
managed/CounterStrikeSharp.API/Core/CoreConfig.cs
Normal file
@@ -0,0 +1,120 @@
|
||||
/*
|
||||
* This file is part of CounterStrikeSharp.
|
||||
* CounterStrikeSharp is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* CounterStrikeSharp is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with CounterStrikeSharp. If not, see <https://www.gnu.org/licenses/>. *
|
||||
*/
|
||||
|
||||
using System;
|
||||
using System.IO;
|
||||
using System.Reflection;
|
||||
using System.Text.Json;
|
||||
using System.Text.Json.Serialization;
|
||||
|
||||
using CounterStrikeSharp.API.Modules.Utils;
|
||||
using CounterStrikeSharp.API.Modules.Admin;
|
||||
using CounterStrikeSharp.API.Modules.Commands;
|
||||
|
||||
namespace CounterStrikeSharp.API.Core
|
||||
{
|
||||
/// <summary>
|
||||
/// Serializable instance of the CoreConfig
|
||||
/// </summary>
|
||||
internal sealed partial class CoreConfigData
|
||||
{
|
||||
[JsonPropertyName("PublicChatTrigger")] public string PublicChatTrigger { get; set; } = "!";
|
||||
|
||||
[JsonPropertyName("SilentChatTrigger")] public string SilentChatTrigger { get; set; } = "/";
|
||||
|
||||
[JsonPropertyName("FollowCS2ServerGuidelines")] public bool FollowCS2ServerGuidelines { get; set; } = true;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Configuration related to the Core API.
|
||||
/// </summary>
|
||||
public static partial class CoreConfig
|
||||
{
|
||||
/// <summary>
|
||||
/// List of characters to use for public chat triggers.
|
||||
/// </summary>
|
||||
public static string PublicChatTrigger => _coreConfig.PublicChatTrigger;
|
||||
|
||||
/// <summary>
|
||||
/// List of characters to use for silent chat triggers.
|
||||
/// </summary>
|
||||
public static string SilentChatTrigger => _coreConfig.SilentChatTrigger;
|
||||
|
||||
/// <summary>
|
||||
/// <para>
|
||||
/// Per <see href="http://blog.counter-strike.net/index.php/server_guidelines/"/>, certain plugin
|
||||
/// functionality will trigger all of the game server owner's Game Server Login Tokens
|
||||
/// (GSLTs) to get banned when executed on a Counter-Strike 2 game server.
|
||||
/// </para>
|
||||
///
|
||||
/// <para>
|
||||
/// Enabling this option will block plugins from using functionality that is known to cause this.
|
||||
///
|
||||
/// Note that this does NOT guarantee that you cannot
|
||||
///
|
||||
/// receive a ban.
|
||||
/// </para>
|
||||
///
|
||||
/// <para>
|
||||
/// Disable this option at your own risk.
|
||||
/// </para>
|
||||
/// </summary>
|
||||
public static bool FollowCS2ServerGuidelines => _coreConfig.FollowCS2ServerGuidelines;
|
||||
}
|
||||
|
||||
public static partial class CoreConfig
|
||||
{
|
||||
private static CoreConfigData _coreConfig = new CoreConfigData();
|
||||
|
||||
static CoreConfig()
|
||||
{
|
||||
CommandUtils.AddStandaloneCommand("css_core_reload", "Reloads the core configuration file.", ReloadCoreConfigCommand);
|
||||
}
|
||||
|
||||
[RequiresPermissions("@css/config")]
|
||||
[CommandHelper(whoCanExecute: CommandUsage.CLIENT_AND_SERVER)]
|
||||
private static void ReloadCoreConfigCommand(CCSPlayerController? player, CommandInfo command)
|
||||
{
|
||||
var rootDir = new FileInfo(Assembly.GetExecutingAssembly().Location).Directory.Parent;
|
||||
Load(Path.Combine(rootDir.FullName, "configs", "core.json"));
|
||||
}
|
||||
|
||||
public static void Load(string coreConfigPath)
|
||||
{
|
||||
if (!File.Exists(coreConfigPath))
|
||||
{
|
||||
Console.WriteLine($"Core configuration could not be found at path '{coreConfigPath}', fallback values will be used.");
|
||||
return;
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
var data = JsonSerializer.Deserialize<CoreConfigData>(File.ReadAllText(coreConfigPath), new JsonSerializerOptions() { ReadCommentHandling = JsonCommentHandling.Skip });
|
||||
|
||||
if (data != null)
|
||||
{
|
||||
_coreConfig = data;
|
||||
}
|
||||
|
||||
Console.WriteLine($"Loaded core configuration");
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Console.WriteLine($"Failed to load core configuration: {ex}, fallback values will be used.");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -37,41 +37,68 @@ public static class GameData
|
||||
{
|
||||
try
|
||||
{
|
||||
_methods = JsonSerializer.Deserialize<Dictionary<string, LoadedGameData>>(File.ReadAllText(gameDataPath));
|
||||
_methods = JsonSerializer.Deserialize<Dictionary<string, LoadedGameData>>(File.ReadAllText(gameDataPath))!;
|
||||
|
||||
Console.WriteLine($"Loaded game data with {_methods.Count} methods.");
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Console.WriteLine($"Failed to load game data: {ex.ToString()}");
|
||||
Console.WriteLine($"Failed to load game data: {ex}");
|
||||
}
|
||||
}
|
||||
|
||||
public static string GetSignature(string key)
|
||||
{
|
||||
if (!_methods.ContainsKey(key)) throw new Exception($"Method {key} not found in gamedata.json");
|
||||
if (_methods[key].Signatures == null) throw new Exception($"No signatures found for {key} in gamedata.json");
|
||||
|
||||
var methodMetadata = _methods[key];
|
||||
if (RuntimeInformation.IsOSPlatform(OSPlatform.Linux))
|
||||
Console.WriteLine($"Getting signature: {key}");
|
||||
if (!_methods.ContainsKey(key))
|
||||
{
|
||||
return methodMetadata.Signatures!.Linux;
|
||||
throw new ArgumentException($"Method {key} not found in gamedata.json");
|
||||
}
|
||||
|
||||
return methodMetadata.Signatures!.Windows;
|
||||
var methodMetadata = _methods[key];
|
||||
if (methodMetadata.Signatures == null)
|
||||
{
|
||||
throw new InvalidOperationException($"No signatures found for {key} in gamedata.json");
|
||||
}
|
||||
|
||||
string signature;
|
||||
|
||||
if (RuntimeInformation.IsOSPlatform(OSPlatform.Linux))
|
||||
{
|
||||
signature = methodMetadata.Signatures?.Linux ?? throw new InvalidOperationException($"No Linux signature for {key} in gamedata.json");
|
||||
}
|
||||
else
|
||||
{
|
||||
signature = methodMetadata.Signatures?.Windows ?? throw new InvalidOperationException($"No Windows signature for {key} in gamedata.json");
|
||||
}
|
||||
|
||||
return signature;
|
||||
}
|
||||
|
||||
public static int GetOffset(string key)
|
||||
{
|
||||
if (!_methods.ContainsKey(key)) throw new Exception($"Method {key} not found in gamedata.json");
|
||||
if (_methods[key].Offsets == null) throw new Exception($"No offsets found for {key} in gamedata.json");
|
||||
|
||||
var methodMetadata = _methods[key];
|
||||
if (RuntimeInformation.IsOSPlatform(OSPlatform.Linux))
|
||||
if (!_methods.ContainsKey(key))
|
||||
{
|
||||
return methodMetadata.Offsets!.Linux;
|
||||
throw new Exception($"Method {key} not found in gamedata.json");
|
||||
}
|
||||
|
||||
return methodMetadata.Offsets!.Windows;
|
||||
var methodMetadata = _methods[key];
|
||||
|
||||
if (methodMetadata.Offsets == null)
|
||||
{
|
||||
throw new Exception($"No offsets found for {key} in gamedata.json");
|
||||
}
|
||||
|
||||
int offset;
|
||||
if (RuntimeInformation.IsOSPlatform(OSPlatform.Linux))
|
||||
{
|
||||
offset = methodMetadata.Offsets?.Linux ?? throw new InvalidOperationException($"No Linux offset for {key} in gamedata.json");
|
||||
}
|
||||
else
|
||||
{
|
||||
offset = methodMetadata.Offsets?.Windows ?? throw new InvalidOperationException($"No Windows offset for {key} in gamedata.json");
|
||||
}
|
||||
|
||||
return offset;
|
||||
}
|
||||
}
|
||||
@@ -59,13 +59,16 @@ namespace CounterStrikeSharp.API.Core
|
||||
}
|
||||
public void InitGlobalContext()
|
||||
{
|
||||
Console.WriteLine("Loading CoreConfig from \"configs/core.json\"");
|
||||
CoreConfig.Load(Path.Combine(rootDir.FullName, "configs", "core.json"));
|
||||
|
||||
Console.WriteLine("Loading GameData from \"gamedata/gamedata.json\"");
|
||||
GameData.Load(Path.Combine(rootDir.FullName, "gamedata", "gamedata.json"));
|
||||
|
||||
Console.WriteLine("Loading Admins from \"configs/admins.json\"");
|
||||
AdminManager.Load(Path.Combine(rootDir.FullName, "configs", "admins.json"));
|
||||
|
||||
for (int i = 1; i <= 9; i++)
|
||||
for (var i = 1; i <= 9; i++)
|
||||
{
|
||||
CommandUtils.AddStandaloneCommand("css_" + i, "Command Key Handler", (player, info) =>
|
||||
{
|
||||
@@ -76,18 +79,18 @@ namespace CounterStrikeSharp.API.Core
|
||||
}
|
||||
|
||||
Console.WriteLine("Loading C# plugins...");
|
||||
int pluginCount = LoadAllPlugins();
|
||||
var pluginCount = LoadAllPlugins();
|
||||
Console.WriteLine($"All managed modules were loaded. {pluginCount} plugins loaded.");
|
||||
|
||||
RegisterPluginCommands();
|
||||
}
|
||||
|
||||
public void LoadPlugin(string path)
|
||||
private void LoadPlugin(string path)
|
||||
{
|
||||
var existingPlugin = FindPluginByModulePath(path);
|
||||
if (existingPlugin != null)
|
||||
{
|
||||
throw new Exception("Plugin is already loaded.");
|
||||
throw new FileLoadException("Plugin is already loaded.");
|
||||
}
|
||||
|
||||
var plugin = new PluginContext(path, _loadedPlugins.Select(x => x.PluginId).DefaultIfEmpty(0).Max() + 1);
|
||||
@@ -95,37 +98,39 @@ namespace CounterStrikeSharp.API.Core
|
||||
_loadedPlugins.Add(plugin);
|
||||
}
|
||||
|
||||
public int LoadAllPlugins()
|
||||
private int LoadAllPlugins()
|
||||
{
|
||||
DirectoryInfo modules_directory_info;
|
||||
DirectoryInfo modulesDirectoryInfo;
|
||||
try
|
||||
{
|
||||
modules_directory_info = new DirectoryInfo(Path.Combine(rootDir.FullName, "plugins"));
|
||||
modulesDirectoryInfo = new DirectoryInfo(Path.Combine(rootDir.FullName, "plugins"));
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
Console.WriteLine(
|
||||
"Unable to access .NET modules directory: " + e.GetType().ToString() + " " + e.Message);
|
||||
Console.WriteLine(e);
|
||||
return 0;
|
||||
}
|
||||
|
||||
DirectoryInfo[] proper_modules_directories;
|
||||
DirectoryInfo[] properModulesDirectories;
|
||||
try
|
||||
{
|
||||
proper_modules_directories = modules_directory_info.GetDirectories();
|
||||
properModulesDirectories = modulesDirectoryInfo.GetDirectories();
|
||||
}
|
||||
catch
|
||||
{
|
||||
proper_modules_directories = new DirectoryInfo[0];
|
||||
properModulesDirectories = Array.Empty<DirectoryInfo>();
|
||||
}
|
||||
|
||||
var filePaths = proper_modules_directories
|
||||
|
||||
var filePaths = properModulesDirectories
|
||||
.Where(d => d.GetFiles().Any((f) => f.Name == d.Name + ".dll"))
|
||||
.Select(d => d.GetFiles().First((f) => f.Name == d.Name + ".dll").FullName)
|
||||
.ToArray();
|
||||
|
||||
|
||||
foreach (var path in filePaths)
|
||||
{
|
||||
Console.WriteLine($"Plugin path: {path}");
|
||||
try
|
||||
{
|
||||
LoadPlugin(path);
|
||||
@@ -317,7 +322,7 @@ namespace CounterStrikeSharp.API.Core
|
||||
|
||||
}
|
||||
|
||||
public void RegisterPluginCommands()
|
||||
private void RegisterPluginCommands()
|
||||
{
|
||||
CommandUtils.AddStandaloneCommand("css", "Counter-Strike Sharp options.", OnCSSCommand);
|
||||
CommandUtils.AddStandaloneCommand("css_plugins", "Counter-Strike Sharp plugin options.", OnCSSPluginCommand);
|
||||
|
||||
@@ -64,7 +64,7 @@ namespace CounterStrikeSharp.API.Core
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
Console.WriteLine(e.StackTrace);
|
||||
Console.WriteLine(e);
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
28
managed/CounterStrikeSharp.API/Core/IPluginConfig.cs
Normal file
28
managed/CounterStrikeSharp.API/Core/IPluginConfig.cs
Normal file
@@ -0,0 +1,28 @@
|
||||
/*
|
||||
* This file is part of CounterStrikeSharp.
|
||||
* CounterStrikeSharp is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* CounterStrikeSharp is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with CounterStrikeSharp. If not, see <https://www.gnu.org/licenses/>. *
|
||||
*/
|
||||
|
||||
namespace CounterStrikeSharp.API.Core
|
||||
{
|
||||
/// <summary>
|
||||
/// An interface that describes a plugin configuration.
|
||||
/// </summary>
|
||||
public interface IPluginConfig<T> where T: IBasePluginConfig, new()
|
||||
{
|
||||
T Config { get; set; }
|
||||
|
||||
public void OnConfigParsed(T config);
|
||||
}
|
||||
}
|
||||
@@ -18,9 +18,10 @@ using CounterStrikeSharp.API.Modules.Memory;
|
||||
|
||||
namespace CounterStrikeSharp.API.Core;
|
||||
|
||||
public partial class CGlowProperty
|
||||
public partial class CBaseModelEntity
|
||||
{
|
||||
// m_bGlowing
|
||||
public ref bool IsGlowing => ref Schema.GetRef<bool>(this.Handle, "CGlowProperty", "m_bGlowing");
|
||||
|
||||
}
|
||||
public void SetModel(string model)
|
||||
{
|
||||
VirtualFunctions.SetModel(Handle, model);
|
||||
}
|
||||
}
|
||||
@@ -20,6 +20,7 @@ using System.Linq;
|
||||
using System.Reflection;
|
||||
using System.Threading.Tasks;
|
||||
using CounterStrikeSharp.API.Core.Attributes;
|
||||
using CounterStrikeSharp.API.Modules.Config;
|
||||
using CounterStrikeSharp.API.Modules.Events;
|
||||
using McMaster.NETCore.Plugins;
|
||||
|
||||
@@ -103,6 +104,7 @@ namespace CounterStrikeSharp.API.Core
|
||||
_plugin = (BasePlugin)Activator.CreateInstance(pluginType)!;
|
||||
_plugin.ModulePath = _path;
|
||||
_plugin.RegisterAllAttributes(_plugin);
|
||||
_plugin.InitializeConfig(_plugin, pluginType);
|
||||
_plugin.Load(hotReload);
|
||||
|
||||
Console.WriteLine($"Finished loading plugin: {Name}");
|
||||
|
||||
@@ -2,7 +2,19 @@
|
||||
<PropertyGroup>
|
||||
<TargetFramework>net7.0</TargetFramework>
|
||||
<EnableDynamicLoading>true</EnableDynamicLoading>
|
||||
<GenerateDocumentationFile>true</GenerateDocumentationFile>
|
||||
<EnablePackageValidation>true</EnablePackageValidation>
|
||||
<NoWarn>$(NoWarn);CS1591</NoWarn>
|
||||
<Nullable>enable</Nullable>
|
||||
|
||||
<Authors>Roflmuffin</Authors>
|
||||
<Description>Official server side runtime assembly for CounterStrikeSharp</Description>
|
||||
<PackageProjectUrl>http://docs.cssharp.dev/</PackageProjectUrl>
|
||||
<RepositoryUrl>https://github.com/roflmuffin/CounterStrikeSharp</RepositoryUrl>
|
||||
<PackageLicenseExpression>GPL-3.0-only</PackageLicenseExpression>
|
||||
<PublishRepositoryUrl>true</PublishRepositoryUrl>
|
||||
<IncludeSymbols>true</IncludeSymbols>
|
||||
<SymbolPackageFormat>snupkg</SymbolPackageFormat>
|
||||
</PropertyGroup>
|
||||
<ItemGroup>
|
||||
<None Remove="Modules\Commands\CommandInfo" />
|
||||
|
||||
@@ -20,11 +20,16 @@ public class ColorMarshaler : ICustomMarshal<Color>
|
||||
{
|
||||
public Color NativeToManaged(IntPtr pointer)
|
||||
{
|
||||
return Color.FromArgb(Marshal.ReadInt32(pointer));
|
||||
var color = Marshal.ReadInt32(pointer);
|
||||
var alpha = (byte)((color >> 24) & 0xFF);
|
||||
var blue = (byte)((color >> 16) & 0xFF);
|
||||
var green = (byte)((color >> 8) & 0xFF);
|
||||
var red = (byte)(color & 0xFF);
|
||||
return Color.FromArgb(alpha, red, green, blue);
|
||||
}
|
||||
|
||||
public void ManagedToNative(IntPtr pointer, Color managedObj)
|
||||
{
|
||||
Marshal.WriteInt32(pointer, managedObj.ToArgb());
|
||||
Marshal.WriteInt32(pointer, (managedObj.A << 24) | (managedObj.B << 16) | (managedObj.G << 8) | managedObj.R);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,79 @@
|
||||
/*
|
||||
* This file is part of CounterStrikeSharp.
|
||||
* CounterStrikeSharp is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* CounterStrikeSharp is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with CounterStrikeSharp. If not, see <https://www.gnu.org/licenses/>. *
|
||||
*/
|
||||
|
||||
using System;
|
||||
using System.IO;
|
||||
using System.Reflection;
|
||||
using System.Text;
|
||||
using System.Text.Json;
|
||||
|
||||
using CounterStrikeSharp.API.Core;
|
||||
|
||||
namespace CounterStrikeSharp.API.Modules.Config
|
||||
{
|
||||
public static class ConfigManager
|
||||
{
|
||||
private static readonly DirectoryInfo? _rootDir;
|
||||
|
||||
private static readonly string _pluginConfigsFolderPath;
|
||||
|
||||
static ConfigManager()
|
||||
{
|
||||
_rootDir = new FileInfo(Assembly.GetExecutingAssembly().Location).Directory.Parent;
|
||||
_pluginConfigsFolderPath = Path.Combine(_rootDir.FullName, "configs", "plugins");
|
||||
}
|
||||
|
||||
public static T Load<T>(string pluginName) where T : IBasePluginConfig, new()
|
||||
{
|
||||
string directoryPath = Path.Combine(_pluginConfigsFolderPath, pluginName);
|
||||
string configPath = Path.Combine(directoryPath, $"{pluginName}.json");
|
||||
|
||||
T config = (T)Activator.CreateInstance(typeof(T))!;
|
||||
|
||||
if (!File.Exists(configPath))
|
||||
{
|
||||
try
|
||||
{
|
||||
if (!Directory.Exists(directoryPath))
|
||||
{
|
||||
Directory.CreateDirectory(directoryPath);
|
||||
}
|
||||
|
||||
StringBuilder builder = new StringBuilder();
|
||||
builder.Append($"// This configuration was automatically generated by CounterStrikeSharp for plugin '{pluginName}', at {DateTimeOffset.Now:yyyy/MM/dd hh:mm:ss}\n");
|
||||
builder.Append(JsonSerializer.Serialize<T>(config, new JsonSerializerOptions { WriteIndented = true }));
|
||||
File.WriteAllText(configPath, builder.ToString());
|
||||
return config;
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Console.WriteLine($"Failed to generate configuration file for {pluginName}: {ex}");
|
||||
}
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
config = JsonSerializer.Deserialize<T>(File.ReadAllText(configPath), new JsonSerializerOptions() { ReadCommentHandling = JsonCommentHandling.Skip })!;
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Console.WriteLine($"Failed to parse configuration '{pluginName}': {ex}");
|
||||
}
|
||||
|
||||
return config;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,16 +1,17 @@
|
||||
using System.IO;
|
||||
using System.Runtime.InteropServices;
|
||||
using CounterStrikeSharp.API.Core;
|
||||
|
||||
namespace CounterStrikeSharp.API.Modules.Memory;
|
||||
|
||||
public class Addresses
|
||||
{
|
||||
public static string EnginePath = Path.Join(Server.GameDirectory, Constants.ROOT_BINARY_PATH, "libengine2.so");
|
||||
public static string Tier0Path = Path.Join(Server.GameDirectory, Constants.ROOT_BINARY_PATH, "libtier0.so");
|
||||
public static string ServerPath = Path.Join(Server.GameDirectory, Constants.GAME_BINARY_PATH, "libserver.so");
|
||||
public static string EnginePath => Path.Join(Server.GameDirectory, Constants.RootBinaryPath, $"{Constants.ModulePrefix}engine2{Constants.ModuleSuffix}");
|
||||
public static string Tier0Path => Path.Join(Server.GameDirectory, Constants.RootBinaryPath, $"{Constants.ModulePrefix}tier0{Constants.ModuleSuffix}");
|
||||
|
||||
public static string SchemaSystemPath =
|
||||
Path.Join(Server.GameDirectory, Constants.ROOT_BINARY_PATH, "libschemasystem.so");
|
||||
public static string ServerPath => Path.Join(Server.GameDirectory, Constants.GameBinaryPath, $"{Constants.ModulePrefix}server{Constants.ModuleSuffix}");
|
||||
|
||||
public static string SchemaSystemPath => Path.Join(Server.GameDirectory, Constants.RootBinaryPath, $"{Constants.ModulePrefix}schemasystem{Constants.ModuleSuffix}");
|
||||
public static string VScriptPath => Path.Join(Server.GameDirectory, Constants.RootBinaryPath, $"{Constants.ModulePrefix}vscript{Constants.ModuleSuffix}");
|
||||
|
||||
public static string VScriptPath = Path.Join(Server.GameDirectory, Constants.ROOT_BINARY_PATH, "libvscript.so");
|
||||
}
|
||||
@@ -10,8 +10,53 @@ public class Schema
|
||||
{
|
||||
private static Dictionary<Tuple<string, string>, short> _schemaOffsets = new();
|
||||
|
||||
private static HashSet<string> _cs2BadList = new HashSet<string>()
|
||||
{
|
||||
"m_bIsValveDS",
|
||||
"m_bIsQuestEligible",
|
||||
// "m_iItemDefinitionIndex", // as of 2023.11.11 this is currently not blocked
|
||||
"m_iEntityLevel",
|
||||
"m_iItemIDHigh",
|
||||
"m_iItemIDLow",
|
||||
"m_iAccountID",
|
||||
"m_iEntityQuality",
|
||||
|
||||
"m_bInitialized",
|
||||
"m_szCustomName",
|
||||
"m_iAttributeDefinitionIndex",
|
||||
"m_iRawValue32",
|
||||
"m_iRawInitialValue32",
|
||||
"m_flValue", // MNetworkAlias "m_iRawValue32"
|
||||
"m_flInitialValue", // MNetworkAlias "m_iRawInitialValue32"
|
||||
"m_bSetBonus",
|
||||
"m_nRefundableCurrency",
|
||||
|
||||
"m_OriginalOwnerXuidLow",
|
||||
"m_OriginalOwnerXuidHigh",
|
||||
|
||||
"m_nFallbackPaintKit",
|
||||
"m_nFallbackSeed",
|
||||
"m_flFallbackWear",
|
||||
"m_nFallbackStatTrak",
|
||||
|
||||
"m_iCompetitiveWins",
|
||||
"m_iCompetitiveRanking",
|
||||
"m_iCompetitiveRankType",
|
||||
"m_iCompetitiveRankingPredicted_Win",
|
||||
"m_iCompetitiveRankingPredicted_Loss",
|
||||
"m_iCompetitiveRankingPredicted_Tie",
|
||||
|
||||
"m_nActiveCoinRank",
|
||||
"m_nMusicID",
|
||||
};
|
||||
|
||||
public static short GetSchemaOffset(string className, string propertyName)
|
||||
{
|
||||
if (CoreConfig.FollowCS2ServerGuidelines && _cs2BadList.Contains(propertyName))
|
||||
{
|
||||
throw new Exception($"Cannot set or get '{className}::{propertyName}' with \"FollowCS2ServerGuidelines\" option enabled.");
|
||||
}
|
||||
|
||||
var key = new Tuple<string, string>(className, propertyName);
|
||||
if (!_schemaOffsets.TryGetValue(key, out var offset))
|
||||
{
|
||||
@@ -29,6 +74,11 @@ public class Schema
|
||||
|
||||
public static void SetSchemaValue<T>(IntPtr handle, string className, string propertyName, T value)
|
||||
{
|
||||
if (CoreConfig.FollowCS2ServerGuidelines && _cs2BadList.Contains(propertyName))
|
||||
{
|
||||
throw new Exception($"Cannot set or get '{className}::{propertyName}' with \"FollowCS2ServerGuidelines\" option enabled.");
|
||||
}
|
||||
|
||||
NativeAPI.SetSchemaValueByName<T>(handle, (int)typeof(T).ToDataType(), className, propertyName, value);
|
||||
}
|
||||
|
||||
|
||||
@@ -24,4 +24,7 @@ public static class VirtualFunctions
|
||||
|
||||
// void(*UTIL_Remove)(CEntityInstance*);
|
||||
public static Action<IntPtr> UTIL_Remove = VirtualFunction.CreateVoid<IntPtr>(GameData.GetSignature("UTIL_Remove"));
|
||||
|
||||
// void(*CBaseModelEntity_SetModel)(CBaseModelEntity*, const char*);
|
||||
public static Action<IntPtr, string> SetModel = VirtualFunction.CreateVoid<IntPtr, string>(GameData.GetSignature("CBaseModelEntity_SetModel"));
|
||||
}
|
||||
@@ -1,8 +0,0 @@
|
||||
{
|
||||
"profiles": {
|
||||
"CounterStrikeSharp.API": {
|
||||
"commandName": "Project",
|
||||
"nativeDebugging": true
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -18,6 +18,8 @@ using System;
|
||||
using System.Drawing;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Text.Json.Serialization;
|
||||
|
||||
using CounterStrikeSharp.API;
|
||||
using CounterStrikeSharp.API.Core;
|
||||
using CounterStrikeSharp.API.Core.Attributes;
|
||||
@@ -32,8 +34,17 @@ using CounterStrikeSharp.API.Modules.Utils;
|
||||
|
||||
namespace TestPlugin
|
||||
{
|
||||
[MinimumApiVersion(1)]
|
||||
public class SamplePlugin : BasePlugin
|
||||
public class SampleConfig : BasePluginConfig
|
||||
{
|
||||
[JsonPropertyName("IsPluginEnabled")]
|
||||
public bool IsPluginEnabled { get; set; } = true;
|
||||
|
||||
[JsonPropertyName("LogPrefix")]
|
||||
public string LogPrefix { get; set; } = "CSSharp";
|
||||
}
|
||||
|
||||
[MinimumApiVersion(33)]
|
||||
public class SamplePlugin : BasePlugin, IPluginConfig<SampleConfig>
|
||||
{
|
||||
public override string ModuleName => "Sample Plugin";
|
||||
public override string ModuleVersion => "v1.0.0";
|
||||
@@ -42,8 +53,24 @@ namespace TestPlugin
|
||||
|
||||
public override string ModuleDescription => "A playground of features used for testing";
|
||||
|
||||
public SampleConfig Config { get; set; }
|
||||
|
||||
// This method is called right before `Load` is called
|
||||
public void OnConfigParsed(SampleConfig config)
|
||||
{
|
||||
// Save config instance
|
||||
Config = config;
|
||||
}
|
||||
|
||||
public override void Load(bool hotReload)
|
||||
{
|
||||
// Basic usage of the configuration system
|
||||
if (!Config.IsPluginEnabled)
|
||||
{
|
||||
Console.WriteLine($"{Config.LogPrefix} {ModuleName} is disabled");
|
||||
return;
|
||||
}
|
||||
|
||||
Console.WriteLine(
|
||||
$"Test Plugin has been loaded, and the hot reload flag was {hotReload}, path is {ModulePath}");
|
||||
|
||||
|
||||
@@ -5,9 +5,12 @@
|
||||
<Platforms>AnyCPU;x86</Platforms>
|
||||
<GenerateAssemblyInfo>false</GenerateAssemblyInfo>
|
||||
<CopyLocalLockFileAssemblies>true</CopyLocalLockFileAssemblies>
|
||||
<CopyLocalLockFileAssemblies>false</CopyLocalLockFileAssemblies>
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<ProjectReference Include="..\CounterStrikeSharp.API\CounterStrikeSharp.API.csproj" />
|
||||
<ProjectReference Include="..\CounterStrikeSharp.API\CounterStrikeSharp.API.csproj">
|
||||
<Private>false</Private>
|
||||
</ProjectReference>
|
||||
</ItemGroup>
|
||||
</Project>
|
||||
|
||||
@@ -18,17 +18,18 @@
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
#include <platform.h>
|
||||
#include "interfaces/interfaces.h"
|
||||
#include <cstdint>
|
||||
#include "core/gameconfig.h"
|
||||
|
||||
class CGameEntitySystem;
|
||||
|
||||
class CGameResourceService
|
||||
{
|
||||
public:
|
||||
CGameEntitySystem *GetGameEntitySystem()
|
||||
{
|
||||
return *reinterpret_cast<CGameEntitySystem **>((uintptr_t)(this) + 0x50);
|
||||
}
|
||||
public:
|
||||
CGameEntitySystem* GetGameEntitySystem()
|
||||
{
|
||||
return *reinterpret_cast<CGameEntitySystem**>(
|
||||
(uintptr_t)(this) +
|
||||
counterstrikesharp::globals::gameConfig->GetOffset("GameEntitySystem"));
|
||||
}
|
||||
};
|
||||
@@ -18,11 +18,12 @@
|
||||
*/
|
||||
|
||||
#include "cs2_interfaces.h"
|
||||
#include "interfaces/interfaces.h"
|
||||
|
||||
#include "tier0/memdbgon.h"
|
||||
#include "core/memory_module.h"
|
||||
#include "core/globals.h"
|
||||
#include "interfaces/interfaces.h"
|
||||
|
||||
// memdbgon must be the last include file in a .cpp file!!!
|
||||
#include "tier0/memdbgon.h"
|
||||
|
||||
namespace counterstrikesharp {
|
||||
void interfaces::Initialize() {
|
||||
|
||||
@@ -5,7 +5,7 @@
|
||||
#include <string_view>
|
||||
#include <array>
|
||||
#include "core/cs2_sdk/interfaces/CUtlTSHash.h"
|
||||
#define CSGO2
|
||||
#define CS2
|
||||
|
||||
#define CSCHEMATYPE_GETSIZES_INDEX 3
|
||||
#define SCHEMASYSTEM_TYPE_SCOPES_OFFSET 0x190
|
||||
@@ -181,7 +181,8 @@ class CSchemaType
|
||||
CSchemaType* element_type_;
|
||||
};
|
||||
|
||||
struct generic_type_t {
|
||||
struct generic_type_t
|
||||
{
|
||||
uint64_t unknown;
|
||||
const char* m_name_; // 0x0008
|
||||
};
|
||||
@@ -316,12 +317,24 @@ class CSchemaSystemTypeScope
|
||||
public:
|
||||
CSchemaClassInfo* FindDeclaredClass(const char* class_name)
|
||||
{
|
||||
#ifdef _WIN32
|
||||
CSchemaClassInfo* rv = nullptr;
|
||||
CALL_VIRTUAL(void, 2, this, &rv, class_name);
|
||||
return rv;
|
||||
#else
|
||||
return CALL_VIRTUAL(CSchemaClassInfo*, 2, this, class_name);
|
||||
#endif
|
||||
}
|
||||
|
||||
CSchemaEnumBinding* FindDeclaredEnum(const char* name)
|
||||
{
|
||||
#ifdef _WIN32
|
||||
CSchemaEnumBinding* rv = nullptr;
|
||||
CALL_VIRTUAL(void, 3, this, &rv, name);
|
||||
return rv;
|
||||
#else
|
||||
return CALL_VIRTUAL(CSchemaEnumBinding*, 3, this, name);
|
||||
#endif
|
||||
}
|
||||
|
||||
CSchemaType* FindSchemaTypeByName(const char* name, std::uintptr_t* pSchema)
|
||||
@@ -349,24 +362,19 @@ class CSchemaSystemTypeScope
|
||||
return CALL_VIRTUAL(CSchemaEnumBinding*, 8, this, name);
|
||||
}
|
||||
|
||||
std::string_view GetScopeName() {
|
||||
return {m_name_.data()};
|
||||
}
|
||||
std::string_view GetScopeName() { return {m_name_.data()}; }
|
||||
|
||||
[[nodiscard]] CUtlTSHash<CSchemaClassBinding*> GetClasses() const {
|
||||
return m_classes_;
|
||||
}
|
||||
[[nodiscard]] CUtlTSHash<CSchemaClassBinding*> GetClasses() const { return m_classes_; }
|
||||
|
||||
[[nodiscard]] CUtlTSHash<CSchemaEnumBinding*> GetEnums() const { return m_enumes_; }
|
||||
|
||||
[[nodiscard]] CUtlTSHash<CSchemaEnumBinding*> GetEnums() const {
|
||||
return m_enumes_;
|
||||
}
|
||||
private:
|
||||
char pad_0x0000[0x8]; // 0x0000
|
||||
std::array<char, 256> m_name_ = {};
|
||||
char pad_0x0108[SCHEMASYSTEMTYPESCOPE_OFF1]; // 0x0108
|
||||
CUtlTSHash<CSchemaClassBinding*> m_classes_; // 0x0588
|
||||
char pad_0x0594[SCHEMASYSTEMTYPESCOPE_OFF2]; // 0x05C8
|
||||
CUtlTSHash<CSchemaEnumBinding*> m_enumes_; // 0x2DD0
|
||||
CUtlTSHash<CSchemaEnumBinding*> m_enumes_; // 0x2DD0
|
||||
private:
|
||||
static constexpr unsigned int s_class_list = 0x580;
|
||||
};
|
||||
|
||||
@@ -20,13 +20,15 @@
|
||||
#include "schema.h"
|
||||
|
||||
#include "interfaces/cs2_interfaces.h"
|
||||
#include "../globals.h"
|
||||
// #include <unordered_map>
|
||||
#include "tier1/utlmap.h"
|
||||
#include "tier0/memdbgon.h"
|
||||
#include "../memory.h"
|
||||
#include "core/globals.h"
|
||||
#include "core/memory.h"
|
||||
#include "core/log.h"
|
||||
|
||||
#include "tier1/utlmap.h"
|
||||
|
||||
// memdbgon must be the last include file in a .cpp file!!!
|
||||
#include "tier0/memdbgon.h"
|
||||
|
||||
using SchemaKeyValueMap_t = CUtlMap<uint32_t, SchemaKey>;
|
||||
using SchemaTableMap_t = CUtlMap<uint32_t, SchemaKeyValueMap_t*>;
|
||||
|
||||
|
||||
@@ -19,23 +19,13 @@
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "stdint.h"
|
||||
|
||||
#ifdef _WIN32
|
||||
#pragma warning(push)
|
||||
#pragma warning(disable : 4005)
|
||||
#endif
|
||||
|
||||
#include <type_traits>
|
||||
|
||||
#ifdef _WIN32
|
||||
#pragma warning(pop)
|
||||
#endif
|
||||
|
||||
#include "tier0/dbg.h"
|
||||
#include "const.h"
|
||||
#include "../../utils/virtual.h"
|
||||
#include "stdint.h"
|
||||
#include "utils/virtual.h"
|
||||
|
||||
#include <stdint.h>
|
||||
#include <type_traits>
|
||||
|
||||
#undef schema
|
||||
|
||||
struct SchemaKey {
|
||||
|
||||
236
src/core/gameconfig.cpp
Normal file
236
src/core/gameconfig.cpp
Normal file
@@ -0,0 +1,236 @@
|
||||
#include "core/gameconfig.h"
|
||||
#include <fstream>
|
||||
|
||||
#include "log.h"
|
||||
#include "metamod_oslink.h"
|
||||
|
||||
namespace counterstrikesharp {
|
||||
|
||||
CGameConfig::CGameConfig(const std::string& path) { m_sPath = path; }
|
||||
|
||||
CGameConfig::~CGameConfig() = default;
|
||||
|
||||
bool CGameConfig::Init(char* conf_error, int conf_error_size)
|
||||
{
|
||||
std::ifstream ifs(m_sPath);
|
||||
if (!ifs) {
|
||||
V_snprintf(conf_error, conf_error_size, "Gamedata file not found.");
|
||||
return false;
|
||||
}
|
||||
|
||||
m_json = json::parse(ifs);
|
||||
|
||||
#if _WIN32
|
||||
constexpr auto platform = "windows";
|
||||
#else
|
||||
constexpr auto platform = "linux";
|
||||
#endif
|
||||
|
||||
try {
|
||||
for (auto& [k, v] : m_json.items()) {
|
||||
if (v.contains("signatures")) {
|
||||
if (auto library = v["signatures"]["library"]; library.is_string()) {
|
||||
m_umLibraries[k] = library.get<std::string>();
|
||||
}
|
||||
if (auto signature = v["signatures"][platform]; signature.is_string()) {
|
||||
m_umSignatures[k] = signature.get<std::string>();
|
||||
}
|
||||
}
|
||||
if (v.contains("offsets")) {
|
||||
if (auto offset = v["offsets"][platform]; offset.is_number_integer()) {
|
||||
m_umOffsets[k] = offset.get<std::int64_t>();
|
||||
}
|
||||
}
|
||||
if (v.contains("patches")) {
|
||||
if (auto patch = v["patches"][platform]; patch.is_string()) {
|
||||
m_umPatches[k] = patch.get<std::string>();
|
||||
}
|
||||
}
|
||||
}
|
||||
} catch (const std::exception& ex) {
|
||||
V_snprintf(conf_error, conf_error_size, "Failed to parse gamedata file: %s", ex.what());
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
const std::string CGameConfig::GetPath()
|
||||
{
|
||||
return m_sPath;
|
||||
}
|
||||
|
||||
const char* CGameConfig::GetLibrary(const std::string& name)
|
||||
{
|
||||
// My recommendation is switch to C++20.
|
||||
auto it = m_umLibraries.find(name);
|
||||
if (it == m_umLibraries.end()) {
|
||||
return nullptr;
|
||||
}
|
||||
return it->second.c_str();
|
||||
}
|
||||
|
||||
const char* CGameConfig::GetSignature(const std::string& name)
|
||||
{
|
||||
auto it = m_umSignatures.find(name);
|
||||
if (it == m_umSignatures.end()) {
|
||||
return nullptr;
|
||||
}
|
||||
return it->second.c_str();
|
||||
}
|
||||
|
||||
const char* CGameConfig::GetSymbol(const char* name)
|
||||
{
|
||||
const char* symbol = this->GetSignature(name);
|
||||
|
||||
if (!symbol || strlen(symbol) <= 1) {
|
||||
CSSHARP_CORE_ERROR("Missing symbol: {}\n", name);
|
||||
return nullptr;
|
||||
}
|
||||
return symbol + 1;
|
||||
}
|
||||
|
||||
const char* CGameConfig::GetPatch(const std::string& name)
|
||||
{
|
||||
auto it = m_umPatches.find(name);
|
||||
if (it == m_umPatches.end()) {
|
||||
return nullptr;
|
||||
}
|
||||
return it->second.c_str();
|
||||
}
|
||||
|
||||
int CGameConfig::GetOffset(const std::string& name)
|
||||
{
|
||||
auto it = m_umOffsets.find(name);
|
||||
if (it == m_umOffsets.end()) {
|
||||
return -1;
|
||||
}
|
||||
return it->second;
|
||||
}
|
||||
|
||||
void* CGameConfig::GetAddress(const std::string& name, void* engine, void* server, char* error,
|
||||
int maxlen)
|
||||
{
|
||||
CSSHARP_CORE_ERROR("Not implemented.");
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
modules::CModule** CGameConfig::GetModule(const char* name)
|
||||
{
|
||||
const char* library = this->GetLibrary(name);
|
||||
if (!library)
|
||||
return nullptr;
|
||||
|
||||
if (strcmp(library, "engine") == 0)
|
||||
return &modules::engine;
|
||||
else if (strcmp(library, "server") == 0)
|
||||
return &modules::server;
|
||||
else if (strcmp(library, "vscript") == 0)
|
||||
return &modules::vscript;
|
||||
else if (strcmp(library, "tier0") == 0)
|
||||
return &modules::tier0;
|
||||
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
bool CGameConfig::IsSymbol(const char* name)
|
||||
{
|
||||
const char* sigOrSymbol = this->GetSignature(name);
|
||||
if (!sigOrSymbol || strlen(sigOrSymbol) <= 0) {
|
||||
CSSHARP_CORE_ERROR("Missing signature or symbol: {}\n", name);
|
||||
return false;
|
||||
}
|
||||
return sigOrSymbol[0] == '@';
|
||||
}
|
||||
|
||||
void* CGameConfig::ResolveSignature(const char* name)
|
||||
{
|
||||
modules::CModule** module = this->GetModule(name);
|
||||
if (!module || !(*module)) {
|
||||
CSSHARP_CORE_ERROR("Invalid Module {}\n", name);
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
void* address = nullptr;
|
||||
if (this->IsSymbol(name)) {
|
||||
const char* symbol = this->GetSymbol(name);
|
||||
if (!symbol) {
|
||||
CSSHARP_CORE_ERROR("Invalid symbol for {}\n", name);
|
||||
return nullptr;
|
||||
}
|
||||
address = dlsym((*module)->m_hModule, symbol);
|
||||
} else {
|
||||
const char* signature = this->GetSignature(name);
|
||||
if (!signature) {
|
||||
CSSHARP_CORE_ERROR("Failed to find signature for {}\n", name);
|
||||
return nullptr;
|
||||
}
|
||||
size_t iLength = 0;
|
||||
byte* pSignature = HexToByte(signature, iLength);
|
||||
if (!pSignature) {
|
||||
return nullptr;
|
||||
}
|
||||
address = (*module)->FindSignature(pSignature, iLength);
|
||||
}
|
||||
|
||||
if (!address) {
|
||||
CSSHARP_CORE_ERROR("Failed to find address for {}\n", name);
|
||||
return nullptr;
|
||||
}
|
||||
return address;
|
||||
}
|
||||
|
||||
std::string CGameConfig::GetDirectoryName(const std::string& directoryPathInput)
|
||||
{
|
||||
std::string directoryPath = std::string(directoryPathInput);
|
||||
|
||||
size_t found = std::string(directoryPath).find_last_of("/\\");
|
||||
if (found != std::string::npos) {
|
||||
return std::string(directoryPath, found + 1);
|
||||
}
|
||||
return "";
|
||||
}
|
||||
|
||||
int CGameConfig::HexStringToUint8Array(const char* hexString, uint8_t* byteArray, size_t maxBytes)
|
||||
{
|
||||
if (!hexString) {
|
||||
printf("Invalid hex string.\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
size_t hexStringLength = strlen(hexString);
|
||||
size_t byteCount = hexStringLength / 4; // Each "\\x" represents one byte.
|
||||
|
||||
if (hexStringLength % 4 != 0 || byteCount == 0 || byteCount > maxBytes) {
|
||||
printf("Invalid hex string format or byte count.\n");
|
||||
return -1; // Return an error code.
|
||||
}
|
||||
|
||||
for (size_t i = 0; i < hexStringLength; i += 4) {
|
||||
if (sscanf(hexString + i, "\\x%2hhX", &byteArray[i / 4]) != 1) {
|
||||
printf("Failed to parse hex string at position %zu.\n", i);
|
||||
return -1; // Return an error code.
|
||||
}
|
||||
}
|
||||
|
||||
byteArray[byteCount] = '\0'; // Add a null-terminating character.
|
||||
|
||||
return byteCount; // Return the number of bytes successfully converted.
|
||||
}
|
||||
|
||||
byte* CGameConfig::HexToByte(const char* src, size_t& length)
|
||||
{
|
||||
if (!src || strlen(src) <= 0) {
|
||||
CSSHARP_CORE_INFO("Invalid hex string\n");
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
length = strlen(src) / 4;
|
||||
uint8_t* dest = new uint8_t[length];
|
||||
int byteCount = HexStringToUint8Array(src, dest, length);
|
||||
if (byteCount <= 0) {
|
||||
CSSHARP_CORE_INFO("Invalid hex format %s\n", src);
|
||||
return nullptr;
|
||||
}
|
||||
return dest;
|
||||
}
|
||||
} // namespace counterstrikesharp
|
||||
51
src/core/gameconfig.h
Normal file
51
src/core/gameconfig.h
Normal file
@@ -0,0 +1,51 @@
|
||||
#pragma once
|
||||
|
||||
|
||||
#include "core/globals.h"
|
||||
#include "core/memory_module.h"
|
||||
#include <KeyValues.h>
|
||||
|
||||
#include <string>
|
||||
#include <unordered_map>
|
||||
|
||||
#undef snprintf
|
||||
#include <nlohmann/json.hpp>
|
||||
|
||||
namespace counterstrikesharp {
|
||||
|
||||
class CGameConfig
|
||||
{
|
||||
public:
|
||||
using json = nlohmann::json;
|
||||
CGameConfig(const std::string& path);
|
||||
~CGameConfig();
|
||||
|
||||
bool Init(char* conf_error, int conf_error_size);
|
||||
const std::string GetPath();
|
||||
const char* GetLibrary(const std::string& name);
|
||||
const char* GetSignature(const std::string& name);
|
||||
const char* GetSymbol(const char* name);
|
||||
const char* GetPatch(const std::string& name);
|
||||
int GetOffset(const std::string& name);
|
||||
void* GetAddress(const std::string& name, void* engine, void* server, char* error, int maxlen);
|
||||
modules::CModule** GetModule(const char* name);
|
||||
bool IsSymbol(const char* name);
|
||||
void* ResolveSignature(const char* name);
|
||||
|
||||
static std::string GetDirectoryName(const std::string& directoryPathInput);
|
||||
static int HexStringToUint8Array(const char* hexString, uint8_t* byteArray, size_t maxBytes);
|
||||
static byte* HexToByte(const char* src, size_t& length);
|
||||
|
||||
private:
|
||||
std::string m_sPath;
|
||||
// use Valve KeyValues in the future.
|
||||
// since we'd better make '\' easier.
|
||||
json m_json;
|
||||
std::unordered_map<std::string, int> m_umOffsets;
|
||||
std::unordered_map<std::string, std::string> m_umSignatures;
|
||||
std::unordered_map<std::string, void*> m_umAddresses;
|
||||
std::unordered_map<std::string, std::string> m_umLibraries;
|
||||
std::unordered_map<std::string, std::string> m_umPatches;
|
||||
};
|
||||
|
||||
} // namespace counterstrikesharp
|
||||
@@ -1,3 +1,4 @@
|
||||
#include "mm_plugin.h"
|
||||
#include "core/globals.h"
|
||||
#include "core/managers/player_manager.h"
|
||||
#include "iserver.h"
|
||||
@@ -12,6 +13,7 @@
|
||||
|
||||
#include "log.h"
|
||||
#include "utils/virtual.h"
|
||||
#include "core/memory.h"
|
||||
#include "core/managers/con_command_manager.h"
|
||||
#include "core/managers/chat_manager.h"
|
||||
#include "memory_module.h"
|
||||
@@ -22,6 +24,7 @@
|
||||
#include <public/game/server/iplayerinfo.h>
|
||||
#include <public/entity2/entitysystem.h>
|
||||
|
||||
|
||||
namespace counterstrikesharp {
|
||||
|
||||
namespace modules {
|
||||
@@ -63,6 +66,7 @@ SourceHook::Impl::CSourceHookImpl source_hook_impl;
|
||||
SourceHook::ISourceHook *source_hook = &source_hook_impl;
|
||||
ISmmAPI *ismm = nullptr;
|
||||
CGameEntitySystem* entitySystem = nullptr;
|
||||
CGameConfig* gameConfig = nullptr;
|
||||
|
||||
// Custom Managers
|
||||
CallbackManager callbackManager;
|
||||
@@ -84,16 +88,20 @@ void Initialize() {
|
||||
|
||||
interfaces::Initialize();
|
||||
|
||||
globals::entitySystem = interfaces::pGameResourceServiceServer->GetGameEntitySystem();
|
||||
entitySystem = interfaces::pGameResourceServiceServer->GetGameEntitySystem();
|
||||
|
||||
gameEventManager = (IGameEventManager2 *)(CALL_VIRTUAL(uintptr_t, 91, server) - 8);
|
||||
if (int offset = -1; (offset = gameConfig->GetOffset("GameEventManager")) != -1) {
|
||||
gameEventManager = (IGameEventManager2*)(CALL_VIRTUAL(uintptr_t, offset, server) - 8);
|
||||
}
|
||||
}
|
||||
|
||||
int source_hook_pluginid = 0;
|
||||
CGlobalVars *getGlobalVars() {
|
||||
INetworkGameServer *server = networkServerService->GetIGameServer();
|
||||
|
||||
if (!server) return nullptr;
|
||||
if (!server) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
return networkServerService->GetIGameServer()->GetGlobals();
|
||||
}
|
||||
|
||||
@@ -50,6 +50,7 @@ class EntityManager;
|
||||
class ChatManager;
|
||||
class ClientCommandManager;
|
||||
class ServerManager;
|
||||
class CGameConfig;
|
||||
|
||||
namespace globals {
|
||||
|
||||
@@ -100,6 +101,7 @@ extern int source_hook_pluginid;
|
||||
extern IGameEventSystem *gameEventSystem;
|
||||
extern CounterStrikeSharpMMPlugin *mmPlugin;
|
||||
extern ISmmAPI *ismm;
|
||||
extern CGameConfig* gameConfig;
|
||||
|
||||
void Initialize();
|
||||
// Should only be called within the active game loop (i e map should be loaded
|
||||
|
||||
@@ -8,17 +8,22 @@ namespace counterstrikesharp {
|
||||
std::shared_ptr<spdlog::logger> Log::m_core_logger;
|
||||
|
||||
void Log::Init() {
|
||||
std::vector<spdlog::sink_ptr> logSinks;
|
||||
auto ansiColorSink = std::make_shared<spdlog::sinks::ansicolor_stderr_sink_mt>();
|
||||
ansiColorSink->set_color(spdlog::level::trace, ansiColorSink->yellow);
|
||||
logSinks.emplace_back(ansiColorSink);
|
||||
logSinks.emplace_back(
|
||||
std::vector<spdlog::sink_ptr> log_sinks;
|
||||
auto color_sink = std::make_shared<spdlog::sinks::stderr_color_sink_mt>();
|
||||
#if _WIN32
|
||||
color_sink->set_color(spdlog::level::trace, 6);
|
||||
#else
|
||||
color_sink->set_color(spdlog::level::trace, color_sink->yellow);
|
||||
#endif
|
||||
|
||||
log_sinks.emplace_back(color_sink);
|
||||
log_sinks.emplace_back(
|
||||
std::make_shared<spdlog::sinks::basic_file_sink_mt>("counterstrikesharp.log", true));
|
||||
|
||||
logSinks[0]->set_pattern("%^[%T.%e] %n: %v%$");
|
||||
logSinks[1]->set_pattern("[%T.%e] [%l] %n: %v");
|
||||
log_sinks[0]->set_pattern("%^[%T.%e] %n: %v%$");
|
||||
log_sinks[1]->set_pattern("[%T.%e] [%l] %n: %v");
|
||||
|
||||
m_core_logger = std::make_shared<spdlog::logger>("CSSharp", begin(logSinks), end(logSinks));
|
||||
m_core_logger = std::make_shared<spdlog::logger>("CSSharp", begin(log_sinks), end(log_sinks));
|
||||
spdlog::register_logger(m_core_logger);
|
||||
m_core_logger->set_level(spdlog::level::info);
|
||||
m_core_logger->flush_on(spdlog::level::info);
|
||||
|
||||
@@ -24,9 +24,12 @@
|
||||
#include <public/eiface.h>
|
||||
#include "core/memory.h"
|
||||
#include "core/log.h"
|
||||
#include "core/gameconfig.h"
|
||||
|
||||
#include <funchook.h>
|
||||
|
||||
#include "core/memory_module.h"
|
||||
|
||||
namespace counterstrikesharp {
|
||||
|
||||
ChatManager::ChatManager() {}
|
||||
@@ -35,11 +38,14 @@ ChatManager::~ChatManager() {}
|
||||
|
||||
void ChatManager::OnAllInitialized()
|
||||
{
|
||||
// TODO: Allow reading of the shared game data json from the C++ side too so this isn't
|
||||
// being hardcoded.
|
||||
m_pHostSay = (HostSay)FindSignature(
|
||||
MODULE_PREFIX "server" MODULE_EXT,
|
||||
R"(\x55\x48\x89\xE5\x41\x57\x49\x89\xFF\x41\x56\x41\x55\x41\x54\x4D\x89\xC4)");
|
||||
m_pHostSay = reinterpret_cast<HostSay>(
|
||||
modules::server->FindSignature(globals::gameConfig->GetSignature("Host_Say"))
|
||||
);
|
||||
|
||||
if (m_pHostSay == nullptr) {
|
||||
CSSHARP_CORE_ERROR("Failed to find signature for \'Host_Say\'");
|
||||
return;
|
||||
}
|
||||
|
||||
auto m_hook = funchook_create();
|
||||
funchook_prepare(m_hook, (void**)&m_pHostSay, (void*)&DetourHostSay);
|
||||
|
||||
@@ -43,6 +43,8 @@
|
||||
#include "core/memory.h"
|
||||
#include "interfaces/cs2_interfaces.h"
|
||||
#include <nlohmann/json.hpp>
|
||||
|
||||
#include "metamod_oslink.h"
|
||||
using json = nlohmann::json;
|
||||
|
||||
namespace counterstrikesharp {
|
||||
@@ -155,10 +157,11 @@ CON_COMMAND(dump_schema, "dump schema symbols")
|
||||
output << std::setw(2) << j << std::endl;
|
||||
}
|
||||
|
||||
SH_DECL_HOOK2_void(
|
||||
ConCommandHandle, Dispatch, SH_NOATTRIB, false, const CCommandContext&, const CCommand&);
|
||||
SH_DECL_HOOK2_void(ConCommandHandle, Dispatch, SH_NOATTRIB, false, const CCommandContext&,
|
||||
const CCommand&);
|
||||
|
||||
void ConCommandInfo::HookChange(CallbackT cb, bool post) {
|
||||
void ConCommandInfo::HookChange(CallbackT cb, bool post)
|
||||
{
|
||||
if (post) {
|
||||
this->callback_post->AddListener(cb);
|
||||
} else {
|
||||
@@ -166,7 +169,8 @@ void ConCommandInfo::HookChange(CallbackT cb, bool post) {
|
||||
}
|
||||
}
|
||||
|
||||
void ConCommandInfo::UnhookChange(CallbackT cb, bool post) {
|
||||
void ConCommandInfo::UnhookChange(CallbackT cb, bool post)
|
||||
{
|
||||
if (post) {
|
||||
if (this->callback_post && this->callback_post->GetFunctionCount()) {
|
||||
callback_post->RemoveListener(cb);
|
||||
@@ -178,8 +182,7 @@ void ConCommandInfo::UnhookChange(CallbackT cb, bool post) {
|
||||
}
|
||||
}
|
||||
|
||||
ConCommandManager::ConCommandManager()
|
||||
: last_command_client(-1) {}
|
||||
ConCommandManager::ConCommandManager() : last_command_client(-1) {}
|
||||
|
||||
ConCommandManager::~ConCommandManager() {}
|
||||
|
||||
@@ -187,16 +190,17 @@ void ConCommandManager::OnAllInitialized() {}
|
||||
|
||||
void ConCommandManager::OnShutdown() {}
|
||||
|
||||
void CommandCallback(const CCommandContext& context, const CCommand& command) {
|
||||
bool rval = globals::conCommandManager.InternalDispatch(
|
||||
context.GetPlayerSlot(), &command);
|
||||
void CommandCallback(const CCommandContext& context, const CCommand& command)
|
||||
{
|
||||
bool rval = globals::conCommandManager.InternalDispatch(context.GetPlayerSlot(), &command);
|
||||
|
||||
if (rval) {
|
||||
RETURN_META(MRES_SUPERCEDE);
|
||||
}
|
||||
}
|
||||
|
||||
void CommandCallback_Post(const CCommandContext& context, const CCommand& command) {
|
||||
void CommandCallback_Post(const CCommandContext& context, const CCommand& command)
|
||||
{
|
||||
bool rval = globals::conCommandManager.InternalDispatch_Post(context.GetPlayerSlot(), &command);
|
||||
|
||||
if (rval) {
|
||||
@@ -204,14 +208,14 @@ void CommandCallback_Post(const CCommandContext& context, const CCommand& comman
|
||||
}
|
||||
}
|
||||
|
||||
ConCommandInfo* ConCommandManager::AddOrFindCommand(const char* name,
|
||||
const char* description,
|
||||
bool server_only,
|
||||
int flags) {
|
||||
ConCommandInfo* ConCommandManager::AddOrFindCommand(const char* name, const char* description,
|
||||
bool server_only, int flags)
|
||||
{
|
||||
ConCommandInfo* p_info = m_cmd_lookup[std::string(name)];
|
||||
|
||||
if (!p_info) {
|
||||
CSSHARP_CORE_TRACE("[ConCommandManager] Could not find command in existing lookup {}", name);
|
||||
CSSHARP_CORE_TRACE("[ConCommandManager] Could not find command in existing lookup {}",
|
||||
name);
|
||||
// auto found = std::find_if(m_cmd_list.begin(), m_cmd_list.end(),
|
||||
// [&](ConCommandInfo* info) {
|
||||
// return V_strcasecmp(info->command->GetName(), name) == 0;
|
||||
@@ -234,11 +238,13 @@ ConCommandInfo* ConCommandManager::AddOrFindCommand(const char* name,
|
||||
char* new_name = strdup(name);
|
||||
char* new_desc = strdup(description);
|
||||
|
||||
CSSHARP_CORE_TRACE("[ConCommandManager] Creating new command {}, {}, {}, {}, {}", (void*)&pointerConCommand, new_name, (void*)CommandCallback, new_desc, flags);
|
||||
CSSHARP_CORE_TRACE("[ConCommandManager] Creating new command {}, {}, {}, {}, {}",
|
||||
(void*)&pointerConCommand, new_name, (void*)CommandCallback,
|
||||
new_desc, flags);
|
||||
|
||||
auto conCommand =
|
||||
new ConCommand(&pointerConCommand, new_name, CommandCallback, new_desc, flags);
|
||||
|
||||
|
||||
CSSHARP_CORE_TRACE("[ConCommandManager] Creating callbacks for command {}", name);
|
||||
|
||||
p_info->command = conCommand;
|
||||
@@ -246,24 +252,22 @@ ConCommandInfo* ConCommandManager::AddOrFindCommand(const char* name,
|
||||
p_info->callback_post = globals::callbackManager.CreateCallback(name);
|
||||
p_info->server_only = server_only;
|
||||
|
||||
CSSHARP_CORE_TRACE("[ConCommandManager] Adding hooks for command callback for command {}", name);
|
||||
CSSHARP_CORE_TRACE(
|
||||
"[ConCommandManager] Adding hooks for command callback for command {}", name);
|
||||
|
||||
SH_ADD_HOOK(ConCommandHandle, Dispatch, &pointerConCommand.handle, SH_STATIC(CommandCallback), false);
|
||||
SH_ADD_HOOK(ConCommandHandle, Dispatch, &pointerConCommand.handle, SH_STATIC(CommandCallback_Post), true);
|
||||
SH_ADD_HOOK(ConCommandHandle, Dispatch, &pointerConCommand.handle,
|
||||
SH_STATIC(CommandCallback), false);
|
||||
SH_ADD_HOOK(ConCommandHandle, Dispatch, &pointerConCommand.handle,
|
||||
SH_STATIC(CommandCallback_Post), true);
|
||||
|
||||
CSSHARP_CORE_TRACE("[ConCommandManager] Adding command to internal lookup {}", name);
|
||||
|
||||
m_cmd_list.push_back(p_info);
|
||||
m_cmd_lookup[name] = p_info;
|
||||
} else {
|
||||
// p_info->callback_pre = globals::callbackManager.CreateCallback(name);
|
||||
// p_info->callback_post = globals::callbackManager.CreateCallback(name);
|
||||
// p_info->server_only = server_only;
|
||||
//
|
||||
// SH_ADD_HOOK(ConCommandHandle, Dispatch, pointerConCommand->handle,
|
||||
// SH_STATIC(CommandCallback), false); SH_ADD_HOOK(ConCommandHandle,
|
||||
// Dispatch, pointerConCommand->handle, SH_STATIC(CommandCallback_Post),
|
||||
// true);
|
||||
p_info->callback_pre = globals::callbackManager.CreateCallback(name);
|
||||
p_info->callback_post = globals::callbackManager.CreateCallback(name);
|
||||
p_info->server_only = server_only;
|
||||
}
|
||||
|
||||
return p_info;
|
||||
@@ -272,8 +276,9 @@ ConCommandInfo* ConCommandManager::AddOrFindCommand(const char* name,
|
||||
return p_info;
|
||||
}
|
||||
|
||||
ConCommandInfo* ConCommandManager::AddCommand(
|
||||
const char* name, const char* description, bool server_only, int flags, CallbackT callback) {
|
||||
ConCommandInfo* ConCommandManager::AddCommand(const char* name, const char* description,
|
||||
bool server_only, int flags, CallbackT callback)
|
||||
{
|
||||
ConCommandInfo* p_info = AddOrFindCommand(name, description, server_only, flags);
|
||||
if (!p_info || !p_info->callback_pre) {
|
||||
return nullptr;
|
||||
@@ -284,10 +289,12 @@ ConCommandInfo* ConCommandManager::AddCommand(
|
||||
return p_info;
|
||||
}
|
||||
|
||||
bool ConCommandManager::RemoveCommand(const char* name, CallbackT callback) {
|
||||
bool ConCommandManager::RemoveCommand(const char* name, CallbackT callback)
|
||||
{
|
||||
auto strName = std::string(strdup(name));
|
||||
ConCommandInfo* p_info = m_cmd_lookup[strName];
|
||||
if (!p_info) return false;
|
||||
if (!p_info)
|
||||
return false;
|
||||
|
||||
if (p_info->callback_pre && p_info->callback_pre->GetFunctionCount()) {
|
||||
p_info->callback_pre->RemoveListener(callback);
|
||||
@@ -298,24 +305,16 @@ bool ConCommandManager::RemoveCommand(const char* name, CallbackT callback) {
|
||||
}
|
||||
|
||||
if (!p_info->callback_pre || p_info->callback_pre->GetFunctionCount() == 0) {
|
||||
// It does not look like this actually removes the con command.
|
||||
// You can still find with `find` command.
|
||||
globals::cvars->UnregisterConCommand(p_info->p_cmd.handle);
|
||||
|
||||
bool success;
|
||||
auto it = std::remove_if(m_cmd_list.begin(), m_cmd_list.end(),
|
||||
[p_info](ConCommandInfo* i) { return p_info == i; });
|
||||
|
||||
if ((success = it != m_cmd_list.end())) m_cmd_list.erase(it, m_cmd_list.end());
|
||||
// if (success) {
|
||||
// m_cmd_lookup[strName] = nullptr;
|
||||
// }
|
||||
|
||||
return success;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
ConCommandInfo* ConCommandManager::FindCommand(const char* name) {
|
||||
ConCommandInfo* ConCommandManager::FindCommand(const char* name)
|
||||
{
|
||||
ConCommandInfo* p_info = m_cmd_lookup[std::string(name)];
|
||||
|
||||
if (p_info == nullptr) {
|
||||
@@ -327,7 +326,8 @@ ConCommandInfo* ConCommandManager::FindCommand(const char* name) {
|
||||
}
|
||||
|
||||
ConCommandHandle p_cmd = globals::cvars->FindCommand(name);
|
||||
if (!p_cmd.IsValid()) return nullptr;
|
||||
if (!p_cmd.IsValid())
|
||||
return nullptr;
|
||||
|
||||
p_info = new ConCommandInfo();
|
||||
p_info->command = globals::cvars->GetCommand(p_cmd);
|
||||
@@ -350,12 +350,14 @@ int ConCommandManager::GetCommandClient() { return last_command_client; }
|
||||
|
||||
void ConCommandManager::SetCommandClient(int client) { last_command_client = client + 1; }
|
||||
|
||||
bool ConCommandManager::InternalDispatch(CPlayerSlot slot, const CCommand* args) {
|
||||
bool ConCommandManager::InternalDispatch(CPlayerSlot slot, const CCommand* args)
|
||||
{
|
||||
const char* cmd = args->Arg(0);
|
||||
|
||||
ConCommandInfo* p_info = m_cmd_lookup[cmd];
|
||||
if (p_info == nullptr) {
|
||||
if (slot.Get() == 0 && !globals::engine->IsDedicatedServer()) return false;
|
||||
if (slot.Get() == 0 && !globals::engine->IsDedicatedServer())
|
||||
return false;
|
||||
|
||||
for (ConCommandInfo* cmdInfo : m_cmd_list) {
|
||||
if ((cmdInfo != nullptr) && strcasecmp(cmdInfo->command->GetName(), cmd) == 0) {
|
||||
@@ -384,12 +386,14 @@ bool ConCommandManager::InternalDispatch(CPlayerSlot slot, const CCommand* args)
|
||||
return result;
|
||||
}
|
||||
|
||||
bool ConCommandManager::InternalDispatch_Post(CPlayerSlot slot, const CCommand* args) {
|
||||
bool ConCommandManager::InternalDispatch_Post(CPlayerSlot slot, const CCommand* args)
|
||||
{
|
||||
const char* cmd = args->Arg(0);
|
||||
|
||||
ConCommandInfo* p_info = m_cmd_lookup[cmd];
|
||||
if (p_info == nullptr) {
|
||||
if (slot.Get() == 0 && !globals::engine->IsDedicatedServer()) return false;
|
||||
if (slot.Get() == 0 && !globals::engine->IsDedicatedServer())
|
||||
return false;
|
||||
|
||||
for (ConCommandInfo* cmdInfo : m_cmd_list) {
|
||||
if ((cmdInfo != nullptr) && strcasecmp(cmdInfo->command->GetName(), cmd) == 0) {
|
||||
@@ -414,9 +418,9 @@ bool ConCommandManager::InternalDispatch_Post(CPlayerSlot slot, const CCommand*
|
||||
return result;
|
||||
}
|
||||
|
||||
bool ConCommandManager::DispatchClientCommand(CPlayerSlot slot,
|
||||
const char* cmd,
|
||||
const CCommand* args) {
|
||||
bool ConCommandManager::DispatchClientCommand(CPlayerSlot slot, const char* cmd,
|
||||
const CCommand* args)
|
||||
{
|
||||
ConCommandInfo* p_info = m_cmd_lookup[cmd];
|
||||
if (p_info == nullptr) {
|
||||
auto found =
|
||||
@@ -430,7 +434,8 @@ bool ConCommandManager::DispatchClientCommand(CPlayerSlot slot,
|
||||
p_info = *found;
|
||||
}
|
||||
|
||||
if (p_info->server_only) return false;
|
||||
if (p_info->server_only)
|
||||
return false;
|
||||
|
||||
bool result = false;
|
||||
if (p_info->callback_pre) {
|
||||
@@ -455,4 +460,4 @@ bool ConCommandManager::DispatchClientCommand(CPlayerSlot slot,
|
||||
|
||||
return result;
|
||||
}
|
||||
} // namespace counterstrikesharp
|
||||
} // namespace counterstrikesharp
|
||||
@@ -44,6 +44,8 @@ class CUtlString;
|
||||
#include "core/globals.h"
|
||||
#include "scripting/script_engine.h"
|
||||
|
||||
|
||||
|
||||
namespace counterstrikesharp {
|
||||
class ScriptCallback;
|
||||
class PluginFunction;
|
||||
|
||||
@@ -381,6 +381,7 @@ bool CPlayer::IsAuthStringValidated() const
|
||||
if (!IsFakeClient()) {
|
||||
return globals::engine->IsClientFullyAuthenticated(m_slot);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
void CPlayer::Authorize() { m_is_authorized = true; }
|
||||
|
||||
@@ -21,12 +21,22 @@
|
||||
|
||||
#include <cstdlib>
|
||||
#include <cstring>
|
||||
#if __linux__
|
||||
#include <dlfcn.h>
|
||||
#include <elf.h>
|
||||
#include <link.h>
|
||||
#else
|
||||
#include <Windows.h>
|
||||
#include <Psapi.h>
|
||||
#endif
|
||||
|
||||
#include <cstdio>
|
||||
|
||||
#include "memory_module.h"
|
||||
#include "metamod_oslink.h"
|
||||
#include "wchartypes.h"
|
||||
|
||||
#if __linux__
|
||||
struct ModuleInfo {
|
||||
const char *path; // in
|
||||
uint8_t *base; // out
|
||||
@@ -106,6 +116,7 @@ int GetModuleInformation(void *hModule, void **base, size_t *length) {
|
||||
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
|
||||
byte *ConvertToByteArray(const char *str, size_t *outLength) {
|
||||
size_t len = strlen(str) / 4; // Every byte is represented as \xHH
|
||||
@@ -124,17 +135,24 @@ void* FindSignature(const char* moduleName, const char* bytesStr) {
|
||||
size_t iSigLength;
|
||||
auto sigBytes = ConvertToByteArray(bytesStr, &iSigLength);
|
||||
|
||||
auto module = dlopen(moduleName, RTLD_NOW);
|
||||
auto module = dlmount(moduleName);
|
||||
if (module == nullptr) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
void *moduleBase;
|
||||
size_t moduleSize;
|
||||
|
||||
#if __linux__
|
||||
if (GetModuleInformation(module, &moduleBase, &moduleSize) != 0) {
|
||||
return nullptr;
|
||||
}
|
||||
#else
|
||||
MODULEINFO m_hModuleInfo;
|
||||
GetModuleInformation(GetCurrentProcess(), module, &m_hModuleInfo, sizeof(m_hModuleInfo));
|
||||
|
||||
moduleBase = (void*)m_hModuleInfo.lpBaseOfDll;
|
||||
moduleSize = m_hModuleInfo.SizeOfImage;
|
||||
#endif
|
||||
|
||||
unsigned char *pMemory;
|
||||
void *returnAddr = nullptr;
|
||||
|
||||
@@ -1,16 +1,18 @@
|
||||
#include <cstring>
|
||||
|
||||
#pragma once
|
||||
|
||||
#ifdef _WIN32
|
||||
#define ROOTBIN "/bin/win64/"
|
||||
#define GAMEBIN "/csgo/bin/win64/"
|
||||
#define MODULE_PREFIX ""
|
||||
#define MODULE_EXT ".dll"
|
||||
#else
|
||||
#define ROOTBIN "/bin/linuxsteamrt64/"
|
||||
#define GAMEBIN "/csgo/bin/linuxsteamrt64/"
|
||||
#endif
|
||||
|
||||
#define MODULE_PREFIX "lib"
|
||||
#define MODULE_EXT ".so"
|
||||
#endif
|
||||
|
||||
#if __linux__
|
||||
int GetModuleInformation(void *hModule, void **base, size_t *length);
|
||||
#endif
|
||||
void* FindSignature(const char* moduleName, const char* bytesStr);
|
||||
|
||||
83
src/core/memory_module.cpp
Normal file
83
src/core/memory_module.cpp
Normal file
@@ -0,0 +1,83 @@
|
||||
#include "core/memory_module.h"
|
||||
|
||||
#if _WIN32
|
||||
#include <Psapi.h>
|
||||
#endif
|
||||
|
||||
#include "dbg.h"
|
||||
#include "core/gameconfig.h"
|
||||
#include "core/memory.h"
|
||||
#include "metamod_oslink.h"
|
||||
|
||||
namespace counterstrikesharp::modules {
|
||||
|
||||
CModule::CModule(const char* path, const char* module) : m_pszModule(module), m_pszPath(path)
|
||||
{
|
||||
char szModule[MAX_PATH];
|
||||
|
||||
V_snprintf(szModule, MAX_PATH, "%s%s%s%s%s", Plat_GetGameDirectory(), path, MODULE_PREFIX,
|
||||
m_pszModule, MODULE_EXT);
|
||||
|
||||
m_hModule = dlmount(szModule);
|
||||
|
||||
if (!m_hModule)
|
||||
Error("Could not find %s\n", szModule);
|
||||
|
||||
#ifdef _WIN32
|
||||
MODULEINFO m_hModuleInfo;
|
||||
GetModuleInformation(GetCurrentProcess(), m_hModule, &m_hModuleInfo, sizeof(m_hModuleInfo));
|
||||
|
||||
m_base = (void*)m_hModuleInfo.lpBaseOfDll;
|
||||
m_size = m_hModuleInfo.SizeOfImage;
|
||||
#else
|
||||
if (int e = GetModuleInformation(m_hModule, &m_base, &m_size))
|
||||
Error("Failed to get module info for %s, error %d\n", szModule, e);
|
||||
#endif
|
||||
}
|
||||
|
||||
void* CModule::FindSignature(const char* signature)
|
||||
{
|
||||
if (strlen(signature) == 0) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
size_t iSigLength = 0;
|
||||
byte* pData = CGameConfig::HexToByte(signature, iSigLength);
|
||||
|
||||
return this->FindSignature(pData, iSigLength);
|
||||
}
|
||||
|
||||
void* CModule::FindSignature(const byte* pData, size_t iSigLength)
|
||||
{
|
||||
unsigned char* pMemory;
|
||||
void* return_addr = nullptr;
|
||||
|
||||
pMemory = (byte*)m_base;
|
||||
|
||||
for (size_t i = 0; i < m_size; i++) {
|
||||
size_t Matches = 0;
|
||||
while (*(pMemory + i + Matches) == pData[Matches] || pData[Matches] == '\x2A') {
|
||||
Matches++;
|
||||
if (Matches == iSigLength)
|
||||
return_addr = (void*)(pMemory + i);
|
||||
}
|
||||
}
|
||||
|
||||
return return_addr;
|
||||
}
|
||||
|
||||
void* CModule::FindInterface(const char* name)
|
||||
{
|
||||
CreateInterfaceFn fn = (CreateInterfaceFn)dlsym(m_hModule, "CreateInterface");
|
||||
|
||||
if (!fn)
|
||||
Error("Could not find CreateInterface in %s\n", m_pszModule);
|
||||
|
||||
void* pInterface = fn(name, nullptr);
|
||||
|
||||
if (!pInterface)
|
||||
Error("Could not find %s in %s\n", name, m_pszModule);
|
||||
|
||||
return pInterface;
|
||||
}
|
||||
}
|
||||
@@ -18,80 +18,31 @@
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
#include "dbg.h"
|
||||
#include <cstdio>
|
||||
|
||||
#include "interface.h"
|
||||
#include "strtools.h"
|
||||
#include "metamod_oslink.h"
|
||||
#include "memory.h"
|
||||
#undef snprintf
|
||||
|
||||
#ifdef _WIN32
|
||||
#include <Psapi.h>
|
||||
#endif
|
||||
namespace counterstrikesharp {
|
||||
namespace modules {
|
||||
namespace counterstrikesharp::modules {
|
||||
|
||||
class CModule {
|
||||
public:
|
||||
CModule(const char *path, const char *module)
|
||||
: m_pszModule(module),
|
||||
m_pszPath(path) {
|
||||
char szModule[MAX_PATH];
|
||||
class CModule
|
||||
{
|
||||
public:
|
||||
CModule(const char* path, const char* module);
|
||||
|
||||
V_snprintf(szModule, MAX_PATH, "%s%s%s%s%s", Plat_GetGameDirectory(), path, MODULE_PREFIX,
|
||||
m_pszModule, MODULE_EXT);
|
||||
void* FindSignature(const char* signature);
|
||||
|
||||
m_hModule = dlmount(szModule);
|
||||
void* FindSignature(const byte* pData, size_t iSigLength);
|
||||
|
||||
if (!m_hModule) Error("Could not find %s\n", szModule);
|
||||
void* FindInterface(const char* name);
|
||||
|
||||
#ifdef _WIN32
|
||||
MODULEINFO m_hModuleInfo;
|
||||
GetModuleInformation(GetCurrentProcess(), m_hModule, &m_hModuleInfo, sizeof(m_hModuleInfo));
|
||||
|
||||
m_base = (void *)m_hModuleInfo.lpBaseOfDll;
|
||||
m_size = m_hModuleInfo.SizeOfImage;
|
||||
#else
|
||||
if (int e = GetModuleInformation(m_hModule, &m_base, &m_size))
|
||||
Error("Failed to get module info for %s, error %d\n", szModule, e);
|
||||
#endif
|
||||
}
|
||||
|
||||
void *FindSignature(const byte *pData) {
|
||||
unsigned char *pMemory;
|
||||
void *return_addr = nullptr;
|
||||
|
||||
size_t iSigLength = V_strlen((const char *)pData);
|
||||
|
||||
pMemory = (byte *)m_base;
|
||||
|
||||
for (size_t i = 0; i < m_size; i++) {
|
||||
size_t Matches = 0;
|
||||
while (*(pMemory + i + Matches) == pData[Matches] || pData[Matches] == '\x2A') {
|
||||
Matches++;
|
||||
if (Matches == iSigLength) return_addr = (void *)(pMemory + i);
|
||||
}
|
||||
}
|
||||
|
||||
return return_addr;
|
||||
}
|
||||
|
||||
void *FindInterface(const char *name) {
|
||||
CreateInterfaceFn fn = (CreateInterfaceFn)dlsym(m_hModule, "CreateInterface");
|
||||
|
||||
if (!fn) Error("Could not find CreateInterface in %s\n", m_pszModule);
|
||||
|
||||
void *pInterface = fn(name, nullptr);
|
||||
|
||||
if (!pInterface) Error("Could not find %s in %s\n", name, m_pszModule);
|
||||
|
||||
return pInterface;
|
||||
}
|
||||
|
||||
const char *m_pszModule;
|
||||
const char *m_pszPath;
|
||||
const char* m_pszModule;
|
||||
const char* m_pszPath;
|
||||
HINSTANCE m_hModule;
|
||||
void *m_base;
|
||||
void* m_base;
|
||||
size_t m_size;
|
||||
};
|
||||
} // namespace modules
|
||||
} // namespace counterstrikesharp
|
||||
|
||||
} // namespace counterstrikesharp::modules
|
||||
@@ -18,6 +18,7 @@
|
||||
|
||||
#include "core/global_listener.h"
|
||||
#include "core/log.h"
|
||||
#include "core/gameconfig.h"
|
||||
#include "core/timer_system.h"
|
||||
#include "core/utils.h"
|
||||
#include "core/managers/entity_manager.h"
|
||||
@@ -29,9 +30,12 @@
|
||||
#include "entity2/entitysystem.h"
|
||||
#include "interfaces/cs2_interfaces.h"
|
||||
|
||||
|
||||
counterstrikesharp::GlobalClass* counterstrikesharp::GlobalClass::head = nullptr;
|
||||
|
||||
extern "C" void InvokeNative(counterstrikesharp::fxNativeContext& context)
|
||||
// TODO: Workaround for windows, we __MUST__ have COUNTERSTRIKESHARP_API to handle it.
|
||||
// like on windows it should be `extern "C" __declspec(dllexport)`, on linux it should be anything else.
|
||||
DLL_EXPORT void InvokeNative(counterstrikesharp::fxNativeContext& context)
|
||||
{
|
||||
if (context.nativeIdentifier == 0)
|
||||
return;
|
||||
@@ -79,6 +83,15 @@ bool CounterStrikeSharpMMPlugin::Load(PluginId id, ISmmAPI* ismm, char* error, s
|
||||
GET_V_IFACE_ANY(GetEngineFactory, globals::gameEventSystem, IGameEventSystem,
|
||||
GAMEEVENTSYSTEM_INTERFACE_VERSION);
|
||||
|
||||
auto gamedata_path = std::string(utils::GamedataDirectory() + "/gamedata.json");
|
||||
globals::gameConfig = new CGameConfig(gamedata_path);
|
||||
char conf_error[255] = "";
|
||||
|
||||
if (!globals::gameConfig->Init(conf_error, sizeof(conf_error))) {
|
||||
CSSHARP_CORE_ERROR("Could not read \'{}\'. Error: {}", gamedata_path, conf_error);
|
||||
return false;
|
||||
}
|
||||
|
||||
globals::Initialize();
|
||||
|
||||
CSSHARP_CORE_INFO("Globals loaded.");
|
||||
|
||||
@@ -35,7 +35,7 @@ void ScriptCallback::AddListener(CallbackT fnPluginFunction)
|
||||
|
||||
bool ScriptCallback::RemoveListener(CallbackT fnPluginFunction)
|
||||
{
|
||||
bool bSuccess;
|
||||
bool bSuccess = true;
|
||||
|
||||
m_functions.erase(std::remove(m_functions.begin(), m_functions.end(), fnPluginFunction),
|
||||
m_functions.end());
|
||||
|
||||
@@ -1,3 +1,19 @@
|
||||
/*
|
||||
* This file is part of CounterStrikeSharp.
|
||||
* CounterStrikeSharp is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* CounterStrikeSharp is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with CounterStrikeSharp. If not, see <https://www.gnu.org/licenses/>. *
|
||||
*/
|
||||
|
||||
#include "scripting/dotnet_host.h"
|
||||
|
||||
#include <dotnet/coreclr_delegates.h>
|
||||
@@ -7,15 +23,19 @@
|
||||
#include <locale>
|
||||
|
||||
#ifdef WIN32
|
||||
#include <Windows.h>
|
||||
#include <direct.h>
|
||||
#include <Windows.h>
|
||||
#include <direct.h>
|
||||
|
||||
#define STR(s) L##s
|
||||
#define CH(c) L##c
|
||||
#define DIR_SEPARATOR L'\\'
|
||||
#define STR(s) L##s
|
||||
#define CH(c) L##c
|
||||
#define DIR_SEPARATOR L'\\'
|
||||
|
||||
#else
|
||||
#include <dlfcn.h>
|
||||
#define STR(s) s
|
||||
#define CH(c) c
|
||||
#define DIR_SEPARATOR '/'
|
||||
|
||||
#include <dlfcn.h>
|
||||
#endif
|
||||
|
||||
#include <cassert>
|
||||
@@ -24,6 +44,8 @@
|
||||
#include "core/log.h"
|
||||
#include "core/utils.h"
|
||||
|
||||
#include "utils/string.h"
|
||||
|
||||
std::wstring_convert<std::codecvt_utf8_utf16<wchar_t>> converter;
|
||||
|
||||
namespace {
|
||||
@@ -33,34 +55,38 @@ hostfxr_close_fn close_fptr;
|
||||
hostfxr_handle cxt;
|
||||
|
||||
bool load_hostfxr();
|
||||
load_assembly_and_get_function_pointer_fn get_dotnet_load_assembly(const char_t *assembly);
|
||||
} // namespace
|
||||
load_assembly_and_get_function_pointer_fn get_dotnet_load_assembly(const char_t* assembly);
|
||||
} // namespace
|
||||
|
||||
namespace {
|
||||
// Forward declarations
|
||||
void *load_library(const char_t *);
|
||||
void *get_export(void *, const char *);
|
||||
void* load_library(const char_t*);
|
||||
void* get_export(void*, const char*);
|
||||
|
||||
#ifdef _WINDOWS
|
||||
void *load_library(const char_t *path) {
|
||||
void* load_library(const char_t* path)
|
||||
{
|
||||
HMODULE h = ::LoadLibraryW(path);
|
||||
assert(h != nullptr);
|
||||
return (void *)h;
|
||||
return (void*)h;
|
||||
}
|
||||
|
||||
void *get_export(void *h, const char *name) {
|
||||
void *f = ::GetProcAddress((HMODULE)h, name);
|
||||
void* get_export(void* h, const char* name)
|
||||
{
|
||||
void* f = ::GetProcAddress((HMODULE)h, name);
|
||||
assert(f != nullptr);
|
||||
return f;
|
||||
}
|
||||
#else
|
||||
void *load_library(const char_t *path) {
|
||||
void *h = dlopen(path, RTLD_LAZY | RTLD_LOCAL);
|
||||
void* load_library(const char_t* path)
|
||||
{
|
||||
void* h = dlopen(path, RTLD_LAZY | RTLD_LOCAL);
|
||||
assert(h != nullptr);
|
||||
return h;
|
||||
}
|
||||
void *get_export(void *h, const char *name) {
|
||||
void *f = dlsym(h, name);
|
||||
void* get_export(void* h, const char* name)
|
||||
{
|
||||
void* f = dlsym(h, name);
|
||||
assert(f != nullptr);
|
||||
return f;
|
||||
}
|
||||
@@ -68,20 +94,39 @@ void *get_export(void *h, const char *name) {
|
||||
|
||||
// <SnippetLoadHostFxr>
|
||||
// Using the nethost library, discover the location of hostfxr and get exports
|
||||
bool load_hostfxr() {
|
||||
std::string baseDir = counterstrikesharp::utils::PluginDirectory();
|
||||
|
||||
std::string buffer = std::string(baseDir + "/dotnet/host/fxr/7.0.11/libhostfxr.so");
|
||||
|
||||
CSSHARP_CORE_TRACE("Loading hostfxr from {0}", buffer.c_str());
|
||||
bool load_hostfxr()
|
||||
{
|
||||
std::string base_dir = counterstrikesharp::utils::PluginDirectory();
|
||||
namespace css = counterstrikesharp;
|
||||
#if _WIN32
|
||||
std::wstring buffer =
|
||||
std::wstring(css::widen(base_dir) + L"\\dotnet\\host\\fxr\\7.0.11\\hostfxr.dll");
|
||||
CSSHARP_CORE_INFO("Loading hostfxr from {0}", css::narrow(buffer).c_str());
|
||||
#else
|
||||
std::string buffer = std::string(base_dir + "/dotnet/host/fxr/7.0.11/libhostfxr.so");
|
||||
CSSHARP_CORE_INFO("Loading hostfxr from {0}", buffer.c_str());
|
||||
#endif
|
||||
|
||||
// Load hostfxr and get desired exports
|
||||
void *lib = load_library(buffer.c_str());
|
||||
void* lib = load_library(buffer.c_str());
|
||||
init_fptr = (hostfxr_initialize_for_runtime_config_fn)get_export(
|
||||
lib, "hostfxr_initialize_for_runtime_config");
|
||||
if (init_fptr == nullptr) {
|
||||
CSSHARP_CORE_CRITICAL(
|
||||
"unable to get export function: \"hostfxr_initialize_for_runtime_config\"");
|
||||
return false;
|
||||
}
|
||||
get_delegate_fptr =
|
||||
(hostfxr_get_runtime_delegate_fn)get_export(lib, "hostfxr_get_runtime_delegate");
|
||||
if (!get_delegate_fptr) {
|
||||
CSSHARP_CORE_CRITICAL("unable to get export function: \"hostfxr_get_runtime_delegate\"");
|
||||
return false;
|
||||
}
|
||||
close_fptr = (hostfxr_close_fn)get_export(lib, "hostfxr_close");
|
||||
if (!close_fptr) {
|
||||
CSSHARP_CORE_CRITICAL("unable to get export function: \"hostfxr_close\"");
|
||||
return false;
|
||||
}
|
||||
|
||||
return (init_fptr && get_delegate_fptr && close_fptr);
|
||||
}
|
||||
@@ -89,12 +134,13 @@ bool load_hostfxr() {
|
||||
|
||||
// <SnippetInitialize>
|
||||
// Load and initialize .NET Core and get desired function pointer for scenario
|
||||
load_assembly_and_get_function_pointer_fn get_dotnet_load_assembly(const char_t *config_path) {
|
||||
load_assembly_and_get_function_pointer_fn get_dotnet_load_assembly(const char_t* config_path)
|
||||
{
|
||||
// Load .NET Core
|
||||
void *load_assembly_and_get_function_pointer = nullptr;
|
||||
void* load_assembly_and_get_function_pointer = nullptr;
|
||||
int rc = init_fptr(config_path, nullptr, &cxt);
|
||||
if (rc != 0 || cxt == nullptr) {
|
||||
std::cerr << "Init failed: " << std::hex << std::showbase << rc << std::endl;
|
||||
CSSHARP_CORE_CRITICAL("Init failed: {0:x}", rc);
|
||||
close_fptr(cxt);
|
||||
return nullptr;
|
||||
}
|
||||
@@ -102,53 +148,75 @@ load_assembly_and_get_function_pointer_fn get_dotnet_load_assembly(const char_t
|
||||
// Get the load assembly function pointer
|
||||
rc = get_delegate_fptr(cxt, hdt_load_assembly_and_get_function_pointer,
|
||||
&load_assembly_and_get_function_pointer);
|
||||
if (rc != 0 || load_assembly_and_get_function_pointer == nullptr)
|
||||
std::cerr << "Get delegate failed: " << std::hex << std::showbase << rc << std::endl;
|
||||
if (rc != 0 || load_assembly_and_get_function_pointer == nullptr) {
|
||||
CSSHARP_CORE_ERROR("Get delegate failed: {0:x}", rc);
|
||||
}
|
||||
|
||||
// close_fptr(cxt);
|
||||
return (load_assembly_and_get_function_pointer_fn)load_assembly_and_get_function_pointer;
|
||||
}
|
||||
|
||||
} // namespace
|
||||
} // namespace
|
||||
|
||||
CDotNetManager::CDotNetManager() {}
|
||||
|
||||
CDotNetManager::~CDotNetManager() {}
|
||||
|
||||
bool CDotNetManager::Initialize() {
|
||||
std::string baseDir = counterstrikesharp::utils::PluginDirectory();
|
||||
bool CDotNetManager::Initialize()
|
||||
{
|
||||
const std::string base_dir = counterstrikesharp::utils::PluginDirectory();
|
||||
|
||||
CSSHARP_CORE_INFO("Loading .NET runtime...");
|
||||
|
||||
if (!load_hostfxr()) {
|
||||
CSSHARP_CORE_ERROR("Failed to initialize .NET");
|
||||
CSSHARP_CORE_ERROR("Failed to initialize .NET runtime.");
|
||||
return false;
|
||||
}
|
||||
CSSHARP_CORE_INFO(".NET Runtime Initialised.");
|
||||
namespace css = counterstrikesharp;
|
||||
#if _WIN32
|
||||
const auto wide_str =
|
||||
std::wstring(css::widen(base_dir) + L"\\api\\CounterStrikeSharp.API.runtimeconfig.json");
|
||||
CSSHARP_CORE_INFO("Loading CSS API, Runtime config: {}",
|
||||
counterstrikesharp::narrow(wide_str).c_str());
|
||||
#else
|
||||
std::string wide_str =
|
||||
std::string((base_dir + "/api/CounterStrikeSharp.API.runtimeconfig.json").c_str());
|
||||
CSSHARP_CORE_INFO("Loading CSS API, Runtime Config: {}", wide_str);
|
||||
#endif
|
||||
|
||||
const auto load_assembly_and_get_function_pointer = get_dotnet_load_assembly(wide_str.c_str());
|
||||
if (load_assembly_and_get_function_pointer == nullptr) {
|
||||
CSSHARP_CORE_ERROR("Failed to load CSS API.");
|
||||
return false;
|
||||
}
|
||||
|
||||
CSSHARP_CORE_INFO(".NET Runtime Initialised.");
|
||||
|
||||
std::string wideStr =
|
||||
std::string((baseDir + "/api/CounterStrikeSharp.API.runtimeconfig.json").c_str());
|
||||
|
||||
load_assembly_and_get_function_pointer_fn load_assembly_and_get_function_pointer = nullptr;
|
||||
load_assembly_and_get_function_pointer = get_dotnet_load_assembly(wideStr.c_str());
|
||||
assert(load_assembly_and_get_function_pointer != nullptr &&
|
||||
"Failure: get_dotnet_load_assembly()");
|
||||
|
||||
#if _WIN32
|
||||
const auto dotnetlib_path =
|
||||
std::wstring(css::widen(base_dir) + L"\\api\\CounterStrikeSharp.API.dll");
|
||||
CSSHARP_CORE_INFO("CSS API DLL: {}", counterstrikesharp::narrow(dotnetlib_path));
|
||||
#else
|
||||
const std::string dotnetlib_path =
|
||||
std::string((baseDir + "/api/CounterStrikeSharp.API.dll").c_str());
|
||||
const char_t *dotnet_type = "CounterStrikeSharp.API.Core.Helpers, CounterStrikeSharp.API";
|
||||
std::string((base_dir + "/api/CounterStrikeSharp.API.dll").c_str());
|
||||
#endif
|
||||
const auto dotnet_type = STR("CounterStrikeSharp.API.Core.Helpers, CounterStrikeSharp.API");
|
||||
// Namespace, assembly name
|
||||
|
||||
typedef int(CORECLR_DELEGATE_CALLTYPE * custom_entry_point_fn)();
|
||||
custom_entry_point_fn entry_point = nullptr;
|
||||
int rc = load_assembly_and_get_function_pointer(dotnetlib_path.c_str(), dotnet_type,
|
||||
"LoadAllPlugins", UNMANAGEDCALLERSONLY_METHOD,
|
||||
nullptr, (void **)&entry_point);
|
||||
const int rc = load_assembly_and_get_function_pointer(
|
||||
dotnetlib_path.c_str(), dotnet_type, STR("LoadAllPlugins"), UNMANAGEDCALLERSONLY_METHOD,
|
||||
nullptr, reinterpret_cast<void**>(&entry_point));
|
||||
if (entry_point == nullptr) {
|
||||
CSSHARP_CORE_ERROR("Trying to get entry point \"LoadAllPlugins\" but failed.");
|
||||
return false;
|
||||
}
|
||||
|
||||
assert(rc == 0 && entry_point != nullptr &&
|
||||
"Failure: load_assembly_and_get_function_pointer()");
|
||||
|
||||
const bool success = entry_point();
|
||||
if (!success) {
|
||||
CSSHARP_CORE_ERROR("Failed to initialize .NET");
|
||||
if (const int invoke_result_code = entry_point(); invoke_result_code == 0) {
|
||||
CSSHARP_CORE_ERROR("LoadAllPlugins return failure.");
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -156,10 +224,13 @@ bool CDotNetManager::Initialize() {
|
||||
return true;
|
||||
}
|
||||
|
||||
void CDotNetManager::UnloadPlugin(PluginContext *context) {}
|
||||
void CDotNetManager::UnloadPlugin(PluginContext* context) {}
|
||||
|
||||
void CDotNetManager::Shutdown() {
|
||||
void CDotNetManager::Shutdown()
|
||||
{
|
||||
// CoreCLR does not currently supporting unloading... :(
|
||||
// I think this is intentionally, you should handle Init/Shutdown manually.
|
||||
// Better rework in the future, but not now.
|
||||
}
|
||||
|
||||
PluginContext *CDotNetManager::FindContext(std::string path) { return nullptr; }
|
||||
PluginContext* CDotNetManager::FindContext(std::string path) { return nullptr; }
|
||||
|
||||
@@ -1,3 +1,19 @@
|
||||
/*
|
||||
* This file is part of CounterStrikeSharp.
|
||||
* CounterStrikeSharp is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* CounterStrikeSharp is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with CounterStrikeSharp. If not, see <https://www.gnu.org/licenses/>. *
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <memory>
|
||||
|
||||
4
src/scripting/listeners/server.yaml
Normal file
4
src/scripting/listeners/server.yaml
Normal file
@@ -0,0 +1,4 @@
|
||||
OnServerHibernationUpdate: isHibernating:bool
|
||||
OnGameServerSteamAPIActivated:
|
||||
OnGameServerSteamAPIDeactivated:
|
||||
OnHostNameChanged: hostname:string
|
||||
@@ -37,11 +37,6 @@ static ConCommandInfo* AddCommand(ScriptContext& script_context)
|
||||
CSSHARP_CORE_TRACE("Adding command {}, {}, {}, {}, {}", name, description, server_only, flags,
|
||||
(void*)callback);
|
||||
|
||||
if (globals::conCommandManager.FindCommand(name)) {
|
||||
script_context.ThrowNativeError("Failed to add command \"%s\", command already exists.", name);
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
return globals::conCommandManager.AddCommand(name, description, server_only, flags, callback);
|
||||
}
|
||||
|
||||
|
||||
@@ -15,7 +15,6 @@
|
||||
*/
|
||||
|
||||
#include <IEngineSound.h>
|
||||
#include <dlfcn.h>
|
||||
#include <edict.h>
|
||||
#include <eiface.h>
|
||||
#include <filesystem.h>
|
||||
@@ -33,6 +32,10 @@
|
||||
#include "core/function.h"
|
||||
// clang-format on
|
||||
|
||||
#if _WIN32
|
||||
#undef GetCurrentTime
|
||||
#endif
|
||||
|
||||
namespace counterstrikesharp {
|
||||
|
||||
const char* GetMapName(ScriptContext& script_context)
|
||||
|
||||
@@ -15,9 +15,11 @@
|
||||
*/
|
||||
#include "core/globals.h"
|
||||
#include "core/log.h"
|
||||
|
||||
#include "core/managers/event_manager.h"
|
||||
#include "scripting/autonative.h"
|
||||
|
||||
|
||||
namespace counterstrikesharp {
|
||||
|
||||
std::vector<IGameEvent *> managed_game_events;
|
||||
@@ -189,7 +191,7 @@ static void *GetPlayerController(ScriptContext &scriptContext) {
|
||||
return gameEvent->GetPlayerController(keyName);
|
||||
}
|
||||
|
||||
static void *SetPlayerController(ScriptContext &scriptContext) {
|
||||
static void SetPlayerController(ScriptContext &scriptContext) {
|
||||
IGameEvent *gameEvent = scriptContext.GetArgument<IGameEvent *>(0);
|
||||
const char *keyName = scriptContext.GetArgument<const char *>(1);
|
||||
auto *value = scriptContext.GetArgument<CEntityInstance *>(2);
|
||||
@@ -199,7 +201,7 @@ static void *SetPlayerController(ScriptContext &scriptContext) {
|
||||
}
|
||||
}
|
||||
|
||||
static void *SetEntity(ScriptContext &scriptContext) {
|
||||
static void SetEntity(ScriptContext &scriptContext) {
|
||||
IGameEvent *gameEvent = scriptContext.GetArgument<IGameEvent *>(0);
|
||||
const char *keyName = scriptContext.GetArgument<const char *>(1);
|
||||
auto *value = scriptContext.GetArgument<CEntityInstance *>(2);
|
||||
@@ -209,7 +211,7 @@ static void *SetEntity(ScriptContext &scriptContext) {
|
||||
}
|
||||
}
|
||||
|
||||
static void *SetEntityIndex(ScriptContext &scriptContext) {
|
||||
static void SetEntityIndex(ScriptContext &scriptContext) {
|
||||
IGameEvent *gameEvent = scriptContext.GetArgument<IGameEvent *>(0);
|
||||
const char *keyName = scriptContext.GetArgument<const char *>(1);
|
||||
auto index = scriptContext.GetArgument<int>(2);
|
||||
@@ -243,7 +245,7 @@ static uint64 GetUint64(ScriptContext &scriptContext) {
|
||||
return gameEvent->GetUint64(keyName);
|
||||
}
|
||||
|
||||
static void *SetUint64(ScriptContext &scriptContext) {
|
||||
static void SetUint64(ScriptContext &scriptContext) {
|
||||
IGameEvent *gameEvent = scriptContext.GetArgument<IGameEvent *>(0);
|
||||
const char *keyName = scriptContext.GetArgument<const char *>(1);
|
||||
auto value = scriptContext.GetArgument<uint64>(2);
|
||||
|
||||
@@ -16,7 +16,6 @@
|
||||
|
||||
#include <ios>
|
||||
#include <sstream>
|
||||
#include <dlfcn.h>
|
||||
|
||||
#include "scripting/autonative.h"
|
||||
#include "core/function.h"
|
||||
|
||||
@@ -16,7 +16,6 @@
|
||||
|
||||
#include <ios>
|
||||
#include <sstream>
|
||||
#include <dlfcn.h>
|
||||
|
||||
#include "scripting/autonative.h"
|
||||
#include "scripting/script_engine.h"
|
||||
|
||||
47
src/utils/string.h
Normal file
47
src/utils/string.h
Normal file
@@ -0,0 +1,47 @@
|
||||
/**
|
||||
* This file is part of CounterStrikeSharp.
|
||||
* CounterStrikeSharp is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* CounterStrikeSharp is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with CounterStrikeSharp. If not, see <https://www.gnu.org/licenses/>. *
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <string>
|
||||
#include <sstream>
|
||||
namespace counterstrikesharp {
|
||||
std::wstring widen(const std::string& str)
|
||||
{
|
||||
std::wostringstream wstm;
|
||||
const auto& ctfacet = std::use_facet<std::ctype<wchar_t>>(wstm.getloc());
|
||||
for (size_t i = 0; i < str.size(); ++i) {
|
||||
wstm << ctfacet.widen(str[i]);
|
||||
}
|
||||
return wstm.str();
|
||||
}
|
||||
|
||||
std::string narrow(const std::wstring& str)
|
||||
{
|
||||
std::ostringstream stm;
|
||||
|
||||
// Incorrect code from the link
|
||||
// const ctype<char>& ctfacet = use_facet<ctype<char>>(stm.getloc());
|
||||
|
||||
// Correct code.
|
||||
const auto& ctfacet = std::use_facet<std::ctype<wchar_t>>(stm.getloc());
|
||||
|
||||
for (size_t i = 0; i < str.size(); ++i) {
|
||||
stm << ctfacet.narrow(str[i], 0);
|
||||
}
|
||||
return stm.str();
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user