Initial commit
This commit is contained in:
commit
3dd53cf457
105 changed files with 35670 additions and 0 deletions
116
.clang-tidy
Normal file
116
.clang-tidy
Normal file
|
|
@ -0,0 +1,116 @@
|
|||
---
|
||||
# Configure clang-tidy for this project.
|
||||
|
||||
# Here is an explanation for why some of the checks are disabled:
|
||||
#
|
||||
# -google-readability-namespace-comments: the *_CLIENT_NS is a macro, and
|
||||
# clang-tidy fails to match it against the initial value.
|
||||
#
|
||||
# -modernize-use-trailing-return-type: clang-tidy recommends using
|
||||
# `auto Foo() -> std::string { return ...; }`, we think the code is less
|
||||
# readable in this form.
|
||||
#
|
||||
# --modernize-concat-nested-namespaces: clang-tidy recommends
|
||||
# `namespace google::cloud {}` over `namespace google { namespace cloud { } }`
|
||||
# We need to support C++14, which does not supported nested namespaces.
|
||||
#
|
||||
# --modernize-use-nodiscard: clang-tidy recommends adding a nodiscard annotation
|
||||
# to functions where the return value should not be ignored.
|
||||
# We need to support C++14, which does not supported the annotation.
|
||||
#
|
||||
# -modernize-return-braced-init-list: We think removing typenames and using
|
||||
# only braced-init can hurt readability.
|
||||
#
|
||||
# -modernize-avoid-c-arrays: We only use C arrays when they seem to be the
|
||||
# right tool for the job, such as `char foo[] = "hello"`. In these cases,
|
||||
# avoiding C arrays often makes the code less readable, and std::array is
|
||||
# not a drop-in replacement because it doesn't deduce the size.
|
||||
#
|
||||
# -performance-move-const-arg: This warning requires the developer to
|
||||
# know/care more about the implementation details of types/functions than
|
||||
# should be necessary. For example, `A a; F(std::move(a));` will trigger a
|
||||
# warning IFF `A` is a trivial type (and therefore the move is
|
||||
# meaningless). It would also warn if `F` accepts by `const&`, which is
|
||||
# another detail that the caller need not care about.
|
||||
#
|
||||
# -readability-redundant-declaration: A friend declaration inside a class
|
||||
# counts as a declaration, so if we also declare that friend outside the
|
||||
# class in order to document it as part of the public API, that will
|
||||
# trigger a redundant declaration warning from this check.
|
||||
#
|
||||
# -readability-function-cognitive-complexity: too many false positives with
|
||||
# clang-tidy-12. We need to disable this check in macros, and that setting
|
||||
# only appears in clang-tidy-13.
|
||||
#
|
||||
# -bugprone-narrowing-conversions: too many false positives around
|
||||
# `std::size_t` vs. `*::difference_type`.
|
||||
#
|
||||
# -bugprone-easily-swappable-parameters: too many false positives.
|
||||
#
|
||||
# -bugprone-implicit-widening-of-multiplication-result: too many false positives.
|
||||
# Almost any expression of the form `2 * variable` or `long x = a_int * b_int;`
|
||||
# generates an error.
|
||||
#
|
||||
# -bugprone-unchecked-optional-access: too many false positives in tests.
|
||||
# Despite what the documentation says, this warning appears after
|
||||
# `ASSERT_TRUE(variable)` or `ASSERT_TRUE(variable.has_value())`.
|
||||
#
|
||||
Checks: >
|
||||
-*,
|
||||
abseil-*,
|
||||
bugprone-*,GetGame
|
||||
google-*,
|
||||
misc-*,
|
||||
modernize-*,
|
||||
performance-*,
|
||||
portability-*,
|
||||
readability-*,
|
||||
-google-readability-braces-around-statements,
|
||||
-google-readability-namespace-comments,
|
||||
-google-runtime-references,
|
||||
-misc-non-private-member-variables-in-classes,
|
||||
-misc-const-correctness,
|
||||
-modernize-return-braced-init-list,
|
||||
-modernize-use-trailing-return-type,
|
||||
-modernize-concat-nested-namespaces,
|
||||
-modernize-use-nodiscard,
|
||||
-modernize-avoid-c-arrays,
|
||||
-performance-move-const-arg,
|
||||
-readability-braces-around-statements,
|
||||
-readability-identifier-length,
|
||||
-readability-magic-numbers,
|
||||
-readability-named-parameter,
|
||||
-readability-redundant-declaration,
|
||||
-readability-function-cognitive-complexity,
|
||||
-readability-convert-member-functions-to-static,
|
||||
-readability-implicit-bool-conversion,
|
||||
-bugprone-narrowing-conversions,
|
||||
-bugprone-easily-swappable-parameters,
|
||||
-bugprone-implicit-widening-of-multiplication-result,
|
||||
-bugprone-unchecked-optional-access
|
||||
|
||||
# Turn all the warnings from the checks above into errors.
|
||||
WarningsAsErrors: "*"
|
||||
|
||||
CheckOptions:
|
||||
google-readability-braces-around-statements.ShortStatementLines: '1'
|
||||
google-readability-function-size.StatementThreshold: '800'
|
||||
google-readability-namespace-comments.ShortNamespaceLines: '10'
|
||||
google-readability-namespace-comments.SpacesBeforeComments: '2'
|
||||
readability-identifier-naming.PrivateMemberPrefix: 'm_'
|
||||
readability-identifier-naming.ProtectedMemberPrefix: 'm_'
|
||||
readability-identifier-naming.MemberPrefix: 'm_'
|
||||
readability-identifier-naming.ClassCase: CamelCase
|
||||
readability-identifier-naming.MemberCase: CamelCase
|
||||
readability-identifier-naming.EnumCase: CamelCase
|
||||
readability-identifier-naming.FunctionCase: CamelCase
|
||||
readability-identifier-naming.ParameterCase: CamelCase
|
||||
readability-identifier-naming.UnionCase: CamelCase
|
||||
readability-identifier-naming.VariableCase: CamelCase
|
||||
readability-identifier-naming.LocalConstantPointerPrefix: 'p'
|
||||
readability-identifier-naming.VariableHungarianPrefix: On
|
||||
readability-identifier-naming.ParameterHungarianPrefix: On
|
||||
readability-identifier-naming.MemberHungarianPrefix: On
|
||||
readability-identifier-naming.PointerParameterHungarianPrefix: On
|
||||
readability-identifier-naming.PointerParameterCase: CamelCase
|
||||
readability-identifier-naming.HungarianNotation.UserDefinedType.std::string: s
|
||||
133
.github/workflows/main.yml
vendored
Normal file
133
.github/workflows/main.yml
vendored
Normal file
|
|
@ -0,0 +1,133 @@
|
|||
name: Continuous Integration
|
||||
|
||||
on:
|
||||
push:
|
||||
tags:
|
||||
- '*'
|
||||
workflow_dispatch:
|
||||
|
||||
permissions:
|
||||
contents: write
|
||||
|
||||
jobs:
|
||||
build-linux:
|
||||
name: Build on Linux via Docker Compose
|
||||
runs-on: ubuntu-latest
|
||||
|
||||
steps:
|
||||
- name: Checkout repository
|
||||
uses: actions/checkout@v4
|
||||
with:
|
||||
submodules: recursive
|
||||
|
||||
- name: Set up Docker Buildx
|
||||
uses: docker/setup-buildx-action@v3
|
||||
|
||||
- name: Build plugin inside container
|
||||
run: docker compose -f docker/docker-compose.yml up --build --abort-on-container-exit
|
||||
|
||||
- name: Upload Linux artifact
|
||||
uses: actions/upload-artifact@v4
|
||||
with:
|
||||
name: TemplatePlugin-linux
|
||||
path: build/addons
|
||||
|
||||
build-windows:
|
||||
name: Build on Windows (MSVC)
|
||||
runs-on: windows-latest
|
||||
|
||||
steps:
|
||||
- name: Checkout repository
|
||||
uses: actions/checkout@v4
|
||||
with:
|
||||
submodules: recursive
|
||||
|
||||
- name: Prepare SDK directory
|
||||
shell: powershell
|
||||
run: |
|
||||
$SDK = "C:\sdk"
|
||||
$HL2SDK = "$SDK\hl2sdk-cs2"
|
||||
$MMS = "$SDK\metamod-source"
|
||||
$PROTO = "$SDK\Protobufs"
|
||||
|
||||
if (Test-Path $SDK) { Remove-Item $SDK -Recurse -Force }
|
||||
New-Item -ItemType Directory -Path $SDK | Out-Null
|
||||
|
||||
Write-Host "=== Downloading HL2SDK-CS2 ==="
|
||||
git clone --depth=1 -b cs2 https://github.com/alliedmodders/hl2sdk $HL2SDK
|
||||
|
||||
Write-Host "=== Downloading Metamod-Source ==="
|
||||
git clone --depth=1 https://github.com/alliedmodders/metamod-source $MMS
|
||||
|
||||
Write-Host "=== Downloading Protobufs ==="
|
||||
git clone --depth=1 https://github.com/SteamDatabase/Protobufs $PROTO
|
||||
|
||||
$HL2SDK_UNIX = $HL2SDK.Replace("\", "/")
|
||||
$MMS_UNIX = $MMS.Replace("\", "/")
|
||||
$PROTO_UNIX = "$($PROTO.Replace('\','/'))/csgo"
|
||||
|
||||
echo "HL2SDKCS2=$HL2SDK_UNIX" | Out-File -FilePath $env:GITHUB_ENV -Append
|
||||
echo "MMSOURCE_DEV=$MMS_UNIX" | Out-File -FilePath $env:GITHUB_ENV -Append
|
||||
echo "CSGO_PROTO=$PROTO_UNIX" | Out-File -FilePath $env:GITHUB_ENV -Append
|
||||
|
||||
Write-Host "Using HL2SDKCS2=$HL2SDK_UNIX"
|
||||
Write-Host "Using MMSOURCE_DEV=$MMS_UNIX"
|
||||
Write-Host "Using CSGO_PROTO=$PROTO_UNIX"
|
||||
|
||||
- name: Configure + Build with MSVC
|
||||
shell: cmd
|
||||
run: |
|
||||
call "C:\Program Files\Microsoft Visual Studio\2022\Enterprise\VC\Auxiliary\Build\vcvars64.bat"
|
||||
cmake -S . -B build -A x64 -DCMAKE_BUILD_TYPE=Release ^
|
||||
-DHL2SDKCS2=%HL2SDKCS2% -DMMSOURCE_DEV=%MMSOURCE_DEV% -DCSGO_PROTO=%CSGO_PROTO%
|
||||
cmake --build build --config Release --target TemplatePlugin
|
||||
|
||||
- name: Strip symbols (Windows)
|
||||
run: |
|
||||
llvm-strip build/Release/TemplatePlugin.dll
|
||||
|
||||
- name: Copy addons structure
|
||||
run: |
|
||||
mkdir -p build/addons/TemplatePlugin/bin/win64
|
||||
copy build/Release/TemplatePlugin.dll build/addons/TemplatePlugin/bin/win64/
|
||||
|
||||
- name: Upload Windows artifact
|
||||
uses: actions/upload-artifact@v4
|
||||
with:
|
||||
name: TemplatePlugin-wwindows
|
||||
path: build/addons
|
||||
|
||||
release:
|
||||
name: Release
|
||||
if: startsWith(github.ref, 'refs/tags/')
|
||||
needs: [build-linux, build-windows]
|
||||
runs-on: ubuntu-latest
|
||||
permissions:
|
||||
contents: write
|
||||
steps:
|
||||
- name: Download Linux artifact
|
||||
uses: actions/download-artifact@v4
|
||||
with:
|
||||
name: TemplatePlugin-linux
|
||||
path: ./build/linux
|
||||
|
||||
- name: Download Windows artifact
|
||||
uses: actions/download-artifact@v4
|
||||
with:
|
||||
name: TemplatePlugin-windows
|
||||
path: ./build/windows
|
||||
|
||||
- name: Archive packages
|
||||
run: |
|
||||
version="${GITHUB_REF#refs/tags/}"
|
||||
tar -czf TemplatePlugin-${version}-linux.tar.gz -C build/linux .
|
||||
tar -czf TemplatePlugin-${version}-windows.tar.gz -C build/windows .
|
||||
|
||||
- name: Upload release archive
|
||||
uses: svenstaro/upload-release-action@v2
|
||||
with:
|
||||
repo_token: ${{ secrets.GITHUB_TOKEN }}
|
||||
file: TemplatePlugin-*.tar.gz
|
||||
tag: ${{ github.ref }}
|
||||
file_glob: true
|
||||
release_name: "${{ github.ref_name }} - Download"
|
||||
557
.gitignore
vendored
Normal file
557
.gitignore
vendored
Normal file
|
|
@ -0,0 +1,557 @@
|
|||
.ccls-cache/
|
||||
.cmake/
|
||||
cmake-build-*/
|
||||
cmake-build-steamrt-docker/
|
||||
cmake-build-relwithdebinfo-docker/
|
||||
.kdev4/
|
||||
generated/
|
||||
!**/protobuf/generated/
|
||||
output/
|
||||
|
||||
vendor/mono/
|
||||
|
||||
CMakeSettings.json
|
||||
|
||||
build-*/
|
||||
build/
|
||||
build_test/
|
||||
|
||||
# Prerequisites
|
||||
*.d
|
||||
|
||||
# Compiled Object files
|
||||
*.slo
|
||||
*.lo
|
||||
*.o
|
||||
*.obj
|
||||
|
||||
# Precompiled Headers
|
||||
*.gch
|
||||
*.pch
|
||||
|
||||
# Compiled Dynamic vendor
|
||||
*.so
|
||||
*.dylib
|
||||
*.dll
|
||||
|
||||
# Fortran module files
|
||||
*.mod
|
||||
*.smod
|
||||
|
||||
# Compiled Static vendor
|
||||
*.lai
|
||||
*.la
|
||||
*.a
|
||||
*.lib
|
||||
|
||||
!mono*.lib
|
||||
!**/external_includes/**/*.lib
|
||||
|
||||
# Executables
|
||||
*.exe
|
||||
*.out
|
||||
*.app
|
||||
|
||||
## Ignore Visual Studio temporary files, build results, and
|
||||
## files generated by popular Visual Studio add-ons.
|
||||
##
|
||||
## Get latest from https://github.com/github/gitignore/blob/master/VisualStudio.gitignore
|
||||
|
||||
# User-specific files
|
||||
*.rsuser
|
||||
*.suo
|
||||
*.user
|
||||
*.userosscache
|
||||
*.sln.docstates
|
||||
|
||||
# User-specific files (MonoDevelop/Xamarin Studio)
|
||||
*.userprefs
|
||||
|
||||
# Mono auto generated files
|
||||
mono_crash.*
|
||||
|
||||
# Build results
|
||||
[Dd]ebug/
|
||||
[Dd]ebugPublic/
|
||||
[Rr]elease/
|
||||
[Rr]eleases/
|
||||
x64/
|
||||
x86/
|
||||
[Ww][Ii][Nn]32/
|
||||
[Aa][Rr][Mm]/
|
||||
[Aa][Rr][Mm]64/
|
||||
bld/
|
||||
[Bb]in/
|
||||
[Oo]bj/
|
||||
[Ll]og/
|
||||
[Ll]ogs/
|
||||
|
||||
# Visual Studio 2015/2017 cache/options directory
|
||||
.vs/
|
||||
# Uncomment if you have tasks that create the project's static files in wwwroot
|
||||
#wwwroot/
|
||||
|
||||
# Visual Studio 2017 auto generated files
|
||||
Generated\ Files/
|
||||
|
||||
# MSTest test Results
|
||||
[Tt]est[Rr]esult*/
|
||||
[Bb]uild[Ll]og.*
|
||||
|
||||
# NUnit
|
||||
*.VisualState.xml
|
||||
TestResult.xml
|
||||
nunit-*.xml
|
||||
|
||||
# Build Results of an ATL Project
|
||||
[Dd]ebugPS/
|
||||
[Rr]eleasePS/
|
||||
dlldata.c
|
||||
|
||||
# Benchmark Results
|
||||
BenchmarkDotNet.Artifacts/
|
||||
|
||||
# .NET HammerIdFix
|
||||
project.lock.json
|
||||
project.fragment.lock.json
|
||||
artifacts/
|
||||
|
||||
# ASP.NET Scaffolding
|
||||
ScaffoldingReadMe.txt
|
||||
|
||||
# StyleCop
|
||||
StyleCopReport.xml
|
||||
|
||||
# Files built by Visual Studio
|
||||
*_i.c
|
||||
*_p.c
|
||||
*_h.h
|
||||
*.ilk
|
||||
*.meta
|
||||
*.obj
|
||||
*.iobj
|
||||
*.pch
|
||||
*.pdb
|
||||
*.ipdb
|
||||
*.pgc
|
||||
*.pgd
|
||||
*.rsp
|
||||
*.sbr
|
||||
*.tlb
|
||||
*.tli
|
||||
*.tlh
|
||||
*.tmp
|
||||
*.tmp_proj
|
||||
*_wpftmp.csproj
|
||||
*.log
|
||||
*.vspscc
|
||||
*.vssscc
|
||||
.builds
|
||||
*.pidb
|
||||
*.svclog
|
||||
*.scc
|
||||
|
||||
# Chutzpah Test files
|
||||
_Chutzpah*
|
||||
|
||||
# Visual C++ cache files
|
||||
ipch/
|
||||
*.aps
|
||||
*.ncb
|
||||
*.opendb
|
||||
*.opensdf
|
||||
*.sdf
|
||||
*.cachefile
|
||||
*.VC.db
|
||||
*.VC.VC.opendb
|
||||
|
||||
# Visual Studio profiler
|
||||
*.psess
|
||||
*.vsp
|
||||
*.vspx
|
||||
*.sap
|
||||
|
||||
# Visual Studio Trace Files
|
||||
*.e2e
|
||||
|
||||
# TFS 2012 Local Workspace
|
||||
$tf/
|
||||
|
||||
# Guidance Automation Toolkit
|
||||
*.gpState
|
||||
|
||||
# ReSharper is a .NET coding add-in
|
||||
_ReSharper*/
|
||||
*.[Rr]e[Ss]harper
|
||||
*.DotSettings.user
|
||||
|
||||
# TeamCity is a build add-in
|
||||
_TeamCity*
|
||||
|
||||
# DotCover is a Code Coverage Tool
|
||||
*.dotCover
|
||||
|
||||
# AxoCover is a Code Coverage Tool
|
||||
.axoCover/*
|
||||
!.axoCover/settings.json
|
||||
|
||||
# Coverlet is a free, cross platform Code Coverage Tool
|
||||
coverage*.json
|
||||
coverage*.xml
|
||||
coverage*.info
|
||||
|
||||
# Visual Studio code coverage results
|
||||
*.coverage
|
||||
*.coveragexml
|
||||
|
||||
# NCrunch
|
||||
_NCrunch_*
|
||||
.*crunch*.local.xml
|
||||
nCrunchTemp_*
|
||||
|
||||
# MightyMoose
|
||||
*.mm.*
|
||||
AutoTest.Net/
|
||||
|
||||
# Web workbench (sass)
|
||||
.sass-cache/
|
||||
|
||||
# Installshield output folder
|
||||
[Ee]xpress/
|
||||
|
||||
# DocProject is a documentation generator add-in
|
||||
DocProject/buildhelp/
|
||||
DocProject/Help/*.HxT
|
||||
DocProject/Help/*.HxC
|
||||
DocProject/Help/*.hhc
|
||||
DocProject/Help/*.hhk
|
||||
DocProject/Help/*.hhp
|
||||
DocProject/Help/Html2
|
||||
DocProject/Help/html
|
||||
|
||||
# Click-Once directory
|
||||
publish/
|
||||
|
||||
# Publish Web Output
|
||||
*.[Pp]ublish.xml
|
||||
*.azurePubxml
|
||||
# Note: Comment the next line if you want to checkin your web deploy settings,
|
||||
# but database connection strings (with potential passwords) will be unencrypted
|
||||
*.pubxml
|
||||
*.publishproj
|
||||
|
||||
# Microsoft Azure Web App publish settings. Comment the next line if you want to
|
||||
# checkin your Azure Web App publish settings, but sensitive information contained
|
||||
# in these scripts will be unencrypted
|
||||
PublishScripts/
|
||||
|
||||
# NuGet Packages
|
||||
*.nupkg
|
||||
# NuGet Symbol Packages
|
||||
*.snupkg
|
||||
# The packages folder can be ignored because of Package Restore
|
||||
**/[Pp]ackages/*
|
||||
# except build/, which is used as an MSBuild target.
|
||||
!**/[Pp]ackages/build/
|
||||
# Uncomment if necessary however generally it will be regenerated when needed
|
||||
#!**/[Pp]ackages/repositories.config
|
||||
# NuGet v3's project.json files produces more ignorable files
|
||||
*.nuget.props
|
||||
*.nuget.targets
|
||||
|
||||
# Microsoft Azure Build Output
|
||||
csx/
|
||||
*.build.csdef
|
||||
|
||||
# Microsoft Azure Emulator
|
||||
ecf/
|
||||
rcf/
|
||||
|
||||
# Windows Store app package directories and files
|
||||
AppPackages/
|
||||
BundleArtifacts/
|
||||
Package.StoreAssociation.xml
|
||||
_pkginfo.txt
|
||||
*.appx
|
||||
*.appxbundle
|
||||
*.appxupload
|
||||
|
||||
# Visual Studio cache files
|
||||
# files ending in .cache can be ignored
|
||||
*.[Cc]ache
|
||||
# but keep track of directories ending in .cache
|
||||
!?*.[Cc]ache/
|
||||
|
||||
# Others
|
||||
ClientBin/
|
||||
~$*
|
||||
*~
|
||||
*.dbmdl
|
||||
*.dbproj.schemaview
|
||||
*.jfm
|
||||
*.pfx
|
||||
*.publishsettings
|
||||
orleans.codegen.cs
|
||||
|
||||
# Including strong name files can present a security risk
|
||||
# (https://github.com/github/gitignore/pull/2483#issue-259490424)
|
||||
#*.snk
|
||||
|
||||
# Since there are multiple workflows, uncomment next line to ignore bower_components
|
||||
# (https://github.com/github/gitignore/pull/1529#issuecomment-104372622)
|
||||
#bower_components/
|
||||
|
||||
# RIA/Silverlight projects
|
||||
Generated_Code/
|
||||
|
||||
# Backup & report files from converting an old project file
|
||||
# to a newer Visual Studio version. Backup files are not needed,
|
||||
# because we have git ;-)
|
||||
_UpgradeReport_Files/
|
||||
Backup*/
|
||||
UpgradeLog*.XML
|
||||
UpgradeLog*.htm
|
||||
ServiceFabricBackup/
|
||||
*.rptproj.bak
|
||||
|
||||
# SQL Server files
|
||||
*.mdf
|
||||
*.ldf
|
||||
*.ndf
|
||||
|
||||
# Business Intelligence projects
|
||||
*.rdl.data
|
||||
*.bim.layout
|
||||
*.bim_*.settings
|
||||
*.rptproj.rsuser
|
||||
*- [Bb]ackup.rdl
|
||||
*- [Bb]ackup ([0-9]).rdl
|
||||
*- [Bb]ackup ([0-9][0-9]).rdl
|
||||
|
||||
# Microsoft Fakes
|
||||
FakesAssemblies/
|
||||
|
||||
# GhostDoc plugin setting file
|
||||
*.GhostDoc.xml
|
||||
|
||||
# Node.js Tools for Visual Studio
|
||||
.ntvs_analysis.dat
|
||||
node_modules/
|
||||
|
||||
# Visual Studio 6 build log
|
||||
*.plg
|
||||
|
||||
# Visual Studio 6 workspace options file
|
||||
*.opt
|
||||
|
||||
# Visual Studio 6 auto-generated workspace file (contains which files were open etc.)
|
||||
*.vbw
|
||||
|
||||
# Visual Studio LightSwitch build output
|
||||
**/*.HTMLClient/GeneratedArtifacts
|
||||
**/*.DesktopClient/GeneratedArtifacts
|
||||
**/*.DesktopClient/ModelManifest.xml
|
||||
**/*.Server/GeneratedArtifacts
|
||||
**/*.Server/ModelManifest.xml
|
||||
_Pvt_Extensions
|
||||
|
||||
# Paket dependency manager
|
||||
.paket/paket.exe
|
||||
paket-files/
|
||||
|
||||
# FAKE - F# Make
|
||||
.fake/
|
||||
|
||||
# CodeRush personal settings
|
||||
.cr/personal
|
||||
|
||||
# Python Tools for Visual Studio (PTVS)
|
||||
__pycache__/
|
||||
*.pyc
|
||||
|
||||
# Cake - Uncomment if you are using it
|
||||
# tools/**
|
||||
# !tools/packages.config
|
||||
|
||||
# Tabs Studio
|
||||
*.tss
|
||||
|
||||
# Telerik's JustMock configuration file
|
||||
*.jmconfig
|
||||
|
||||
# BizTalk build output
|
||||
*.btp.cs
|
||||
*.btm.cs
|
||||
*.odx.cs
|
||||
*.xsd.cs
|
||||
|
||||
# OpenCover UI analysis results
|
||||
OpenCover/
|
||||
|
||||
# Azure Stream Analytics local run output
|
||||
ASALocalRun/
|
||||
|
||||
# MSBuild Binary and Structured Log
|
||||
*.binlog
|
||||
|
||||
# NVidia Nsight GPU debugger configuration file
|
||||
*.nvuser
|
||||
|
||||
# MFractors (Xamarin productivity tool) working folder
|
||||
.mfractor/
|
||||
|
||||
# Local History for Visual Studio
|
||||
.localhistory/
|
||||
|
||||
# BeatPulse healthcheck temp database
|
||||
healthchecksdb
|
||||
|
||||
# Backup folder for Package Reference Convert tool in Visual Studio 2017
|
||||
MigrationBackup/
|
||||
|
||||
# Ionide (cross platform F# VS Code tools) working folder
|
||||
.ionide/
|
||||
|
||||
# Fody - auto-generated XML schema
|
||||
FodyWeavers.xsd
|
||||
|
||||
## Ignore Visual Studio temporary files, build results, and
|
||||
## files generated by popular Visual Studio add-ons.
|
||||
|
||||
# User-specific files
|
||||
*.suo
|
||||
*.user
|
||||
*.sln.docstates
|
||||
|
||||
# Build results
|
||||
|
||||
[Dd]ebug/
|
||||
[Rr]elease/
|
||||
x64/
|
||||
[Bb]in/
|
||||
[Oo]bj/
|
||||
|
||||
# MSTest test Results
|
||||
[Tt]est[Rr]esult*/
|
||||
[Bb]uild[Ll]og.*
|
||||
|
||||
*_i.c
|
||||
*_p.c
|
||||
*_i.h
|
||||
*.ilk
|
||||
*.meta
|
||||
*.obj
|
||||
*.pch
|
||||
*.pdb
|
||||
*.pgc
|
||||
*.pgd
|
||||
*.rsp
|
||||
*.sbr
|
||||
*.tlb
|
||||
*.tli
|
||||
*.tlh
|
||||
*.tmp
|
||||
*.tmp_proj
|
||||
*.log
|
||||
*.vspscc
|
||||
*.vssscc
|
||||
.builds
|
||||
*.pidb
|
||||
*.log
|
||||
*.svclog
|
||||
*.scc
|
||||
|
||||
# Visual C++ cache files
|
||||
ipch/
|
||||
*.aps
|
||||
*.ncb
|
||||
*.opensdf
|
||||
*.sdf
|
||||
*.cachefile
|
||||
|
||||
# Visual Studio profiler
|
||||
*.psess
|
||||
*.vsp
|
||||
*.vspx
|
||||
|
||||
# Guidance Automation Toolkit
|
||||
*.gpState
|
||||
|
||||
# ReSharper is a .NET coding add-in
|
||||
_ReSharper*/
|
||||
*.[Rr]e[Ss]harper
|
||||
*.DotSettings.user
|
||||
|
||||
# Click-Once directory
|
||||
publish/
|
||||
|
||||
# Publish Web Output
|
||||
*.Publish.xml
|
||||
*.pubxml
|
||||
*.azurePubxml
|
||||
|
||||
# NuGet Packages Directory
|
||||
## TODO: If you have NuGet Package Restore enabled, uncomment the next line
|
||||
packages/
|
||||
## TODO: If the tool you use requires repositories.config, also uncomment the next line
|
||||
!packages/repositories.config
|
||||
|
||||
# Windows Azure Build Output
|
||||
csx/
|
||||
*.build.csdef
|
||||
|
||||
# Windows Store app package directory
|
||||
AppPackages/
|
||||
|
||||
# Others
|
||||
sql/
|
||||
*.Cache
|
||||
ClientBin/
|
||||
[Ss]tyle[Cc]op.*
|
||||
![Ss]tyle[Cc]op.targets
|
||||
~$*
|
||||
*~
|
||||
*.dbmdl
|
||||
*.[Pp]ublish.xml
|
||||
|
||||
*.publishsettings
|
||||
|
||||
# RIA/Silverlight projects
|
||||
Generated_Code/
|
||||
|
||||
# Backup & report files from converting an old project file to a newer
|
||||
# Visual Studio version. Backup files are not needed, because we have git ;-)
|
||||
_UpgradeReport_Files/
|
||||
Backup*/
|
||||
UpgradeLog*.XML
|
||||
UpgradeLog*.htm
|
||||
|
||||
# SQL Server files
|
||||
App_Data/*.mdf
|
||||
App_Data/*.ldf
|
||||
|
||||
# =========================
|
||||
# Windows detritus
|
||||
# =========================
|
||||
|
||||
# Windows image file caches
|
||||
Thumbs.db
|
||||
ehthumbs.db
|
||||
|
||||
# Folder config file
|
||||
Desktop.ini
|
||||
|
||||
# Recycle Bin used on file shares
|
||||
$RECYCLE.BIN/
|
||||
|
||||
# Mac desktop service store files
|
||||
.DS_Store
|
||||
|
||||
_NCrunch*
|
||||
|
||||
.idea/
|
||||
|
||||
# docfx
|
||||
docfx/_site/
|
||||
docfx/api/
|
||||
docfx/_exported_templates/
|
||||
6
.gitmodules
vendored
Normal file
6
.gitmodules
vendored
Normal file
|
|
@ -0,0 +1,6 @@
|
|||
[submodule "vendor/spdlog"]
|
||||
path = vendor/spdlog
|
||||
url = https://github.com/gabime/spdlog
|
||||
[submodule "vendor/funchook"]
|
||||
path = vendor/funchook
|
||||
url = https://github.com/kubo/funchook
|
||||
128
CMakeLists.txt
Normal file
128
CMakeLists.txt
Normal file
|
|
@ -0,0 +1,128 @@
|
|||
cmake_minimum_required(VERSION 3.18)
|
||||
project(TemplatePlugin C CXX ASM)
|
||||
|
||||
set(CMAKE_MSVC_RUNTIME_LIBRARY "MultiThreaded$<$<CONFIG:Debug>:Debug>")
|
||||
set(FUNCHOOK_BUILD_TESTS OFF CACHE BOOL "Disable building tests for funchook." FORCE)
|
||||
set(FMT_WERROR OFF CACHE BOOL "" FORCE)
|
||||
|
||||
if(DEFINED ENV{HL2SDKCS2})
|
||||
set(SOURCESDK_DIR $ENV{HL2SDKCS2})
|
||||
else()
|
||||
message(FATAL_ERROR "Environment variable HL2SDKCS2 is not set!")
|
||||
endif()
|
||||
|
||||
if(DEFINED ENV{MMSOURCE_DEV})
|
||||
set(METAMOD_DIR $ENV{MMSOURCE_DEV})
|
||||
else()
|
||||
message(FATAL_ERROR "Environment variable MMSOURCE_DEV is not set!")
|
||||
endif()
|
||||
|
||||
if(DEFINED ENV{CSGO_PROTO})
|
||||
set(CSGO_PROTO_DIR $ENV{CSGO_PROTO})
|
||||
else()
|
||||
message(FATAL_ERROR "Environment variable CSGO_PROTO is not set!")
|
||||
endif()
|
||||
|
||||
include(makefiles/shared.cmake)
|
||||
include(makefiles/protobuf.cmake)
|
||||
|
||||
add_subdirectory(vendor/spdlog)
|
||||
add_subdirectory(vendor/funchook)
|
||||
|
||||
file(GLOB_RECURSE SOURCE_FILES
|
||||
src/*.cpp
|
||||
src/*.h
|
||||
src/*.hpp
|
||||
)
|
||||
|
||||
list(APPEND SOURCE_FILES
|
||||
${SOURCESDK_DIR}/public/tier0/memoverride.cpp
|
||||
${SOURCESDK_DIR}/tier1/generichash.cpp
|
||||
${SOURCESDK_DIR}/tier1/keyvalues3.cpp
|
||||
${SOURCESDK_DIR}/tier1/convar.cpp
|
||||
${SOURCESDK_DIR}/entity2/entityidentity.cpp
|
||||
${SOURCESDK_DIR}/entity2/entitysystem.cpp
|
||||
${SOURCESDK_DIR}/entity2/entitykeyvalues.cpp
|
||||
${METAMOD_DIR}/core/sourcehook/sourcehook.cpp
|
||||
${METAMOD_DIR}/core/sourcehook/sourcehook_impl_chookidman.cpp
|
||||
${METAMOD_DIR}/core/sourcehook/sourcehook_impl_chookmaninfo.cpp
|
||||
${METAMOD_DIR}/core/sourcehook/sourcehook_impl_cvfnptr.cpp
|
||||
${METAMOD_DIR}/core/sourcehook/sourcehook_impl_cproto.cpp
|
||||
vendor/dynlibutils/module.cpp
|
||||
vendor/dynlibutils/module.h
|
||||
)
|
||||
|
||||
foreach(f ${SOURCE_FILES})
|
||||
message(STATUS "Zdrojový soubor: ${f}")
|
||||
endforeach()
|
||||
|
||||
add_library(${PROJECT_NAME} SHARED ${SOURCE_FILES})
|
||||
target_compile_definitions(${PROJECT_NAME}
|
||||
PUBLIC PROJECT_NAMESPACE=${PROJECT_NAME}
|
||||
PUBLIC PROJECT_NAMESPACE_STR=${PROJECT_NAME}
|
||||
)
|
||||
|
||||
target_include_directories(${PROJECT_NAME} PUBLIC
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/src
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/src/cs2_sdk
|
||||
)
|
||||
|
||||
find_package(Git QUIET)
|
||||
if (GIT_FOUND)
|
||||
execute_process(
|
||||
COMMAND ${GIT_EXECUTABLE} rev-parse --short HEAD
|
||||
WORKING_DIRECTORY ${CMAKE_SOURCE_DIR}
|
||||
OUTPUT_VARIABLE GIT_SHA
|
||||
OUTPUT_STRIP_TRAILING_WHITESPACE
|
||||
ERROR_QUIET
|
||||
)
|
||||
else()
|
||||
set(GIT_SHA "nogit")
|
||||
endif()
|
||||
|
||||
string(TIMESTAMP BUILD_TIME_UTC "%Y%m%d%H%M%S" UTC)
|
||||
set(_seed_input "${GIT_SHA}-${BUILD_TIME_UTC}")
|
||||
string(SHA1 _sha1 "${_seed_input}")
|
||||
string(SUBSTRING ${_sha1} 0 16 _seed16)
|
||||
set(BUILD_SEED_HEX "0x${_seed16}")
|
||||
message(STATUS "Obfuscation BUILD_SEED: ${BUILD_SEED_HEX} (from ${_seed_input})")
|
||||
add_compile_definitions(BUILD_SEED=${BUILD_SEED_HEX})
|
||||
|
||||
if (CMAKE_CXX_COMPILER_ID MATCHES "GNU|Clang")
|
||||
target_compile_options(${PROJECT_NAME} PRIVATE -fvisibility=hidden -fdata-sections -ffunction-sections)
|
||||
target_link_options(${PROJECT_NAME} PRIVATE -Wl,--gc-sections)
|
||||
endif()
|
||||
|
||||
set_target_properties(${PROJECT_NAME} PROPERTIES INTERPROCEDURAL_OPTIMIZATION OFF)
|
||||
|
||||
if (CMAKE_BUILD_TYPE STREQUAL "Release")
|
||||
find_program(STRIP_EXECUTABLE strip)
|
||||
if (STRIP_EXECUTABLE)
|
||||
add_custom_command(TARGET ${PROJECT_NAME} POST_BUILD
|
||||
COMMAND ${STRIP_EXECUTABLE} --strip-unneeded $<TARGET_FILE:${PROJECT_NAME}>
|
||||
COMMENT "Stripping symbols from $<TARGET_FILE:${PROJECT_NAME}>"
|
||||
)
|
||||
endif()
|
||||
endif()
|
||||
|
||||
if (LINUX)
|
||||
include(${CMAKE_SOURCE_DIR}/makefiles/linux.base.cmake)
|
||||
set_target_properties(${PROJECT_NAME} PROPERTIES
|
||||
PREFIX ""
|
||||
LIBRARY_OUTPUT_DIRECTORY "${CMAKE_BINARY_DIR}/addons/TemplatePlugin/bin/linuxsteamrt64"
|
||||
)
|
||||
elseif (WIN32)
|
||||
include(${CMAKE_SOURCE_DIR}/makefiles/windows.base.cmake)
|
||||
set_target_properties(${PROJECT_NAME} PROPERTIES
|
||||
PREFIX ""
|
||||
LIBRARY_OUTPUT_DIRECTORY "${CMAKE_BINARY_DIR}/addons/TemplatePlugin/bin/win64"
|
||||
)
|
||||
endif()
|
||||
|
||||
target_link_libraries(${PROJECT_NAME} ${LINK_LIBRARIES})
|
||||
|
||||
add_custom_command(
|
||||
TARGET ${PROJECT_NAME} PRE_BUILD
|
||||
COMMAND ${CMAKE_COMMAND} -E copy_directory
|
||||
${CMAKE_SOURCE_DIR}/configs ${CMAKE_BINARY_DIR}
|
||||
)
|
||||
674
LICENSE
Normal file
674
LICENSE
Normal file
|
|
@ -0,0 +1,674 @@
|
|||
GNU GENERAL PUBLIC LICENSE
|
||||
Version 3, 29 June 2007
|
||||
|
||||
Copyright (C) 2007 Free Software Foundation, Inc. <https://fsf.org/>
|
||||
Everyone is permitted to copy and distribute verbatim copies
|
||||
of this license document, but changing it is not allowed.
|
||||
|
||||
Preamble
|
||||
|
||||
The GNU General Public License is a free, copyleft license for
|
||||
software and other kinds of works.
|
||||
|
||||
The licenses for most software and other practical works are designed
|
||||
to take away your freedom to share and change the works. By contrast,
|
||||
the GNU General Public License is intended to guarantee your freedom to
|
||||
share and change all versions of a program--to make sure it remains free
|
||||
software for all its users. We, the Free Software Foundation, use the
|
||||
GNU General Public License for most of our software; it applies also to
|
||||
any other work released this way by its authors. You can apply it to
|
||||
your programs, too.
|
||||
|
||||
When we speak of free software, we are referring to freedom, not
|
||||
price. Our General Public Licenses are designed to make sure that you
|
||||
have the freedom to distribute copies of free software (and charge for
|
||||
them if you wish), that you receive source code or can get it if you
|
||||
want it, that you can change the software or use pieces of it in new
|
||||
free programs, and that you know you can do these things.
|
||||
|
||||
To protect your rights, we need to prevent others from denying you
|
||||
these rights or asking you to surrender the rights. Therefore, you have
|
||||
certain responsibilities if you distribute copies of the software, or if
|
||||
you modify it: responsibilities to respect the freedom of others.
|
||||
|
||||
For example, if you distribute copies of such a program, whether
|
||||
gratis or for a fee, you must pass on to the recipients the same
|
||||
freedoms that you received. You must make sure that they, too, receive
|
||||
or can get the source code. And you must show them these terms so they
|
||||
know their rights.
|
||||
|
||||
Developers that use the GNU GPL protect your rights with two steps:
|
||||
(1) assert copyright on the software, and (2) offer you this License
|
||||
giving you legal permission to copy, distribute and/or modify it.
|
||||
|
||||
For the developers' and authors' protection, the GPL clearly explains
|
||||
that there is no warranty for this free software. For both users' and
|
||||
authors' sake, the GPL requires that modified versions be marked as
|
||||
changed, so that their problems will not be attributed erroneously to
|
||||
authors of previous versions.
|
||||
|
||||
Some devices are designed to deny users access to install or run
|
||||
modified versions of the software inside them, although the manufacturer
|
||||
can do so. This is fundamentally incompatible with the aim of
|
||||
protecting users' freedom to change the software. The systematic
|
||||
pattern of such abuse occurs in the area of products for individuals to
|
||||
use, which is precisely where it is most unacceptable. Therefore, we
|
||||
have designed this version of the GPL to prohibit the practice for those
|
||||
products. If such problems arise substantially in other domains, we
|
||||
stand ready to extend this provision to those domains in future versions
|
||||
of the GPL, as needed to protect the freedom of users.
|
||||
|
||||
Finally, every program is threatened constantly by software patents.
|
||||
States should not allow patents to restrict development and use of
|
||||
software on general-purpose computers, but in those that do, we wish to
|
||||
avoid the special danger that patents applied to a free program could
|
||||
make it effectively proprietary. To prevent this, the GPL assures that
|
||||
patents cannot be used to render the program non-free.
|
||||
|
||||
The precise terms and conditions for copying, distribution and
|
||||
modification follow.
|
||||
|
||||
TERMS AND CONDITIONS
|
||||
|
||||
0. Definitions.
|
||||
|
||||
"This License" refers to version 3 of the GNU General Public License.
|
||||
|
||||
"Copyright" also means copyright-like laws that apply to other kinds of
|
||||
works, such as semiconductor masks.
|
||||
|
||||
"The Program" refers to any copyrightable work licensed under this
|
||||
License. Each licensee is addressed as "you". "Licensees" and
|
||||
"recipients" may be individuals or organizations.
|
||||
|
||||
To "modify" a work means to copy from or adapt all or part of the work
|
||||
in a fashion requiring copyright permission, other than the making of an
|
||||
exact copy. The resulting work is called a "modified version" of the
|
||||
earlier work or a work "based on" the earlier work.
|
||||
|
||||
A "covered work" means either the unmodified Program or a work based
|
||||
on the Program.
|
||||
|
||||
To "propagate" a work means to do anything with it that, without
|
||||
permission, would make you directly or secondarily liable for
|
||||
infringement under applicable copyright law, except executing it on a
|
||||
computer or modifying a private copy. Propagation includes copying,
|
||||
distribution (with or without modification), making available to the
|
||||
public, and in some countries other activities as well.
|
||||
|
||||
To "convey" a work means any kind of propagation that enables other
|
||||
parties to make or receive copies. Mere interaction with a user through
|
||||
a computer network, with no transfer of a copy, is not conveying.
|
||||
|
||||
An interactive user interface displays "Appropriate Legal Notices"
|
||||
to the extent that it includes a convenient and prominently visible
|
||||
feature that (1) displays an appropriate copyright notice, and (2)
|
||||
tells the user that there is no warranty for the work (except to the
|
||||
extent that warranties are provided), that licensees may convey the
|
||||
work under this License, and how to view a copy of this License. If
|
||||
the interface presents a list of user commands or options, such as a
|
||||
menu, a prominent item in the list meets this criterion.
|
||||
|
||||
1. Source Code.
|
||||
|
||||
The "source code" for a work means the preferred form of the work
|
||||
for making modifications to it. "Object code" means any non-source
|
||||
form of a work.
|
||||
|
||||
A "Standard Interface" means an interface that either is an official
|
||||
standard defined by a recognized standards body, or, in the case of
|
||||
interfaces specified for a particular programming language, one that
|
||||
is widely used among developers working in that language.
|
||||
|
||||
The "System Libraries" of an executable work include anything, other
|
||||
than the work as a whole, that (a) is included in the normal form of
|
||||
packaging a Major Component, but which is not part of that Major
|
||||
Component, and (b) serves only to enable use of the work with that
|
||||
Major Component, or to implement a Standard Interface for which an
|
||||
implementation is available to the public in source code form. A
|
||||
"Major Component", in this context, means a major essential component
|
||||
(kernel, window system, and so on) of the specific operating system
|
||||
(if any) on which the executable work runs, or a compiler used to
|
||||
produce the work, or an object code interpreter used to run it.
|
||||
|
||||
The "Corresponding Source" for a work in object code form means all
|
||||
the source code needed to generate, install, and (for an executable
|
||||
work) run the object code and to modify the work, including scripts to
|
||||
control those activities. However, it does not include the work's
|
||||
System Libraries, or general-purpose tools or generally available free
|
||||
programs which are used unmodified in performing those activities but
|
||||
which are not part of the work. For example, Corresponding Source
|
||||
includes interface definition files associated with source files for
|
||||
the work, and the source code for shared libraries and dynamically
|
||||
linked subprograms that the work is specifically designed to require,
|
||||
such as by intimate data communication or control flow between those
|
||||
subprograms and other parts of the work.
|
||||
|
||||
The Corresponding Source need not include anything that users
|
||||
can regenerate automatically from other parts of the Corresponding
|
||||
Source.
|
||||
|
||||
The Corresponding Source for a work in source code form is that
|
||||
same work.
|
||||
|
||||
2. Basic Permissions.
|
||||
|
||||
All rights granted under this License are granted for the term of
|
||||
copyright on the Program, and are irrevocable provided the stated
|
||||
conditions are met. This License explicitly affirms your unlimited
|
||||
permission to run the unmodified Program. The output from running a
|
||||
covered work is covered by this License only if the output, given its
|
||||
content, constitutes a covered work. This License acknowledges your
|
||||
rights of fair use or other equivalent, as provided by copyright law.
|
||||
|
||||
You may make, run and propagate covered works that you do not
|
||||
convey, without conditions so long as your license otherwise remains
|
||||
in force. You may convey covered works to others for the sole purpose
|
||||
of having them make modifications exclusively for you, or provide you
|
||||
with facilities for running those works, provided that you comply with
|
||||
the terms of this License in conveying all material for which you do
|
||||
not control copyright. Those thus making or running the covered works
|
||||
for you must do so exclusively on your behalf, under your direction
|
||||
and control, on terms that prohibit them from making any copies of
|
||||
your copyrighted material outside their relationship with you.
|
||||
|
||||
Conveying under any other circumstances is permitted solely under
|
||||
the conditions stated below. Sublicensing is not allowed; section 10
|
||||
makes it unnecessary.
|
||||
|
||||
3. Protecting Users' Legal Rights From Anti-Circumvention Law.
|
||||
|
||||
No covered work shall be deemed part of an effective technological
|
||||
measure under any applicable law fulfilling obligations under article
|
||||
11 of the WIPO copyright treaty adopted on 20 December 1996, or
|
||||
similar laws prohibiting or restricting circumvention of such
|
||||
measures.
|
||||
|
||||
When you convey a covered work, you waive any legal power to forbid
|
||||
circumvention of technological measures to the extent such circumvention
|
||||
is effected by exercising rights under this License with respect to
|
||||
the covered work, and you disclaim any intention to limit operation or
|
||||
modification of the work as a means of enforcing, against the work's
|
||||
users, your or third parties' legal rights to forbid circumvention of
|
||||
technological measures.
|
||||
|
||||
4. Conveying Verbatim Copies.
|
||||
|
||||
You may convey verbatim copies of the Program's source code as you
|
||||
receive it, in any medium, provided that you conspicuously and
|
||||
appropriately publish on each copy an appropriate copyright notice;
|
||||
keep intact all notices stating that this License and any
|
||||
non-permissive terms added in accord with section 7 apply to the code;
|
||||
keep intact all notices of the absence of any warranty; and give all
|
||||
recipients a copy of this License along with the Program.
|
||||
|
||||
You may charge any price or no price for each copy that you convey,
|
||||
and you may offer support or warranty protection for a fee.
|
||||
|
||||
5. Conveying Modified Source Versions.
|
||||
|
||||
You may convey a work based on the Program, or the modifications to
|
||||
produce it from the Program, in the form of source code under the
|
||||
terms of section 4, provided that you also meet all of these conditions:
|
||||
|
||||
a) The work must carry prominent notices stating that you modified
|
||||
it, and giving a relevant date.
|
||||
|
||||
b) The work must carry prominent notices stating that it is
|
||||
released under this License and any conditions added under section
|
||||
7. This requirement modifies the requirement in section 4 to
|
||||
"keep intact all notices".
|
||||
|
||||
c) You must license the entire work, as a whole, under this
|
||||
License to anyone who comes into possession of a copy. This
|
||||
License will therefore apply, along with any applicable section 7
|
||||
additional terms, to the whole of the work, and all its parts,
|
||||
regardless of how they are packaged. This License gives no
|
||||
permission to license the work in any other way, but it does not
|
||||
invalidate such permission if you have separately received it.
|
||||
|
||||
d) If the work has interactive user interfaces, each must display
|
||||
Appropriate Legal Notices; however, if the Program has interactive
|
||||
interfaces that do not display Appropriate Legal Notices, your
|
||||
work need not make them do so.
|
||||
|
||||
A compilation of a covered work with other separate and independent
|
||||
works, which are not by their nature extensions of the covered work,
|
||||
and which are not combined with it such as to form a larger program,
|
||||
in or on a volume of a storage or distribution medium, is called an
|
||||
"aggregate" if the compilation and its resulting copyright are not
|
||||
used to limit the access or legal rights of the compilation's users
|
||||
beyond what the individual works permit. Inclusion of a covered work
|
||||
in an aggregate does not cause this License to apply to the other
|
||||
parts of the aggregate.
|
||||
|
||||
6. Conveying Non-Source Forms.
|
||||
|
||||
You may convey a covered work in object code form under the terms
|
||||
of sections 4 and 5, provided that you also convey the
|
||||
machine-readable Corresponding Source under the terms of this License,
|
||||
in one of these ways:
|
||||
|
||||
a) Convey the object code in, or embodied in, a physical product
|
||||
(including a physical distribution medium), accompanied by the
|
||||
Corresponding Source fixed on a durable physical medium
|
||||
customarily used for software interchange.
|
||||
|
||||
b) Convey the object code in, or embodied in, a physical product
|
||||
(including a physical distribution medium), accompanied by a
|
||||
written offer, valid for at least three years and valid for as
|
||||
long as you offer spare parts or customer support for that product
|
||||
model, to give anyone who possesses the object code either (1) a
|
||||
copy of the Corresponding Source for all the software in the
|
||||
product that is covered by this License, on a durable physical
|
||||
medium customarily used for software interchange, for a price no
|
||||
more than your reasonable cost of physically performing this
|
||||
conveying of source, or (2) access to copy the
|
||||
Corresponding Source from a network server at no charge.
|
||||
|
||||
c) Convey individual copies of the object code with a copy of the
|
||||
written offer to provide the Corresponding Source. This
|
||||
alternative is allowed only occasionally and noncommercially, and
|
||||
only if you received the object code with such an offer, in accord
|
||||
with subsection 6b.
|
||||
|
||||
d) Convey the object code by offering access from a designated
|
||||
place (gratis or for a charge), and offer equivalent access to the
|
||||
Corresponding Source in the same way through the same place at no
|
||||
further charge. You need not require recipients to copy the
|
||||
Corresponding Source along with the object code. If the place to
|
||||
copy the object code is a network server, the Corresponding Source
|
||||
may be on a different server (operated by you or a third party)
|
||||
that supports equivalent copying facilities, provided you maintain
|
||||
clear directions next to the object code saying where to find the
|
||||
Corresponding Source. Regardless of what server hosts the
|
||||
Corresponding Source, you remain obligated to ensure that it is
|
||||
available for as long as needed to satisfy these requirements.
|
||||
|
||||
e) Convey the object code using peer-to-peer transmission, provided
|
||||
you inform other peers where the object code and Corresponding
|
||||
Source of the work are being offered to the general public at no
|
||||
charge under subsection 6d.
|
||||
|
||||
A separable portion of the object code, whose source code is excluded
|
||||
from the Corresponding Source as a System Library, need not be
|
||||
included in conveying the object code work.
|
||||
|
||||
A "User Product" is either (1) a "consumer product", which means any
|
||||
tangible personal property which is normally used for personal, family,
|
||||
or household purposes, or (2) anything designed or sold for incorporation
|
||||
into a dwelling. In determining whether a product is a consumer product,
|
||||
doubtful cases shall be resolved in favor of coverage. For a particular
|
||||
product received by a particular user, "normally used" refers to a
|
||||
typical or common use of that class of product, regardless of the status
|
||||
of the particular user or of the way in which the particular user
|
||||
actually uses, or expects or is expected to use, the product. A product
|
||||
is a consumer product regardless of whether the product has substantial
|
||||
commercial, industrial or non-consumer uses, unless such uses represent
|
||||
the only significant mode of use of the product.
|
||||
|
||||
"Installation Information" for a User Product means any methods,
|
||||
procedures, authorization keys, or other information required to install
|
||||
and execute modified versions of a covered work in that User Product from
|
||||
a modified version of its Corresponding Source. The information must
|
||||
suffice to ensure that the continued functioning of the modified object
|
||||
code is in no case prevented or interfered with solely because
|
||||
modification has been made.
|
||||
|
||||
If you convey an object code work under this section in, or with, or
|
||||
specifically for use in, a User Product, and the conveying occurs as
|
||||
part of a transaction in which the right of possession and use of the
|
||||
User Product is transferred to the recipient in perpetuity or for a
|
||||
fixed term (regardless of how the transaction is characterized), the
|
||||
Corresponding Source conveyed under this section must be accompanied
|
||||
by the Installation Information. But this requirement does not apply
|
||||
if neither you nor any third party retains the ability to install
|
||||
modified object code on the User Product (for example, the work has
|
||||
been installed in ROM).
|
||||
|
||||
The requirement to provide Installation Information does not include a
|
||||
requirement to continue to provide support service, warranty, or updates
|
||||
for a work that has been modified or installed by the recipient, or for
|
||||
the User Product in which it has been modified or installed. Access to a
|
||||
network may be denied when the modification itself materially and
|
||||
adversely affects the operation of the network or violates the rules and
|
||||
protocols for communication across the network.
|
||||
|
||||
Corresponding Source conveyed, and Installation Information provided,
|
||||
in accord with this section must be in a format that is publicly
|
||||
documented (and with an implementation available to the public in
|
||||
source code form), and must require no special password or key for
|
||||
unpacking, reading or copying.
|
||||
|
||||
7. Additional Terms.
|
||||
|
||||
"Additional permissions" are terms that supplement the terms of this
|
||||
License by making exceptions from one or more of its conditions.
|
||||
Additional permissions that are applicable to the entire Program shall
|
||||
be treated as though they were included in this License, to the extent
|
||||
that they are valid under applicable law. If additional permissions
|
||||
apply only to part of the Program, that part may be used separately
|
||||
under those permissions, but the entire Program remains governed by
|
||||
this License without regard to the additional permissions.
|
||||
|
||||
When you convey a copy of a covered work, you may at your option
|
||||
remove any additional permissions from that copy, or from any part of
|
||||
it. (Additional permissions may be written to require their own
|
||||
removal in certain cases when you modify the work.) You may place
|
||||
additional permissions on material, added by you to a covered work,
|
||||
for which you have or can give appropriate copyright permission.
|
||||
|
||||
Notwithstanding any other provision of this License, for material you
|
||||
add to a covered work, you may (if authorized by the copyright holders of
|
||||
that material) supplement the terms of this License with terms:
|
||||
|
||||
a) Disclaiming warranty or limiting liability differently from the
|
||||
terms of sections 15 and 16 of this License; or
|
||||
|
||||
b) Requiring preservation of specified reasonable legal notices or
|
||||
author attributions in that material or in the Appropriate Legal
|
||||
Notices displayed by works containing it; or
|
||||
|
||||
c) Prohibiting misrepresentation of the origin of that material, or
|
||||
requiring that modified versions of such material be marked in
|
||||
reasonable ways as different from the original version; or
|
||||
|
||||
d) Limiting the use for publicity purposes of names of licensors or
|
||||
authors of the material; or
|
||||
|
||||
e) Declining to grant rights under trademark law for use of some
|
||||
trade names, trademarks, or service marks; or
|
||||
|
||||
f) Requiring indemnification of licensors and authors of that
|
||||
material by anyone who conveys the material (or modified versions of
|
||||
it) with contractual assumptions of liability to the recipient, for
|
||||
any liability that these contractual assumptions directly impose on
|
||||
those licensors and authors.
|
||||
|
||||
All other non-permissive additional terms are considered "further
|
||||
restrictions" within the meaning of section 10. If the Program as you
|
||||
received it, or any part of it, contains a notice stating that it is
|
||||
governed by this License along with a term that is a further
|
||||
restriction, you may remove that term. If a license document contains
|
||||
a further restriction but permits relicensing or conveying under this
|
||||
License, you may add to a covered work material governed by the terms
|
||||
of that license document, provided that the further restriction does
|
||||
not survive such relicensing or conveying.
|
||||
|
||||
If you add terms to a covered work in accord with this section, you
|
||||
must place, in the relevant source files, a statement of the
|
||||
additional terms that apply to those files, or a notice indicating
|
||||
where to find the applicable terms.
|
||||
|
||||
Additional terms, permissive or non-permissive, may be stated in the
|
||||
form of a separately written license, or stated as exceptions;
|
||||
the above requirements apply either way.
|
||||
|
||||
8. Termination.
|
||||
|
||||
You may not propagate or modify a covered work except as expressly
|
||||
provided under this License. Any attempt otherwise to propagate or
|
||||
modify it is void, and will automatically terminate your rights under
|
||||
this License (including any patent licenses granted under the third
|
||||
paragraph of section 11).
|
||||
|
||||
However, if you cease all violation of this License, then your
|
||||
license from a particular copyright holder is reinstated (a)
|
||||
provisionally, unless and until the copyright holder explicitly and
|
||||
finally terminates your license, and (b) permanently, if the copyright
|
||||
holder fails to notify you of the violation by some reasonable means
|
||||
prior to 60 days after the cessation.
|
||||
|
||||
Moreover, your license from a particular copyright holder is
|
||||
reinstated permanently if the copyright holder notifies you of the
|
||||
violation by some reasonable means, this is the first time you have
|
||||
received notice of violation of this License (for any work) from that
|
||||
copyright holder, and you cure the violation prior to 30 days after
|
||||
your receipt of the notice.
|
||||
|
||||
Termination of your rights under this section does not terminate the
|
||||
licenses of parties who have received copies or rights from you under
|
||||
this License. If your rights have been terminated and not permanently
|
||||
reinstated, you do not qualify to receive new licenses for the same
|
||||
material under section 10.
|
||||
|
||||
9. Acceptance Not Required for Having Copies.
|
||||
|
||||
You are not required to accept this License in order to receive or
|
||||
run a copy of the Program. Ancillary propagation of a covered work
|
||||
occurring solely as a consequence of using peer-to-peer transmission
|
||||
to receive a copy likewise does not require acceptance. However,
|
||||
nothing other than this License grants you permission to propagate or
|
||||
modify any covered work. These actions infringe copyright if you do
|
||||
not accept this License. Therefore, by modifying or propagating a
|
||||
covered work, you indicate your acceptance of this License to do so.
|
||||
|
||||
10. Automatic Licensing of Downstream Recipients.
|
||||
|
||||
Each time you convey a covered work, the recipient automatically
|
||||
receives a license from the original licensors, to run, modify and
|
||||
propagate that work, subject to this License. You are not responsible
|
||||
for enforcing compliance by third parties with this License.
|
||||
|
||||
An "entity transaction" is a transaction transferring control of an
|
||||
organization, or substantially all assets of one, or subdividing an
|
||||
organization, or merging organizations. If propagation of a covered
|
||||
work results from an entity transaction, each party to that
|
||||
transaction who receives a copy of the work also receives whatever
|
||||
licenses to the work the party's predecessor in interest had or could
|
||||
give under the previous paragraph, plus a right to possession of the
|
||||
Corresponding Source of the work from the predecessor in interest, if
|
||||
the predecessor has it or can get it with reasonable efforts.
|
||||
|
||||
You may not impose any further restrictions on the exercise of the
|
||||
rights granted or affirmed under this License. For example, you may
|
||||
not impose a license fee, royalty, or other charge for exercise of
|
||||
rights granted under this License, and you may not initiate litigation
|
||||
(including a cross-claim or counterclaim in a lawsuit) alleging that
|
||||
any patent claim is infringed by making, using, selling, offering for
|
||||
sale, or importing the Program or any portion of it.
|
||||
|
||||
11. Patents.
|
||||
|
||||
A "contributor" is a copyright holder who authorizes use under this
|
||||
License of the Program or a work on which the Program is based. The
|
||||
work thus licensed is called the contributor's "contributor version".
|
||||
|
||||
A contributor's "essential patent claims" are all patent claims
|
||||
owned or controlled by the contributor, whether already acquired or
|
||||
hereafter acquired, that would be infringed by some manner, permitted
|
||||
by this License, of making, using, or selling its contributor version,
|
||||
but do not include claims that would be infringed only as a
|
||||
consequence of further modification of the contributor version. For
|
||||
purposes of this definition, "control" includes the right to grant
|
||||
patent sublicenses in a manner consistent with the requirements of
|
||||
this License.
|
||||
|
||||
Each contributor grants you a non-exclusive, worldwide, royalty-free
|
||||
patent license under the contributor's essential patent claims, to
|
||||
make, use, sell, offer for sale, import and otherwise run, modify and
|
||||
propagate the contents of its contributor version.
|
||||
|
||||
In the following three paragraphs, a "patent license" is any express
|
||||
agreement or commitment, however denominated, not to enforce a patent
|
||||
(such as an express permission to practice a patent or covenant not to
|
||||
sue for patent infringement). To "grant" such a patent license to a
|
||||
party means to make such an agreement or commitment not to enforce a
|
||||
patent against the party.
|
||||
|
||||
If you convey a covered work, knowingly relying on a patent license,
|
||||
and the Corresponding Source of the work is not available for anyone
|
||||
to copy, free of charge and under the terms of this License, through a
|
||||
publicly available network server or other readily accessible means,
|
||||
then you must either (1) cause the Corresponding Source to be so
|
||||
available, or (2) arrange to deprive yourself of the benefit of the
|
||||
patent license for this particular work, or (3) arrange, in a manner
|
||||
consistent with the requirements of this License, to extend the patent
|
||||
license to downstream recipients. "Knowingly relying" means you have
|
||||
actual knowledge that, but for the patent license, your conveying the
|
||||
covered work in a country, or your recipient's use of the covered work
|
||||
in a country, would infringe one or more identifiable patents in that
|
||||
country that you have reason to believe are valid.
|
||||
|
||||
If, pursuant to or in connection with a single transaction or
|
||||
arrangement, you convey, or propagate by procuring conveyance of, a
|
||||
covered work, and grant a patent license to some of the parties
|
||||
receiving the covered work authorizing them to use, propagate, modify
|
||||
or convey a specific copy of the covered work, then the patent license
|
||||
you grant is automatically extended to all recipients of the covered
|
||||
work and works based on it.
|
||||
|
||||
A patent license is "discriminatory" if it does not include within
|
||||
the scope of its coverage, prohibits the exercise of, or is
|
||||
conditioned on the non-exercise of one or more of the rights that are
|
||||
specifically granted under this License. You may not convey a covered
|
||||
work if you are a party to an arrangement with a third party that is
|
||||
in the business of distributing software, under which you make payment
|
||||
to the third party based on the extent of your activity of conveying
|
||||
the work, and under which the third party grants, to any of the
|
||||
parties who would receive the covered work from you, a discriminatory
|
||||
patent license (a) in connection with copies of the covered work
|
||||
conveyed by you (or copies made from those copies), or (b) primarily
|
||||
for and in connection with specific products or compilations that
|
||||
contain the covered work, unless you entered into that arrangement,
|
||||
or that patent license was granted, prior to 28 March 2007.
|
||||
|
||||
Nothing in this License shall be construed as excluding or limiting
|
||||
any implied license or other defenses to infringement that may
|
||||
otherwise be available to you under applicable patent law.
|
||||
|
||||
12. No Surrender of Others' Freedom.
|
||||
|
||||
If conditions are imposed on you (whether by court order, agreement or
|
||||
otherwise) that contradict the conditions of this License, they do not
|
||||
excuse you from the conditions of this License. If you cannot convey a
|
||||
covered work so as to satisfy simultaneously your obligations under this
|
||||
License and any other pertinent obligations, then as a consequence you may
|
||||
not convey it at all. For example, if you agree to terms that obligate you
|
||||
to collect a royalty for further conveying from those to whom you convey
|
||||
the Program, the only way you could satisfy both those terms and this
|
||||
License would be to refrain entirely from conveying the Program.
|
||||
|
||||
13. Use with the GNU Affero General Public License.
|
||||
|
||||
Notwithstanding any other provision of this License, you have
|
||||
permission to link or combine any covered work with a work licensed
|
||||
under version 3 of the GNU Affero General Public License into a single
|
||||
combined work, and to convey the resulting work. The terms of this
|
||||
License will continue to apply to the part which is the covered work,
|
||||
but the special requirements of the GNU Affero General Public License,
|
||||
section 13, concerning interaction through a network will apply to the
|
||||
combination as such.
|
||||
|
||||
14. Revised Versions of this License.
|
||||
|
||||
The Free Software Foundation may publish revised and/or new versions of
|
||||
the GNU General Public License from time to time. Such new versions will
|
||||
be similar in spirit to the present version, but may differ in detail to
|
||||
address new problems or concerns.
|
||||
|
||||
Each version is given a distinguishing version number. If the
|
||||
Program specifies that a certain numbered version of the GNU General
|
||||
Public License "or any later version" applies to it, you have the
|
||||
option of following the terms and conditions either of that numbered
|
||||
version or of any later version published by the Free Software
|
||||
Foundation. If the Program does not specify a version number of the
|
||||
GNU General Public License, you may choose any version ever published
|
||||
by the Free Software Foundation.
|
||||
|
||||
If the Program specifies that a proxy can decide which future
|
||||
versions of the GNU General Public License can be used, that proxy's
|
||||
public statement of acceptance of a version permanently authorizes you
|
||||
to choose that version for the Program.
|
||||
|
||||
Later license versions may give you additional or different
|
||||
permissions. However, no additional obligations are imposed on any
|
||||
author or copyright holder as a result of your choosing to follow a
|
||||
later version.
|
||||
|
||||
15. Disclaimer of Warranty.
|
||||
|
||||
THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY
|
||||
APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT
|
||||
HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY
|
||||
OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO,
|
||||
THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
|
||||
PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM
|
||||
IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF
|
||||
ALL NECESSARY SERVICING, REPAIR OR CORRECTION.
|
||||
|
||||
16. Limitation of Liability.
|
||||
|
||||
IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
|
||||
WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS
|
||||
THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY
|
||||
GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE
|
||||
USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF
|
||||
DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD
|
||||
PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS),
|
||||
EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF
|
||||
SUCH DAMAGES.
|
||||
|
||||
17. Interpretation of Sections 15 and 16.
|
||||
|
||||
If the disclaimer of warranty and limitation of liability provided
|
||||
above cannot be given local legal effect according to their terms,
|
||||
reviewing courts shall apply local law that most closely approximates
|
||||
an absolute waiver of all civil liability in connection with the
|
||||
Program, unless a warranty or assumption of liability accompanies a
|
||||
copy of the Program in return for a fee.
|
||||
|
||||
END OF TERMS AND CONDITIONS
|
||||
|
||||
How to Apply These Terms to Your New Programs
|
||||
|
||||
If you develop a new program, and you want it to be of the greatest
|
||||
possible use to the public, the best way to achieve this is to make it
|
||||
free software which everyone can redistribute and change under these terms.
|
||||
|
||||
To do so, attach the following notices to the program. It is safest
|
||||
to attach them to the start of each source file to most effectively
|
||||
state the exclusion of warranty; and each file should have at least
|
||||
the "copyright" line and a pointer to where the full notice is found.
|
||||
|
||||
<one line to give the program's name and a brief idea of what it does.>
|
||||
Copyright (C) <year> <name of author>
|
||||
|
||||
This program 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.
|
||||
|
||||
This program 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 this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
|
||||
Also add information on how to contact you by electronic and paper mail.
|
||||
|
||||
If the program does terminal interaction, make it output a short
|
||||
notice like this when it starts in an interactive mode:
|
||||
|
||||
<program> Copyright (C) <year> <name of author>
|
||||
This program comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
|
||||
This is free software, and you are welcome to redistribute it
|
||||
under certain conditions; type `show c' for details.
|
||||
|
||||
The hypothetical commands `show w' and `show c' should show the appropriate
|
||||
parts of the General Public License. Of course, your program's commands
|
||||
might be different; for a GUI interface, you would use an "about box".
|
||||
|
||||
You should also get your employer (if you work as a programmer) or school,
|
||||
if any, to sign a "copyright disclaimer" for the program, if necessary.
|
||||
For more information on this, and how to apply and follow the GNU GPL, see
|
||||
<https://www.gnu.org/licenses/>.
|
||||
|
||||
The GNU General Public License does not permit incorporating your program
|
||||
into proprietary programs. If your program is a subroutine library, you
|
||||
may consider it more useful to permit linking proprietary applications with
|
||||
the library. If this is what you want to do, use the GNU Lesser General
|
||||
Public License instead of this License. But first, please read
|
||||
<https://www.gnu.org/licenses/why-not-lgpl.html>.
|
||||
403
configs/addons/TemplatePlugin/gamedata.json
Normal file
403
configs/addons/TemplatePlugin/gamedata.json
Normal file
|
|
@ -0,0 +1,403 @@
|
|||
{
|
||||
"CNavPhysicsInterface_TraceShape": {
|
||||
"offsets": {
|
||||
"windows": 4,
|
||||
"linux": 5
|
||||
}
|
||||
},
|
||||
"CSmokeGrenadeProjectileCreateFunc": {
|
||||
"signatures": {
|
||||
"library": "server",
|
||||
"windows": "",
|
||||
"linux": "55 4C 89 C1 48 89 E5 41 57 49 89 FF 41 56 45 89 CE"
|
||||
}
|
||||
},
|
||||
"GameSystem_Think_CheckSteamBan": {
|
||||
"signatures": {
|
||||
"library": "server",
|
||||
"windows": "",
|
||||
"linux": "55 48 8D 3D ?? ?? ?? ?? BE ?? ?? ?? ?? 48 89 E5 41 57 41 56 41 55 41 54 53 48 81 EC ?? ?? ?? ?? E8 ?? ?? ?? ?? 48 85 C0 0F 84 ?? ?? ?? ?? 8B 10"
|
||||
}
|
||||
},
|
||||
"CCSGameRules__sm_mapGcBanInformation": {
|
||||
"signatures": {
|
||||
"library": "server",
|
||||
"windows": "",
|
||||
"linux": "48 8D 0D ?? ?? ?? ?? 48 63 51 ?? 83 FA ?? 0F 84 ?? ?? ?? ?? F7 41 ?? ?? ?? ?? ?? 74"
|
||||
}
|
||||
},
|
||||
"CServerSideClientBase_ProcessServerStatus": {
|
||||
"signatures": {
|
||||
"library": "engine2",
|
||||
"windows": "",
|
||||
"linux": "55 0F B6 56 48 8B 77 48 48 89 E5 48 8B 7F 50 E8 ? ? ? ? B8"
|
||||
}
|
||||
},
|
||||
"CBaseEntity_EmitSoundParams": {
|
||||
"signatures": {
|
||||
"library": "server",
|
||||
"windows": "",
|
||||
"linux": "48 B8 ? ? ? ? ? ? ? ? 55 0F 28 D0"
|
||||
}
|
||||
},
|
||||
"CBaseEntity_EmitSoundFilter": {
|
||||
"signatures": {
|
||||
"library": "server",
|
||||
"windows": "",
|
||||
"linux": "55 48 89 E5 53 48 89 FB 48 83 EC ? E8 ? ? ? ? 48 89 D8 48 8B 5D ? C9 C3 CC CC CC CC CC CC 48 B8"
|
||||
}
|
||||
},
|
||||
"CSoundOpGameSystem_StartSoundEvent": {
|
||||
"signatures": {
|
||||
"library": "server",
|
||||
"windows": "",
|
||||
"linux": "55 48 89 E5 41 57 45 89 CF 41 56 49 89 CE 41 55 41 54 45 89 C4"
|
||||
}
|
||||
},
|
||||
"CSoundOpGameSystem_SetSoundEventParam": {
|
||||
"signatures": {
|
||||
"library": "server",
|
||||
"windows": "",
|
||||
"linux": "55 48 89 E5 41 57 41 56 45 89 CE 41 55 45 89 C5"
|
||||
}
|
||||
},
|
||||
"CBaseEntity_StartTouch": {
|
||||
"offsets": {
|
||||
"windows": 150,
|
||||
"linux": 152
|
||||
}
|
||||
},
|
||||
"CTakeDamageInfo_Constructor": {
|
||||
"signatures": {
|
||||
"library": "server",
|
||||
"windows": "",
|
||||
"linux": "F3 0F 12 C0 55 49 89 F2 48 89 D6 48 89 E5 41 57 49 89 CF 41 56 41 55 4D 89 C5 41 54 4D 89 CC 53 48 89 FB 48 83 EC ? 4C 8B 75 ? 4D 85 D2"
|
||||
}
|
||||
},
|
||||
"CCSPlayer_MovementServices_ProcessMovement": {
|
||||
"signatures": {
|
||||
"library": "server",
|
||||
"windows": "",
|
||||
"linux": "55 48 89 E5 41 57 41 56 41 55 41 54 49 89 F4 53 48 89 FB 48 83 EC 38 48 8B 7F 30"
|
||||
}
|
||||
},
|
||||
"CBaseModelEntity_SetBodygroupByName": {
|
||||
"signatures": {
|
||||
"library": "server",
|
||||
"windows": "",
|
||||
"linux": "55 48 89 E5 41 55 41 89 F5 41 54 41 89 D4 53 48 89 FB 48 83 EC 08 E8"
|
||||
}
|
||||
},
|
||||
"UTIL_ClientPrintAll": {
|
||||
"signatures": {
|
||||
"library": "server",
|
||||
"windows": "48 89 5C 24 ? 48 89 6C 24 ? 48 89 74 24 ? 57 48 83 EC ? 8B E9 49 8B D9",
|
||||
"linux": "55 48 89 E5 41 57 4D 89 CF 41 56 4D 89 C6 41 55 49 89 CD 41 54 49 89 D4 53 48 8D"
|
||||
}
|
||||
},
|
||||
"ClientPrint": {
|
||||
"signatures": {
|
||||
"library": "server",
|
||||
"windows": "48 85 C9 0F 84 ? ? ? ? 48 89 5C 24 ? 55",
|
||||
"linux": "55 48 8D 05 ? ? ? ? 48 89 E5 41 57 41 89 F7 31 F6"
|
||||
}
|
||||
},
|
||||
"CCSPlayerController_SwitchTeam": {
|
||||
"signatures": {
|
||||
"library": "server",
|
||||
"windows": "40 53 57 48 81 EC ? ? ? ? 48 8B D9 8B FA",
|
||||
"linux": "55 48 89 E5 41 54 49 89 FC 89 F7"
|
||||
}
|
||||
},
|
||||
"CCSPlayerController_ChangeTeam": {
|
||||
"offsets": {
|
||||
"windows": 106,
|
||||
"linux": 108
|
||||
}
|
||||
},
|
||||
"CCSPlayerController_Respawn": {
|
||||
"offsets": {
|
||||
"windows": 275,
|
||||
"linux": 279
|
||||
}
|
||||
},
|
||||
"CCSPlayerController_HandleCommand_JoinTeam": {
|
||||
"signatures": {
|
||||
"library": "server",
|
||||
"windows": "",
|
||||
"linux": "55 48 89 E5 41 57 41 56 41 55 41 54 41 89 F4 53 48 89 FB 48 81 EC ? ? ? ? 48 8D 05"
|
||||
}
|
||||
},
|
||||
"CCSPlayerController_HandleCommand_WeaponDrop": {
|
||||
"signatures": {
|
||||
"library": "server",
|
||||
"windows": "",
|
||||
"linux": "55 48 89 E5 41 54 49 89 F4 53 E8 ? ? ? ? 48 85 C0 74 ? 48 89 C3"
|
||||
}
|
||||
},
|
||||
"CBasePlayerController_SetPawn": {
|
||||
"signatures": {
|
||||
"library": "server",
|
||||
"windows": "44 88 4C 24 ? 53 57",
|
||||
"linux": "55 48 8D 87 ? ? ? ? 48 89 E5 41 57 41 56 41 89 CE 41 55 45 89 CD"
|
||||
}
|
||||
},
|
||||
"CCSPlayerPawnBase_PostThink": {
|
||||
"signatures": {
|
||||
"library": "server",
|
||||
"windows": "48 ? ? 55 53 56 57 41 ? 48 ? ? ? 48 ? ? ? ? ? ? 4C 89 68",
|
||||
"linux": "55 48 89 E5 41 56 41 55 41 54 53 48 89 FB 48 83 EC 40 E8 ? ? ? ? F3 0F 10 83"
|
||||
}
|
||||
},
|
||||
"CGameEventManager_Init": {
|
||||
"signatures": {
|
||||
"library": "server",
|
||||
"windows": "40 53 48 83 EC 20 48 8B 01 48 8B D9 FF 50 10",
|
||||
"linux": "55 48 89 E5 53 48 89 FB 48 83 EC 08 48 8B 07 FF 50 18"
|
||||
}
|
||||
},
|
||||
"GiveNamedItem": {
|
||||
"signatures": {
|
||||
"library": "server",
|
||||
"windows": "48 89 5C 24 ? 48 89 74 24 ? 55 57 41 55 41 56 41 57 48 8D 6C 24 ? 48 81 EC ? ? ? ? 4D 8B F9",
|
||||
"linux": "55 48 89 E5 41 57 41 56 41 55 41 54 53 48 81 EC F8 00 00 00 48 89 BD ? ? ? ? 89 95"
|
||||
}
|
||||
},
|
||||
"UTIL_Remove": {
|
||||
"signatures": {
|
||||
"library": "server",
|
||||
"windows": "48 85 C9 74 ? 48 8B D1 48 8B 0D ? ? ? ?",
|
||||
"linux": "48 89 FE 48 85 FF 74 ? 48 8D 05 ? ? ? ? 48"
|
||||
}
|
||||
},
|
||||
"CBaseModelEntity_SetModel": {
|
||||
"signatures": {
|
||||
"library": "server",
|
||||
"windows": "40 53 48 83 EC ? 48 8B D9 4C 8B C2 48 8B 0D ? ? ? ? 48 8D 54 24 ? 48 8B 01 FF 50 ? 48 8B 44 24 ? 48 8D 54 24 ? 48 8B CB 48 89 44 24 ? E8 ? ? ? ? 48 83 C4 ? 5B C3 CC CC CC CC CC 48 89 5C 24",
|
||||
"linux": "55 48 89 F2 48 89 E5 53 48 89 FB 48 8D 7D ? 48 83 EC ? 48 8D 05 ? ? ? ? 48 8B 30 48 8B 06 FF 50 ? 48 8B 45 ? 48 8D 75 ? 48 89 DF 48 89 45 ? E8 ? ? ? ? 48 8B 5D ? C9 C3 CC CC CC 55"
|
||||
}
|
||||
},
|
||||
"CCSPlayer_WeaponServices_CanUse": {
|
||||
"signatures": {
|
||||
"library": "server",
|
||||
"windows": "48 89 5C 24 ? 48 89 6C 24 ? 56 57 41 56 48 83 EC ? 48 8B 01 48 8B FA",
|
||||
"linux": "55 48 8D 15 ? ? ? ? 48 89 E5 41 55 41 54 49 89 FC 53 48 89 F3 48 83 EC ? 48 8B 07 48 8B 80 ? ? ? ?"
|
||||
}
|
||||
},
|
||||
"CCSPlayer_ItemServices_CanAcquire": {
|
||||
"signatures": {
|
||||
"library": "server",
|
||||
"windows": "44 89 44 24 ? 48 89 54 24 ? 48 89 4C 24 ? 55 53 56 57 41 55 41 56 41 57 48 8B EC",
|
||||
"linux": "55 48 89 E5 41 57 41 56 41 55 49 89 CD 41 54 49 89 FC 53 48 89 F3 48 83 EC 78"
|
||||
}
|
||||
},
|
||||
"GetCSWeaponDataFromKey": {
|
||||
"signatures": {
|
||||
"library": "server",
|
||||
"windows": "48 89 5C 24 ? 48 89 6C 24 ? 48 89 74 24 ? 57 48 83 EC 20 33 ED 48 8B FA 8B F1",
|
||||
"linux": "55 48 89 E5 41 54 53 48 81 EC 10 01 00 00 48 85 FF"
|
||||
}
|
||||
},
|
||||
"CCSPlayer_ItemServices_GiveNamedItem": {
|
||||
"offsets": {
|
||||
"windows": 18,
|
||||
"linux": 19
|
||||
}
|
||||
},
|
||||
"CCSPlayer_ItemServices_DropActivePlayerWeapon": {
|
||||
"offsets": {
|
||||
"windows": 20,
|
||||
"linux": 21
|
||||
}
|
||||
},
|
||||
"CCSPlayer_ItemServices_RemoveWeapons": {
|
||||
"offsets": {
|
||||
"windows": 22,
|
||||
"linux": 23
|
||||
}
|
||||
},
|
||||
"CGameSceneNode_GetSkeletonInstance": {
|
||||
"offsets": {
|
||||
"windows": 8,
|
||||
"linux": 8
|
||||
}
|
||||
},
|
||||
"CCSGameRules_TerminateRound": {
|
||||
"signatures": {
|
||||
"library": "server",
|
||||
"windows": "48 8B C4 4C 89 48 ? 48 89 48 ? 55 56",
|
||||
"linux": "55 48 89 E5 41 57 41 56 49 89 FE 41 55 41 54 53 48 81 EC ? ? ? ? 48 8D 05 ? ? ? ? F3 0F 11 85"
|
||||
}
|
||||
},
|
||||
"CCSGameRules_FindPickerEntity": {
|
||||
"offsets": {
|
||||
"windows": 25,
|
||||
"linux": 26
|
||||
}
|
||||
},
|
||||
"CTakeDamageInfo_HitGroup": {
|
||||
"offsets": {
|
||||
"windows": 104,
|
||||
"linux": 104
|
||||
}
|
||||
},
|
||||
"UTIL_CreateEntityByName": {
|
||||
"signatures": {
|
||||
"library": "server",
|
||||
"windows": "48 83 EC 48 C6 44 24 30 00",
|
||||
"linux": "48 8D 05 ? ? ? ? 55 48 89 FA"
|
||||
}
|
||||
},
|
||||
"CBaseEntity_DispatchSpawn": {
|
||||
"signatures": {
|
||||
"library": "server",
|
||||
"windows": "48 89 5C 24 10 57 48 83 EC 30 48 8B DA 48 8B F9 48 85 C9",
|
||||
"linux": "48 85 FF 74 ? 55 48 89 E5 41 55 49 89 FD"
|
||||
}
|
||||
},
|
||||
"CEntityInstance_AcceptInput": {
|
||||
"signatures": {
|
||||
"library": "server",
|
||||
"windows": "89 5C 24 ? 48 89 74 24 ? 57 48 83 EC ? 49 8B F0 48 8B D9 48 8B 0D",
|
||||
"linux": "55 48 89 F0 48 89 E5 41 57 49 89 FF 41 56 48 8D 7D C0"
|
||||
}
|
||||
},
|
||||
"CEntitySystem_AddEntityIOEvent": {
|
||||
"signatures": {
|
||||
"library": "server",
|
||||
"windows": "48 89 5C 24 ? 4C 89 4C 24 ? 48 89 4C 24 ? 55 56 57 41 54 41 55 41 56 41 57 48 83 EC ? 49 8B F9",
|
||||
"linux": "55 48 89 E5 41 55 49 89 CD 41 54 49 89 FC"
|
||||
}
|
||||
},
|
||||
"LegacyGameEventListener": {
|
||||
"signatures": {
|
||||
"library": "server",
|
||||
"windows": "48 8B 15 ? ? ? ? 48 85 D2 74 ? 83 F9 ? 77 ? 48 63 C1 48 C1 E0",
|
||||
"linux": "48 8B 05 ? ? ? ? 48 85 C0 74 ? 83 FF ? 77 ? 48 63 FF 48 C1 E7 ? 48 8D 44 38"
|
||||
}
|
||||
},
|
||||
"CBasePlayerPawn_CommitSuicide": {
|
||||
"offsets": {
|
||||
"windows": 408,
|
||||
"linux": 408
|
||||
}
|
||||
},
|
||||
"CBasePlayerPawn_RemovePlayerItem": {
|
||||
"signatures": {
|
||||
"library": "server",
|
||||
"windows": "48 ? ? 0F 84 ? ? ? ? 48 89 5C 24 ? 57 48 ? ? ? 48 ? ? 48 ? ? E8",
|
||||
"linux": "55 48 89 E5 41 54 49 89 FC 53 48 89 F3 E8 ? ? ? ? 48 39 C3 74 ? 4C 89 E7 E8 ? ? ? ? 48 39 C3 74 ? 4C 89 E7 48 89 DE E8 ? ? ? ? 48 89 DF 5B 41 5C 5D E9 ? ? ? ? 0F 1F 44 00 00"
|
||||
}
|
||||
},
|
||||
"CBaseEntity_CollisionRulesChanged": {
|
||||
"offsets": {
|
||||
"windows": 190,
|
||||
"linux": 190
|
||||
}
|
||||
},
|
||||
"CBaseEntity_Teleport": {
|
||||
"offsets": {
|
||||
"windows": 168,
|
||||
"linux": 167
|
||||
}
|
||||
},
|
||||
"CBaseEntity_TakeDamageOld": {
|
||||
"signatures": {
|
||||
"library": "server",
|
||||
"windows": "4C 8B DC 56 57 48 81 EC ? ? ? ? 48 8B 41",
|
||||
"linux": "55 48 89 E5 41 57 41 56 49 89 F6 41 55 41 54 49 89 FC 53 48 89 D3 48 83 EC ?? 48 85 D2"
|
||||
}
|
||||
},
|
||||
"CBaseTrigger_StartTouch": {
|
||||
"signatures": {
|
||||
"library": "server",
|
||||
"windows": "40 57 41 56 48 83 EC ? 48 8B 01",
|
||||
"linux": "55 48 89 E5 41 56 41 55 49 89 F5 41 54 53 48 89 FB 48 83 EC 10 48 8B 07"
|
||||
}
|
||||
},
|
||||
"CBaseTrigger_EndTouch": {
|
||||
"signatures": {
|
||||
"library": "server",
|
||||
"windows": "40 53 41 55 48 83 EC 28",
|
||||
"linux": "55 BA FF FF FF FF 48 89 E5 41 57 41 56 41 55 49 89 F5 41"
|
||||
}
|
||||
},
|
||||
"GameEntitySystem": {
|
||||
"offsets": {
|
||||
"windows": 88,
|
||||
"linux": 80
|
||||
}
|
||||
},
|
||||
"GameEventManager": {
|
||||
"offsets": {
|
||||
"windows": 93,
|
||||
"linux": 93
|
||||
}
|
||||
},
|
||||
"CEntityIOOutput_FireOutputInternal": {
|
||||
"signatures": {
|
||||
"library": "server",
|
||||
"windows": "4C 89 4C 24 ? 48 89 4C 24 ? 53 56",
|
||||
"linux": "55 48 89 E5 41 57 49 89 FF 41 56 41 55 41 54 49 89 D4 53 48 89 F3"
|
||||
}
|
||||
},
|
||||
"IGameSystem_InitAllSystems_pFirst": {
|
||||
"signatures": {
|
||||
"library": "server",
|
||||
"windows": "48 8B 1D ? ? ? ? 48 85 DB 0F 84 ? ? ? ? BD",
|
||||
"linux": "4C 8B 35 ? ? ? ? 4D 85 F6 75"
|
||||
}
|
||||
},
|
||||
"CEntityResourceManifest_AddResource": {
|
||||
"offsets": {
|
||||
"windows": 2,
|
||||
"linux": 0
|
||||
}
|
||||
},
|
||||
"CheckTransmit": {
|
||||
"signatures": {
|
||||
"library": "server",
|
||||
"windows": "48 8B C4 4C 89 48 ? 48 89 50 ? 48 89 48 ? 55 48 8D A8",
|
||||
"linux": "55 48 89 E5 41 57 49 89 FF 41 56 48 8D 3D ? ? ? ? 41 55 41 89 D5"
|
||||
}
|
||||
},
|
||||
"CheckTransmitPlayerSlot": {
|
||||
"offsets": {
|
||||
"windows": 576,
|
||||
"linux": 576
|
||||
}
|
||||
},
|
||||
"NetworkStateChanged": {
|
||||
"signatures": {
|
||||
"library": "server",
|
||||
"windows": "4C 8B C2 48 8B D1 48 8B 09",
|
||||
"linux": "48 8B 07 48 85 C0 74 ? 48 8B 50 10"
|
||||
}
|
||||
},
|
||||
"SetStateChanged": {
|
||||
"offsets": {
|
||||
"windows": 25,
|
||||
"linux": 26
|
||||
}
|
||||
},
|
||||
"ISource2GameEntities::CheckTransmit": {
|
||||
"offsets": {
|
||||
"windows": 12,
|
||||
"linux": 13
|
||||
}
|
||||
},
|
||||
"Host_Say": {
|
||||
"signatures": {
|
||||
"library": "server",
|
||||
"windows": "44 89 4C 24 20 44 88 44 24 18",
|
||||
"linux": "55 48 89 E5 41 57 49 89 F7 41 56 41 55 41 54 4D 89 C4"
|
||||
}
|
||||
},
|
||||
"IsHearingClient": {
|
||||
"signatures": {
|
||||
"library": "engine2",
|
||||
"windows": "55 48 89 E5 41 56 41 55 41 54 53 48 89 FB 39 77",
|
||||
"linux": "55 48 89 E5 41 56 41 55 41 54 53 48 89 FB 39 77"
|
||||
}
|
||||
}
|
||||
}
|
||||
5
configs/addons/metamod/TemplatePlugin.vdf
Normal file
5
configs/addons/metamod/TemplatePlugin.vdf
Normal file
|
|
@ -0,0 +1,5 @@
|
|||
"Metamod Plugin"
|
||||
{
|
||||
"alias" "NadeKingChallenges"
|
||||
"file" "addons/NadeKingChallenges/bin/linuxsteamrt64/NadeKingChallenges"
|
||||
}
|
||||
28
docker/Dockerfile
Normal file
28
docker/Dockerfile
Normal file
|
|
@ -0,0 +1,28 @@
|
|||
FROM registry.gitlab.steamos.cloud/steamrt/sniper/sdk:latest
|
||||
|
||||
WORKDIR /app
|
||||
|
||||
RUN apt update && apt install -y \
|
||||
build-essential \
|
||||
g++ \
|
||||
cmake \
|
||||
ninja-build \
|
||||
git \
|
||||
zlib1g \
|
||||
zlib1g-dev \
|
||||
libssl-dev \
|
||||
libprotobuf-dev \
|
||||
protobuf-compiler \
|
||||
pkg-config \
|
||||
libcurl4-openssl-dev \
|
||||
libmaxminddb-dev \
|
||||
curl
|
||||
|
||||
RUN git config --system --add safe.directory '*'
|
||||
|
||||
COPY docker/docker-entrypoint.sh ./docker-entrypoint.sh
|
||||
RUN sed -i 's/\r$//' ./docker-entrypoint.sh && chmod +x ./docker-entrypoint.sh
|
||||
|
||||
WORKDIR /app/source
|
||||
|
||||
CMD ["/bin/bash", "../docker-entrypoint.sh"]
|
||||
8
docker/docker-compose.yml
Normal file
8
docker/docker-compose.yml
Normal file
|
|
@ -0,0 +1,8 @@
|
|||
services:
|
||||
builder:
|
||||
image: cmake-builder
|
||||
build:
|
||||
context: ..
|
||||
dockerfile: docker/Dockerfile
|
||||
volumes:
|
||||
- ..:/app/source
|
||||
53
docker/docker-entrypoint.sh
Normal file
53
docker/docker-entrypoint.sh
Normal file
|
|
@ -0,0 +1,53 @@
|
|||
#!/bin/bash
|
||||
set -e
|
||||
|
||||
git submodule update --init --recursive
|
||||
|
||||
if git describe --tags --exact-match >/dev/null 2>&1; then
|
||||
export SEMVER="$(git describe --tags --exact-match)"
|
||||
fi
|
||||
|
||||
export GITHUB_SHA_SHORT="$(git rev-parse --short HEAD)"
|
||||
|
||||
### --- Download HL2SDK-CS2 + Metamod-Source -------------------------------
|
||||
SDK_DIR="/tmp/sdk"
|
||||
HL2SDK_DIR="$SDK_DIR/hl2sdk-cs2"
|
||||
MMSOURCE_DIR="$SDK_DIR/metamod-source"
|
||||
CSGO_PROTO_DIR="$SDK_DIR/Protobufs"
|
||||
|
||||
echo "=== Preparing temporary SDK directory ==="
|
||||
rm -rf "$SDK_DIR"
|
||||
mkdir -p "$SDK_DIR"
|
||||
|
||||
echo "=== Downloading HL2SDK-CS2 ==="
|
||||
git clone --depth=1 -b cs2 https://github.com/alliedmodders/hl2sdk "$HL2SDK_DIR"
|
||||
|
||||
echo "=== Downloading Metamod-Source ==="
|
||||
git clone --depth=1 https://github.com/alliedmodders/metamod-source "$MMSOURCE_DIR"
|
||||
|
||||
echo "=== Downloading Protobufs ==="
|
||||
git clone --depth=1 https://github.com/SteamDatabase/Protobufs "$CSGO_PROTO_DIR"
|
||||
|
||||
### --- Export env vars for CMake ------------------------------------------
|
||||
export HL2SDKCS2="$HL2SDK_DIR"
|
||||
export MMSOURCE_DEV="$MMSOURCE_DIR"
|
||||
export CSGO_PROTO="$CSGO_PROTO_DIR/csgo"
|
||||
|
||||
echo "Using HL2SDKCS2=$HL2SDKCS2"
|
||||
echo "Using MMSOURCE_DEV=$MMSOURCE_DEV"
|
||||
echo "Using CSGO_PROTO=$CSGO_PROTO"
|
||||
|
||||
### --- Build ---------------------------------------------------------------
|
||||
echo "=== Starting build ==="
|
||||
|
||||
rm -rf build
|
||||
mkdir build
|
||||
cd build
|
||||
|
||||
cmake .. \
|
||||
-DCMAKE_BUILD_TYPE=Release \
|
||||
-DCMAKE_C_COMPILER=gcc \
|
||||
-DCMAKE_CXX_COMPILER=g++
|
||||
|
||||
echo "=== Building with GCC | Release | All ==="
|
||||
cmake --build . --config Release -j"$(nproc)"
|
||||
38
makefiles/linux.base.cmake
Normal file
38
makefiles/linux.base.cmake
Normal file
|
|
@ -0,0 +1,38 @@
|
|||
add_definitions(
|
||||
-D_LINUX
|
||||
-DPOSIX
|
||||
-DLINUX
|
||||
-DGNUC
|
||||
-DCOMPILER_GCC
|
||||
-DPLATFORM_64BITS
|
||||
-D_FILE_OFFSET_BITS=64
|
||||
-D_GLIBCXX_USE_CXX11_ABI=0
|
||||
)
|
||||
|
||||
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} -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} -Wno-error=stringop-overflow")
|
||||
|
||||
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(CMAKE_SHARED_LINKER_FLAGS "${CMAKE_SHARED_LINKER_FLAGS} -static-libgcc -static-libstdc++")
|
||||
set(CMAKE_SHARED_LINKER_FLAGS "${CMAKE_SHARED_LINKER_FLAGS} -Wl,--exclude-libs=libprotobuf.a")
|
||||
|
||||
set(LINK_LIBRARIES
|
||||
${SOURCESDK_LIB}/linux64/libtier0.so
|
||||
${SOURCESDK_LIB}/linux64/tier1.a
|
||||
${SOURCESDK_LIB}/linux64/interfaces.a
|
||||
${SOURCESDK_LIB}/linux64/mathlib.a
|
||||
spdlog
|
||||
Protobufs
|
||||
distorm
|
||||
funchook-static
|
||||
)
|
||||
5
makefiles/metamod/TemplatePlugin.vdf.in
Normal file
5
makefiles/metamod/TemplatePlugin.vdf.in
Normal file
|
|
@ -0,0 +1,5 @@
|
|||
"Metamod Plugin"
|
||||
{
|
||||
"alias" "NadeKingChallenges"
|
||||
"file" "addons/NadeKingChallenges/bin/${PROJECT_VDF_PLATFORM}/NadeKingChallenges"
|
||||
}
|
||||
10
makefiles/metamod/configure_metamod.cmake
Normal file
10
makefiles/metamod/configure_metamod.cmake
Normal file
|
|
@ -0,0 +1,10 @@
|
|||
if (WIN32)
|
||||
set(PROJECT_VDF_PLATFORM "win64")
|
||||
else()
|
||||
set(PROJECT_VDF_PLATFORM "linuxsteamrt64")
|
||||
endif()
|
||||
|
||||
configure_file(
|
||||
${CMAKE_CURRENT_LIST_DIR}/TemplatePlugin.vdf.in
|
||||
${PROJECT_SOURCE_DIR}/configs/addons/metamod/TemplatePlugin.vdf
|
||||
)
|
||||
64
makefiles/protobuf.cmake
Normal file
64
makefiles/protobuf.cmake
Normal file
|
|
@ -0,0 +1,64 @@
|
|||
# Credit for this protobuf generation cmake file goes to Poggicek.
|
||||
# Based on their work at https://github.com/Poggicek/StickerInspect
|
||||
|
||||
set(PROTO_TARGETS
|
||||
${CSGO_PROTO_DIR}/network_connection.proto
|
||||
${CSGO_PROTO_DIR}/networkbasetypes.proto
|
||||
${CSGO_PROTO_DIR}/cs_gameevents.proto
|
||||
${CSGO_PROTO_DIR}/cs_usercmd.proto
|
||||
${CSGO_PROTO_DIR}/base_gcmessages.proto
|
||||
${CSGO_PROTO_DIR}/econ_gcmessages.proto
|
||||
${CSGO_PROTO_DIR}/engine_gcmessages.proto
|
||||
${CSGO_PROTO_DIR}/gcsdk_gcmessages.proto
|
||||
${CSGO_PROTO_DIR}/gcsystemmsgs.proto
|
||||
${CSGO_PROTO_DIR}/cstrike15_gcmessages.proto
|
||||
${CSGO_PROTO_DIR}/cstrike15_usermessages.proto
|
||||
${CSGO_PROTO_DIR}/netmessages.proto
|
||||
${CSGO_PROTO_DIR}/steammessages.proto
|
||||
${CSGO_PROTO_DIR}/usercmd.proto
|
||||
${CSGO_PROTO_DIR}/usermessages.proto
|
||||
${CSGO_PROTO_DIR}/gameevents.proto
|
||||
${CSGO_PROTO_DIR}/clientmessages.proto
|
||||
${CSGO_PROTO_DIR}/te.proto
|
||||
)
|
||||
|
||||
if(UNIX)
|
||||
set(PROTOC_EXECUTABLE ${SOURCESDK_DIR}/devtools/bin/linux/protoc)
|
||||
elseif(WIN32)
|
||||
set(PROTOC_EXECUTABLE ${SOURCESDK_DIR}/devtools/bin/protoc.exe)
|
||||
endif()
|
||||
|
||||
foreach(PROTO_TARGET ${PROTO_TARGETS})
|
||||
get_filename_component(PROTO_FILENAME ${PROTO_TARGET} NAME_WLE)
|
||||
list(APPEND PROTO_OUTPUT ${PROTO_FILENAME}.pb.cc ${PROTO_FILENAME}.pb.h)
|
||||
list(APPEND PROTO_INPUT ${PROTO_FILENAME}.proto)
|
||||
get_filename_component(PROTO_PATH ${PROTO_TARGET} DIRECTORY)
|
||||
list(APPEND PROTO_PATHS "--proto_path=${PROTO_PATH}")
|
||||
endforeach()
|
||||
|
||||
list(REMOVE_DUPLICATES PROTO_PATHS)
|
||||
list(TRANSFORM PROTO_OUTPUT PREPEND ${CMAKE_CURRENT_BINARY_DIR}/protobufcompiler/)
|
||||
file(MAKE_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}/protobufcompiler)
|
||||
|
||||
add_custom_command(
|
||||
OUTPUT ${PROTO_OUTPUT}
|
||||
COMMAND "${PROTOC_EXECUTABLE}" -I ${SOURCESDK_DIR}/thirdparty/protobuf-3.21.8/src --proto_path=${CSGO_PROTO_DIR} ${PROTO_PATHS} --cpp_out=${CMAKE_CURRENT_BINARY_DIR}/protobufcompiler ${PROTO_INPUT}
|
||||
COMMENT "Generating protobuf file"
|
||||
)
|
||||
|
||||
add_library(Protobufs STATIC
|
||||
${PROTO_OUTPUT}
|
||||
)
|
||||
|
||||
target_include_directories(Protobufs
|
||||
PUBLIC ${CMAKE_CURRENT_BINARY_DIR}/protobufcompiler
|
||||
PUBLIC ${SOURCESDK_DIR}/thirdparty/protobuf-3.21.8/src
|
||||
)
|
||||
|
||||
if(WIN32)
|
||||
target_link_libraries(Protobufs PUBLIC ${SOURCESDK_DIR}/lib/public/win64/2015/libprotobuf.lib)
|
||||
elseif(UNIX)
|
||||
target_link_libraries(Protobufs PUBLIC ${SOURCESDK_DIR}/lib/linux64/release/libprotobuf.a)
|
||||
endif()
|
||||
set_target_properties(Protobufs PROPERTIES LINKER_LANGUAGE CXX)
|
||||
set_target_properties(Protobufs PROPERTIES FOLDER SDK)
|
||||
67
makefiles/shared.cmake
Normal file
67
makefiles/shared.cmake
Normal file
|
|
@ -0,0 +1,67 @@
|
|||
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_STANDARD 20)
|
||||
|
||||
if (LINUX)
|
||||
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fPIC")
|
||||
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -fPIC")
|
||||
endif ()
|
||||
|
||||
set(CMAKE_STATIC_LIBRARY_PREFIX "")
|
||||
|
||||
set(SOURCESDK ${SOURCESDK_DIR}/${BRANCH})
|
||||
set(SOURCESDK_LIB ${SOURCESDK}/lib)
|
||||
|
||||
add_definitions(-DMETA_IS_SOURCE2 -D_ITERATOR_DEBUG_LEVEL=0)
|
||||
|
||||
if (DEFINED ENV{GITHUB_SHA_SHORT})
|
||||
add_definitions(-DGITHUB_SHA="$ENV{GITHUB_SHA_SHORT}")
|
||||
else ()
|
||||
add_definitions(-DGITHUB_SHA="Local")
|
||||
endif ()
|
||||
|
||||
if (DEFINED ENV{SEMVER})
|
||||
add_definitions(-DSEMVER="$ENV{SEMVER}")
|
||||
else ()
|
||||
add_definitions(-DSEMVER="Local")
|
||||
endif ()
|
||||
|
||||
if (CMAKE_CXX_COMPILER_ID STREQUAL "GNU")
|
||||
add_compile_definitions(_GLIBCXX_USE_CXX11_ABI=0)
|
||||
endif ()
|
||||
|
||||
include_directories(
|
||||
${CMAKE_SOURCE_DIR}
|
||||
${SOURCESDK}
|
||||
${SOURCESDK}/thirdparty/protobuf-3.21.8/src
|
||||
${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/schemasystem
|
||||
${METAMOD_DIR}/core
|
||||
${METAMOD_DIR}/core/sourcehook
|
||||
vendor/funchook/include
|
||||
vendor/spdlog/include
|
||||
vendor/nlohmann
|
||||
vendor
|
||||
)
|
||||
|
||||
include(${CMAKE_CURRENT_LIST_DIR}/metamod/configure_metamod.cmake)
|
||||
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(CMAKE_SHARED_LINKER_FLAGS_DEBUG "${CMAKE_SHARED_LINKER_FLAGS_DEBUG} /NODEFAULTLIB:libcmt")
|
||||
|
||||
set(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
|
||||
Protobufs
|
||||
distorm
|
||||
funchook-static
|
||||
)
|
||||
86
src/EntityData.h
Normal file
86
src/EntityData.h
Normal file
|
|
@ -0,0 +1,86 @@
|
|||
//
|
||||
// Created by Michal Přikryl on 15.09.2025.
|
||||
// Copyright (c) 2025 slynxcz. All rights reserved.
|
||||
//
|
||||
#pragma once
|
||||
#include <random>
|
||||
#include <string>
|
||||
#include "schema/CCSPlayerController.h"
|
||||
|
||||
namespace TemplatePlugin {
|
||||
enum class EntityType {
|
||||
None = 0,
|
||||
};
|
||||
|
||||
template<typename T>
|
||||
struct EntityCustomData {
|
||||
T *Value = nullptr;
|
||||
|
||||
explicit EntityCustomData(T *v = nullptr) : Value(v) {
|
||||
}
|
||||
};
|
||||
|
||||
enum class ActionType_t {
|
||||
None = 0,
|
||||
EPush = 1,
|
||||
EPushPower = 2,
|
||||
IgnoreKnife = 3,
|
||||
FToPickup = 4,
|
||||
NoDoorFix = 5,
|
||||
};
|
||||
|
||||
struct EntityData_t {
|
||||
EntityType Type = EntityType::None;
|
||||
|
||||
std::function<void(CHandle<CEntityInstance>, CHandle<CCSPlayerController>)> OnTouch;
|
||||
std::function<void(CHandle<CEntityInstance>, CHandle<CCSPlayerController>)> OnUse;
|
||||
|
||||
std::unique_ptr<EntityCustomData<void> > CustomData;
|
||||
|
||||
CHandle<CCSPlayerController> GrabHolder = nullptr;
|
||||
float GrabDistance = 0.0f;
|
||||
|
||||
CHandle<CBaseEntity> TouchedTo = nullptr;
|
||||
int NextSoundBlockTick = 0;
|
||||
|
||||
ActionType_t ActionType = ActionType_t::None;
|
||||
|
||||
bool SkinInitialized = false;
|
||||
|
||||
void Init() {
|
||||
Type = EntityType::None;
|
||||
OnTouch = nullptr;
|
||||
OnUse = nullptr;
|
||||
CustomData.reset();
|
||||
GrabHolder = nullptr;
|
||||
GrabDistance = 0.0f;
|
||||
TouchedTo = nullptr;
|
||||
NextSoundBlockTick = 0;
|
||||
ActionType = ActionType_t::None;
|
||||
SkinInitialized = false;
|
||||
}
|
||||
};
|
||||
|
||||
struct ActionEntity {
|
||||
std::string HammerId;
|
||||
int Number = 0;
|
||||
|
||||
ActionEntity(const std::string &hammerId, int number)
|
||||
: HammerId(hammerId), Number(number) {
|
||||
}
|
||||
};
|
||||
|
||||
struct HandleHasher {
|
||||
size_t operator()(const CHandle<CBaseEntity> &h) const noexcept {
|
||||
return std::hash<int>()(h.GetEntryIndex());
|
||||
}
|
||||
};
|
||||
|
||||
struct HandleEqual {
|
||||
bool operator()(const CHandle<CBaseEntity> &a, const CHandle<CBaseEntity> &b) const noexcept {
|
||||
return a.GetEntryIndex() == b.GetEntryIndex();
|
||||
}
|
||||
};
|
||||
|
||||
inline std::unordered_map<CHandle<CBaseEntity>, EntityData_t, HandleHasher, HandleEqual> EntityData;
|
||||
}
|
||||
56
src/PlayersData.cpp
Normal file
56
src/PlayersData.cpp
Normal file
|
|
@ -0,0 +1,56 @@
|
|||
//
|
||||
// Created by Michal Přikryl on 12.07.2025.
|
||||
// Copyright (c) 2025 slynxcz. All rights reserved.
|
||||
//
|
||||
#include "PlayersData.h"
|
||||
|
||||
namespace TemplatePlugin {
|
||||
bool PlayerDataHandler::Add(uint64_t steamid, const PlayerData &data) {
|
||||
if (steamid == 0 || players_.contains(steamid)) return false;
|
||||
players_[steamid] = data;
|
||||
return true;
|
||||
}
|
||||
|
||||
PlayerData* PlayerDataHandler::TryGet(uint64_t steamid) {
|
||||
auto it = players_.find(steamid);
|
||||
return it != players_.end() ? &it->second : nullptr;
|
||||
}
|
||||
|
||||
bool PlayerDataHandler::Remove(uint64_t steamid) {
|
||||
return players_.erase(steamid) > 0;
|
||||
}
|
||||
|
||||
PlayerData& PlayerDataHandler::Ensure(uint64_t steamid) {
|
||||
return players_[steamid];
|
||||
}
|
||||
|
||||
bool PlayerDataHandler::Add(CCSPlayerController* player, const PlayerData& data) {
|
||||
if (!player) return false;
|
||||
uint64_t steamid = player->GetSteamID();
|
||||
if (steamid == 0) return false;
|
||||
return Add(steamid, data);
|
||||
}
|
||||
|
||||
PlayerData* PlayerDataHandler::TryGet(CCSPlayerController* player) {
|
||||
if (!player) return nullptr;
|
||||
uint64_t steamid = player->GetSteamID();
|
||||
return steamid ? TryGet(steamid) : nullptr;
|
||||
}
|
||||
|
||||
bool PlayerDataHandler::Remove(CCSPlayerController* player) {
|
||||
if (!player) return false;
|
||||
uint64_t steamid = player->GetSteamID();
|
||||
return steamid ? Remove(steamid) : false;
|
||||
}
|
||||
|
||||
PlayerData& PlayerDataHandler::Ensure(CCSPlayerController* player) {
|
||||
static PlayerData dummy{};
|
||||
if (!player) return dummy;
|
||||
uint64_t steamid = player->GetSteamID();
|
||||
return steamid ? Ensure(steamid) : dummy;
|
||||
}
|
||||
|
||||
void PlayerDataHandler::ClearAll() {
|
||||
players_.clear();
|
||||
}
|
||||
}
|
||||
30
src/PlayersData.h
Normal file
30
src/PlayersData.h
Normal file
|
|
@ -0,0 +1,30 @@
|
|||
//
|
||||
// Created by Michal Přikryl on 12.07.2025.
|
||||
// Copyright (c) 2025 slynxcz. All rights reserved.
|
||||
//
|
||||
#pragma once
|
||||
#include <unordered_map>
|
||||
#include "schema/CCSPlayerController.h"
|
||||
|
||||
namespace TemplatePlugin {
|
||||
struct PlayerData {
|
||||
};
|
||||
|
||||
class PlayerDataHandler {
|
||||
public:
|
||||
static bool Add(uint64_t steamid, const PlayerData &data = {});
|
||||
static PlayerData* TryGet(uint64_t steamid);
|
||||
static bool Remove(uint64_t steamid);
|
||||
static PlayerData& Ensure(uint64_t steamid);
|
||||
|
||||
static bool Add(CCSPlayerController* player, const PlayerData& data = {});
|
||||
static PlayerData* TryGet(CCSPlayerController* player);
|
||||
static bool Remove(CCSPlayerController* player);
|
||||
static PlayerData& Ensure(CCSPlayerController* player);
|
||||
|
||||
static void ClearAll();
|
||||
|
||||
private:
|
||||
static inline std::unordered_map<uint64_t, PlayerData> players_;
|
||||
};
|
||||
}
|
||||
139
src/RayTrace.cpp
Normal file
139
src/RayTrace.cpp
Normal file
|
|
@ -0,0 +1,139 @@
|
|||
//
|
||||
// Created by Michal Přikryl on 30.08.2025.
|
||||
// Copyright (c) 2025 slynxcz. All rights reserved.
|
||||
//
|
||||
#include "RayTrace.h"
|
||||
#include <Shared.h>
|
||||
#include "schema/CBaseModelEntity.h"
|
||||
#include "vectorextends.h"
|
||||
#include "dynlibutils/memaddr.h"
|
||||
#include "dynlibutils/module.h"
|
||||
#include "colors.h"
|
||||
#include "log.h"
|
||||
|
||||
namespace TemplatePlugin::RayTrace
|
||||
{
|
||||
using TraceShapeFn = bool(*)(void* pThis,
|
||||
Ray_t& ray,
|
||||
Vector& start,
|
||||
Vector& end,
|
||||
CTraceFilter* filter,
|
||||
CGameTrace* trace);
|
||||
static TraceShapeFn s_TraceShape = nullptr;
|
||||
|
||||
bool Initialize()
|
||||
{
|
||||
void* pCNavPhysicsInterfaceVTable =
|
||||
DynLibUtils::CModule(shared::g_pServer).GetVirtualTableByName("CNavPhysicsInterface");
|
||||
|
||||
if (!pCNavPhysicsInterfaceVTable)
|
||||
{
|
||||
FP_ERROR("Failed to find CNavPhysicsInterface vtable!");
|
||||
return false;
|
||||
}
|
||||
|
||||
auto table = static_cast<void**>(pCNavPhysicsInterfaceVTable);
|
||||
s_TraceShape = reinterpret_cast<TraceShapeFn>(table[shared::g_pGameConfig->GetOffset("CNavPhysicsInterface_TraceShape")]);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
static void DrawBeam(const Vector& start, const Vector& end, const Color& color)
|
||||
{
|
||||
CBeam* beam = UTIL_CreateEntityByName<CBeam>("env_beam");
|
||||
if (!beam) return;
|
||||
|
||||
beam->m_clrRender().SetColor(color.r(), color.g(), color.b(), color.a());
|
||||
beam->m_fWidth() = 1.5f;
|
||||
beam->m_nRenderMode() = kRenderGlow;
|
||||
beam->m_nRenderFX() = kRenderFxNone;
|
||||
|
||||
beam->Teleport(&start, &VectorExtends::RotationZero, &VectorExtends::VectorZero);
|
||||
beam->m_vecEndPos() = end;
|
||||
beam->DispatchSpawn();
|
||||
}
|
||||
|
||||
std::optional<TraceResult> TraceShapeEx(
|
||||
const Vector& start,
|
||||
const Vector& end,
|
||||
CTraceFilter& filterInc,
|
||||
Ray_t rayInc)
|
||||
{
|
||||
if (!s_TraceShape) return std::nullopt;
|
||||
|
||||
CGameTrace tr{};
|
||||
Vector startCopy = start;
|
||||
Vector endCopy = end;
|
||||
s_TraceShape(nullptr, rayInc, startCopy, endCopy,
|
||||
&filterInc, &tr);
|
||||
|
||||
TraceResult r{};
|
||||
r.EndPos = tr.m_vEndPos;
|
||||
r.HitEntity = tr.m_pEnt;
|
||||
r.Fraction = tr.m_flFraction;
|
||||
r.AllSolid = tr.m_bStartInSolid;
|
||||
r.Normal = tr.m_vHitNormal;
|
||||
|
||||
return r;
|
||||
}
|
||||
|
||||
std::optional<TraceResult> TraceShape(
|
||||
const Vector& origin,
|
||||
const QAngle& viewangles,
|
||||
CBaseEntity* ignorePlayer,
|
||||
const TraceOptions* opts)
|
||||
{
|
||||
Vector forward;
|
||||
AngleVectors(viewangles, &forward);
|
||||
Vector endOrigin{
|
||||
origin.x + forward.x * 8192.f,
|
||||
origin.y + forward.y * 8192.f,
|
||||
origin.z + forward.z * 8192.f
|
||||
};
|
||||
|
||||
CTraceFilterEx filter = ignorePlayer ? CTraceFilterEx(ignorePlayer) : CTraceFilterEx();
|
||||
|
||||
if (opts)
|
||||
{
|
||||
if (opts->InteractsWith) filter.m_nInteractsWith = static_cast<uint64_t>(*opts->InteractsWith);
|
||||
if (opts->InteractsExclude) filter.m_nInteractsExclude = static_cast<uint64_t>(*opts->InteractsExclude);
|
||||
}
|
||||
|
||||
Ray_t ray;
|
||||
auto res = TraceShapeEx(origin, endOrigin, filter, ray);
|
||||
|
||||
if (opts && opts->DrawBeam)
|
||||
{
|
||||
Color col = res.has_value() ? colors::Red().ToValveColor() : colors::Green().ToValveColor();
|
||||
DrawBeam(origin, res ? res->EndPos : endOrigin, col);
|
||||
}
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
std::optional<TraceResult> TraceEndShape(
|
||||
const Vector& origin,
|
||||
const Vector& endOrigin,
|
||||
CBaseEntity* ignorePlayer,
|
||||
const TraceOptions* opts)
|
||||
{
|
||||
CTraceFilterEx filter = ignorePlayer ? CTraceFilterEx(ignorePlayer) : CTraceFilterEx();
|
||||
|
||||
if (opts)
|
||||
{
|
||||
if (opts->InteractsWith) filter.m_nInteractsWith = static_cast<uint64_t>(*opts->InteractsWith);
|
||||
if (opts->InteractsExclude) filter.m_nInteractsExclude = static_cast<uint64_t>(*opts->InteractsExclude);
|
||||
}
|
||||
|
||||
Ray_t ray;
|
||||
auto res = TraceShapeEx(origin, endOrigin, filter, ray);
|
||||
|
||||
if (opts && opts->DrawBeam)
|
||||
{
|
||||
Color col = res.has_value() ? colors::Red().ToValveColor() : colors::Green().ToValveColor();
|
||||
DrawBeam(origin, res ? res->EndPos : endOrigin, col);
|
||||
}
|
||||
|
||||
return res;
|
||||
}
|
||||
}
|
||||
126
src/RayTrace.h
Normal file
126
src/RayTrace.h
Normal file
|
|
@ -0,0 +1,126 @@
|
|||
//
|
||||
// Created by Michal Přikryl on 30.08.2025.
|
||||
// Copyright (c) 2025 slynxcz. All rights reserved.
|
||||
//
|
||||
#pragma once
|
||||
#include <optional>
|
||||
#include <cstdint>
|
||||
#include "vector.h"
|
||||
#include "gametrace.h"
|
||||
#include "trace.h"
|
||||
#include "cmodel.h"
|
||||
#include "schema/CBaseEntity.h"
|
||||
|
||||
namespace TemplatePlugin::RayTrace
|
||||
{
|
||||
enum class InteractionLayers : uint64_t
|
||||
{
|
||||
Solid = 0x1,
|
||||
Hitboxes = 0x2,
|
||||
Trigger = 0x4,
|
||||
Sky = 0x8,
|
||||
PlayerClip = 0x10,
|
||||
NPCClip = 0x20,
|
||||
BlockLOS = 0x40,
|
||||
BlockLight = 0x80,
|
||||
Ladder = 0x100,
|
||||
Pickup = 0x200,
|
||||
BlockSound = 0x400,
|
||||
NoDraw = 0x800,
|
||||
Window = 0x1000,
|
||||
PassBullets = 0x2000,
|
||||
WorldGeometry = 0x4000,
|
||||
Water = 0x8000,
|
||||
Slime = 0x10000,
|
||||
TouchAll = 0x20000,
|
||||
Player = 0x40000,
|
||||
NPC = 0x80000,
|
||||
Debris = 0x100000,
|
||||
Physics_Prop = 0x200000,
|
||||
NavIgnore = 0x400000,
|
||||
NavLocalIgnore = 0x800000,
|
||||
PostProcessingVolume = 0x1000000,
|
||||
UnusedLayer3 = 0x2000000,
|
||||
CarriedObject = 0x4000000,
|
||||
PushAway = 0x8000000,
|
||||
ServerEntityOnClient = 0x10000000,
|
||||
CarriedWeapon = 0x20000000,
|
||||
StaticLevel = 0x40000000,
|
||||
csgo_team1 = 0x80000000,
|
||||
csgo_team2 = 0x100000000,
|
||||
csgo_grenadeclip = 0x200000000,
|
||||
csgo_droneclip = 0x400000000,
|
||||
csgo_moveable = 0x800000000,
|
||||
csgo_opaque = 0x1000000000,
|
||||
csgo_monster = 0x2000000000,
|
||||
csgo_thrown_grenade = 0x8000000000,
|
||||
FUNPLAY_IGNORE_PLAYER = (0x8000000000ull << 1)
|
||||
};
|
||||
|
||||
inline InteractionLayers operator|(InteractionLayers a, InteractionLayers b)
|
||||
{
|
||||
return static_cast<InteractionLayers>(
|
||||
static_cast<uint64_t>(a) | static_cast<uint64_t>(b)
|
||||
);
|
||||
}
|
||||
|
||||
inline InteractionLayers& operator|=(InteractionLayers& a, InteractionLayers b)
|
||||
{
|
||||
a = a | b;
|
||||
return a;
|
||||
}
|
||||
|
||||
class CTraceFilterEx : public CTraceFilter
|
||||
{
|
||||
public:
|
||||
explicit CTraceFilterEx(CBaseEntity* entityToIgnore)
|
||||
: CTraceFilter(static_cast<CEntityInstance*>(entityToIgnore),
|
||||
entityToIgnore ? entityToIgnore->m_hOwnerEntity.Get() : nullptr,
|
||||
entityToIgnore ? entityToIgnore->m_pCollision()->m_collisionAttribute().m_nHierarchyId() : static_cast<uint16>(0xFFFFFFFF),
|
||||
0x2c3011,
|
||||
COLLISION_GROUP_DEFAULT, true)
|
||||
{
|
||||
}
|
||||
|
||||
CTraceFilterEx() : CTraceFilter(0x2c3011, COLLISION_GROUP_DEFAULT, true)
|
||||
{
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
struct TraceOptions
|
||||
{
|
||||
std::optional<InteractionLayers> InteractsWith{static_cast<InteractionLayers>(0x2c3011)};
|
||||
std::optional<InteractionLayers> InteractsExclude{};
|
||||
bool DrawBeam{false};
|
||||
};
|
||||
|
||||
struct TraceResult
|
||||
{
|
||||
Vector EndPos{};
|
||||
CEntityInstance* HitEntity{};
|
||||
float Fraction{};
|
||||
bool AllSolid{};
|
||||
Vector Normal{};
|
||||
};
|
||||
|
||||
bool Initialize();
|
||||
|
||||
std::optional<TraceResult> TraceShape(
|
||||
const Vector& origin,
|
||||
const QAngle& viewangles,
|
||||
CBaseEntity* ignorePlayer = nullptr,
|
||||
const TraceOptions* opts = nullptr);
|
||||
|
||||
std::optional<TraceResult> TraceEndShape(
|
||||
const Vector& origin,
|
||||
const Vector& endOrigin,
|
||||
CBaseEntity* ignorePlayer = nullptr,
|
||||
const TraceOptions* opts = nullptr);
|
||||
|
||||
std::optional<TraceResult> TraceShapeEx(
|
||||
const Vector& vecStart,
|
||||
const Vector& vecEnd,
|
||||
CTraceFilter& filterInc,
|
||||
Ray_t rayInc);
|
||||
}
|
||||
62
src/Shared.cpp
Normal file
62
src/Shared.cpp
Normal file
|
|
@ -0,0 +1,62 @@
|
|||
//
|
||||
// Created by Michal Přikryl on 20.09.2025.
|
||||
// Copyright (c) 2025 slynxcz. All rights reserved.
|
||||
//
|
||||
#include "Shared.h"
|
||||
#include <icvar.h>
|
||||
#include <iserver.h>
|
||||
#include <schemasystem.h>
|
||||
#include <sourcehook/sourcehook.h>
|
||||
#include <sourcehook/sourcehook_impl.h>
|
||||
|
||||
namespace TemplatePlugin::shared
|
||||
{
|
||||
ICvar* g_pCVar = nullptr;
|
||||
IServerGameDLL* g_pServer = nullptr;
|
||||
ISource2Server* g_pSource2Server = nullptr;
|
||||
IVEngineServer* g_pEngine = nullptr;
|
||||
CSchemaSystem* g_pSchemaSystem = nullptr;
|
||||
IGameEventManager2* g_pGameEventManager = nullptr;
|
||||
IGameEventSystem* g_pGameEventSystem = nullptr;
|
||||
ISource2GameEntities* g_pGameEntities = nullptr;
|
||||
INetworkMessages* g_pNetworkMessages = nullptr;
|
||||
INetworkServerService* g_pNetworkServerService = nullptr;
|
||||
CGameEntitySystem* g_pEntitySystem = nullptr;
|
||||
IServerGameClients* g_pGameClients = nullptr;
|
||||
CGlobalVars *g_pGlobalVars = nullptr;
|
||||
CGameResourceService *g_pGameResourceServiceServer = nullptr;
|
||||
CGameConfig *g_pGameConfig = nullptr;
|
||||
|
||||
SourceHook::Impl::CSourceHookImpl source_hook_impl;
|
||||
SourceHook::ISourceHook* source_hook = &source_hook_impl;
|
||||
|
||||
int source_hook_pluginid = 0;
|
||||
|
||||
CGlobalVars *getGlobalVars() {
|
||||
INetworkGameServer *server = g_pNetworkServerService->GetIGameServer();
|
||||
if (!server) return nullptr;
|
||||
if (!g_pGlobalVars) g_pGlobalVars = server->GetGlobals();
|
||||
return g_pNetworkServerService->GetIGameServer()->GetGlobals();
|
||||
}
|
||||
constexpr float engine_fixed_tick_interval = 0.015625f;
|
||||
const char* GetMapName()
|
||||
{
|
||||
if (getGlobalVars() == nullptr) return nullptr;
|
||||
|
||||
return getGlobalVars()->mapname.ToCStr();
|
||||
}
|
||||
void ServerCommand(const char* command)
|
||||
{
|
||||
auto clean_command = std::string(command);
|
||||
clean_command.append("\n\0");
|
||||
g_pEngine->ServerCommand(clean_command.c_str());
|
||||
}
|
||||
double GetEngineTime() { return Plat_FloatTime(); }
|
||||
float GetTickInterval() { return engine_fixed_tick_interval; }
|
||||
float GetCurrentTime() { return getGlobalVars()->curtime; }
|
||||
int GetTickCount() { return getGlobalVars()->tickcount; }
|
||||
float GetGameFrameTime() { return getGlobalVars()->frametime; }
|
||||
|
||||
bool g_bHasTicked = false;
|
||||
bool g_bDetoursLoaded = false;
|
||||
}
|
||||
55
src/Shared.h
Normal file
55
src/Shared.h
Normal file
|
|
@ -0,0 +1,55 @@
|
|||
//
|
||||
// Created by Michal Přikryl on 20.09.2025.
|
||||
// Copyright (c) 2025 slynxcz. All rights reserved.
|
||||
//
|
||||
#pragma once
|
||||
#include <icvar.h>
|
||||
#include <memory>
|
||||
#include <schemasystem.h>
|
||||
#include <vector>
|
||||
#include <eiface.h>
|
||||
#include <gameconfig.h>
|
||||
#include <igameeventsystem.h>
|
||||
#include "schema/cgameresourceserviceserver.h"
|
||||
#include <sourcehook/sourcehook.h>
|
||||
|
||||
class CGameEntitySystem;
|
||||
|
||||
namespace TemplatePlugin::shared
|
||||
{
|
||||
extern ICvar* g_pCVar;
|
||||
extern IServerGameDLL* g_pServer;
|
||||
extern ISource2Server* g_pSource2Server;
|
||||
extern IVEngineServer* g_pEngine;
|
||||
extern CSchemaSystem* g_pSchemaSystem;
|
||||
extern IGameEventManager2* g_pGameEventManager;
|
||||
extern IGameEventSystem* g_pGameEventSystem;
|
||||
extern ISource2GameEntities* g_pGameEntities;
|
||||
extern INetworkMessages* g_pNetworkMessages;
|
||||
extern INetworkServerService* g_pNetworkServerService;
|
||||
extern CGameEntitySystem* g_pEntitySystem;
|
||||
extern IServerGameClients* g_pGameClients;
|
||||
extern CGlobalVars* g_pGlobalVars;
|
||||
extern CGameResourceService* g_pGameResourceServiceServer;
|
||||
extern CGameConfig *g_pGameConfig;
|
||||
|
||||
extern SourceHook::ISourceHook *source_hook;
|
||||
extern int source_hook_pluginid;
|
||||
|
||||
CGlobalVars* getGlobalVars();
|
||||
extern const char *GetMapName();
|
||||
extern void ServerCommand(const char *command);
|
||||
extern double GetEngineTime();
|
||||
extern float GetTickInterval();
|
||||
extern float GetCurrentTime();
|
||||
extern int GetTickCount();
|
||||
extern float GetGameFrameTime();
|
||||
|
||||
extern bool g_bHasTicked;
|
||||
extern bool g_bDetoursLoaded;
|
||||
}
|
||||
|
||||
#undef SH_GLOB_SHPTR
|
||||
#define SH_GLOB_SHPTR TemplatePlugin::shared::source_hook
|
||||
#undef SH_GLOB_PLUGPTR
|
||||
#define SH_GLOB_PLUGPTR TemplatePlugin::shared::source_hook_pluginid
|
||||
133
src/TemplatePlugin.cpp
Normal file
133
src/TemplatePlugin.cpp
Normal file
|
|
@ -0,0 +1,133 @@
|
|||
#include "TemplatePlugin.h"
|
||||
#include "path.h"
|
||||
#include "Shared.h"
|
||||
#include "dynlibutils/module.h"
|
||||
#include <entitysystem.h>
|
||||
#include "igameevents.h"
|
||||
#include <iserver.h>
|
||||
#include "game_system.h"
|
||||
#include "schemasystem/schemasystem.h"
|
||||
#include "schema/CCSPlayerController.h"
|
||||
#include "schema/cgameresourceserviceserver.h"
|
||||
#include "schema/plat.h"
|
||||
#include <filesystem>
|
||||
#include <cstdio>
|
||||
#include <detours.h>
|
||||
#include <fstream>
|
||||
#include <gameconfig.h>
|
||||
#include <regex>
|
||||
#include <listeners/Listeners.h>
|
||||
#include "EntityData.h"
|
||||
#include "log.h"
|
||||
#include "PlayersData.h"
|
||||
#include "tasks.h"
|
||||
#include "commands/Commands.h"
|
||||
#include "events/Events.h"
|
||||
#include "hooks/Hooks.h"
|
||||
#include "schema/CGameRules.h"
|
||||
|
||||
#define VERSION_STRING SEMVER " @ " GITHUB_SHA
|
||||
#define BUILD_TIMESTAMP __DATE__ " " __TIME__
|
||||
|
||||
PLUGIN_EXPOSE(Template, TemplatePlugin::g_iPlugin);
|
||||
|
||||
CGameEntitySystem* GameEntitySystem()
|
||||
{
|
||||
return *reinterpret_cast<CGameEntitySystem**>((uintptr_t)(g_pGameResourceServiceServer) +
|
||||
TemplatePlugin::shared::g_pGameConfig->GetOffset("GameEntitySystem"));
|
||||
}
|
||||
|
||||
class GameSessionConfiguration_t
|
||||
{
|
||||
};
|
||||
|
||||
namespace TemplatePlugin
|
||||
{
|
||||
ITemplatePlugin g_iPlugin;
|
||||
|
||||
bool ITemplatePlugin::Load(PluginId id, ISmmAPI* ismm, char* error, size_t maxlen, bool late)
|
||||
{
|
||||
PLUGIN_SAVEVARS();
|
||||
|
||||
GET_V_IFACE_CURRENT(GetEngineFactory, shared::g_pCVar, ICvar, CVAR_INTERFACE_VERSION);
|
||||
GET_V_IFACE_ANY(GetServerFactory, shared::g_pSource2Server, ISource2Server, SOURCE2SERVER_INTERFACE_VERSION);
|
||||
GET_V_IFACE_ANY(GetServerFactory, shared::g_pServer, IServerGameDLL, INTERFACEVERSION_SERVERGAMEDLL);
|
||||
GET_V_IFACE_CURRENT(GetEngineFactory, shared::g_pEngine, IVEngineServer, INTERFACEVERSION_VENGINESERVER);
|
||||
GET_V_IFACE_ANY(GetEngineFactory, shared::g_pSchemaSystem, CSchemaSystem, SCHEMASYSTEM_INTERFACE_VERSION);
|
||||
GET_V_IFACE_ANY(GetEngineFactory, shared::g_pGameEventSystem, IGameEventSystem,
|
||||
GAMEEVENTSYSTEM_INTERFACE_VERSION);
|
||||
GET_V_IFACE_ANY(GetServerFactory, shared::g_pGameEntities, ISource2GameEntities,
|
||||
SOURCE2GAMEENTITIES_INTERFACE_VERSION);
|
||||
GET_V_IFACE_ANY(GetServerFactory, shared::g_pGameClients, IServerGameClients,
|
||||
SOURCE2GAMECLIENTS_INTERFACE_VERSION);
|
||||
GET_V_IFACE_CURRENT(GetEngineFactory, g_pGameResourceServiceServer, IGameResourceService,
|
||||
GAMERESOURCESERVICESERVER_INTERFACE_VERSION);
|
||||
GET_V_IFACE_ANY(GetEngineFactory, shared::g_pNetworkMessages, INetworkMessages,
|
||||
NETWORKMESSAGES_INTERFACE_VERSION);
|
||||
GET_V_IFACE_ANY(GetEngineFactory, shared::g_pNetworkServerService, INetworkServerService,
|
||||
NETWORKSERVERSERVICE_INTERFACE_VERSION);
|
||||
|
||||
g_pCVar = shared::g_pCVar;
|
||||
g_pSource2GameEntities = shared::g_pGameEntities;
|
||||
shared::g_pGameResourceServiceServer = (CGameResourceService*)g_pGameResourceServiceServer;
|
||||
if (!shared::g_pGameResourceServiceServer)
|
||||
return false;
|
||||
|
||||
Tasks::Init();
|
||||
auto gamedata_path = std::string(Paths::GetRootDirectory() + "/gamedata.json");
|
||||
shared::g_pGameConfig = new CGameConfig(gamedata_path);
|
||||
char conf_error[255] = "";
|
||||
|
||||
if (!shared::g_pGameConfig->Init(conf_error, sizeof(conf_error)))
|
||||
{
|
||||
FP_ERROR("Could not read '{}'. Error: {}", gamedata_path, conf_error);
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!InitGameSystems())
|
||||
return false;
|
||||
|
||||
g_SMAPI->AddListener(this, this);
|
||||
Listeners::InitListeners();
|
||||
|
||||
g_pCVar = shared::g_pCVar;
|
||||
ConVar_Register(FCVAR_RELEASE | FCVAR_CLIENT_CAN_EXECUTE | FCVAR_GAMEDLL);
|
||||
|
||||
if (late)
|
||||
{
|
||||
shared::g_pEntitySystem = GameEntitySystem();
|
||||
shared::g_pEntitySystem->AddListenerEntity(&Detours::entityListener);
|
||||
Commands::InitCommands();
|
||||
Events::InitEvents();
|
||||
Hooks::InitHooks();
|
||||
Detours::InitHooks();
|
||||
RayTrace::Initialize();
|
||||
shared::g_bDetoursLoaded = true;
|
||||
}
|
||||
|
||||
FP_INFO("<<< Load() success! >>>");
|
||||
return true;
|
||||
}
|
||||
|
||||
bool ITemplatePlugin::Unload(char* error, size_t maxlen)
|
||||
{
|
||||
Listeners::DestructListeners();
|
||||
Detours::ShutdownHooks();
|
||||
Detours::Shutdown();
|
||||
shared::g_pEntitySystem->RemoveListenerEntity(&Detours::entityListener);
|
||||
Tasks::Shutdown();
|
||||
|
||||
FP_INFO("<<< Unload() success! >>>");
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
const char* ITemplatePlugin::GetAuthor() { return "Slynx"; }
|
||||
const char* ITemplatePlugin::GetName() { return "TemplatePlugin"; }
|
||||
const char* ITemplatePlugin::GetDescription() { return "TemplatePlugin Metamod plugin for CS2 servers."; }
|
||||
const char* ITemplatePlugin::GetURL() { return "https://slynxdev.cz"; }
|
||||
const char* ITemplatePlugin::GetLicense() { return "GPLv3"; }
|
||||
const char* ITemplatePlugin::GetVersion() { return VERSION_STRING; }
|
||||
const char* ITemplatePlugin::GetDate() { return BUILD_TIMESTAMP; }
|
||||
const char* ITemplatePlugin::GetLogTag() { return "TemplatePlugin"; }
|
||||
}
|
||||
30
src/TemplatePlugin.h
Normal file
30
src/TemplatePlugin.h
Normal file
|
|
@ -0,0 +1,30 @@
|
|||
#ifndef _INCLUDE_METAMOD_SOURCE_STUB_PLUGIN_H_
|
||||
#define _INCLUDE_METAMOD_SOURCE_STUB_PLUGIN_H_
|
||||
|
||||
#include <igameevents.h>
|
||||
#include <ISmmPlugin.h>
|
||||
#include "entitysystem.h"
|
||||
|
||||
namespace TemplatePlugin
|
||||
{
|
||||
class ITemplatePlugin : public ISmmPlugin, public IMetamodListener
|
||||
{
|
||||
public:
|
||||
bool Load(PluginId id, ISmmAPI *ismm, char *error, size_t maxlen, bool late) override;
|
||||
bool Unload(char *error, size_t maxlen) override;
|
||||
const char *GetAuthor() override;
|
||||
const char *GetName() override;
|
||||
const char *GetDescription() override;
|
||||
const char *GetURL() override;
|
||||
const char *GetLicense() override;
|
||||
const char *GetVersion() override;
|
||||
const char *GetDate() override;
|
||||
const char *GetLogTag() override;
|
||||
};
|
||||
|
||||
extern ITemplatePlugin g_iPlugin;
|
||||
}
|
||||
|
||||
#endif //_INCLUDE_METAMOD_SOURCE_STUB_PLUGIN_H_
|
||||
|
||||
PLUGIN_GLOBALVARS();
|
||||
137
src/colors.h
Normal file
137
src/colors.h
Normal file
|
|
@ -0,0 +1,137 @@
|
|||
#pragma once
|
||||
#include <string>
|
||||
#include <sstream>
|
||||
#include <cstdio>
|
||||
#include <Color.h>
|
||||
#include <cmath>
|
||||
#include <chrono>
|
||||
|
||||
namespace TemplatePlugin {
|
||||
struct colors {
|
||||
float r, g, b, a;
|
||||
|
||||
colors(float red, float green, float blue, float alpha = 1.0f)
|
||||
: r(red), g(green), b(blue), a(alpha) {}
|
||||
|
||||
static colors Red() { return colors(1.f, 0.f, 0.f, 1.f); }
|
||||
static colors Green() { return colors(0.f, 1.f, 0.f, 1.f); }
|
||||
static colors Blue() { return colors(0.f, 0.f, 1.f, 1.f); }
|
||||
static colors Yellow() { return colors(1.f, 1.f, 0.f, 1.f); }
|
||||
static colors Purple() { return colors(0.5f, 0.f, 0.5f, 1.f); }
|
||||
static colors Orange() { return colors(1.f, 0.5f, 0.f, 1.f); }
|
||||
static colors Rainbow() { return colors(0.247f, 0.655f, 0.839f, 1.0f); }
|
||||
|
||||
static colors FromHex(const std::string& hex) {
|
||||
unsigned int rgb = 0;
|
||||
std::string clean = hex;
|
||||
if (clean.starts_with("#"))
|
||||
clean = clean.substr(1);
|
||||
|
||||
std::stringstream ss;
|
||||
ss << std::hex << clean;
|
||||
ss >> rgb;
|
||||
|
||||
float rf = ((rgb >> 16) & 0xFF) / 255.0f;
|
||||
float gf = ((rgb >> 8) & 0xFF) / 255.0f;
|
||||
float bf = (rgb & 0xFF) / 255.0f;
|
||||
|
||||
return colors(rf, gf, bf);
|
||||
}
|
||||
|
||||
static colors FromHSV(double h, double s, double v, double a = 1.0) {
|
||||
h = fmod(h, 360.0);
|
||||
double c = v * s;
|
||||
double x = c * (1 - std::fabs(fmod(h / 60.0, 2) - 1));
|
||||
double m = v - c;
|
||||
|
||||
double rf = 0, gf = 0, bf = 0;
|
||||
|
||||
if (h < 60) {
|
||||
rf = c; gf = x; bf = 0;
|
||||
} else if (h < 120) {
|
||||
rf = x; gf = c; bf = 0;
|
||||
} else if (h < 180) {
|
||||
rf = 0; gf = c; bf = x;
|
||||
} else if (h < 240) {
|
||||
rf = 0; gf = x; bf = c;
|
||||
} else if (h < 300) {
|
||||
rf = x; gf = 0; bf = c;
|
||||
} else {
|
||||
rf = c; gf = 0; bf = x;
|
||||
}
|
||||
|
||||
return colors(
|
||||
static_cast<float>(rf + m),
|
||||
static_cast<float>(gf + m),
|
||||
static_cast<float>(bf + m),
|
||||
static_cast<float>(a)
|
||||
);
|
||||
}
|
||||
|
||||
bool IsEmpty() const {
|
||||
return r == 0.0f && g == 0.0f && b == 0.0f && a == 0.0f;
|
||||
}
|
||||
|
||||
bool IsRainbow() const {
|
||||
return ToHexString() == "#3FA7D6";
|
||||
}
|
||||
|
||||
std::string ToHexString() const {
|
||||
int ir = static_cast<int>(r * 255);
|
||||
int ig = static_cast<int>(g * 255);
|
||||
int ib = static_cast<int>(b * 255);
|
||||
|
||||
char buf[8];
|
||||
std::snprintf(buf, sizeof(buf), "#%02X%02X%02X", ir, ig, ib);
|
||||
return std::string(buf);
|
||||
}
|
||||
|
||||
uint32_t ToARGB() const {
|
||||
return (static_cast<uint32_t>(a * 255) << 24) |
|
||||
(static_cast<uint32_t>(b * 255) << 16) |
|
||||
(static_cast<uint32_t>(g * 255) << 8) |
|
||||
(static_cast<uint32_t>(r * 255));
|
||||
}
|
||||
|
||||
static colors FromARGB(uint32_t packed) {
|
||||
float rf = (packed & 0xFF) / 255.0f;
|
||||
float gf = ((packed >> 8) & 0xFF) / 255.0f;
|
||||
float bf = ((packed >> 16) & 0xFF) / 255.0f;
|
||||
float af = ((packed >> 24) & 0xFF) / 255.0f;
|
||||
return colors(rf, gf, bf, af);
|
||||
}
|
||||
|
||||
Color ToValveColor() const {
|
||||
return Color(
|
||||
static_cast<int>(r * 255.0f),
|
||||
static_cast<int>(g * 255.0f),
|
||||
static_cast<int>(b * 255.0f),
|
||||
static_cast<int>(a * 255.0f)
|
||||
);
|
||||
}
|
||||
|
||||
static inline const char* MapColorToCode(const colors& c) {
|
||||
if (c.IsEmpty())
|
||||
return "\x01";
|
||||
|
||||
const std::string hex = c.ToHexString();
|
||||
if (hex == "#FF0000") return "\x07"; // red
|
||||
if (hex == "#008000") return "\x04"; // green
|
||||
if (hex == "#0000FF") return "\x0B"; // blue
|
||||
if (hex == "#FFFF00") return "\x09"; // yellow
|
||||
if (hex == "#800080") return "\x0E"; // purple
|
||||
if (hex == "#FFA500") return "\x10"; // orange
|
||||
if (hex == "#FFFFFF") return "\x01"; // white
|
||||
return "\x01";
|
||||
}
|
||||
|
||||
static colors GetRainbowColor() {
|
||||
using namespace std::chrono;
|
||||
auto now = system_clock::now();
|
||||
auto ms = duration_cast<milliseconds>(now.time_since_epoch()).count();
|
||||
|
||||
double hue = fmod((ms % 1000) / 1000.0 * 360.0, 360.0);
|
||||
return FromHSV(hue, 1.0, 1.0);
|
||||
}
|
||||
};
|
||||
}
|
||||
14
src/commands/Commands.cpp
Normal file
14
src/commands/Commands.cpp
Normal file
|
|
@ -0,0 +1,14 @@
|
|||
//
|
||||
// Created by Michal Přikryl on 21.11.2025.
|
||||
// Copyright (c) 2025 slynxcz. All rights reserved.
|
||||
//
|
||||
#include "Commands.h"
|
||||
#include <detours.h>
|
||||
|
||||
namespace TemplatePlugin::Commands
|
||||
{
|
||||
void InitCommands()
|
||||
{
|
||||
|
||||
}
|
||||
}
|
||||
11
src/commands/Commands.h
Normal file
11
src/commands/Commands.h
Normal file
|
|
@ -0,0 +1,11 @@
|
|||
//
|
||||
// Created by Michal Přikryl on 21.11.2025.
|
||||
// Copyright (c) 2025 slynxcz. All rights reserved.
|
||||
//
|
||||
#pragma once
|
||||
#include "detourtypes.h"
|
||||
|
||||
namespace TemplatePlugin::Commands
|
||||
{
|
||||
void InitCommands();
|
||||
}
|
||||
369
src/detours.cpp
Normal file
369
src/detours.cpp
Normal file
|
|
@ -0,0 +1,369 @@
|
|||
//
|
||||
// Created by Michal Přikryl on 09.07.2025.
|
||||
// Copyright (c) 2025 slynxcz. All rights reserved.
|
||||
//
|
||||
#include <funchook/include/funchook.h>
|
||||
#include <igameevents.h>
|
||||
#include <sourcehook.h>
|
||||
#include <cstring>
|
||||
#include <unordered_set>
|
||||
#include "schema/CCSPlayerController.h"
|
||||
#include "detours.h"
|
||||
|
||||
#include <Shared.h>
|
||||
#include <TemplatePlugin.h>
|
||||
|
||||
#include "log.h"
|
||||
|
||||
namespace TemplatePlugin {
|
||||
SH_DECL_HOOK2(IGameEventManager2, FireEvent, SH_NOATTRIB, 0, bool, IGameEvent*, bool);
|
||||
SH_DECL_HOOK3_void(ICvar, DispatchConCommand, SH_NOATTRIB, 0, ConCommandRef, const CCommandContext&,
|
||||
const CCommand&);
|
||||
|
||||
namespace Detours {
|
||||
std::vector<std::unique_ptr<ConCommand> > registeredCommands;
|
||||
static std::unordered_map<std::string, std::vector<CommandEntry> > consoleListeners;
|
||||
static std::unordered_map<std::string, std::vector<EventEntry> > gameEvents;
|
||||
static EventManager eventManager;
|
||||
static std::vector<IGameEvent *> eventStack;
|
||||
static std::vector<EntityEventHandler> entitySpawnedListeners;
|
||||
static std::vector<EntityEventHandler> entityCreatedListeners;
|
||||
static std::vector<EntityEventHandler> entityDeletedListeners;
|
||||
static std::vector<EntityParentChangedHandler> entityParentChangerListeners;
|
||||
static std::unordered_set<std::string> registeredNames;
|
||||
static std::unordered_map<std::string, CommandHandler> commandCallbacks;
|
||||
struct OutputHookKey {
|
||||
CEntityInstance *entity;
|
||||
std::string output;
|
||||
HookMode mode;
|
||||
|
||||
bool operator==(const OutputHookKey &o) const noexcept {
|
||||
return entity == o.entity && output == o.output && mode == o.mode;
|
||||
}
|
||||
};
|
||||
|
||||
struct OutputHookKeyHasher {
|
||||
size_t operator()(const OutputHookKey &k) const noexcept {
|
||||
return std::hash<void *>{}(k.entity) ^ (std::hash<std::string>{}(k.output) << 1)
|
||||
^ (std::hash<int>{}(static_cast<int>(k.mode)) << 2);
|
||||
}
|
||||
};
|
||||
static std::unordered_map<OutputHookKey, std::vector<EntityOutputHandler>, OutputHookKeyHasher>
|
||||
g_entityOutputHooks;
|
||||
|
||||
void ConCommandRouter(const CCommandContext &ctx, const CCommand &args) {
|
||||
if (args.ArgC() < 1)
|
||||
return;
|
||||
|
||||
std::string name = args.Arg(0);
|
||||
auto it = commandCallbacks.find(name);
|
||||
if (it == commandCallbacks.end())
|
||||
return;
|
||||
|
||||
(void) it->second(ctx, args, HookMode::Post);
|
||||
}
|
||||
|
||||
void RegisterChatListener(const std::string &name,
|
||||
const std::function<void(const CCommandContext &, const CCommand &, HookMode)> &
|
||||
handler) {
|
||||
CommandHandler nativeHandler = WrapVoidHandler(handler);
|
||||
|
||||
RegisterConsoleListener(name, nativeHandler, HookMode::Pre);
|
||||
RegisterConsoleListener("/" + name, nativeHandler, HookMode::Pre);
|
||||
RegisterConsoleListener("!" + name, nativeHandler, HookMode::Pre);
|
||||
}
|
||||
|
||||
void RegisterConsoleCommand(const std::string &name,
|
||||
const std::function<void(const CCommandContext &, const CCommand &, HookMode)> &
|
||||
handler) {
|
||||
CommandHandler nativeHandler = WrapVoidHandler(handler);
|
||||
|
||||
if (shared::g_pCVar && shared::g_pCVar->FindConCommand(name.c_str()).IsValidRef()) {
|
||||
RegisterConsoleListener(name, nativeHandler, HookMode::Pre);
|
||||
RegisterConsoleListener("/" + name, nativeHandler, HookMode::Pre);
|
||||
RegisterConsoleListener("!" + name, nativeHandler, HookMode::Pre);
|
||||
return;
|
||||
}
|
||||
|
||||
if (!registeredNames.contains(name)) {
|
||||
auto cmd = std::make_unique<ConCommand>(
|
||||
name.c_str(),
|
||||
ConCommandRouter,
|
||||
("Registered command: " + name).c_str(),
|
||||
FCVAR_NONE
|
||||
);
|
||||
registeredCommands.push_back(std::move(cmd));
|
||||
registeredNames.insert(name);
|
||||
}
|
||||
|
||||
RegisterConsoleListener(name, nativeHandler, HookMode::Pre);
|
||||
RegisterConsoleListener("/" + name, nativeHandler, HookMode::Pre);
|
||||
RegisterConsoleListener("!" + name, nativeHandler, HookMode::Pre);
|
||||
}
|
||||
|
||||
void InitHooks() {
|
||||
SH_ADD_HOOK(IGameEventManager2, FireEvent, shared::g_pGameEventManager, Detours::OnFireEvent, false);
|
||||
SH_ADD_HOOK(IGameEventManager2, FireEvent, shared::g_pGameEventManager, Detours::OnFireEventPost, true);
|
||||
SH_ADD_HOOK(ICvar, DispatchConCommand, shared::g_pCVar, Hook_DispatchConCommand, false);
|
||||
}
|
||||
|
||||
void ShutdownHooks() {
|
||||
SH_REMOVE_HOOK(IGameEventManager2, FireEvent, shared::g_pGameEventManager, Detours::OnFireEvent, false);
|
||||
SH_REMOVE_HOOK(IGameEventManager2, FireEvent, shared::g_pGameEventManager, Detours::OnFireEventPost, true);
|
||||
SH_REMOVE_HOOK(ICvar, DispatchConCommand, shared::g_pCVar, Hook_DispatchConCommand, false);
|
||||
}
|
||||
|
||||
void RegisterConsoleListener(const std::string &name, CommandHandler handler, HookMode mode) {
|
||||
consoleListeners[name].push_back({handler, mode});
|
||||
}
|
||||
|
||||
void RegisterGameEvent(const std::string &name, GameEventHandler handler, HookMode mode) {
|
||||
gameEvents[name].push_back({handler, mode});
|
||||
if (!shared::g_pGameEventManager->FindListener(&eventManager, name.c_str()))
|
||||
{
|
||||
shared::g_pGameEventManager->AddListener(&eventManager, name.c_str(), true);
|
||||
}
|
||||
}
|
||||
|
||||
void EventManager::FireGameEvent(IGameEvent* pEvent) {}
|
||||
|
||||
void RegisterEntityListener(EntityEventHandler handler, EntityEventType type) {
|
||||
switch (type) {
|
||||
case EntityEventType::ENTITY_SPAWNED:
|
||||
entitySpawnedListeners.push_back(handler);
|
||||
break;
|
||||
case EntityEventType::ENTITY_CREATED:
|
||||
entityCreatedListeners.push_back(handler);
|
||||
break;
|
||||
case EntityEventType::ENTITY_DELETED:
|
||||
entityDeletedListeners.push_back(handler);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
void *FindModuleSignature(const DynLibUtils::CModule& module, const char *name) {
|
||||
return module.FindPattern(
|
||||
shared::g_pGameConfig->GetSignature(name)
|
||||
);
|
||||
}
|
||||
|
||||
HookResult DispatchConsoleListener(const CCommandContext &ctx, const CCommand &args, HookMode mode) {
|
||||
std::string name = args.Arg(0);
|
||||
std::transform(name.begin(), name.end(), name.begin(),
|
||||
[](unsigned char c) { return static_cast<char>(std::tolower(c)); });
|
||||
|
||||
auto it = consoleListeners.find(name);
|
||||
if (it == consoleListeners.end())
|
||||
return HookResult::Continue;
|
||||
|
||||
HookResult result = HookResult::Continue;
|
||||
|
||||
for (const auto &entry: it->second) {
|
||||
if (entry.mode != mode)
|
||||
continue;
|
||||
|
||||
HookResult thisResult = entry.handler(ctx, args, mode);
|
||||
|
||||
if (thisResult == HookResult::Stop)
|
||||
return HookResult::Stop;
|
||||
|
||||
if (thisResult == HookResult::Handled && mode == HookMode::Pre)
|
||||
return HookResult::Handled;
|
||||
|
||||
if (static_cast<int>(thisResult) > static_cast<int>(result))
|
||||
result = thisResult;
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
bool DispatchGameEvent(IGameEvent *event, HookMode mode, bool &dontBroadcast) {
|
||||
const char *name = event->GetName();
|
||||
auto it = gameEvents.find(name);
|
||||
if (it == gameEvents.end())
|
||||
return true;
|
||||
|
||||
EventOverride override{dontBroadcast};
|
||||
|
||||
for (const auto &hook: it->second) {
|
||||
if (hook.mode != mode)
|
||||
continue;
|
||||
|
||||
HookResult result = hook.handler(event, mode, override);
|
||||
|
||||
if (result == HookResult::Handled || result == HookResult::Stop)
|
||||
return false;
|
||||
}
|
||||
|
||||
dontBroadcast = override.dontBroadcast;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void DispatchEntitySpawn(CEntityInstance *ent) {
|
||||
for (auto &fn: entitySpawnedListeners) {
|
||||
fn(ent);
|
||||
}
|
||||
}
|
||||
|
||||
void DispatchEntityCreate(CEntityInstance *ent) {
|
||||
for (auto &fn: entityCreatedListeners) {
|
||||
fn(ent);
|
||||
}
|
||||
}
|
||||
|
||||
void DispatchEntityDelete(CEntityInstance *ent) {
|
||||
for (auto &fn: entityDeletedListeners) {
|
||||
fn(ent);
|
||||
}
|
||||
}
|
||||
|
||||
void HookSingleEntityOutput(CEntityInstance *entity,
|
||||
const std::string &outputName,
|
||||
EntityOutputHandler handler,
|
||||
HookMode mode) {
|
||||
g_entityOutputHooks[{entity, outputName, mode}].push_back(std::move(handler));
|
||||
}
|
||||
|
||||
void UnhookSingleEntityOutput(CEntityInstance *entity,
|
||||
const std::string &outputName,
|
||||
EntityOutputHandler handler,
|
||||
HookMode mode) {
|
||||
auto key = OutputHookKey{entity, outputName, mode};
|
||||
auto it = g_entityOutputHooks.find(key);
|
||||
if (it == g_entityOutputHooks.end()) return;
|
||||
|
||||
auto &vec = it->second;
|
||||
vec.erase(std::remove_if(vec.begin(), vec.end(),
|
||||
[&](const EntityOutputHandler &h) {
|
||||
return h.target<void>() == handler.target<void>();
|
||||
}),
|
||||
vec.end());
|
||||
|
||||
if (vec.empty())
|
||||
g_entityOutputHooks.erase(it);
|
||||
}
|
||||
|
||||
HookResult DispatchEntityOutput(CEntityIOOutput *output,
|
||||
const char *name,
|
||||
CEntityInstance *activator,
|
||||
CEntityInstance *caller,
|
||||
const CVariant *value,
|
||||
float delay,
|
||||
HookMode mode) {
|
||||
HookResult result = HookResult::Continue;
|
||||
|
||||
for (auto &[key, handlers]: g_entityOutputHooks) {
|
||||
if (key.entity != caller) continue;
|
||||
if (key.output != name) continue;
|
||||
if (key.mode != mode) continue;
|
||||
|
||||
for (auto &fn: handlers) {
|
||||
HookResult r = fn(output, name, activator, caller, value, delay);
|
||||
if (r == HookResult::Stop) return HookResult::Stop;
|
||||
if (static_cast<int>(r) > static_cast<int>(result))
|
||||
result = r;
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
bool OnFireEvent(IGameEvent *event, bool bDontBroadcast) {
|
||||
if (!event)
|
||||
RETURN_META_VALUE(MRES_IGNORED, false);
|
||||
|
||||
bool localDontBroadcast = bDontBroadcast;
|
||||
if (!DispatchGameEvent(event, HookMode::Pre, localDontBroadcast))
|
||||
RETURN_META_VALUE(MRES_SUPERCEDE, false);
|
||||
|
||||
if (IGameEvent *copy = shared::g_pGameEventManager->DuplicateEvent(event)) eventStack.push_back(copy);
|
||||
|
||||
if (localDontBroadcast != bDontBroadcast)
|
||||
RETURN_META_VALUE_NEWPARAMS(MRES_IGNORED, true, &IGameEventManager2::FireEvent,
|
||||
(event, localDontBroadcast));
|
||||
|
||||
RETURN_META_VALUE(MRES_IGNORED, true);
|
||||
}
|
||||
|
||||
bool OnFireEventPost(IGameEvent *event, bool bDontBroadcast) {
|
||||
if (!event)
|
||||
RETURN_META_VALUE(MRES_IGNORED, false);
|
||||
|
||||
if (!eventStack.empty()) {
|
||||
IGameEvent *copy = eventStack.back();
|
||||
eventStack.pop_back();
|
||||
|
||||
bool dummy = bDontBroadcast;
|
||||
DispatchGameEvent(copy, HookMode::Post, dummy);
|
||||
shared::g_pGameEventManager->FreeEvent(copy);
|
||||
}
|
||||
|
||||
RETURN_META_VALUE(MRES_IGNORED, true);
|
||||
}
|
||||
|
||||
void Hook_DispatchConCommand(ConCommandRef, const CCommandContext &ctx, const CCommand &args) {
|
||||
if (args.ArgC() >= 2) {
|
||||
const char *cmd = args.Arg(0);
|
||||
const char *msg = args.Arg(1);
|
||||
|
||||
if (V_strcmp(cmd, "say") == 0 || V_strcmp(cmd, "say_team") == 0) {
|
||||
std::string message = msg;
|
||||
|
||||
if (message.size() >= 2 && message.front() == '"' && message.back() == '"')
|
||||
message = message.substr(1, message.size() - 2);
|
||||
|
||||
if (!message.empty() && (message[0] == '!' || message[0] == '/')) {
|
||||
std::string cleaned = message.substr(1);
|
||||
|
||||
CCommand parsed;
|
||||
parsed.Tokenize(cleaned.c_str());
|
||||
|
||||
if (parsed.ArgC() > 0) {
|
||||
HookResult r = DispatchConsoleListener(ctx, parsed, HookMode::Pre);
|
||||
if (r != HookResult::Stop)
|
||||
DispatchConsoleListener(ctx, parsed, HookMode::Post);
|
||||
}
|
||||
|
||||
RETURN_META(MRES_SUPERCEDE);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
HookResult result = DispatchConsoleListener(ctx, args, HookMode::Pre);
|
||||
|
||||
if (result == HookResult::Handled || result == HookResult::Stop)
|
||||
RETURN_META(MRES_SUPERCEDE);
|
||||
|
||||
DispatchConsoleListener(ctx, args, HookMode::Post);
|
||||
}
|
||||
|
||||
void Shutdown() {
|
||||
consoleListeners.clear();
|
||||
shared::g_pGameEventManager->RemoveListener(&eventManager);
|
||||
gameEvents.clear();
|
||||
entitySpawnedListeners.clear();
|
||||
entityCreatedListeners.clear();
|
||||
entityDeletedListeners.clear();
|
||||
entityParentChangerListeners.clear();
|
||||
commandCallbacks.clear();
|
||||
registeredNames.clear();
|
||||
registeredCommands.clear();
|
||||
for (auto hook: hookHandles) {
|
||||
if (!hook) continue;
|
||||
|
||||
int rc = funchook_uninstall(hook, 0);
|
||||
if (rc != 0) {
|
||||
FP_ERROR("Failed to uninstall hook: {}", rc);
|
||||
}
|
||||
|
||||
rc = funchook_destroy(hook);
|
||||
if (rc != 0) {
|
||||
FP_ERROR("Failed to destroy hook: {}", rc);
|
||||
}
|
||||
}
|
||||
hookHandles.clear();
|
||||
signatureHooks.clear();
|
||||
shared::g_pEntitySystem->RemoveListenerEntity(&entityListener);
|
||||
}
|
||||
}
|
||||
}
|
||||
293
src/detours.h
Normal file
293
src/detours.h
Normal file
|
|
@ -0,0 +1,293 @@
|
|||
//
|
||||
// Created by Michal Přikryl on 20.06.2025.
|
||||
// Copyright (c) 2025 slynxcz. All rights reserved.
|
||||
//
|
||||
#pragma once
|
||||
|
||||
#include <any>
|
||||
#include <functional>
|
||||
#include <string>
|
||||
#include <igameevents.h>
|
||||
#include <convar.h>
|
||||
#include <features.h>
|
||||
#include <ISmmPlugin.h>
|
||||
#include <TemplatePlugin.h>
|
||||
#include <funchook/include/funchook.h>
|
||||
#include <type_traits>
|
||||
#include "detourtypes.h"
|
||||
#include "entitysystem.h"
|
||||
#include "log.h"
|
||||
#include "dynlibutils/module.h"
|
||||
|
||||
namespace TemplatePlugin::Detours
|
||||
{
|
||||
struct CommandEntry
|
||||
{
|
||||
CommandHandler handler;
|
||||
HookMode mode;
|
||||
};
|
||||
|
||||
struct EventEntry
|
||||
{
|
||||
GameEventHandler handler;
|
||||
HookMode mode;
|
||||
};
|
||||
|
||||
class EventManager : public IGameEventListener2
|
||||
{
|
||||
void FireGameEvent(IGameEvent* pEvent) override;
|
||||
};
|
||||
|
||||
static std::unordered_map<std::string, std::vector<SignatureEntry>> signatureHooks;
|
||||
static std::mutex signatureHooksMutex;
|
||||
static std::vector<funchook_t*> hookHandles;
|
||||
extern std::unordered_map<std::string, std::any> overriddenReturns;
|
||||
extern std::mutex overriddenReturnsMutex;
|
||||
|
||||
void Shutdown();
|
||||
|
||||
void InitHooks();
|
||||
|
||||
void ShutdownHooks();
|
||||
|
||||
bool OnFireEvent(IGameEvent* event, bool bDontBroadcast);
|
||||
|
||||
bool OnFireEventPost(IGameEvent* event, bool bDontBroadcast);
|
||||
|
||||
void ConCommandRouter(const CCommandContext& ctx, const CCommand& args);
|
||||
|
||||
void Hook_DispatchConCommand(ConCommandRef, const CCommandContext&, const CCommand&);
|
||||
|
||||
void RegisterConsoleListener(const std::string& name, CommandHandler handler, HookMode mode = HookMode::Post);
|
||||
|
||||
void RegisterChatListener(const std::string& name,
|
||||
const std::function<void(const CCommandContext&, const CCommand&, HookMode)>& handler);
|
||||
|
||||
void RegisterConsoleCommand(const std::string& name,
|
||||
const std::function<void(const CCommandContext&, const CCommand&,
|
||||
HookMode)>& handler);
|
||||
|
||||
void RegisterGameEvent(const std::string& name, GameEventHandler handler, HookMode mode = HookMode::Post);
|
||||
|
||||
void RegisterEntityListener(EntityEventHandler handler, EntityEventType type);
|
||||
|
||||
inline void RegisterSignatureHandler(const std::string& name,
|
||||
SignatureHandler handler,
|
||||
HookMode mode = HookMode::Post)
|
||||
{
|
||||
std::scoped_lock lock(signatureHooksMutex);
|
||||
signatureHooks[name].push_back({handler, mode});
|
||||
}
|
||||
|
||||
void* FindModuleSignature(const DynLibUtils::CModule& module, const char* name);
|
||||
|
||||
template <typename T>
|
||||
inline void* ToVoidArg(T&& v)
|
||||
{
|
||||
return const_cast<void*>(reinterpret_cast<const void*>(&v));
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
inline void* ToVoidArg(T* v)
|
||||
{
|
||||
return const_cast<void*>(reinterpret_cast<const void*>(v));
|
||||
}
|
||||
|
||||
template <typename Fn, typename... Args>
|
||||
auto DispatchSignatureCall(const std::string& name, Fn original, Args... args)
|
||||
-> decltype(original(args...))
|
||||
{
|
||||
using Ret = decltype(original(args...));
|
||||
std::vector<SignatureEntry> hooksCopy;
|
||||
|
||||
{
|
||||
std::scoped_lock lock(signatureHooksMutex);
|
||||
auto it = signatureHooks.find(name);
|
||||
if (it != signatureHooks.end())
|
||||
hooksCopy = it->second;
|
||||
}
|
||||
|
||||
void* argArray[] = {ToVoidArg(args)...};
|
||||
constexpr size_t argCount = sizeof...(Args);
|
||||
void* self = argCount > 0 ? argArray[0] : nullptr;
|
||||
|
||||
bool skipOriginal = false;
|
||||
bool allowReturnOverride = false;
|
||||
|
||||
if constexpr (!std::is_void_v<Ret>)
|
||||
{
|
||||
Ret result{};
|
||||
DynamicHook hook{argArray, argCount, self, &result};
|
||||
|
||||
// --- PRE hooks ---
|
||||
for (auto& entry : hooksCopy)
|
||||
{
|
||||
if (entry.mode != HookMode::Pre) continue;
|
||||
HookResult r = entry.handler(&hook, HookMode::Pre);
|
||||
if (r == HookResult::Stop) return result;
|
||||
if (r == HookResult::Handled)
|
||||
{
|
||||
skipOriginal = true;
|
||||
return result;
|
||||
}
|
||||
if (r == HookResult::Changed) allowReturnOverride = true;
|
||||
}
|
||||
|
||||
// --- Originál ---
|
||||
if (!skipOriginal && original)
|
||||
{
|
||||
if (!(allowReturnOverride && hook.returnOverridden))
|
||||
{
|
||||
result = original(args...);
|
||||
}
|
||||
}
|
||||
|
||||
// --- POST hooks ---
|
||||
for (auto& entry : hooksCopy)
|
||||
{
|
||||
if (entry.mode != HookMode::Post) continue;
|
||||
HookResult r = entry.handler(&hook, HookMode::Post);
|
||||
if (r == HookResult::Stop) break;
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
else
|
||||
{
|
||||
DynamicHook hook{argArray, argCount, self, nullptr};
|
||||
|
||||
// --- PRE hooks ---
|
||||
for (auto& entry : hooksCopy)
|
||||
{
|
||||
if (entry.mode != HookMode::Pre) continue;
|
||||
HookResult r = entry.handler(&hook, HookMode::Pre);
|
||||
if (r == HookResult::Stop) return;
|
||||
if (r == HookResult::Handled)
|
||||
{
|
||||
skipOriginal = true;
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
// --- Originál ---
|
||||
if (!skipOriginal && original)
|
||||
{
|
||||
original(args...);
|
||||
}
|
||||
|
||||
// --- POST hooks ---
|
||||
for (auto& entry : hooksCopy)
|
||||
{
|
||||
if (entry.mode != HookMode::Post) continue;
|
||||
HookResult r = entry.handler(&hook, HookMode::Post);
|
||||
if (r == HookResult::Stop) break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
template <typename R, typename... Args>
|
||||
void RegisterSignatureDetour(
|
||||
const std::string& sigName,
|
||||
DynLibUtils::CModule module,
|
||||
R (**ppOriginal)(Args...),
|
||||
SignatureHandler handler,
|
||||
HookMode mode
|
||||
)
|
||||
{
|
||||
std::scoped_lock lock(signatureHooksMutex);
|
||||
|
||||
auto it = signatureHooks.find(sigName);
|
||||
if (it != signatureHooks.end())
|
||||
{
|
||||
it->second.push_back({handler, mode});
|
||||
return;
|
||||
}
|
||||
|
||||
void* addr = FindModuleSignature(std::move(module), sigName.c_str());
|
||||
if (!addr)
|
||||
{
|
||||
FP_ERROR("Failed to find signature for '{}'", sigName);
|
||||
return;
|
||||
}
|
||||
|
||||
*ppOriginal = reinterpret_cast<R(*)(Args...)>(addr);
|
||||
SignatureStorage<R(*)(Args...)>::name = sigName;
|
||||
|
||||
auto detour = [](Args... args) -> R
|
||||
{
|
||||
auto orig = SignatureStorage<R(*)(Args...)>::original;
|
||||
return DispatchSignatureCall(SignatureStorage<R(*)(Args...)>::name, orig, args...);
|
||||
};
|
||||
|
||||
auto hook = funchook_create();
|
||||
using FnType = R(*)(Args...);
|
||||
|
||||
if (funchook_prepare(
|
||||
hook,
|
||||
reinterpret_cast<void**>(ppOriginal),
|
||||
reinterpret_cast<void*>(static_cast<FnType>(detour))
|
||||
) != 0 ||
|
||||
funchook_install(hook, 0) != 0)
|
||||
{
|
||||
FP_ERROR("Failed to hook '{}'", sigName);
|
||||
return;
|
||||
}
|
||||
|
||||
SignatureStorage<R(*)(Args...)>::original = *ppOriginal;
|
||||
|
||||
signatureHooks[sigName] = {};
|
||||
signatureHooks[sigName].push_back({handler, mode});
|
||||
hookHandles.push_back(hook);
|
||||
}
|
||||
|
||||
HookResult DispatchConsoleListener(const CCommandContext& ctx, const CCommand& args, HookMode mode);
|
||||
|
||||
bool DispatchGameEvent(IGameEvent* event, HookMode mode, bool& dontBroadcast);
|
||||
|
||||
void DispatchEntitySpawn(CEntityInstance* entity);
|
||||
|
||||
void DispatchEntityCreate(CEntityInstance* entity);
|
||||
|
||||
void DispatchEntityDelete(CEntityInstance* entity);
|
||||
|
||||
class CEntityListener : public IEntityListener
|
||||
{
|
||||
void OnEntitySpawned(CEntityInstance* pEntity) override { DispatchEntitySpawn(pEntity); }
|
||||
void OnEntityCreated(CEntityInstance* pEntity) override { DispatchEntityCreate(pEntity); }
|
||||
void OnEntityDeleted(CEntityInstance* pEntity) override { DispatchEntityDelete(pEntity); }
|
||||
|
||||
void OnEntityParentChanged(CEntityInstance* pEntity, CEntityInstance* pNewParent) override
|
||||
{
|
||||
}
|
||||
};
|
||||
|
||||
void HookSingleEntityOutput(CEntityInstance* entity,
|
||||
const std::string& outputName,
|
||||
EntityOutputHandler handler,
|
||||
HookMode mode = HookMode::Post);
|
||||
|
||||
void UnhookSingleEntityOutput(CEntityInstance* entity,
|
||||
const std::string& outputName,
|
||||
EntityOutputHandler handler,
|
||||
HookMode mode = HookMode::Post);
|
||||
|
||||
HookResult DispatchEntityOutput(CEntityIOOutput* output,
|
||||
const char* name,
|
||||
CEntityInstance* activator,
|
||||
CEntityInstance* caller,
|
||||
const CVariant* value,
|
||||
float delay,
|
||||
HookMode mode);
|
||||
|
||||
inline CEntityListener entityListener;
|
||||
|
||||
inline CommandHandler WrapVoidHandler(
|
||||
const std::function<void(const CCommandContext&, const CCommand&, HookMode)>& fn)
|
||||
{
|
||||
return [fn](const CCommandContext& ctx, const CCommand& args, HookMode mode) -> HookResult
|
||||
{
|
||||
fn(ctx, args, mode);
|
||||
return HookResult::Continue;
|
||||
};
|
||||
}
|
||||
}
|
||||
207
src/detourtypes.h
Normal file
207
src/detourtypes.h
Normal file
|
|
@ -0,0 +1,207 @@
|
|||
//
|
||||
// Created by Michal Přikryl on 23.08.2025.
|
||||
// Copyright (c) 2025 slynxcz. All rights reserved.
|
||||
//
|
||||
#pragma once
|
||||
#include <functional>
|
||||
#include <igameevents.h>
|
||||
#include <entitysystem.h>
|
||||
#include <convar.h>
|
||||
#include <string>
|
||||
|
||||
namespace TemplatePlugin
|
||||
{
|
||||
class CBaseEntity;
|
||||
class CTakeDamageInfo;
|
||||
class CTakeDamageResult;
|
||||
|
||||
enum class HookResult
|
||||
{
|
||||
Continue = 0,
|
||||
Changed = 1,
|
||||
Handled = 3,
|
||||
Stop = 4,
|
||||
};
|
||||
|
||||
enum class HookMode
|
||||
{
|
||||
Pre,
|
||||
Post
|
||||
};
|
||||
|
||||
struct DynamicHook
|
||||
{
|
||||
void** args;
|
||||
size_t argCount;
|
||||
void* self;
|
||||
void* returnValue;
|
||||
bool returnOverridden = false;
|
||||
|
||||
template <typename T>
|
||||
T GetParam(size_t index) const
|
||||
{
|
||||
if (index >= argCount)
|
||||
throw std::out_of_range("arg index");
|
||||
|
||||
if constexpr (std::is_pointer_v<T>)
|
||||
{
|
||||
return reinterpret_cast<T>(args[index]);
|
||||
}
|
||||
else
|
||||
{
|
||||
return *reinterpret_cast<T*>(args[index]);
|
||||
}
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
void SetParam(size_t index, const T& value)
|
||||
{
|
||||
if (index >= argCount)
|
||||
throw std::out_of_range("arg index");
|
||||
|
||||
if constexpr (std::is_pointer_v<T>)
|
||||
{
|
||||
if constexpr (std::is_pointer_v<std::remove_pointer_t<T>>)
|
||||
{
|
||||
**reinterpret_cast<T*>(args[index]) = *value;
|
||||
}
|
||||
else
|
||||
{
|
||||
args[index] = const_cast<std::remove_const_t<T>>(value);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
*reinterpret_cast<T*>(args[index]) = value;
|
||||
}
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
T GetReturn() const
|
||||
{
|
||||
if (!returnValue)
|
||||
return T{};
|
||||
|
||||
if constexpr (std::is_pointer_v<T>)
|
||||
{
|
||||
return *reinterpret_cast<T*>(returnValue);
|
||||
}
|
||||
else
|
||||
{
|
||||
return *reinterpret_cast<T*>(returnValue);
|
||||
}
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
void SetReturn(const T& value)
|
||||
{
|
||||
if (!returnValue)
|
||||
return;
|
||||
|
||||
if constexpr (std::is_pointer_v<T>)
|
||||
{
|
||||
*reinterpret_cast<T*>(returnValue) = value;
|
||||
}
|
||||
else
|
||||
{
|
||||
*reinterpret_cast<T*>(returnValue) = value;
|
||||
}
|
||||
|
||||
returnOverridden = true;
|
||||
}
|
||||
};
|
||||
|
||||
struct EventOverride
|
||||
{
|
||||
bool dontBroadcast = false;
|
||||
};
|
||||
|
||||
enum class EntityEventType
|
||||
{
|
||||
ENTITY_SPAWNED,
|
||||
ENTITY_CREATED,
|
||||
ENTITY_DELETED
|
||||
};
|
||||
|
||||
struct EntityIOConnectionDesc_t
|
||||
{
|
||||
string_t m_targetDesc;
|
||||
string_t m_targetInput;
|
||||
string_t m_valueOverride;
|
||||
CEntityHandle m_hTarget;
|
||||
EntityIOTargetType_t m_nTargetType;
|
||||
int32 m_nTimesToFire;
|
||||
float m_flDelay;
|
||||
};
|
||||
|
||||
struct EntityIOConnection_t : EntityIOConnectionDesc_t
|
||||
{
|
||||
bool m_bMarkedForRemoval;
|
||||
EntityIOConnection_t* m_pNext;
|
||||
};
|
||||
|
||||
struct EntityIOOutputDesc_t
|
||||
{
|
||||
const char* m_pName;
|
||||
uint32 m_nFlags;
|
||||
uint32 m_nOutputOffset;
|
||||
};
|
||||
|
||||
class CEntityIOOutput
|
||||
{
|
||||
public:
|
||||
void* vtable;
|
||||
EntityIOConnection_t* m_pConnections;
|
||||
EntityIOOutputDesc_t* m_pDesc;
|
||||
};
|
||||
|
||||
using CommandHandler = std::function<HookResult(const CCommandContext&, const CCommand&, HookMode)>;
|
||||
using GameEventHandler = std::function<HookResult(IGameEvent* event, HookMode mode, EventOverride& override)>;
|
||||
using EntityEventHandler = void(*)(CEntityInstance*);
|
||||
using EntityParentChangedHandler = void(*)(CEntityInstance*, CEntityInstance*);
|
||||
using EntityOutputHandler = std::function<HookResult(CEntityIOOutput*, const char*, CEntityInstance*,
|
||||
CEntityInstance*, const CVariant*, float)>;
|
||||
using SignatureHandler = std::function<HookResult(DynamicHook* hook, HookMode mode)>;
|
||||
using CBaseEntity_TakeDamageOld_t = int64_t(*)(CBaseEntity* pThis, CTakeDamageInfo* info, CTakeDamageResult* unk3);
|
||||
|
||||
struct SignatureEntry
|
||||
{
|
||||
SignatureHandler handler;
|
||||
HookMode mode;
|
||||
|
||||
SignatureEntry(SignatureHandler h, HookMode m)
|
||||
: handler(std::move(h)), mode(m)
|
||||
{
|
||||
}
|
||||
|
||||
SignatureEntry(const SignatureEntry& other)
|
||||
: handler(other.handler), mode(other.mode)
|
||||
{
|
||||
}
|
||||
|
||||
SignatureEntry& operator=(const SignatureEntry& other)
|
||||
{
|
||||
if (this != &other)
|
||||
{
|
||||
handler = other.handler;
|
||||
mode = other.mode;
|
||||
}
|
||||
return *this;
|
||||
}
|
||||
|
||||
SignatureEntry(SignatureEntry&&) noexcept = default;
|
||||
|
||||
SignatureEntry& operator=(SignatureEntry&&) noexcept = default;
|
||||
};
|
||||
|
||||
template <typename T>
|
||||
struct SignatureStorage;
|
||||
|
||||
template <typename R, typename... Args>
|
||||
struct SignatureStorage<R(*)(Args...)>
|
||||
{
|
||||
static inline std::string name;
|
||||
|
||||
static inline R (*original)(Args...) = nullptr;
|
||||
};
|
||||
}
|
||||
13
src/events/Events.cpp
Normal file
13
src/events/Events.cpp
Normal file
|
|
@ -0,0 +1,13 @@
|
|||
//
|
||||
// Created by Michal Přikryl on 21.11.2025.
|
||||
// Copyright (c) 2025 slynxcz. All rights reserved.
|
||||
//
|
||||
#include "Events.h"
|
||||
#include <detours.h>
|
||||
|
||||
namespace TemplatePlugin::Events
|
||||
{
|
||||
void InitEvents()
|
||||
{
|
||||
}
|
||||
}
|
||||
11
src/events/Events.h
Normal file
11
src/events/Events.h
Normal file
|
|
@ -0,0 +1,11 @@
|
|||
//
|
||||
// Created by Michal Přikryl on 21.11.2025.
|
||||
// Copyright (c) 2025 slynxcz. All rights reserved.
|
||||
//
|
||||
#pragma once
|
||||
#include "detourtypes.h"
|
||||
|
||||
namespace TemplatePlugin::Events
|
||||
{
|
||||
void InitEvents();
|
||||
}
|
||||
46
src/game_system.cpp
Normal file
46
src/game_system.cpp
Normal file
|
|
@ -0,0 +1,46 @@
|
|||
//
|
||||
// Created by Michal Přikryl on 21.09.2025.
|
||||
// Copyright (c) 2025 slynxcz. All rights reserved.
|
||||
//
|
||||
#include "Shared.h"
|
||||
#include "game_system.h"
|
||||
#include <tier0/vprof.h>
|
||||
|
||||
#include "log.h"
|
||||
#include "dynlibutils/module.h"
|
||||
|
||||
CBaseGameSystemFactory** CBaseGameSystemFactory::sm_pFirst = nullptr;
|
||||
|
||||
CGameSystem g_GameSystem;
|
||||
IGameSystemFactory* CGameSystem::sm_Factory = nullptr;
|
||||
|
||||
IEntityResourceManifest* m_exportResourceManifest = nullptr;
|
||||
|
||||
// This mess is needed to get the pointer to sm_pFirst so we can insert game systems
|
||||
bool InitGameSystems()
|
||||
{
|
||||
DynLibUtils::CModule libserver(TemplatePlugin::shared::g_pServer);
|
||||
|
||||
auto result = libserver.FindPattern(TemplatePlugin::shared::g_pGameConfig->GetSignature("IGameSystem_InitAllSystems_pFirst"));
|
||||
if (!result)
|
||||
{
|
||||
FP_ERROR("Failed to find IGameSystem_InitAllSystems_pFirst!");
|
||||
return false;
|
||||
}
|
||||
|
||||
uint8_t* ptr = reinterpret_cast<uint8_t*>(result.GetPtr()) + 3;
|
||||
uint32 offset = *(uint32*)ptr;
|
||||
ptr += 4;
|
||||
|
||||
CBaseGameSystemFactory::sm_pFirst = (CBaseGameSystemFactory**)(ptr + offset);
|
||||
CGameSystem::sm_Factory = new CGameSystemStaticFactory<CGameSystem>("Template_GameSystem", &g_GameSystem);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
GS_EVENT_MEMBER(CGameSystem, BuildGameSessionManifest)
|
||||
{
|
||||
IEntityResourceManifest* pResourceManifest = msg->m_pResourceManifest;
|
||||
|
||||
m_exportResourceManifest = pResourceManifest;
|
||||
}
|
||||
30
src/game_system.h
Normal file
30
src/game_system.h
Normal file
|
|
@ -0,0 +1,30 @@
|
|||
//
|
||||
// Created by Michal Přikryl on 21.09.2025.
|
||||
// Copyright (c) 2025 slynxcz. All rights reserved.
|
||||
//
|
||||
#pragma once
|
||||
|
||||
#include "entitysystem.h"
|
||||
#include "igamesystemfactory.h"
|
||||
|
||||
bool InitGameSystems();
|
||||
|
||||
class CGameSystem : public CBaseGameSystem
|
||||
{
|
||||
public:
|
||||
GS_EVENT(BuildGameSessionManifest);
|
||||
|
||||
void Shutdown() override
|
||||
{
|
||||
delete sm_Factory;
|
||||
}
|
||||
|
||||
void SetGameSystemGlobalPtrs(void* pValue) override
|
||||
{
|
||||
if (sm_Factory) sm_Factory->SetGlobalPtr(pValue);
|
||||
}
|
||||
|
||||
bool DoesGameSystemReallocate() override { return sm_Factory->ShouldAutoAdd(); }
|
||||
|
||||
static IGameSystemFactory* sm_Factory;
|
||||
};
|
||||
102
src/gameconfig.cpp
Normal file
102
src/gameconfig.cpp
Normal file
|
|
@ -0,0 +1,102 @@
|
|||
//
|
||||
// Created by Michal Přikryl on 20.06.2025.
|
||||
// Copyright (c) 2025 slynxcz. All rights reserved.
|
||||
//
|
||||
#include "gameconfig.h"
|
||||
#include <fstream>
|
||||
#include <TemplatePlugin.h>
|
||||
|
||||
namespace TemplatePlugin
|
||||
{
|
||||
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::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::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;
|
||||
}
|
||||
}
|
||||
41
src/gameconfig.h
Normal file
41
src/gameconfig.h
Normal file
|
|
@ -0,0 +1,41 @@
|
|||
//
|
||||
// Created by Michal Přikryl on 20.06.2025.
|
||||
// Copyright (c) 2025 slynxcz. All rights reserved.
|
||||
//
|
||||
#pragma once
|
||||
#include <KeyValues.h>
|
||||
#include <string>
|
||||
#include <unordered_map>
|
||||
|
||||
#undef snprintf
|
||||
#include <nlohmann/json.hpp>
|
||||
|
||||
namespace TemplatePlugin {
|
||||
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);
|
||||
|
||||
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 Core
|
||||
18
src/hooks/Hooks.cpp
Normal file
18
src/hooks/Hooks.cpp
Normal file
|
|
@ -0,0 +1,18 @@
|
|||
//
|
||||
// Created by Michal Přikryl on 21.11.2025.
|
||||
// Copyright (c) 2025 slynxcz. All rights reserved.
|
||||
//
|
||||
#include "Hooks.h"
|
||||
#include "detours.h"
|
||||
#include "log.h"
|
||||
#include "PlayersData.h"
|
||||
#include "PluginData.h"
|
||||
#include "schema/CCSPlayerController.h"
|
||||
#include "schema/CUserCmd.h"
|
||||
|
||||
namespace TemplatePlugin::Hooks
|
||||
{
|
||||
void InitHooks()
|
||||
{
|
||||
}
|
||||
}
|
||||
11
src/hooks/Hooks.h
Normal file
11
src/hooks/Hooks.h
Normal file
|
|
@ -0,0 +1,11 @@
|
|||
//
|
||||
// Created by Michal Přikryl on 21.11.2025.
|
||||
// Copyright (c) 2025 slynxcz. All rights reserved.
|
||||
//
|
||||
#pragma once
|
||||
#include "detourtypes.h"
|
||||
|
||||
namespace TemplatePlugin::Hooks
|
||||
{
|
||||
void InitHooks();
|
||||
}
|
||||
86
src/listeners/Listeners.cpp
Normal file
86
src/listeners/Listeners.cpp
Normal file
|
|
@ -0,0 +1,86 @@
|
|||
//
|
||||
// Created by Michal Přikryl on 10.07.2025.
|
||||
// Copyright (c) 2025 slynxcz. All rights reserved.
|
||||
//
|
||||
#include "Listeners.h"
|
||||
#include <detours.h>
|
||||
#include <RayTrace.h>
|
||||
#include <Shared.h>
|
||||
#include <tasks.h>
|
||||
#include <commands/Commands.h>
|
||||
#include <dynlibutils/module.h>
|
||||
#include <events/Events.h>
|
||||
#include <schema/CGameRules.h>
|
||||
|
||||
class GameSessionConfiguration_t
|
||||
{
|
||||
};
|
||||
|
||||
namespace TemplatePlugin::Listeners {
|
||||
SourceHooks sourceHooks;
|
||||
|
||||
SH_DECL_HOOK3_void(IServerGameDLL, GameFrame, SH_NOATTRIB, 0, bool, bool, bool);
|
||||
SH_DECL_HOOK3_void(INetworkServerService, StartupServer, SH_NOATTRIB, 0, const GameSessionConfiguration_t&,
|
||||
ISource2WorldSession*, const char*);
|
||||
SH_DECL_HOOK2(IGameEventManager2, LoadEventsFromFile, SH_NOATTRIB, 0, int, const char*, bool);
|
||||
|
||||
int g_iLoadEventsFromFileId = -1;
|
||||
|
||||
void InitListeners() {
|
||||
SH_ADD_HOOK(IServerGameDLL, GameFrame, shared::g_pServer,
|
||||
SH_MEMBER(&sourceHooks,&SourceHooks::Hook_GameFrame), false);
|
||||
SH_ADD_HOOK(INetworkServerService, StartupServer, shared::g_pNetworkServerService,
|
||||
SH_MEMBER(&sourceHooks, &SourceHooks::Hook_StartupServer), true);
|
||||
auto pCGameEventManagerVTable = DynLibUtils::CModule(shared::g_pServer).
|
||||
GetVirtualTableByName("CGameEventManager").RCast<IGameEventManager2*>();
|
||||
g_iLoadEventsFromFileId = SH_ADD_DVPHOOK(IGameEventManager2, LoadEventsFromFile, pCGameEventManagerVTable,
|
||||
SH_MEMBER(&sourceHooks, &SourceHooks::Hook_LoadEventsFromFile), false);
|
||||
}
|
||||
|
||||
void DestructListeners() {
|
||||
SH_REMOVE_HOOK(IServerGameDLL, GameFrame, shared::g_pServer,
|
||||
SH_MEMBER(&sourceHooks,&SourceHooks::Hook_GameFrame), false);
|
||||
SH_REMOVE_HOOK(INetworkServerService, StartupServer, shared::g_pNetworkServerService,
|
||||
SH_MEMBER(&sourceHooks, &SourceHooks::Hook_StartupServer), true);
|
||||
SH_REMOVE_HOOK_ID(g_iLoadEventsFromFileId);
|
||||
}
|
||||
|
||||
void SourceHooks::Hook_GameFrame(bool simulating, bool bFirstTick, bool bLastTick)
|
||||
{
|
||||
Tasks::Tick(simulating);
|
||||
if (!shared::getGlobalVars())
|
||||
return;
|
||||
|
||||
shared::g_bHasTicked = true;
|
||||
|
||||
if (CCSGameRules::FindGameRules())
|
||||
CCSGameRules::FindGameRules()->m_bGameRestart =
|
||||
CCSGameRules::FindGameRules()->m_flRestartRoundTime < shared::GetCurrentTime();
|
||||
}
|
||||
|
||||
void SourceHooks::Hook_StartupServer(const GameSessionConfiguration_t& config,
|
||||
ISource2WorldSession*, const char*)
|
||||
{
|
||||
if (!shared::g_bDetoursLoaded)
|
||||
{
|
||||
shared::g_pEntitySystem = GameEntitySystem();
|
||||
shared::g_pEntitySystem->AddListenerEntity(&Detours::entityListener);
|
||||
Commands::InitCommands();
|
||||
Events::InitEvents();
|
||||
Detours::InitHooks();
|
||||
RayTrace::Initialize();
|
||||
shared::g_bDetoursLoaded = true;
|
||||
}
|
||||
if (shared::g_bHasTicked)
|
||||
{
|
||||
Tasks::RemoveMapChangeTimers();
|
||||
}
|
||||
shared::g_bHasTicked = false;
|
||||
}
|
||||
|
||||
int SourceHooks::Hook_LoadEventsFromFile(const char* filename, bool bSearchAll)
|
||||
{
|
||||
ExecuteOnce(shared::g_pGameEventManager = META_IFACEPTR(IGameEventManager2));
|
||||
RETURN_META_VALUE(MRES_IGNORED, 0);
|
||||
}
|
||||
}
|
||||
23
src/listeners/Listeners.h
Normal file
23
src/listeners/Listeners.h
Normal file
|
|
@ -0,0 +1,23 @@
|
|||
//
|
||||
// Created by Michal Přikryl on 09.07.2025.
|
||||
// Copyright (c) 2025 slynxcz. All rights reserved.
|
||||
//
|
||||
#pragma once
|
||||
#include <eiface.h>
|
||||
#include <sourcehook.h>
|
||||
#include <iserver.h>
|
||||
|
||||
namespace TemplatePlugin::Listeners {
|
||||
void InitListeners();
|
||||
|
||||
void DestructListeners();
|
||||
|
||||
class SourceHooks {
|
||||
public:
|
||||
void Hook_GameFrame(bool simulating, bool bFirstTick, bool bLastTick);
|
||||
void Hook_StartupServer(const GameSessionConfiguration_t& config, ISource2WorldSession*, const char*);
|
||||
int Hook_LoadEventsFromFile(const char* filename, bool bSearchAll);
|
||||
};
|
||||
|
||||
extern SourceHooks sourceHooks;
|
||||
}
|
||||
49
src/log.cpp
Normal file
49
src/log.cpp
Normal file
|
|
@ -0,0 +1,49 @@
|
|||
//
|
||||
// Created by Michal Přikryl on 22.12.2025.
|
||||
// Copyright (c) 2025 slynxcz. All rights reserved.
|
||||
//
|
||||
#include "log.h"
|
||||
|
||||
#include <spdlog/sinks/basic_file_sink.h>
|
||||
#include <spdlog/sinks/stdout_color_sinks.h>
|
||||
#include <spdlog/cfg/env.h>
|
||||
|
||||
#if defined(_WIN32)
|
||||
#include <windows.h>
|
||||
#endif
|
||||
|
||||
namespace TemplatePlugin {
|
||||
std::shared_ptr<spdlog::logger> Log::m_FP_logger;
|
||||
|
||||
void Log::Init() {
|
||||
#if defined(_WIN32)
|
||||
HANDLE hOut = GetStdHandle(STD_ERROR_HANDLE);
|
||||
DWORD dwMode = 0;
|
||||
if (GetConsoleMode(hOut, &dwMode))
|
||||
SetConsoleMode(hOut, dwMode | ENABLE_VIRTUAL_TERMINAL_PROCESSING);
|
||||
#endif
|
||||
|
||||
std::vector<spdlog::sink_ptr> sinks;
|
||||
|
||||
auto color_sink = std::make_shared<spdlog::sinks::stderr_color_sink_mt>();
|
||||
color_sink->set_pattern("%^[%T.%e] %n: %v%$");
|
||||
|
||||
auto file_sink = std::make_shared<spdlog::sinks::basic_file_sink_mt>("TemplatePlugin.log", true);
|
||||
file_sink->set_pattern("[%T.%e] [%^%l%$] %n: %v");
|
||||
|
||||
sinks.emplace_back(color_sink);
|
||||
sinks.emplace_back(file_sink);
|
||||
|
||||
m_FP_logger = std::make_shared<spdlog::logger>("TemplatePlugin", sinks.begin(), sinks.end());
|
||||
register_logger(m_FP_logger);
|
||||
m_FP_logger->set_level(spdlog::level::trace);
|
||||
m_FP_logger->flush_on(spdlog::level::info);
|
||||
|
||||
spdlog::cfg::load_env_levels();
|
||||
}
|
||||
|
||||
void Log::Close() {
|
||||
spdlog::drop("TemplatePlugin");
|
||||
m_FP_logger.reset();
|
||||
}
|
||||
}
|
||||
28
src/log.h
Normal file
28
src/log.h
Normal file
|
|
@ -0,0 +1,28 @@
|
|||
//
|
||||
// Created by Michal Přikryl on 22.12.2025.
|
||||
// Copyright (c) 2025 slynxcz. All rights reserved.
|
||||
//
|
||||
#pragma once
|
||||
|
||||
#include <memory>
|
||||
#include <spdlog/spdlog.h>
|
||||
|
||||
namespace TemplatePlugin {
|
||||
class Log {
|
||||
public:
|
||||
static void Init();
|
||||
static void Close();
|
||||
|
||||
static std::shared_ptr<spdlog::logger>& GetLogger() { return m_FP_logger; }
|
||||
|
||||
private:
|
||||
static std::shared_ptr<spdlog::logger> m_FP_logger;
|
||||
};
|
||||
}
|
||||
|
||||
#define FP_TRACE(fmt, ...) ::TemplatePlugin::Log::GetLogger()->trace("- [ " fmt " ] -", ##__VA_ARGS__)
|
||||
#define FP_DEBUG(fmt, ...) ::TemplatePlugin::Log::GetLogger()->debug("- [ " fmt " ] -", ##__VA_ARGS__)
|
||||
#define FP_INFO(fmt, ...) ::TemplatePlugin::Log::GetLogger()->info("- [ " fmt " ] -", ##__VA_ARGS__)
|
||||
#define FP_WARN(fmt, ...) ::TemplatePlugin::Log::GetLogger()->warn("- [ " fmt " ] -", ##__VA_ARGS__)
|
||||
#define FP_ERROR(fmt, ...) ::TemplatePlugin::Log::GetLogger()->error("- [ " fmt " ] -", ##__VA_ARGS__)
|
||||
#define FP_CRITICAL(fmt, ...) ::TemplatePlugin::Log::GetLogger()->critical("- [ " fmt " ] -", ##__VA_ARGS__)
|
||||
29
src/path.h
Normal file
29
src/path.h
Normal file
|
|
@ -0,0 +1,29 @@
|
|||
//
|
||||
// Created by Michal Přikryl on 19.06.2025.
|
||||
// Copyright (c) 2025 slynxcz. All rights reserved.
|
||||
//
|
||||
#pragma once
|
||||
|
||||
#include <eiface.h>
|
||||
#include <string>
|
||||
#include "Shared.h"
|
||||
|
||||
namespace TemplatePlugin::Paths {
|
||||
static std::string gameDirectory;
|
||||
|
||||
inline std::string GameDirectory() {
|
||||
if (gameDirectory.empty()) {
|
||||
CBufferStringGrowable<255> gamePath;
|
||||
shared::g_pEngine->GetGameDir(gamePath);
|
||||
gameDirectory = std::string(gamePath.Get());
|
||||
}
|
||||
return gameDirectory;
|
||||
}
|
||||
|
||||
inline std::string GetRootDirectory() { return GameDirectory() + "/addons/TemplatePlugin"; }
|
||||
inline std::string EnginePath() { return GameDirectory() + "../bin/linuxsteamrt64/libengine2.so"; }
|
||||
inline std::string Tier0Path() { return GameDirectory() + "../bin/linuxsteamrt64/libtier0.so"; }
|
||||
inline std::string ServerPath() { return GameDirectory() + "/bin/linuxsteamrt64/libserver.so"; }
|
||||
inline std::string SchemaSystemPath() { return GameDirectory() + "../bin/linuxsteamrt64/libschemasystem.so"; }
|
||||
inline std::string VScriptPath() { return GameDirectory() + "../bin/linuxsteamrt64/libvscript.so"; }
|
||||
} // namespace TemplatePlugin::Paths
|
||||
65
src/prints.cpp
Normal file
65
src/prints.cpp
Normal file
|
|
@ -0,0 +1,65 @@
|
|||
//
|
||||
// Created by Michal Přikryl on 10.07.2025.
|
||||
// Copyright (c) 2025 slynxcz. All rights reserved.
|
||||
//
|
||||
#include "prints.h"
|
||||
#include "PlayersData.h"
|
||||
#include <igameeventsystem.h>
|
||||
#include <regex>
|
||||
#include <networksystem/inetworkmessages.h>
|
||||
#include "usermessages.pb.h"
|
||||
#include "tier0/memdbgon.h"
|
||||
|
||||
namespace TemplatePlugin::Prints
|
||||
{
|
||||
std::string ReplaceColorTags(const std::string &input) {
|
||||
static const std::vector<std::pair<std::string, std::string> > tags = {
|
||||
{"[[DEFAULT]]", "\x01"}, {"[[DARKRED]]", "\x02"}, {"[[LIGHTPURPLE]]", "\x03"}, {"[[GREEN]]", "\x04"},
|
||||
{"[[OLIVE]]", "\x05"}, {"[[LIME]]", "\x06"}, {"[[RED]]", "\x07"}, {"[[GREY]]", "\x08"},
|
||||
{"[[YELLOW]]", "\x09"}, {"[[SILVER]]", "\x0A"}, {"[[BLUE]]", "\x0B"}, {"[[DARKBLUE]]", "\x0C"},
|
||||
{"[[ORANGE]]", "\x10"}, {"[[PURPLE]]", "\x0E"}
|
||||
};
|
||||
|
||||
std::string result = input;
|
||||
for (const auto &[tag, code]: tags) {
|
||||
size_t pos;
|
||||
while ((pos = result.find(tag)) != std::string::npos)
|
||||
result.replace(pos, tag.length(), code);
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
std::string ReplaceFormatTags(const std::string &input) {
|
||||
std::string result = ReplaceColorTags(input);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
void ChatToPlayer(CCSPlayerController* player, const std::string& msg)
|
||||
{
|
||||
if (!player || !player->CheckValid())
|
||||
return;
|
||||
|
||||
ClientPrintNative(player->GetPlayerSlot(), HudDestination::Chat, ReplaceColorTags(" " + msg).c_str());
|
||||
}
|
||||
|
||||
void ClientPrintNative(CPlayerSlot slot, HudDestination dest, const char* msg)
|
||||
{
|
||||
INetworkMessageInternal* pNetMsg = shared::g_pNetworkMessages->FindNetworkMessagePartial("TextMsg");
|
||||
auto data = pNetMsg->AllocateMessage()->ToPB<CUserMessageTextMsg>();
|
||||
data->set_dest(static_cast<google::protobuf::uint32>(dest));
|
||||
data->add_param(msg);
|
||||
|
||||
CPlayerBitVec recipients;
|
||||
recipients.Set(slot.Get());
|
||||
|
||||
shared::g_pGameEventSystem->PostEventAbstract(
|
||||
CSplitScreenSlot(-1), false, ABSOLUTE_PLAYER_LIMIT,
|
||||
reinterpret_cast<const uint64*>(recipients.Base()), pNetMsg, data,
|
||||
0, BUF_RELIABLE
|
||||
);
|
||||
|
||||
delete data;
|
||||
}
|
||||
}
|
||||
35
src/prints.h
Normal file
35
src/prints.h
Normal file
|
|
@ -0,0 +1,35 @@
|
|||
//
|
||||
// Created by Michal Přikryl on 10.07.2025.
|
||||
// Copyright (c) 2025 slynxcz. All rights reserved.
|
||||
//
|
||||
#pragma once
|
||||
#include <string>
|
||||
#include <vector>
|
||||
#include "schema/CCSPlayerController.h"
|
||||
#include "log.h"
|
||||
|
||||
namespace TemplatePlugin::Prints
|
||||
{
|
||||
enum class HudDestination : int
|
||||
{
|
||||
Center = 1,
|
||||
Alert = 2,
|
||||
Chat = 3
|
||||
};
|
||||
|
||||
void ClientPrintNative(CPlayerSlot slot, HudDestination dest, const char* msg);
|
||||
|
||||
std::string ReplaceColorTags(const std::string& input);
|
||||
|
||||
std::string ReplaceFormatTags(const std::string &input);
|
||||
|
||||
template<typename... Args>
|
||||
std::string FormatMessage(fmt::format_string<Args...> fmtStr, Args &&... args) {
|
||||
std::string formatted = fmt::format(fmtStr, std::forward<Args>(args)...);
|
||||
return ReplaceFormatTags(formatted);
|
||||
}
|
||||
|
||||
inline const char* PrefixCl() { return "[[DARKRED]][!][[DEFAULT]] "; }
|
||||
|
||||
void ChatToPlayer(CCSPlayerController* player, const std::string& msg);
|
||||
}
|
||||
45
src/schema/CBaseAnimGraph.h
Normal file
45
src/schema/CBaseAnimGraph.h
Normal file
|
|
@ -0,0 +1,45 @@
|
|||
//
|
||||
// Created by Michal Přikryl on 26.06.2025.
|
||||
// Copyright (c) 2025 slynxcz. All rights reserved.
|
||||
//
|
||||
#pragma once
|
||||
#include "CBaseEntity.h"
|
||||
#include "globaltypes.h"
|
||||
#include "CBaseModelEntity.h"
|
||||
|
||||
namespace
|
||||
TemplatePlugin
|
||||
{
|
||||
class IChoreoServices
|
||||
{
|
||||
DECLARE_SCHEMA_CLASS(IChoreoServices)
|
||||
};
|
||||
|
||||
class PhysicsRagdollPose_t
|
||||
{
|
||||
DECLARE_SCHEMA_CLASS(PhysicsRagdollPose_t)
|
||||
|
||||
SCHEMA_FIELD_POINTER(CUtlVector<CTransform>, m_Transforms)
|
||||
SCHEMA_FIELD(CHandle<CBaseEntity>, m_hOwner)
|
||||
SCHEMA_FIELD(bool, m_bSetFromDebugHistory)
|
||||
};
|
||||
|
||||
class CBaseAnimGraph : public CBaseModelEntity
|
||||
{
|
||||
public:
|
||||
DECLARE_SCHEMA_CLASS(CBaseAnimGraph)
|
||||
|
||||
SCHEMA_FIELD(bool, m_bInitiallyPopulateInterpHistory)
|
||||
SCHEMA_FIELD(IChoreoServices *, m_pChoreoServices)
|
||||
SCHEMA_FIELD(bool, m_bAnimGraphUpdateEnabled)
|
||||
SCHEMA_FIELD(float, m_flMaxSlopeDistance)
|
||||
SCHEMA_FIELD(Vector, m_vLastSlopeCheckPos)
|
||||
SCHEMA_FIELD(bool, m_bAnimationUpdateScheduled)
|
||||
SCHEMA_FIELD(Vector, m_vecForce)
|
||||
SCHEMA_FIELD(int32, m_nForceBone)
|
||||
SCHEMA_FIELD(PhysicsRagdollPose_t, m_RagdollPose)
|
||||
SCHEMA_FIELD(bool, m_bRagdollEnabled)
|
||||
SCHEMA_FIELD(bool, m_bRagdollClientSide)
|
||||
SCHEMA_FIELD(CTransform, m_xParentedRagdollRootInEntitySpace)
|
||||
};
|
||||
}
|
||||
53
src/schema/CBaseButton.h
Normal file
53
src/schema/CBaseButton.h
Normal file
|
|
@ -0,0 +1,53 @@
|
|||
//
|
||||
// Created by Michal Přikryl on 07.11.2025.
|
||||
// Copyright (c) 2025 slynxcz. All rights reserved.
|
||||
//
|
||||
#pragma once
|
||||
#include "CBaseTrigger.h"
|
||||
#include "globaltypes.h"
|
||||
|
||||
namespace
|
||||
TemplatePlugin
|
||||
{
|
||||
class locksound_t
|
||||
{
|
||||
public:
|
||||
DECLARE_SCHEMA_CLASS(locksound_t);
|
||||
|
||||
SCHEMA_FIELD_POINTER(char, sLockedSound)
|
||||
SCHEMA_FIELD_POINTER(char, sUnlockedSound)
|
||||
SCHEMA_FIELD(float, flwaitSound)
|
||||
};
|
||||
|
||||
class CBaseButton : public CBaseToggle
|
||||
{
|
||||
public:
|
||||
DECLARE_SCHEMA_CLASS(CBaseButton);
|
||||
|
||||
SCHEMA_FIELD(QAngle, m_angMoveEntitySpace)
|
||||
SCHEMA_FIELD(bool, m_fStayPushed)
|
||||
SCHEMA_FIELD(bool, m_fRotating)
|
||||
SCHEMA_FIELD(locksound_t, m_ls)
|
||||
SCHEMA_FIELD_POINTER(char, m_sUseSound)
|
||||
SCHEMA_FIELD_POINTER(char, m_sLockedSound)
|
||||
SCHEMA_FIELD_POINTER(char, m_sUnlockedSound)
|
||||
SCHEMA_FIELD_POINTER(char, m_sOverrideAnticipationName)
|
||||
SCHEMA_FIELD(bool, m_bLocked)
|
||||
SCHEMA_FIELD(bool, m_bDisabled)
|
||||
SCHEMA_FIELD(float, m_flUseLockedTime)
|
||||
SCHEMA_FIELD(bool, m_bSolidBsp)
|
||||
SCHEMA_FIELD(CEntityIOOutput, m_OnDamaged)
|
||||
SCHEMA_FIELD(CEntityIOOutput, m_OnPressed)
|
||||
SCHEMA_FIELD(CEntityIOOutput, m_OnUseLocked)
|
||||
SCHEMA_FIELD(CEntityIOOutput, m_OnIn)
|
||||
SCHEMA_FIELD(CEntityIOOutput, m_OnOut)
|
||||
SCHEMA_FIELD(int32, m_nState)
|
||||
SCHEMA_FIELD(CHandle<CEntityInstance>, m_hConstraint)
|
||||
SCHEMA_FIELD(CHandle<CEntityInstance>, m_hConstraintParent)
|
||||
SCHEMA_FIELD(bool, m_bForceNpcExclude)
|
||||
SCHEMA_FIELD_POINTER(char, m_sGlowEntity)
|
||||
SCHEMA_FIELD(CHandle<CBaseModelEntity>, m_glowEntity)
|
||||
SCHEMA_FIELD(bool, m_usable)
|
||||
SCHEMA_FIELD_POINTER(char, m_szDisplayText)
|
||||
};
|
||||
}
|
||||
485
src/schema/CBaseEntity.h
Normal file
485
src/schema/CBaseEntity.h
Normal file
|
|
@ -0,0 +1,485 @@
|
|||
//
|
||||
// Created by Michal Přikryl on 26.06.2025.
|
||||
// Copyright (c) 2025 slynxcz. All rights reserved.
|
||||
//
|
||||
#pragma once
|
||||
#include <entitysystem.h>
|
||||
#include <entity2/entityidentity.h>
|
||||
#include "mathlib/vector.h"
|
||||
#include "schemasystem.h"
|
||||
#include "ccollisionproperty.h"
|
||||
#include "globaltypes.h"
|
||||
#include "ctakedamageinfo.h"
|
||||
#include "virtual.h"
|
||||
#include "dynlibutils/module.h"
|
||||
#include "Shared.h"
|
||||
|
||||
namespace
|
||||
TemplatePlugin
|
||||
{
|
||||
using UTIL_CreateEntityByName_t = CEntityInstance* (*)(const char* /*name*/, int /*forceEdictIndex*/);
|
||||
inline UTIL_CreateEntityByName_t g_UTIL_CreateEntityByName = nullptr;
|
||||
|
||||
template <typename T>
|
||||
inline T* UTIL_CreateEntityByName(const char* name)
|
||||
{
|
||||
if (!g_UTIL_CreateEntityByName)
|
||||
{
|
||||
UTIL_CreateEntityByName_t addr = DynLibUtils::CModule(shared::g_pServer).FindPattern(
|
||||
shared::g_pGameConfig->GetSignature("UTIL_CreateEntityByName")).RCast<UTIL_CreateEntityByName_t>();
|
||||
|
||||
if (!addr)
|
||||
return nullptr;
|
||||
|
||||
g_UTIL_CreateEntityByName = addr;
|
||||
}
|
||||
return reinterpret_cast<T*>(g_UTIL_CreateEntityByName(name, -1));
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
inline std::vector<T*> UTIL_FindAllEntitiesByDesignerName(const char* designerName)
|
||||
{
|
||||
std::vector<T*> results;
|
||||
|
||||
if (!designerName || !shared::g_pEntitySystem)
|
||||
return results;
|
||||
|
||||
auto* it = shared::g_pEntitySystem->m_EntityList.m_pFirstActiveEntity;
|
||||
for (; it; it = it->m_pNext)
|
||||
{
|
||||
if (!it->m_pInstance) continue;
|
||||
|
||||
const char* dn = it->m_designerName.String();
|
||||
if (!dn) continue;
|
||||
|
||||
if (std::strcmp(dn, designerName) == 0)
|
||||
results.push_back((T*)it->m_pInstance);
|
||||
}
|
||||
|
||||
return results;
|
||||
}
|
||||
|
||||
inline CEntityInstance* UTIL_GetEntityByIndex(int index)
|
||||
{
|
||||
if (!shared::g_pEntitySystem) return nullptr;
|
||||
CEntityIdentity* pEntity = shared::g_pEntitySystem->m_EntityList.m_pFirstActiveEntity;
|
||||
|
||||
for (; pEntity; pEntity = pEntity->m_pNext)
|
||||
{
|
||||
if (pEntity->m_EHandle.GetEntryIndex() == index)
|
||||
return pEntity->m_pInstance;
|
||||
};
|
||||
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
inline CEntityInstance* UTIL_FindEntityByClassname(const char* name)
|
||||
{
|
||||
if (!shared::g_pEntitySystem) return nullptr;
|
||||
CEntityIdentity* pEntity = shared::g_pEntitySystem->m_EntityList.m_pFirstActiveEntity;
|
||||
|
||||
for (; pEntity; pEntity = pEntity->m_pNext)
|
||||
{
|
||||
if (!strcmp(pEntity->m_designerName.String(), name))
|
||||
return pEntity->m_pInstance;
|
||||
};
|
||||
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
inline CEntityInstance* UTIL_FindEntityByEHandle(CEntityInstance* pFind)
|
||||
{
|
||||
if (!shared::g_pEntitySystem) return nullptr;
|
||||
CEntityIdentity* pEntity = shared::g_pEntitySystem->m_EntityList.m_pFirstActiveEntity;
|
||||
|
||||
for (; pEntity; pEntity = pEntity->m_pNext)
|
||||
{
|
||||
if (pEntity->GetRefEHandle() == pFind)
|
||||
return pEntity->m_pInstance;
|
||||
};
|
||||
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
typedef void (*CEntityInstance_AcceptInput_t)(CEntityInstance* pThis, const char* pInputName,
|
||||
CEntityInstance* pActivator, CEntityInstance* pCaller,
|
||||
const variant_t& pValue, int nOutputID, void* pUnk1);
|
||||
inline CEntityInstance_AcceptInput_t g_CEntityInstance_AcceptInput = nullptr;
|
||||
|
||||
typedef void (*CEntitySystem_AddEntityIOEvent_t)(CEntitySystem* pEntitySystem, CEntityInstance* pThis,
|
||||
const char* pInputName, CEntityInstance* pActivator,
|
||||
CEntityInstance* pCaller, const variant_t& pValue, float delay,
|
||||
int nOutputID, void* pUnk1, void* pUnk2);
|
||||
inline CEntitySystem_AddEntityIOEvent_t g_CEntitySystem_AddEntityIOEvent = nullptr;
|
||||
|
||||
|
||||
class CGameSceneNode
|
||||
{
|
||||
public:
|
||||
DECLARE_SCHEMA_CLASS(CGameSceneNode)
|
||||
|
||||
SCHEMA_FIELD(CEntityInstance*, m_pOwner);
|
||||
|
||||
SCHEMA_FIELD(CGameSceneNode*, m_pParent);
|
||||
|
||||
SCHEMA_FIELD(CGameSceneNode*, m_pChild);
|
||||
|
||||
SCHEMA_FIELD(CNetworkOriginCellCoordQuantizedVector, m_vecOrigin);
|
||||
|
||||
SCHEMA_FIELD(QAngle, m_angRotation);
|
||||
|
||||
SCHEMA_FIELD(float, m_flScale);
|
||||
|
||||
SCHEMA_FIELD(float, m_flAbsScale);
|
||||
|
||||
SCHEMA_FIELD(Vector, m_vecAbsOrigin);
|
||||
|
||||
SCHEMA_FIELD(QAngle, m_angAbsRotation);
|
||||
|
||||
SCHEMA_FIELD(Vector, m_vRenderOrigin);
|
||||
|
||||
matrix3x4_t EntityToWorldTransform()
|
||||
{
|
||||
matrix3x4_t mat;
|
||||
|
||||
QAngle angles = this->m_angAbsRotation();
|
||||
float sr, sp, sy, cr, cp, cy;
|
||||
SinCos(DEG2RAD(angles[YAW]), &sy, &cy);
|
||||
SinCos(DEG2RAD(angles[PITCH]), &sp, &cp);
|
||||
SinCos(DEG2RAD(angles[ROLL]), &sr, &cr);
|
||||
mat[0][0] = cp * cy;
|
||||
mat[1][0] = cp * sy;
|
||||
mat[2][0] = -sp;
|
||||
|
||||
float crcy = cr * cy;
|
||||
float crsy = cr * sy;
|
||||
float srcy = sr * cy;
|
||||
float srsy = sr * sy;
|
||||
mat[0][1] = sp * srcy - crsy;
|
||||
mat[1][1] = sp * srsy + crcy;
|
||||
mat[2][1] = sr * cp;
|
||||
|
||||
mat[0][2] = (sp * crcy + srsy);
|
||||
mat[1][2] = (sp * crsy - srcy);
|
||||
mat[2][2] = cr * cp;
|
||||
|
||||
Vector pos = this->m_vecAbsOrigin();
|
||||
mat[0][3] = pos.x;
|
||||
mat[1][3] = pos.y;
|
||||
mat[2][3] = pos.z;
|
||||
|
||||
return mat;
|
||||
}
|
||||
};
|
||||
|
||||
class CBodyComponent
|
||||
{
|
||||
public:
|
||||
DECLARE_SCHEMA_CLASS(CBodyComponent)
|
||||
|
||||
SCHEMA_FIELD(CGameSceneNode *, m_pSceneNode);
|
||||
};
|
||||
|
||||
class CModelState
|
||||
{
|
||||
public:
|
||||
DECLARE_SCHEMA_CLASS(CModelState)
|
||||
|
||||
SCHEMA_FIELD(CUtlSymbolLarge, m_ModelName)
|
||||
|
||||
SCHEMA_FIELD(uint64, m_MeshGroupMask)
|
||||
};
|
||||
|
||||
class CSkeletonInstance : public CGameSceneNode
|
||||
{
|
||||
public:
|
||||
DECLARE_SCHEMA_CLASS(CSkeletonInstance)
|
||||
|
||||
SCHEMA_FIELD(CModelState, m_modelState)
|
||||
};
|
||||
|
||||
class CEntitySubclassVDataBase
|
||||
{
|
||||
public:
|
||||
DECLARE_SCHEMA_CLASS(CEntitySubclassVDataBase)
|
||||
};
|
||||
|
||||
class CBaseEntity : public CEntityInstance
|
||||
{
|
||||
public:
|
||||
DECLARE_SCHEMA_CLASS(CBaseEntity)
|
||||
|
||||
SCHEMA_FIELD(float32, m_flSimulationTime)
|
||||
|
||||
SCHEMA_FIELD(float, m_flCreateTime);
|
||||
|
||||
SCHEMA_FIELD(CBodyComponent *, m_CBodyComponent)
|
||||
|
||||
SCHEMA_FIELD(CBitVec<64>, m_isSteadyState)
|
||||
|
||||
SCHEMA_FIELD(float, m_lastNetworkChange)
|
||||
|
||||
SCHEMA_FIELD_POINTER(CNetworkTransmitComponent, m_NetworkTransmitComponent)
|
||||
|
||||
SCHEMA_FIELD_POINTER(char, m_iszDamageFilterName);
|
||||
|
||||
SCHEMA_FIELD(int, m_iHealth)
|
||||
|
||||
SCHEMA_FIELD(int, m_iMaxHealth)
|
||||
|
||||
SCHEMA_FIELD(int, m_iTeamNum)
|
||||
|
||||
SCHEMA_FIELD(bool, m_bLagCompensate)
|
||||
|
||||
SCHEMA_FIELD(Vector, m_vecAbsVelocity)
|
||||
|
||||
SCHEMA_FIELD(Vector, m_vecBaseVelocity)
|
||||
|
||||
SCHEMA_FIELD(CCollisionProperty*, m_pCollision)
|
||||
|
||||
SCHEMA_FIELD(MoveCollide_t, m_MoveCollide)
|
||||
|
||||
SCHEMA_FIELD(MoveType_t, m_MoveType)
|
||||
|
||||
SCHEMA_FIELD(MoveType_t, m_nActualMoveType)
|
||||
|
||||
SCHEMA_FIELD(CHandle<CBaseEntity>, m_hEffectEntity)
|
||||
|
||||
SCHEMA_FIELD(uint32, m_spawnflags)
|
||||
|
||||
SCHEMA_FIELD(uint32, m_fFlags)
|
||||
|
||||
SCHEMA_FIELD(LifeState_t, m_lifeState)
|
||||
|
||||
SCHEMA_FIELD(float, m_flDamageAccumulator)
|
||||
|
||||
SCHEMA_FIELD(bool, m_bTakesDamage)
|
||||
|
||||
SCHEMA_FIELD(TakeDamageFlags_t, m_nTakeDamageFlags)
|
||||
|
||||
SCHEMA_FIELD_POINTER(CUtlStringToken, m_nSubclassID)
|
||||
|
||||
SCHEMA_FIELD(float, m_flFriction)
|
||||
|
||||
SCHEMA_FIELD(float, m_flActualGravityScale)
|
||||
|
||||
SCHEMA_FIELD(float, m_flTimeScale)
|
||||
|
||||
SCHEMA_FIELD(float, m_flSpeed)
|
||||
|
||||
SCHEMA_FIELD(CUtlString, m_sUniqueHammerID)
|
||||
|
||||
SCHEMA_FIELD(CUtlSymbolLarge, m_target)
|
||||
|
||||
SCHEMA_FIELD(CUtlSymbolLarge, m_iGlobalname)
|
||||
|
||||
SCHEMA_FIELD(CHandle<CBaseEntity>, m_hOwnerEntity)
|
||||
|
||||
SCHEMA_FIELD(CHandle<CBaseEntity>, m_hGroundEntity);
|
||||
|
||||
SCHEMA_FIELD(uint32, m_fEffects)
|
||||
|
||||
SCHEMA_FIELD(QAngle, m_vecAngVelocity)
|
||||
|
||||
// ---------------------------
|
||||
// Flag helpers
|
||||
// ---------------------------
|
||||
void SetFlags(uint32_t mask)
|
||||
{
|
||||
auto& flags = m_fFlags();
|
||||
flags = mask;
|
||||
}
|
||||
|
||||
void AddFlags(uint32_t mask)
|
||||
{
|
||||
auto& flags = m_fFlags();
|
||||
flags |= mask;
|
||||
}
|
||||
|
||||
void ClearFlags(uint32_t mask)
|
||||
{
|
||||
auto& flags = m_fFlags();
|
||||
flags &= ~mask;
|
||||
}
|
||||
|
||||
bool HasFlags(uint32_t mask) const
|
||||
{
|
||||
return (const_cast<CBaseEntity*>(this)->m_fFlags() & mask) == mask;
|
||||
}
|
||||
|
||||
uint32_t GetFlags() const
|
||||
{
|
||||
return const_cast<CBaseEntity*>(this)->m_fFlags();
|
||||
}
|
||||
|
||||
// ---------------------------
|
||||
// Basic entity info
|
||||
// ---------------------------
|
||||
Vector GetAbsOrigin()
|
||||
{
|
||||
if (!m_CBodyComponent) return Vector{};
|
||||
if (!m_CBodyComponent->m_pSceneNode) return Vector{};
|
||||
return m_CBodyComponent->m_pSceneNode->m_vecAbsOrigin();
|
||||
}
|
||||
|
||||
QAngle GetAngRotation()
|
||||
{
|
||||
if (!m_CBodyComponent) return QAngle{};
|
||||
if (!m_CBodyComponent->m_pSceneNode) return QAngle{};
|
||||
return m_CBodyComponent->m_pSceneNode->m_angRotation();
|
||||
}
|
||||
|
||||
QAngle GetAbsRotation()
|
||||
{
|
||||
if (!m_CBodyComponent) return QAngle{};
|
||||
if (!m_CBodyComponent->m_pSceneNode) return QAngle{};
|
||||
return m_CBodyComponent->m_pSceneNode->m_angAbsRotation();
|
||||
}
|
||||
|
||||
Vector GetAbsVelocity() { return m_vecAbsVelocity; }
|
||||
|
||||
void SetAbsOrigin(const Vector& vecOrigin)
|
||||
{
|
||||
if (!m_CBodyComponent) return;
|
||||
if (!m_CBodyComponent->m_pSceneNode) return;
|
||||
m_CBodyComponent->m_pSceneNode->m_vecAbsOrigin(vecOrigin);
|
||||
}
|
||||
|
||||
void SetAbsRotation(const QAngle& angAbsRotation)
|
||||
{
|
||||
if (!m_CBodyComponent) return;
|
||||
if (!m_CBodyComponent->m_pSceneNode) return;
|
||||
m_CBodyComponent->m_pSceneNode->m_angAbsRotation(angAbsRotation);
|
||||
}
|
||||
|
||||
void SetAngRotation(const QAngle& angRotation)
|
||||
{
|
||||
if (!m_CBodyComponent) return;
|
||||
if (!m_CBodyComponent->m_pSceneNode) return;
|
||||
m_CBodyComponent->m_pSceneNode->m_angRotation(angRotation);
|
||||
}
|
||||
|
||||
void SetAbsVelocity(const Vector& vecVelocity) { m_vecAbsVelocity = vecVelocity; }
|
||||
|
||||
void SetBaseVelocity(const Vector& vecVelocity) { m_vecBaseVelocity = vecVelocity; }
|
||||
|
||||
CEntitySubclassVDataBase* GetVData()
|
||||
{
|
||||
return *(CEntitySubclassVDataBase**)((uint8*)(m_nSubclassID()) + 4);
|
||||
}
|
||||
|
||||
// ---------------------------
|
||||
// Engine calls
|
||||
// ---------------------------
|
||||
void Teleport(const Vector* position, const QAngle* angles, const Vector* velocity)
|
||||
{
|
||||
static int offset = shared::g_pGameConfig->GetOffset("CBaseEntity_Teleport");
|
||||
CALL_VIRTUAL(void, offset, this, position, angles, velocity);
|
||||
}
|
||||
|
||||
void SetMoveType(MoveType_t nMoveType)
|
||||
{
|
||||
m_MoveType() = nMoveType;
|
||||
m_nActualMoveType() = nMoveType;
|
||||
}
|
||||
|
||||
void CollisionRulesChanged()
|
||||
{
|
||||
static int offset = shared::g_pGameConfig->GetOffset("CBaseEntity_CollisionRulesChanged");
|
||||
CALL_VIRTUAL(void, offset, this);
|
||||
}
|
||||
|
||||
int GetTeam() { return m_iTeamNum(); }
|
||||
bool IsAlive() { return m_lifeState() == LifeState_t::LIFE_ALIVE; }
|
||||
|
||||
CHandle<CBaseEntity> GetHandle() const { return m_pEntity->m_EHandle; }
|
||||
|
||||
const char* GetName() const { return m_pEntity->m_name.String(); }
|
||||
const char* GetDesignerName() const { return m_pEntity ? m_pEntity->m_designerName.String() : ""; }
|
||||
|
||||
// ---------------------------
|
||||
// Detours
|
||||
// ---------------------------
|
||||
void DispatchSpawn()
|
||||
{
|
||||
using DispatchSpawn_t = void (*)(CBaseEntity* /*self*/, void* /*pMapData*/);
|
||||
static DispatchSpawn_t s_DispatchSpawn = nullptr;
|
||||
|
||||
if (!s_DispatchSpawn)
|
||||
{
|
||||
DispatchSpawn_t addr = DynLibUtils::CModule(shared::g_pServer).FindPattern(
|
||||
shared::g_pGameConfig->GetSignature("CBaseEntity_DispatchSpawn")).RCast<DispatchSpawn_t>();
|
||||
if (!addr) return;
|
||||
s_DispatchSpawn = addr;
|
||||
}
|
||||
|
||||
s_DispatchSpawn(this, nullptr);
|
||||
}
|
||||
|
||||
void AcceptInput(const char* pInputName, CEntityInstance* pActivator = nullptr,
|
||||
CEntityInstance* pCaller = nullptr, const char* value = "")
|
||||
{
|
||||
if (!g_CEntityInstance_AcceptInput)
|
||||
{
|
||||
g_CEntityInstance_AcceptInput =
|
||||
DynLibUtils::CModule(shared::g_pServer)
|
||||
.FindPattern(shared::g_pGameConfig->GetSignature("CEntityInstance_AcceptInput"))
|
||||
.RCast<CEntityInstance_AcceptInput_t>();
|
||||
|
||||
if (!g_CEntityInstance_AcceptInput)
|
||||
return;
|
||||
}
|
||||
|
||||
g_CEntityInstance_AcceptInput(this, pInputName, pActivator, pCaller, variant_t(value), 0, 0LL);
|
||||
}
|
||||
|
||||
void AddEntityIOEvent(const char* pInputName, CEntityInstance* pActivator = nullptr,
|
||||
CEntityInstance* pCaller = nullptr, const char* value = "", float flDelay = 0.0)
|
||||
{
|
||||
if (!g_CEntitySystem_AddEntityIOEvent)
|
||||
{
|
||||
g_CEntitySystem_AddEntityIOEvent =
|
||||
DynLibUtils::CModule(shared::g_pServer)
|
||||
.FindPattern(shared::g_pGameConfig->GetSignature("CEntitySystem_AddEntityIOEvent"))
|
||||
.RCast<CEntitySystem_AddEntityIOEvent_t>();
|
||||
|
||||
if (!g_CEntitySystem_AddEntityIOEvent)
|
||||
return;
|
||||
}
|
||||
|
||||
g_CEntitySystem_AddEntityIOEvent(shared::g_pEntitySystem, this, pInputName, pActivator, pCaller,
|
||||
variant_t(value), flDelay, 0,
|
||||
0LL, 0LL);
|
||||
}
|
||||
};
|
||||
|
||||
class CBodyComponentSkeletonInstance : public CBodyComponent
|
||||
{
|
||||
public:
|
||||
DECLARE_SCHEMA_CLASS(CBodyComponentSkeletonInstance);
|
||||
};
|
||||
|
||||
class CBaseAnimGraphController
|
||||
{
|
||||
public:
|
||||
DECLARE_SCHEMA_CLASS_INLINE(CBaseAnimGraphController);
|
||||
|
||||
SCHEMA_FIELD(float, m_flPlaybackRate);
|
||||
};
|
||||
|
||||
class CBodyComponentBaseAnimGraph : public CBodyComponentSkeletonInstance
|
||||
{
|
||||
public:
|
||||
DECLARE_SCHEMA_CLASS(CBodyComponentBaseAnimGraph);
|
||||
|
||||
SCHEMA_FIELD(CBaseAnimGraphController, m_animationController);
|
||||
};
|
||||
|
||||
class SpawnPoint : public CBaseEntity
|
||||
{
|
||||
public:
|
||||
DECLARE_SCHEMA_CLASS(SpawnPoint);
|
||||
|
||||
SCHEMA_FIELD(bool, m_bEnabled);
|
||||
};
|
||||
}
|
||||
21
src/schema/CBaseFilter.h
Normal file
21
src/schema/CBaseFilter.h
Normal file
|
|
@ -0,0 +1,21 @@
|
|||
//
|
||||
// Created by Michal Přikryl on 07.11.2025.
|
||||
// Copyright (c) 2025 slynxcz. All rights reserved.
|
||||
//
|
||||
#pragma once
|
||||
#include "CBaseTrigger.h"
|
||||
#include "globaltypes.h"
|
||||
|
||||
namespace
|
||||
TemplatePlugin
|
||||
{
|
||||
class CBaseFilter : public CBaseEntity
|
||||
{
|
||||
public:
|
||||
DECLARE_SCHEMA_CLASS(CBaseFilter);
|
||||
|
||||
SCHEMA_FIELD(bool, m_bNegated)
|
||||
SCHEMA_FIELD(CEntityIOOutput, m_OnPass)
|
||||
SCHEMA_FIELD(CEntityIOOutput, m_OnFail)
|
||||
};
|
||||
}
|
||||
33
src/schema/CBaseGrenade.h
Normal file
33
src/schema/CBaseGrenade.h
Normal file
|
|
@ -0,0 +1,33 @@
|
|||
//
|
||||
// Created by Michal Přikryl on 26.06.2025.
|
||||
// Copyright (c) 2025 slynxcz. All rights reserved.
|
||||
//
|
||||
#pragma once
|
||||
#include "CBaseModelEntity.h"
|
||||
#include "CBasePlayerPawn.h"
|
||||
#include "globaltypes.h"
|
||||
|
||||
namespace TemplatePlugin {
|
||||
class CBaseGrenade : public CBaseModelEntity
|
||||
{
|
||||
public:
|
||||
DECLARE_SCHEMA_CLASS(CBaseGrenade);
|
||||
SCHEMA_FIELD(CHandle<CCSPlayerPawn>, m_hThrower);
|
||||
SCHEMA_FIELD(float, m_flDamage);
|
||||
SCHEMA_FIELD(float, m_DmgRadius);
|
||||
};
|
||||
|
||||
class CBaseCSGrenadeProjectile : public CBaseGrenade
|
||||
{
|
||||
public:
|
||||
DECLARE_SCHEMA_CLASS(CBaseCSGrenadeProjectile);
|
||||
};
|
||||
|
||||
class CSmokeGrenadeProjectile : public CBaseCSGrenadeProjectile
|
||||
{
|
||||
public:
|
||||
DECLARE_SCHEMA_CLASS(CSmokeGrenadeProjectile);
|
||||
SCHEMA_FIELD(Vector, m_vSmokeColor);
|
||||
SCHEMA_FIELD(int, m_nSmokeEffectTickBegin);
|
||||
};
|
||||
}
|
||||
89
src/schema/CBaseModelEntity.h
Normal file
89
src/schema/CBaseModelEntity.h
Normal file
|
|
@ -0,0 +1,89 @@
|
|||
//
|
||||
// Created by Michal Přikryl on 26.06.2025.
|
||||
// Copyright (c) 2025 slynxcz. All rights reserved.
|
||||
//
|
||||
#pragma once
|
||||
#include "CBaseEntity.h"
|
||||
#include "globaltypes.h"
|
||||
|
||||
namespace
|
||||
TemplatePlugin
|
||||
{
|
||||
class CBaseModelEntity : public CBaseEntity
|
||||
{
|
||||
public:
|
||||
DECLARE_SCHEMA_CLASS(CBaseModelEntity);
|
||||
|
||||
SCHEMA_FIELD(CCollisionProperty, m_Collision)
|
||||
|
||||
SCHEMA_FIELD(CGlowProperty, m_Glow)
|
||||
|
||||
SCHEMA_FIELD(Color, m_clrRender)
|
||||
|
||||
SCHEMA_FIELD(RenderMode_t, m_nRenderMode)
|
||||
|
||||
SCHEMA_FIELD(RenderFx_t, m_nRenderFX)
|
||||
|
||||
SCHEMA_FIELD(float, m_flDissolveStartTime)
|
||||
|
||||
SCHEMA_FIELD(Vector, m_vecViewOffset)
|
||||
|
||||
SCHEMA_FIELD(float32, m_flShadowStrength)
|
||||
|
||||
void SetModel(const char* model)
|
||||
{
|
||||
using SetModel_t = void (*)(CBaseModelEntity*, const char*);
|
||||
static SetModel_t s_SetModel = nullptr;
|
||||
|
||||
if (!s_SetModel)
|
||||
{
|
||||
SetModel_t addr =
|
||||
DynLibUtils::CModule(shared::g_pServer)
|
||||
.FindPattern(shared::g_pGameConfig->GetSignature("CBaseModelEntity_SetModel"))
|
||||
.RCast<SetModel_t>();
|
||||
|
||||
if (!addr) return;
|
||||
s_SetModel = addr;
|
||||
}
|
||||
|
||||
s_SetModel(this, model);
|
||||
}
|
||||
|
||||
void SetBodyGroup(std::string name, int value)
|
||||
{
|
||||
char bodygroupStr[64];
|
||||
g_SMAPI->Format(bodygroupStr, sizeof(bodygroupStr), "%s,%i", name.c_str(), value);
|
||||
this->AcceptInput(
|
||||
"SetBodyGroup",
|
||||
this,
|
||||
this,
|
||||
bodygroupStr
|
||||
);
|
||||
}
|
||||
|
||||
CUtlSymbolLarge GetModelName()
|
||||
{
|
||||
if (m_CBodyComponent == nullptr) return CUtlSymbolLarge();
|
||||
if (m_CBodyComponent->m_pSceneNode == nullptr) return CUtlSymbolLarge();
|
||||
if (((CSkeletonInstance*)m_CBodyComponent->m_pSceneNode.Get()) == nullptr) return CUtlSymbolLarge();
|
||||
return ((CSkeletonInstance*)m_CBodyComponent->m_pSceneNode.Get())->m_modelState().m_ModelName.Get();
|
||||
}
|
||||
|
||||
Vector GetEyePosition()
|
||||
{
|
||||
const auto x = m_vecViewOffset();
|
||||
return x + GetAbsOrigin();
|
||||
}
|
||||
};
|
||||
|
||||
class CBeam : public CBaseModelEntity
|
||||
{
|
||||
public:
|
||||
DECLARE_SCHEMA_CLASS(CBeam);
|
||||
SCHEMA_FIELD(Vector, m_vecEndPos);
|
||||
|
||||
SCHEMA_FIELD(float, m_fWidth);
|
||||
|
||||
SCHEMA_FIELD(float, m_fEndWidth);
|
||||
};
|
||||
}
|
||||
83
src/schema/CBasePlayerController.h
Normal file
83
src/schema/CBasePlayerController.h
Normal file
|
|
@ -0,0 +1,83 @@
|
|||
//
|
||||
// Created by Michal Přikryl on 26.06.2025.
|
||||
// Copyright (c) 2025 slynxcz. All rights reserved.
|
||||
//
|
||||
#pragma once
|
||||
#include "ehandle.h"
|
||||
#include "CCSPlayerPawn.h"
|
||||
|
||||
namespace TemplatePlugin
|
||||
{
|
||||
enum class PlayerConnectedState : uint32_t
|
||||
{
|
||||
PlayerNeverConnected = 0xFFFFFFFF,
|
||||
PlayerConnected = 0x0,
|
||||
PlayerConnecting = 0x1,
|
||||
PlayerReconnecting = 0x2,
|
||||
PlayerDisconnecting = 0x3,
|
||||
PlayerDisconnected = 0x4,
|
||||
PlayerReserved = 0x5,
|
||||
};
|
||||
|
||||
class CBasePlayerController : public CBaseEntity
|
||||
{
|
||||
public:
|
||||
DECLARE_SCHEMA_CLASS(CBasePlayerController);
|
||||
|
||||
SCHEMA_FIELD(CHandle<CBasePlayerPawn>, m_hPawn)
|
||||
|
||||
SCHEMA_FIELD_POINTER(char, m_iszPlayerName)
|
||||
|
||||
SCHEMA_FIELD(PlayerConnectedState, m_iConnected)
|
||||
|
||||
SCHEMA_FIELD(uint32_t, m_iDesiredFOV);
|
||||
|
||||
SCHEMA_FIELD_POINTER(uint64_t, m_steamID)
|
||||
|
||||
SCHEMA_FIELD_POINTER(bool, m_bIsHLTV)
|
||||
|
||||
CBasePlayerPawn* GetPawn() { return m_hPawn.Get(); }
|
||||
const char* GetPlayerName() { return m_iszPlayerName(); }
|
||||
|
||||
void SetPlayerName(const std::string& name)
|
||||
{
|
||||
std::strncpy(m_iszPlayerName(), name.c_str(), 128);
|
||||
m_iszPlayerName()[127] = '\0';
|
||||
}
|
||||
|
||||
int GetPlayerSlot() { return GetEntityIndex().Get() - 1; }
|
||||
bool IsConnected() { return m_iConnected() == PlayerConnectedState::PlayerConnected; }
|
||||
|
||||
uint64_t GetSteamID() { return *m_steamID(); }
|
||||
void SetSteamID(uint64_t id) { *m_steamID() = id; }
|
||||
|
||||
bool GetIsHLTV() { return *m_bIsHLTV(); }
|
||||
void SetIsHLTV(bool value) { *m_bIsHLTV() = value; }
|
||||
|
||||
uint64_t& SteamID() { return *m_steamID(); }
|
||||
bool& IsHLTV() { return *m_bIsHLTV(); }
|
||||
|
||||
using CBasePlayerController_SetPawn_t = void(*)(CBasePlayerController* pController, CCSPlayerPawn* pPawn,
|
||||
bool a3, bool a4, bool a5, bool a6);
|
||||
|
||||
void SetPawn(CCSPlayerPawn* pawn)
|
||||
{
|
||||
if (!pawn) return;
|
||||
|
||||
CBasePlayerController_SetPawn_t CBasePlayerController_SetPawn = nullptr;
|
||||
|
||||
if (!CBasePlayerController_SetPawn)
|
||||
{
|
||||
CBasePlayerController_SetPawn_t addr = addr =
|
||||
DynLibUtils::CModule(shared::g_pServer)
|
||||
.FindPattern(shared::g_pGameConfig->GetSignature("CBasePlayerController_SetPawn"))
|
||||
.RCast<CBasePlayerController_SetPawn_t>();
|
||||
if (!addr)
|
||||
return;
|
||||
CBasePlayerController_SetPawn = addr;
|
||||
}
|
||||
|
||||
CBasePlayerController_SetPawn(this, pawn, true, false, false, false);
|
||||
}
|
||||
};
|
||||
}
|
||||
76
src/schema/CBasePlayerPawn.h
Normal file
76
src/schema/CBasePlayerPawn.h
Normal file
|
|
@ -0,0 +1,76 @@
|
|||
//
|
||||
// Created by Michal Přikryl on 26.06.2025.
|
||||
// Copyright (c) 2025 slynxcz. All rights reserved.
|
||||
//
|
||||
#pragma once
|
||||
#include "CBaseEntity.h"
|
||||
#include "CBaseModelEntity.h"
|
||||
#include "services.h"
|
||||
|
||||
namespace TemplatePlugin {
|
||||
enum class Hull_t : uint32
|
||||
{
|
||||
HULL_HUMAN = 0,
|
||||
HULL_SMALL_CENTERED = 1,
|
||||
HULL_WIDE_HUMAN = 2,
|
||||
HULL_TINY = 3,
|
||||
HULL_MEDIUM = 4,
|
||||
HULL_TINY_CENTERED = 5,
|
||||
HULL_LARGE = 6,
|
||||
HULL_LARGE_CENTERED = 7,
|
||||
HULL_MEDIUM_TALL = 8,
|
||||
HULL_SMALL = 9,
|
||||
NUM_HULLS = 10,
|
||||
HULL_NONE = 11,
|
||||
};
|
||||
|
||||
class CMovementStatsProperty
|
||||
{
|
||||
public:
|
||||
DECLARE_SCHEMA_CLASS(CMovementStatsProperty);
|
||||
|
||||
SCHEMA_FIELD(uint32, m_nUseCounter);
|
||||
SCHEMA_FIELD(void*, m_emaMovementDirection);
|
||||
};
|
||||
|
||||
class CBaseCombatCharacter : public CBaseModelEntity
|
||||
{
|
||||
public:
|
||||
DECLARE_SCHEMA_CLASS(CBaseCombatCharacter);
|
||||
|
||||
SCHEMA_FIELD(bool, m_bForceServerRagdoll);
|
||||
SCHEMA_FIELD_POINTER(CUtlVector<CHandle<CEconWearable>>, m_hMyWearables)
|
||||
SCHEMA_FIELD(float, m_impactEnergyScale);
|
||||
SCHEMA_FIELD(bool, m_bApplyStressDamage);
|
||||
SCHEMA_FIELD(bool, m_bDeathEventsDispatched);
|
||||
SCHEMA_FIELD(CUtlString, m_strRelationships);
|
||||
SCHEMA_FIELD(Hull_t, m_eHull);
|
||||
SCHEMA_FIELD(uint32, m_nNavHullIdx);
|
||||
SCHEMA_FIELD(CMovementStatsProperty, m_movementStats);
|
||||
};
|
||||
|
||||
class CBasePlayerPawn : public CBaseCombatCharacter
|
||||
{
|
||||
public:
|
||||
DECLARE_SCHEMA_CLASS(CBasePlayerPawn);
|
||||
|
||||
SCHEMA_FIELD(CCSPlayer_MovementServices*, m_pMovementServices)
|
||||
SCHEMA_FIELD(CCSPlayer_WeaponServices*, m_pWeaponServices)
|
||||
SCHEMA_FIELD(CCSPlayer_ItemServices*, m_pItemServices)
|
||||
SCHEMA_FIELD(CPlayer_ObserverServices*, m_pObserverServices)
|
||||
SCHEMA_FIELD(CPlayer_CameraServices*, m_pCameraServices)
|
||||
SCHEMA_FIELD(CHandle<CBasePlayerController>, m_hController)
|
||||
SCHEMA_FIELD(QAngle, v_angle)
|
||||
SCHEMA_FIELD(QAngle, v_anglePrevious)
|
||||
SCHEMA_FIELD(uint32, m_iHideHUD)
|
||||
SCHEMA_FIELD(bool, m_fInitHUD)
|
||||
|
||||
void CommitSuicide(bool bExplode, bool bForce)
|
||||
{
|
||||
static int offset = shared::g_pGameConfig->GetOffset("CBasePlayerPawn_CommitSuicide");
|
||||
CALL_VIRTUAL(void, offset, this, bExplode, bForce);
|
||||
}
|
||||
|
||||
CBasePlayerController *GetController() { return m_hController.Get(); }
|
||||
};
|
||||
}
|
||||
23
src/schema/CBaseProp.h
Normal file
23
src/schema/CBaseProp.h
Normal file
|
|
@ -0,0 +1,23 @@
|
|||
//
|
||||
// Created by Michal Přikryl on 31.10.2025.
|
||||
// Copyright (c) 2025 slynxcz. All rights reserved.
|
||||
//
|
||||
#pragma once
|
||||
#include "CBaseEntity.h"
|
||||
#include "globaltypes.h"
|
||||
#include "CBaseAnimGraph.h"
|
||||
|
||||
namespace
|
||||
TemplatePlugin
|
||||
{
|
||||
class CBaseProp : public CBaseAnimGraph
|
||||
{
|
||||
public:
|
||||
DECLARE_SCHEMA_CLASS(CBaseProp)
|
||||
|
||||
SCHEMA_FIELD(bool, m_bModelOverrodeBlockLOS)
|
||||
SCHEMA_FIELD(int, m_iShapeType)
|
||||
SCHEMA_FIELD(bool, m_bConformToCollisionBounds)
|
||||
SCHEMA_FIELD(CTransform, m_mPreferredCatchTransform)
|
||||
};
|
||||
}
|
||||
79
src/schema/CBaseTrigger.h
Normal file
79
src/schema/CBaseTrigger.h
Normal file
|
|
@ -0,0 +1,79 @@
|
|||
//
|
||||
// Created by Michal Přikryl on 26.06.2025.
|
||||
// Copyright (c) 2025 slynxcz. All rights reserved.
|
||||
//
|
||||
#pragma once
|
||||
|
||||
#include "CBaseModelEntity.h"
|
||||
#include "schemasystem.h"
|
||||
|
||||
#define SF_TRIG_PUSH_ONCE 0x80
|
||||
|
||||
namespace TemplatePlugin {
|
||||
enum TOGGLE_STATE : uint32_t
|
||||
{
|
||||
TS_AT_TOP = 0,
|
||||
TS_AT_BOTTOM = 1,
|
||||
TS_GOING_UP = 2,
|
||||
TS_GOING_DOWN = 3,
|
||||
DOOR_OPEN = 0,
|
||||
DOOR_CLOSED = 1,
|
||||
DOOR_OPENING = 2,
|
||||
DOOR_CLOSING = 3,
|
||||
};
|
||||
|
||||
class CBaseToggle : public CBaseModelEntity
|
||||
{
|
||||
public:
|
||||
DECLARE_SCHEMA_CLASS(CBaseToggle);
|
||||
SCHEMA_FIELD(TOGGLE_STATE, m_toggle_state)
|
||||
SCHEMA_FIELD(float32, m_flMoveDistance)
|
||||
SCHEMA_FIELD(float32, m_flWait)
|
||||
SCHEMA_FIELD(float32, m_flLip)
|
||||
SCHEMA_FIELD(bool, m_bAlwaysFireBlockedOutputs)
|
||||
SCHEMA_FIELD(Vector, m_vecPosition1)
|
||||
SCHEMA_FIELD(Vector, m_vecPosition2)
|
||||
SCHEMA_FIELD(QAngle, m_vecMoveAng)
|
||||
SCHEMA_FIELD(QAngle, m_vecAngle1)
|
||||
SCHEMA_FIELD(QAngle, m_vecAngle2)
|
||||
SCHEMA_FIELD(float32, m_flHeight)
|
||||
SCHEMA_FIELD(CEntityHandle, m_hActivator)
|
||||
SCHEMA_FIELD(Vector, m_vecFinalDest)
|
||||
SCHEMA_FIELD(QAngle, m_vecFinalAngle)
|
||||
SCHEMA_FIELD(int32, m_movementType)
|
||||
SCHEMA_FIELD(CUtlSymbolLarge, m_sMaster)
|
||||
};
|
||||
|
||||
class CBaseTrigger : public CBaseToggle
|
||||
{
|
||||
public:
|
||||
DECLARE_SCHEMA_CLASS(CBaseTrigger);
|
||||
SCHEMA_FIELD(CEntityIOOutput, m_OnStartTouch);
|
||||
SCHEMA_FIELD(CEntityIOOutput, m_OnStartTouchAll);
|
||||
SCHEMA_FIELD(CEntityIOOutput, m_OnEndTouch);
|
||||
SCHEMA_FIELD(CEntityIOOutput, m_OnEndTouchAll);
|
||||
SCHEMA_FIELD(CEntityIOOutput, m_OnTouching);
|
||||
SCHEMA_FIELD(CEntityIOOutput, m_OnTouchingEachEntity);
|
||||
SCHEMA_FIELD(CEntityIOOutput, m_OnNotTouching);
|
||||
SCHEMA_FIELD_POINTER(CUtlVector<CHandle<CBaseEntity>>, m_hTouchingEntities)
|
||||
SCHEMA_FIELD(CUtlSymbolLarge, m_iFilterName)
|
||||
SCHEMA_FIELD(CEntityHandle, m_hFilter)
|
||||
SCHEMA_FIELD(bool, m_bDisabled);
|
||||
SCHEMA_FIELD(bool, m_bUseAsyncQueries);
|
||||
};
|
||||
|
||||
class CTriggerMultiple : public CBaseTrigger
|
||||
{
|
||||
public:
|
||||
DECLARE_SCHEMA_CLASS(CTriggerMultiple);
|
||||
SCHEMA_FIELD(CEntityIOOutput, m_OnTrigger);
|
||||
};
|
||||
|
||||
class CBombTarget : public CBaseTrigger
|
||||
{
|
||||
public:
|
||||
DECLARE_SCHEMA_CLASS(CBombTarget);
|
||||
|
||||
SCHEMA_FIELD(bool, m_bIsBombSiteB);
|
||||
};
|
||||
}
|
||||
81
src/schema/CBreakableProp.h
Normal file
81
src/schema/CBreakableProp.h
Normal file
|
|
@ -0,0 +1,81 @@
|
|||
//
|
||||
// Created by Michal Přikryl on 01.11.2025.
|
||||
// Copyright (c) 2025 slynxcz. All rights reserved.
|
||||
//
|
||||
#pragma once
|
||||
#include "CBaseEntity.h"
|
||||
#include "globaltypes.h"
|
||||
#include "CBaseProp.h"
|
||||
|
||||
namespace
|
||||
TemplatePlugin
|
||||
{
|
||||
class CPropDataComponent : public CEntityComponent
|
||||
{
|
||||
public:
|
||||
DECLARE_SCHEMA_CLASS(CPropDataComponent)
|
||||
|
||||
SCHEMA_FIELD(float, m_flDmgModBullet)
|
||||
SCHEMA_FIELD(float, m_flDmgModClub)
|
||||
SCHEMA_FIELD(float, m_flDmgModExplosive)
|
||||
SCHEMA_FIELD(float, m_flDmgModFire)
|
||||
SCHEMA_FIELD_POINTER(char, m_iszPhysicsDamageTableName)
|
||||
SCHEMA_FIELD_POINTER(char, m_iszBasePropData)
|
||||
SCHEMA_FIELD(int32, m_nInteractions)
|
||||
SCHEMA_FIELD(bool, m_bSpawnMotionDisabled)
|
||||
SCHEMA_FIELD(int32, m_nDisableTakePhysicsDamageSpawnFlag)
|
||||
SCHEMA_FIELD(int32, m_nMotionDisabledSpawnFlag)
|
||||
};
|
||||
|
||||
enum BreakableContentsType_t : uint
|
||||
{
|
||||
BC_DEFAULT = 0x0,
|
||||
BC_EMPTY = 0x1,
|
||||
BC_PROP_GROUP_OVERRIDE = 0x2,
|
||||
BC_PARTICLE_SYSTEM_OVERRIDE = 0x3,
|
||||
};
|
||||
|
||||
enum PerformanceMode_t : uint
|
||||
{
|
||||
PM_NORMAL = 0x0,
|
||||
PM_NO_GIBS = 0x1,
|
||||
};
|
||||
|
||||
class CBreakableProp : public CBaseProp
|
||||
{
|
||||
public:
|
||||
DECLARE_SCHEMA_CLASS(CBreakableProp);
|
||||
|
||||
SCHEMA_FIELD(CPropDataComponent, m_CPropDataComponent)
|
||||
SCHEMA_FIELD(CEntityIOOutput, m_OnStartDeath)
|
||||
SCHEMA_FIELD(CEntityIOOutput, m_OnBreak)
|
||||
SCHEMA_FIELD(CEntityIOOutput, m_OnTakeDamage)
|
||||
SCHEMA_FIELD(float, m_impactEnergyScale)
|
||||
SCHEMA_FIELD(int32, m_iMinHealthDmg)
|
||||
SCHEMA_FIELD(QAngle, m_preferredCarryAngles)
|
||||
SCHEMA_FIELD(float, m_flPressureDelay)
|
||||
SCHEMA_FIELD(float, m_flDefBurstScale)
|
||||
SCHEMA_FIELD(Vector, m_vDefBurstOffset)
|
||||
SCHEMA_FIELD(CHandle<CBaseEntity>, m_hBreaker)
|
||||
SCHEMA_FIELD(PerformanceMode_t, m_PerformanceMode)
|
||||
SCHEMA_FIELD(float, m_flPreventDamageBeforeTime)
|
||||
SCHEMA_FIELD(BreakableContentsType_t, m_BreakableContentsType)
|
||||
SCHEMA_FIELD_POINTER(char, m_strBreakableContentsPropGroupOverride)
|
||||
SCHEMA_FIELD_POINTER(char, m_strBreakableContentsParticleOverride)
|
||||
SCHEMA_FIELD(bool, m_bHasBreakPiecesOrCommands)
|
||||
SCHEMA_FIELD(float, m_explodeDamage)
|
||||
SCHEMA_FIELD(float, m_explodeRadius)
|
||||
SCHEMA_FIELD(float, m_explosionDelay)
|
||||
SCHEMA_FIELD_POINTER(char, m_explosionBuildupSound)
|
||||
SCHEMA_FIELD_POINTER(char, m_explosionCustomEffect)
|
||||
SCHEMA_FIELD_POINTER(char, m_explosionCustomSound)
|
||||
SCHEMA_FIELD_POINTER(char, m_explosionModifier)
|
||||
SCHEMA_FIELD(CHandle<CBasePlayerPawn>, m_hPhysicsAttacker)
|
||||
SCHEMA_FIELD(float, m_flLastPhysicsInfluenceTime)
|
||||
SCHEMA_FIELD(float, m_flDefaultFadeScale)
|
||||
SCHEMA_FIELD(CHandle<CBaseEntity>, m_hLastAttacker)
|
||||
SCHEMA_FIELD_POINTER(char, m_iszPuntSound)
|
||||
SCHEMA_FIELD(bool, m_bUsePuntSound)
|
||||
SCHEMA_FIELD(bool, m_bOriginalBlockLOS)
|
||||
};
|
||||
}
|
||||
18
src/schema/CC4.h
Normal file
18
src/schema/CC4.h
Normal file
|
|
@ -0,0 +1,18 @@
|
|||
//
|
||||
// Created by Michal Přikryl on 26.06.2025.
|
||||
// Copyright (c) 2025 slynxcz. All rights reserved.
|
||||
//
|
||||
#pragma once
|
||||
#include <entity2/entityidentity.h>
|
||||
#include "CGameRules.h"
|
||||
#include "schemasystem.h"
|
||||
|
||||
namespace TemplatePlugin {
|
||||
class CC4
|
||||
{
|
||||
public:
|
||||
DECLARE_SCHEMA_CLASS(CC4);
|
||||
|
||||
SCHEMA_FIELD(GameTime_t, m_fArmedTime);
|
||||
};
|
||||
}
|
||||
727
src/schema/CCSPlayerController.h
Normal file
727
src/schema/CCSPlayerController.h
Normal file
|
|
@ -0,0 +1,727 @@
|
|||
//
|
||||
// Created by Michal Přikryl on 26.06.2025.
|
||||
// Copyright (c) 2025 slynxcz. All rights reserved.
|
||||
//
|
||||
#pragma once
|
||||
#include <colors.h>
|
||||
#include <detourtypes.h>
|
||||
#include <tasks.h>
|
||||
#include <vectorextends.h>
|
||||
#include "CBasePlayerController.h"
|
||||
#include "serversideclient.h"
|
||||
#include "services.h"
|
||||
#include "Shared.h"
|
||||
#include "RayTrace.h"
|
||||
|
||||
namespace TemplatePlugin {
|
||||
extern CServerSideClient* GetClientBySlot(CPlayerSlot slot);
|
||||
|
||||
class CCSPlayerController : public CBasePlayerController
|
||||
{
|
||||
public:
|
||||
DECLARE_SCHEMA_CLASS(CCSPlayerController);
|
||||
|
||||
SCHEMA_FIELD(CCSPlayerController_InGameMoneyServices*, m_pInGameMoneyServices);
|
||||
|
||||
SCHEMA_FIELD(CCSPlayerController_ActionTrackingServices*, m_pActionTrackingServices);
|
||||
|
||||
SCHEMA_FIELD(CCSPlayerController_InventoryServices*, m_pInventoryServices);
|
||||
|
||||
SCHEMA_FIELD(uint32_t, m_iPing);
|
||||
|
||||
SCHEMA_FIELD(CUtlSymbolLarge, m_szClan);
|
||||
|
||||
SCHEMA_FIELD_POINTER(char, m_szClanName) // char m_szClanName[32]
|
||||
SCHEMA_FIELD(bool, m_bEverFullyConnected);
|
||||
|
||||
SCHEMA_FIELD(bool, m_bPawnIsAlive);
|
||||
|
||||
SCHEMA_FIELD(int32_t, m_nDisconnectionTick);
|
||||
|
||||
SCHEMA_FIELD(CHandle<CCSPlayerPawn>, m_hPlayerPawn);
|
||||
|
||||
SCHEMA_FIELD(int32, m_DesiredObserverMode);
|
||||
|
||||
SCHEMA_FIELD(int16_t, m_nPawnCharacterDefIndex);
|
||||
|
||||
SCHEMA_FIELD(CHandle<CCSPlayerPawnBase>, m_hObserverPawn);
|
||||
|
||||
SCHEMA_FIELD(CHandle<CCSPlayerController>, m_hOriginalControllerOfCurrentPawn);
|
||||
|
||||
SCHEMA_FIELD(uint32_t, m_iPawnHealth);
|
||||
|
||||
SCHEMA_FIELD(int32_t, m_iPawnArmor);
|
||||
|
||||
SCHEMA_FIELD(int32_t, m_iScore);
|
||||
|
||||
SCHEMA_FIELD(int32_t, m_iRoundScore);
|
||||
|
||||
SCHEMA_FIELD(int32_t, m_iRoundsWon);
|
||||
|
||||
SCHEMA_FIELD(int32_t, m_iMVPs);
|
||||
|
||||
SCHEMA_FIELD(float, m_flSmoothedPing);
|
||||
|
||||
SCHEMA_FIELD(GameTime_t, m_flForceTeamTime);
|
||||
|
||||
SCHEMA_FIELD(int32_t, m_iCompetitiveRanking);
|
||||
|
||||
SCHEMA_FIELD(int8_t, m_iCompetitiveRankType);
|
||||
|
||||
SCHEMA_FIELD(int32_t, m_iCompetitiveWins);
|
||||
|
||||
SCHEMA_FIELD(byte, m_iPendingTeamNum);
|
||||
|
||||
SCHEMA_FIELD(byte, m_bTeamChanged);
|
||||
|
||||
SCHEMA_FIELD(byte, m_bInSwitchTeam);
|
||||
|
||||
static CCSPlayerController* FromUserId(int userid)
|
||||
{
|
||||
for (int i = 0; i < shared::getGlobalVars()->maxClients; ++i)
|
||||
{
|
||||
CCSPlayerController* controller = FromSlot(i);
|
||||
if (!controller)
|
||||
continue;
|
||||
|
||||
int iUserId = shared::g_pEngine->GetPlayerUserId(i).Get();
|
||||
if (userid == iUserId) return controller;
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
static CCSPlayerController* FromPawn(CCSPlayerPawn* pawn)
|
||||
{
|
||||
return reinterpret_cast<CCSPlayerController*>(pawn->m_hController().Get());
|
||||
}
|
||||
|
||||
static CCSPlayerController* FromIndex(int iIndex)
|
||||
{
|
||||
return static_cast<CCSPlayerController*>(shared::g_pEntitySystem->
|
||||
GetEntityInstance(CEntityIndex(iIndex)));
|
||||
}
|
||||
|
||||
static CCSPlayerController* FromSlot(int iSlot)
|
||||
{
|
||||
return static_cast<CCSPlayerController*>(shared::g_pEntitySystem->
|
||||
GetEntityInstance(CEntityIndex(iSlot + 1)));
|
||||
}
|
||||
|
||||
static CCSPlayerController* FromSteamId(uint64 steamid)
|
||||
{
|
||||
for (int i = 0; i < shared::getGlobalVars()->maxClients; ++i)
|
||||
{
|
||||
CCSPlayerController* controller = FromSlot(i);
|
||||
if (!controller)
|
||||
continue;
|
||||
|
||||
if (steamid == controller->GetSteamID()) return controller;
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
CServerSideClient* GetServerSideClient()
|
||||
{
|
||||
return GetClientBySlot(GetPlayerSlot());
|
||||
}
|
||||
|
||||
CCSPlayerPawn* GetPlayerPawn()
|
||||
{
|
||||
if (auto handle = m_hPlayerPawn(); handle.IsValid())
|
||||
return handle.Get();
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
CCSPlayerPawn* GetObserverPawn()
|
||||
{
|
||||
if (auto handle = m_hObserverPawn(); handle.IsValid())
|
||||
return static_cast<CCSPlayerPawn*>(handle.Get());
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
bool IsBot() { return GetSteamID() == 0; }
|
||||
|
||||
void ChangeTeam(CsTeam iTeam)
|
||||
{
|
||||
CALL_VIRTUAL(void, shared::g_pGameConfig->GetOffset("CCSPlayerController_ChangeTeam"), this,
|
||||
static_cast<byte>(iTeam));
|
||||
}
|
||||
|
||||
static std::string CsTeamToString(CsTeam team)
|
||||
{
|
||||
switch (team)
|
||||
{
|
||||
case CsTeam::None: return "None";
|
||||
case CsTeam::Spectator: return "Spectator";
|
||||
case CsTeam::Terrorist: return "Terrorist";
|
||||
case CsTeam::CounterTerrorist: return "CounterTerrorist";
|
||||
default: return "Unknown";
|
||||
}
|
||||
}
|
||||
|
||||
CsTeam Team()
|
||||
{
|
||||
byte teamNum = GetTeam();
|
||||
if (teamNum < static_cast<byte>(CsTeam::None) || teamNum > static_cast<byte>(CsTeam::CounterTerrorist))
|
||||
return CsTeam::None;
|
||||
|
||||
return static_cast<CsTeam>(teamNum);
|
||||
}
|
||||
|
||||
void Respawn()
|
||||
{
|
||||
CCSPlayerPawn* pPawn = GetPlayerPawn();
|
||||
if (!pPawn || m_bPawnIsAlive)
|
||||
return;
|
||||
|
||||
SetPawn(pPawn);
|
||||
CALL_VIRTUAL(void, shared::g_pGameConfig->GetOffset("CCSPlayerController_Respawn"), this);
|
||||
}
|
||||
|
||||
bool CheckValid(bool alive = false)
|
||||
{
|
||||
CCSPlayerPawn* pawn = GetPlayerPawn();
|
||||
|
||||
if (IsBot() || GetIsHLTV() || GetSteamID() <= 0 || !IsConnected() || !pawn)
|
||||
return false;
|
||||
|
||||
if (alive && !m_bPawnIsAlive())
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void TakeFakeDamage(CCSPlayerController* attacker, int damage)
|
||||
{
|
||||
static CBaseEntity_TakeDamageOld_t s_TakeDamageOld = nullptr;
|
||||
|
||||
if (!s_TakeDamageOld)
|
||||
{
|
||||
CBaseEntity_TakeDamageOld_t addr =
|
||||
DynLibUtils::CModule(shared::g_pServer)
|
||||
.FindPattern(shared::g_pGameConfig->GetSignature("CBaseEntity_TakeDamageOld"))
|
||||
.RCast<CBaseEntity_TakeDamageOld_t>();
|
||||
|
||||
if (!addr) return;
|
||||
s_TakeDamageOld = addr;
|
||||
}
|
||||
|
||||
if (!CheckValid(true) || !attacker || !attacker->CheckValid())
|
||||
return;
|
||||
|
||||
auto* victimPawn = GetPlayerPawn();
|
||||
if (!victimPawn) return;
|
||||
|
||||
auto* attackerPawn = attacker->GetPlayerPawn();
|
||||
if (!attackerPawn) return;
|
||||
|
||||
const size_t infoSize = schema::GetClassSize("CTakeDamageInfo");
|
||||
const size_t resultSize = schema::GetClassSize("CTakeDamageResult");
|
||||
|
||||
auto* infoMem = std::malloc(infoSize);
|
||||
auto* resultMem = std::malloc(resultSize);
|
||||
|
||||
if (!infoMem || !resultMem)
|
||||
{
|
||||
std::free(infoMem);
|
||||
std::free(resultMem);
|
||||
return;
|
||||
}
|
||||
|
||||
std::memset(infoMem, 0, infoSize);
|
||||
std::memset(resultMem, 0, resultSize);
|
||||
|
||||
CAttackerInfo attackerInfo(attacker);
|
||||
std::memcpy(reinterpret_cast<std::uint8_t*>(infoMem) + 0x98, &attackerInfo, sizeof(CAttackerInfo));
|
||||
|
||||
auto* info = reinterpret_cast<CTakeDamageInfo*>(infoMem);
|
||||
auto* result = reinterpret_cast<CTakeDamageResult*>(resultMem);
|
||||
|
||||
info->m_hInflictor() = attackerPawn->GetHandle();
|
||||
info->m_hAttacker() = attackerPawn->GetHandle();
|
||||
info->m_flDamage() = static_cast<float>(damage);
|
||||
info->m_flFriendlyFireDamageReductionRatio() = static_cast<float>(0);
|
||||
info->m_bInTakeDamageFlow() = true;
|
||||
info->m_bitsDamageType() = DMG_GENERIC;
|
||||
|
||||
result->m_pOriginatingInfo() = info;
|
||||
result->m_nDamageDealt() = damage;
|
||||
result->m_nHealthLost() = damage;
|
||||
result->m_flPreModifiedDamage() = static_cast<float>(damage);
|
||||
result->m_nTotalledDamageDealt() = damage;
|
||||
result->m_nTotalledHealthLost() = damage;
|
||||
result->m_bWasDamageSuppressed() = false;
|
||||
|
||||
s_TakeDamageOld(victimPawn, info, result);
|
||||
|
||||
std::free(infoMem);
|
||||
std::free(resultMem);
|
||||
}
|
||||
|
||||
void Kick(ENetworkDisconnectionReason reason)
|
||||
{
|
||||
if (!CheckValid()) return;
|
||||
|
||||
CPlayerSlot slot = CPlayerSlot(GetPlayerSlot());
|
||||
|
||||
Tasks::NextFrame([slot, reason]
|
||||
{
|
||||
shared::g_pEngine->DisconnectClient(
|
||||
slot, reason);
|
||||
});
|
||||
}
|
||||
|
||||
PlayerConnectedState GetConnectedState() { return m_iConnected(); }
|
||||
|
||||
CSPlayerState GetPawnState()
|
||||
{
|
||||
CCSPlayerPawnBase* pPawn = static_cast<CCSPlayerPawnBase*>(GetPawn());
|
||||
if (!pPawn)
|
||||
return STATE_WELCOME;
|
||||
|
||||
return pPawn->m_iPlayerState();
|
||||
}
|
||||
|
||||
CSPlayerState GetPlayerPawnState()
|
||||
{
|
||||
CCSPlayerPawn* pPawn = GetPlayerPawn();
|
||||
if (!pPawn)
|
||||
return STATE_WELCOME;
|
||||
|
||||
return pPawn->m_iPlayerState();
|
||||
}
|
||||
|
||||
CBaseEntity* GetObserverTarget()
|
||||
{
|
||||
auto pPawn = GetPawn();
|
||||
|
||||
if (!pPawn)
|
||||
return nullptr;
|
||||
|
||||
return pPawn->m_pObserverServices->m_hObserverTarget().Get();
|
||||
}
|
||||
|
||||
// --- HEALTH & ARMOR ---
|
||||
int GetHealth()
|
||||
{
|
||||
if (!CheckValid(true)) return 0;
|
||||
auto pawn = GetPlayerPawn();
|
||||
return pawn->m_iHealth;
|
||||
}
|
||||
|
||||
void SetHealth(int health)
|
||||
{
|
||||
if (!CheckValid(true) || health <= 0) return;
|
||||
auto pawn = GetPlayerPawn();
|
||||
pawn->m_iHealth = health;
|
||||
m_iPawnHealth = health;
|
||||
if (health > pawn->m_iMaxHealth)
|
||||
pawn->m_iMaxHealth = health;
|
||||
}
|
||||
|
||||
void AddHealth(int delta)
|
||||
{
|
||||
if (!CheckValid(true) || delta <= 0) return;
|
||||
auto pawn = GetPlayerPawn();
|
||||
pawn->m_iHealth += delta;
|
||||
m_iPawnHealth += delta;
|
||||
}
|
||||
|
||||
void SetMaxHealth(int maxHp)
|
||||
{
|
||||
if (!CheckValid(true) || maxHp <= 0) return;
|
||||
auto pawn = GetPlayerPawn();
|
||||
pawn->m_iMaxHealth = maxHp;
|
||||
}
|
||||
|
||||
void SetArmor(int armor, bool helmet = false)
|
||||
{
|
||||
if (!CheckValid(true) || armor < 0) return;
|
||||
auto pawn = GetPlayerPawn();
|
||||
pawn->m_ArmorValue = armor;
|
||||
m_iPawnArmor = armor;
|
||||
if (helmet && pawn->m_pItemServices)
|
||||
pawn->m_pItemServices->m_bHasHelmet = true;
|
||||
}
|
||||
|
||||
void AddArmor(int delta)
|
||||
{
|
||||
if (!CheckValid(true) || delta <= 0) return;
|
||||
auto pawn = GetPlayerPawn();
|
||||
pawn->m_ArmorValue() += delta;
|
||||
m_iPawnArmor() += delta;
|
||||
}
|
||||
|
||||
// --- WEAPONS ---
|
||||
std::vector<CCSWeaponBase*> GetWeapons()
|
||||
{
|
||||
std::vector<CCSWeaponBase*> weapons;
|
||||
auto pawn = GetPlayerPawn();
|
||||
if (!pawn || !pawn->m_pWeaponServices() || !pawn->m_pWeaponServices()->m_hMyWeapons())
|
||||
return weapons;
|
||||
|
||||
const auto& myWeapons = *pawn->m_pWeaponServices()->m_hMyWeapons();
|
||||
|
||||
for (int i = 0; i < myWeapons.Count(); ++i)
|
||||
{
|
||||
const auto& handle = myWeapons[i];
|
||||
if (!handle.IsValid()) continue;
|
||||
|
||||
if (auto* weapon = static_cast<CCSWeaponBase*>(handle.Get()))
|
||||
{
|
||||
weapons.push_back(weapon);
|
||||
}
|
||||
}
|
||||
|
||||
return weapons;
|
||||
}
|
||||
|
||||
CCSWeaponBase* GetWeaponByDefIndex(int defIndex)
|
||||
{
|
||||
for (auto* base : GetWeapons())
|
||||
{
|
||||
if (base->m_AttributeManager().m_Item().m_iItemDefinitionIndex() == defIndex)
|
||||
return base;
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
CCSWeaponBase* GetWeaponBySlot(gear_slot_t slot)
|
||||
{
|
||||
for (auto* base : GetWeapons())
|
||||
{
|
||||
if (base->GetWeaponVData() && base->GetWeaponVData()->m_GearSlot() == slot)
|
||||
return base;
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
CCSWeaponBase* GetWeaponByName(const std::string& weaponName)
|
||||
{
|
||||
for (auto* base : GetWeapons())
|
||||
{
|
||||
if (base->GetDesignerName() == weaponName)
|
||||
return base;
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
bool HasWeaponByName(const std::string& weaponName)
|
||||
{
|
||||
return GetWeaponByName(weaponName) != nullptr;
|
||||
}
|
||||
|
||||
bool HasWeaponInSlot(gear_slot_t slot)
|
||||
{
|
||||
return GetWeaponBySlot(slot) != nullptr;
|
||||
}
|
||||
|
||||
std::string GetWeaponNameBySlot(gear_slot_t slot)
|
||||
{
|
||||
if (auto* w = GetWeaponBySlot(slot))
|
||||
{
|
||||
return w->GetDesignerName();
|
||||
}
|
||||
return {};
|
||||
}
|
||||
|
||||
void DropWeaponByName(const std::string& weaponName)
|
||||
{
|
||||
auto pawn = GetPlayerPawn();
|
||||
if (!pawn || !pawn->m_pWeaponServices()) return;
|
||||
|
||||
if (auto* weapon = GetWeaponByName(weaponName))
|
||||
{
|
||||
pawn->m_pWeaponServices()->m_hActiveWeapon() = CHandle<CBaseEntity>(weapon);
|
||||
pawn->m_pItemServices()->DropActiveWeapon(weapon);
|
||||
}
|
||||
}
|
||||
|
||||
// --- POSITION / AIM ---
|
||||
Vector GetEyePosition()
|
||||
{
|
||||
auto pawn = GetPlayerPawn();
|
||||
if (!pawn) return {0, 0, 0};
|
||||
Vector origin = pawn->GetAbsOrigin();
|
||||
Vector offset = pawn->m_vecViewOffset();
|
||||
return {origin.x, origin.y, origin.z + offset.z};
|
||||
}
|
||||
|
||||
CBaseEntity* GetAimEntity(bool includePlayers = false)
|
||||
{
|
||||
if (!CheckValid(true))
|
||||
return nullptr;
|
||||
|
||||
auto* pawn = GetPlayerPawn();
|
||||
if (!pawn)
|
||||
return nullptr;
|
||||
|
||||
QAngle eyeAngles = pawn->GetEyeAngles();
|
||||
Vector eyePos = GetEyePosition();
|
||||
|
||||
RayTrace::TraceOptions opts{};
|
||||
if (!includePlayers)
|
||||
opts.InteractsExclude = RayTrace::InteractionLayers::Player;
|
||||
|
||||
auto result = RayTrace::TraceShape(
|
||||
eyePos,
|
||||
eyeAngles,
|
||||
pawn,
|
||||
&opts
|
||||
);
|
||||
|
||||
return result.has_value()
|
||||
? static_cast<CBaseEntity*>(result->HitEntity)
|
||||
: nullptr;
|
||||
}
|
||||
|
||||
struct AimPositionResult
|
||||
{
|
||||
bool Hit{false};
|
||||
Vector Origin{};
|
||||
Vector Normal{};
|
||||
};
|
||||
|
||||
AimPositionResult GetAimPositionEx(bool includePlayers = true)
|
||||
{
|
||||
AimPositionResult result{};
|
||||
|
||||
if (!CheckValid(true))
|
||||
return result;
|
||||
|
||||
auto* pawn = GetPlayerPawn();
|
||||
if (!pawn)
|
||||
return result;
|
||||
|
||||
QAngle eyeAngles = pawn->GetEyeAngles();
|
||||
Vector eyePos = GetEyePosition();
|
||||
|
||||
Vector forward{};
|
||||
AngleVectors(eyeAngles, &forward, nullptr, nullptr);
|
||||
|
||||
Vector origin = eyePos + forward * 15.0f;
|
||||
|
||||
RayTrace::TraceOptions opts{};
|
||||
if (!includePlayers)
|
||||
opts.InteractsExclude = RayTrace::InteractionLayers::Player;
|
||||
|
||||
auto traceResult = RayTrace::TraceShape(
|
||||
eyePos,
|
||||
eyeAngles,
|
||||
pawn,
|
||||
&opts
|
||||
);
|
||||
|
||||
if (traceResult.has_value())
|
||||
{
|
||||
result.Hit = true;
|
||||
result.Origin = traceResult->EndPos;
|
||||
result.Normal = traceResult->Normal;
|
||||
return result;
|
||||
}
|
||||
|
||||
result.Hit = false;
|
||||
result.Origin = origin + forward * 8192.0f;
|
||||
return result;
|
||||
}
|
||||
|
||||
Vector GetAimPosition(bool includePlayers = true)
|
||||
{
|
||||
if (!CheckValid(true))
|
||||
return {0, 0, 0};
|
||||
|
||||
auto* pawn = GetPlayerPawn();
|
||||
if (!pawn)
|
||||
return {0, 0, 0};
|
||||
|
||||
QAngle eyeAngles = pawn->GetEyeAngles();
|
||||
Vector eyePos = GetEyePosition();
|
||||
|
||||
Vector forward{};
|
||||
AngleVectors(eyeAngles, &forward, nullptr, nullptr);
|
||||
|
||||
Vector origin = eyePos + forward * 15.0f;
|
||||
|
||||
RayTrace::TraceOptions opts{};
|
||||
if (!includePlayers)
|
||||
opts.InteractsExclude = RayTrace::InteractionLayers::Player;
|
||||
|
||||
auto traceResult = RayTrace::TraceShape(
|
||||
eyePos,
|
||||
eyeAngles,
|
||||
pawn,
|
||||
&opts
|
||||
);
|
||||
|
||||
if (traceResult.has_value())
|
||||
{
|
||||
return traceResult->EndPos;
|
||||
}
|
||||
|
||||
return origin + forward * 8192.0f;
|
||||
}
|
||||
|
||||
bool IsPlayerInSightRange(CCSPlayerController* target,
|
||||
float distance = 0.0f, float angle = 90.0f, bool heightCheck = true,
|
||||
bool negativeAngle = false)
|
||||
{
|
||||
if (!CheckValid(true) || !target->CheckValid(true) || GetPlayerPawn()->GetAbsOrigin().IsZero() ||
|
||||
target->GetPlayerPawn()->GetAbsOrigin().IsZero())
|
||||
return false;
|
||||
|
||||
float resultDistance = 0;
|
||||
auto playerEyeAngles = GetPlayerPawn()->GetEyeAngles();
|
||||
playerEyeAngles.x = 0.0f;
|
||||
playerEyeAngles.z = 0.0f;
|
||||
Vector angleVector;
|
||||
AngleVectors(playerEyeAngles, &angleVector, nullptr, nullptr);
|
||||
angleVector = VectorExtends::Normalize(angleVector);
|
||||
|
||||
if (negativeAngle)
|
||||
angleVector = VectorExtends::NegateVector(angleVector);
|
||||
|
||||
auto playerOrigin = GetPlayerPawn()->GetAbsOrigin();
|
||||
auto targetOrigin = target->GetPlayerPawn()->GetAbsOrigin();
|
||||
|
||||
if (heightCheck && distance > 0.0f)
|
||||
resultDistance = VectorExtends::Distance(playerOrigin, targetOrigin);
|
||||
|
||||
if (distance > 0.0f)
|
||||
{
|
||||
if (resultDistance > distance)
|
||||
return false;
|
||||
}
|
||||
|
||||
playerOrigin.z = 0.0f;
|
||||
targetOrigin.z = 0.0f;
|
||||
|
||||
auto targetVector = VectorExtends::MakeVectorFromPoints(playerOrigin, targetOrigin);
|
||||
targetVector = VectorExtends::Normalize(targetVector);
|
||||
auto resultAngle = VectorExtends::RadToDeg(
|
||||
VectorExtends::ArcCosine(VectorExtends::GetVectorDotProduct(targetVector, angleVector)));
|
||||
|
||||
if (resultAngle > angle / 2)
|
||||
return false;
|
||||
|
||||
if (distance > 0.0f)
|
||||
{
|
||||
if (!heightCheck)
|
||||
resultDistance = VectorExtends::Distance(playerOrigin, targetOrigin);
|
||||
return resultDistance <= distance;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void TeleportTo(CCSPlayerController* target)
|
||||
{
|
||||
if (!CheckValid(true) || !target || !target->CheckValid(true)) return;
|
||||
|
||||
auto pawn = GetPlayerPawn();
|
||||
auto tpawn = target->GetPlayerPawn();
|
||||
if (!pawn || !tpawn) return;
|
||||
|
||||
Vector origin = tpawn->GetAbsOrigin();
|
||||
QAngle rot = tpawn->GetAbsRotation();
|
||||
Vector vel = tpawn->GetAbsVelocity();
|
||||
|
||||
pawn->Teleport(&origin, &rot, &vel);
|
||||
}
|
||||
|
||||
void TeleportPlayer(CCSPlayerController* target)
|
||||
{
|
||||
CCSPlayerPawn* myPawn = GetPlayerPawn();
|
||||
CCSPlayerPawn* targetPawn = target ? target->GetPlayerPawn() : nullptr;
|
||||
|
||||
if (!myPawn || !targetPawn)
|
||||
return;
|
||||
|
||||
const Vector& origin = targetPawn->GetAbsOrigin();
|
||||
const QAngle& rotation = targetPawn->GetAbsRotation();
|
||||
const Vector& velocity = targetPawn->GetAbsVelocity();
|
||||
|
||||
myPawn->Teleport(&origin, &rotation, &velocity);
|
||||
}
|
||||
|
||||
void SetPlayerRenderColor(int a = 255, int r = 255, int g = 255, int b = 255)
|
||||
{
|
||||
CCSPlayerPawn* pawn = GetPlayerPawn();
|
||||
if (!pawn) return;
|
||||
|
||||
pawn->m_clrRender() = Color(r, g, b, a);
|
||||
}
|
||||
|
||||
void SetPlayerInvisible(int alpha = 0)
|
||||
{
|
||||
if (alpha < 0) alpha = 0;
|
||||
if (alpha > 255) alpha = 255;
|
||||
|
||||
CCSPlayerPawn* pawn = GetPlayerPawn();
|
||||
if (!pawn)
|
||||
return;
|
||||
|
||||
SetPlayerRenderColor(alpha);
|
||||
|
||||
if (auto weaponServices = pawn->m_pWeaponServices())
|
||||
{
|
||||
CHandle<CBasePlayerWeapon> activeWeapon = weaponServices->m_hActiveWeapon();
|
||||
if (activeWeapon && activeWeapon.IsValid())
|
||||
{
|
||||
auto* weapon = activeWeapon.Get();
|
||||
weapon->m_clrRender() = colors(255, 255, 255, alpha).ToValveColor();
|
||||
weapon->m_flShadowStrength() = 0.0f;
|
||||
}
|
||||
|
||||
if (auto myWeapons = weaponServices->m_hMyWeapons())
|
||||
{
|
||||
FOR_EACH_VEC(*myWeapons, i)
|
||||
{
|
||||
const CHandle<CBasePlayerWeapon>& handle = (*myWeapons)[i];
|
||||
if (!handle.IsValid() || !handle.Get())
|
||||
continue;
|
||||
|
||||
auto* weapon = handle.Get();
|
||||
weapon->m_clrRender() = colors(255, 255, 255, 0).ToValveColor();
|
||||
weapon->m_flShadowStrength() = 0.0f;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void SetPlayerVisible()
|
||||
{
|
||||
CCSPlayerPawn* pawn = GetPlayerPawn();
|
||||
if (!pawn)
|
||||
return;
|
||||
|
||||
SetPlayerRenderColor();
|
||||
|
||||
if (auto weaponServices = pawn->m_pWeaponServices())
|
||||
{
|
||||
CHandle<CBasePlayerWeapon> activeWeapon = weaponServices->m_hActiveWeapon();
|
||||
if (activeWeapon && activeWeapon.IsValid())
|
||||
{
|
||||
auto* weapon = activeWeapon.Get();
|
||||
weapon->m_clrRender() = colors(255, 255, 255, 255).ToValveColor();
|
||||
weapon->m_flShadowStrength() = 1.0f;
|
||||
}
|
||||
|
||||
if (auto myWeapons = weaponServices->m_hMyWeapons())
|
||||
{
|
||||
FOR_EACH_VEC(*myWeapons, i)
|
||||
{
|
||||
const CHandle<CBasePlayerWeapon>& handle = (*myWeapons)[i];
|
||||
if (!handle.IsValid() || !handle.Get())
|
||||
continue;
|
||||
|
||||
auto* weapon = handle.Get();
|
||||
weapon->m_clrRender() = colors(255, 255, 255, 255).ToValveColor();
|
||||
weapon->m_flShadowStrength() = 1.0f;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
141
src/schema/CCSPlayerPawn.h
Normal file
141
src/schema/CCSPlayerPawn.h
Normal file
|
|
@ -0,0 +1,141 @@
|
|||
//
|
||||
// Created by Michal Přikryl on 26.06.2025.
|
||||
// Copyright (c) 2025 slynxcz. All rights reserved.
|
||||
//
|
||||
#pragma once
|
||||
#include "ehandle.h"
|
||||
#include "CBasePlayerPawn.h"
|
||||
#include "services.h"
|
||||
#include "CCSWeaponBase.h"
|
||||
|
||||
namespace TemplatePlugin {
|
||||
enum CSPlayerState
|
||||
{
|
||||
STATE_ACTIVE = 0x0,
|
||||
STATE_WELCOME = 0x1,
|
||||
STATE_PICKINGTEAM = 0x2,
|
||||
STATE_PICKINGCLASS = 0x3,
|
||||
STATE_DEATH_ANIM = 0x4,
|
||||
STATE_DEATH_WAIT_FOR_KEY = 0x5,
|
||||
STATE_OBSERVER_MODE = 0x6,
|
||||
STATE_GUNGAME_RESPAWN = 0x7,
|
||||
STATE_DORMANT = 0x8,
|
||||
NUM_PLAYER_STATES = 0x9,
|
||||
};
|
||||
|
||||
class CCSPlayerController;
|
||||
|
||||
struct EntitySpottedState_t
|
||||
{
|
||||
private:
|
||||
[[maybe_unused]] std::uint8_t __pad0000[ 0x8 ]; // 0x0
|
||||
public:
|
||||
// MNetworkEnable
|
||||
// MNetworkChangeCallback "OnIsSpottedChanged"
|
||||
bool m_bSpotted; // 0x8
|
||||
private:
|
||||
[[maybe_unused]] std::uint8_t __pad0009[ 0x3 ]; // 0x9
|
||||
public:
|
||||
// MNetworkEnable
|
||||
// MNetworkChangeCallback "OnIsSpottedChanged"
|
||||
std::uint32_t m_bSpottedByMask[2]; // 0xc
|
||||
};
|
||||
|
||||
class CTouchExpansionComponent : public CEntityComponent
|
||||
{
|
||||
DECLARE_SCHEMA_CLASS(CTouchExpansionComponent)
|
||||
};
|
||||
|
||||
class CCSPlayerPawnBase : public CBasePlayerPawn {
|
||||
public:
|
||||
DECLARE_SCHEMA_CLASS(CCSPlayerPawnBase);
|
||||
|
||||
SCHEMA_FIELD(CTouchExpansionComponent, m_CTouchExpansionComponent)
|
||||
SCHEMA_FIELD(GameTime_t, m_blindUntilTime)
|
||||
SCHEMA_FIELD(GameTime_t, m_blindStartTime)
|
||||
SCHEMA_FIELD(CSPlayerState, m_iPlayerState)
|
||||
SCHEMA_FIELD(bool, m_bRespawning)
|
||||
SCHEMA_FIELD(GameTime_t, m_fImmuneToGunGameDamageTime)
|
||||
SCHEMA_FIELD(bool, m_bGunGameImmunity)
|
||||
SCHEMA_FIELD(float, m_fMolotovDamageTime)
|
||||
SCHEMA_FIELD(bool, m_bHasMovedSinceSpawn)
|
||||
SCHEMA_FIELD(int32, m_iNumSpawns)
|
||||
SCHEMA_FIELD(float, m_flIdleTimeSinceLastAction)
|
||||
SCHEMA_FIELD(float, m_fNextRadarUpdateTime)
|
||||
SCHEMA_FIELD(float, m_flFlashDuration)
|
||||
SCHEMA_FIELD(float, m_flFlashMaxAlpha)
|
||||
SCHEMA_FIELD(float, m_flProgressBarStartTime)
|
||||
SCHEMA_FIELD(int32, m_iProgressBarDuration)
|
||||
SCHEMA_FIELD(bool, m_wasNotKilledNaturally)
|
||||
SCHEMA_FIELD(bool, m_bCommittingSuicideOnTeamChange)
|
||||
SCHEMA_FIELD(CHandle<CCSPlayerController>, m_hOriginalController)
|
||||
};
|
||||
|
||||
enum CSPlayerBlockingUseAction_t : uint
|
||||
{
|
||||
k_CSPlayerBlockingUseAction_None = 0x0,
|
||||
k_CSPlayerBlockingUseAction_DefusingDefault = 0x1,
|
||||
k_CSPlayerBlockingUseAction_DefusingWithKit = 0x2,
|
||||
k_CSPlayerBlockingUseAction_HostageGrabbing = 0x3,
|
||||
k_CSPlayerBlockingUseAction_HostageDropping = 0x4,
|
||||
k_CSPlayerBlockingUseAction_MapLongUseEntity_Pickup = 0x5,
|
||||
k_CSPlayerBlockingUseAction_MapLongUseEntity_Place = 0x6,
|
||||
k_CSPlayerBlockingUseAction_MaxCount = 0x7,
|
||||
};
|
||||
|
||||
class CCSPlayerPawn : public CCSPlayerPawnBase
|
||||
{
|
||||
public:
|
||||
DECLARE_SCHEMA_CLASS(CCSPlayerPawn);
|
||||
|
||||
SCHEMA_FIELD(CEconItemView, m_EconGloves)
|
||||
SCHEMA_FIELD(uint8, m_nEconGlovesChanged)
|
||||
SCHEMA_FIELD(uint16, m_nCharacterDefIndex)
|
||||
SCHEMA_FIELD(CUtlString, m_strVOPrefix)
|
||||
SCHEMA_FIELD(float, m_flVelocityModifier)
|
||||
SCHEMA_FIELD(CCSPlayer_ActionTrackingServices*, m_pActionTrackingServices)
|
||||
SCHEMA_FIELD(QAngle, m_angEyeAngles)
|
||||
SCHEMA_FIELD(GameTime_t, m_flHealthShotBoostExpirationTime)
|
||||
SCHEMA_FIELD(int32, m_ArmorValue)
|
||||
SCHEMA_FIELD(bool, m_bInBuyZone)
|
||||
SCHEMA_FIELD(bool, m_bInBombZone);
|
||||
SCHEMA_FIELD(EntitySpottedState_t, m_entitySpottedState)
|
||||
SCHEMA_FIELD(bool, m_bIsScoped)
|
||||
SCHEMA_FIELD(int, m_aimPunchTickBase)
|
||||
SCHEMA_FIELD(float, m_aimPunchTickFraction)
|
||||
SCHEMA_FIELD(QAngle, m_aimPunchAngle)
|
||||
SCHEMA_FIELD(QAngle, m_aimPunchAngleVel)
|
||||
SCHEMA_FIELD(CSPlayerBlockingUseAction_t, m_iBlockingUseActionInProgress);
|
||||
|
||||
uint8 GetCollisionGroup()
|
||||
{
|
||||
return m_Collision().m_collisionAttribute().m_nCollisionGroup();
|
||||
}
|
||||
|
||||
void SetCollisionGroup(uint8 nCollisionGroup = COLLISION_GROUP_DEBRIS)
|
||||
{
|
||||
m_Collision().m_CollisionGroup() = nCollisionGroup;
|
||||
m_Collision().m_collisionAttribute().m_nCollisionGroup() = nCollisionGroup;
|
||||
CollisionRulesChanged();
|
||||
}
|
||||
|
||||
QAngle GetEyeAngles() {
|
||||
return m_angEyeAngles.Get();
|
||||
}
|
||||
};
|
||||
|
||||
class CCSGO_TeamPreviewCharacterPosition: public CBaseEntity
|
||||
{
|
||||
public:
|
||||
DECLARE_SCHEMA_CLASS(CCSGO_TeamPreviewCharacterPosition);
|
||||
|
||||
SCHEMA_FIELD(int32, m_nVariant);
|
||||
SCHEMA_FIELD(int32, m_nRandom);
|
||||
SCHEMA_FIELD(int32, m_nOrdinal);
|
||||
SCHEMA_FIELD(CUtlString, m_sWeaponName);
|
||||
SCHEMA_FIELD(uint64, m_xuid);
|
||||
SCHEMA_FIELD_POINTER(CEconItemView, m_agentItem);
|
||||
SCHEMA_FIELD_POINTER(CEconItemView, m_glovesItem);
|
||||
SCHEMA_FIELD_POINTER(CEconItemView, m_weaponItem);
|
||||
};
|
||||
}
|
||||
232
src/schema/CCSWeaponBase.h
Normal file
232
src/schema/CCSWeaponBase.h
Normal file
|
|
@ -0,0 +1,232 @@
|
|||
//
|
||||
// Created by Michal Přikryl on 26.06.2025.
|
||||
// Copyright (c) 2025 slynxcz. All rights reserved.
|
||||
//
|
||||
#pragma once
|
||||
|
||||
#include "CBaseEntity.h"
|
||||
#include "virtual.h"
|
||||
|
||||
namespace TemplatePlugin {
|
||||
enum gear_slot_t : uint32_t
|
||||
{
|
||||
GEAR_SLOT_INVALID = 0xffffffff,
|
||||
GEAR_SLOT_RIFLE = 0x0,
|
||||
GEAR_SLOT_PISTOL = 0x1,
|
||||
GEAR_SLOT_KNIFE = 0x2,
|
||||
GEAR_SLOT_GRENADES = 0x3,
|
||||
GEAR_SLOT_C4 = 0x4,
|
||||
GEAR_SLOT_RESERVED_SLOT6 = 0x5,
|
||||
GEAR_SLOT_RESERVED_SLOT7 = 0x6,
|
||||
GEAR_SLOT_RESERVED_SLOT8 = 0x7,
|
||||
GEAR_SLOT_RESERVED_SLOT9 = 0x8,
|
||||
GEAR_SLOT_RESERVED_SLOT10 = 0x9,
|
||||
GEAR_SLOT_RESERVED_SLOT11 = 0xa,
|
||||
GEAR_SLOT_BOOSTS = 0xb,
|
||||
GEAR_SLOT_UTILITY = 0xc,
|
||||
GEAR_SLOT_COUNT = 0xd,
|
||||
GEAR_SLOT_FIRST = 0x0,
|
||||
GEAR_SLOT_LAST = 0xc,
|
||||
};
|
||||
|
||||
enum CSWeaponType : uint32_t
|
||||
{
|
||||
WEAPONTYPE_KNIFE = 0,
|
||||
WEAPONTYPE_PISTOL = 1,
|
||||
WEAPONTYPE_SUBMACHINEGUN = 2,
|
||||
WEAPONTYPE_RIFLE = 3,
|
||||
WEAPONTYPE_SHOTGUN = 4,
|
||||
WEAPONTYPE_SNIPER_RIFLE = 5,
|
||||
WEAPONTYPE_MACHINEGUN = 6,
|
||||
WEAPONTYPE_C4 = 7,
|
||||
WEAPONTYPE_TASER = 8,
|
||||
WEAPONTYPE_GRENADE = 9,
|
||||
WEAPONTYPE_EQUIPMENT = 10,
|
||||
WEAPONTYPE_STACKABLEITEM = 11,
|
||||
WEAPONTYPE_UNKNOWN = 12,
|
||||
};
|
||||
|
||||
enum CSWeaponCategory : uint32_t
|
||||
{
|
||||
WEAPONCATEGORY_OTHER = 0,
|
||||
WEAPONCATEGORY_MELEE = 1,
|
||||
WEAPONCATEGORY_SECONDARY = 2,
|
||||
WEAPONCATEGORY_SMG = 3,
|
||||
WEAPONCATEGORY_RIFLE = 4,
|
||||
WEAPONCATEGORY_HEAVY = 5,
|
||||
WEAPONCATEGORY_COUNT = 6,
|
||||
};
|
||||
|
||||
class CAttributeManager
|
||||
{
|
||||
public:
|
||||
DECLARE_SCHEMA_CLASS_INLINE(CAttributeManager);
|
||||
SCHEMA_FIELD_POINTER(CUtlVector<CAttributeManager>, m_CachedResults);
|
||||
};
|
||||
|
||||
class CEconItemAttribute
|
||||
{
|
||||
public:
|
||||
DECLARE_SCHEMA_CLASS_INLINE(CEconItemAttribute);
|
||||
SCHEMA_FIELD(uint16_t, m_iAttributeDefinitionIndex);
|
||||
SCHEMA_FIELD(float32, m_flValue);
|
||||
SCHEMA_FIELD(float32, m_flInitialValue);
|
||||
SCHEMA_FIELD(int32, m_nRefundableCurrency);
|
||||
SCHEMA_FIELD(bool, m_bSetBonus);
|
||||
};
|
||||
|
||||
class CAttributeList
|
||||
{
|
||||
public:
|
||||
DECLARE_SCHEMA_CLASS_INLINE(CAttributeList);
|
||||
SCHEMA_FIELD_POINTER(CUtlVector<CEconItemAttribute>, m_Attributes)
|
||||
SCHEMA_FIELD(CAttributeManager*, m_pManager);
|
||||
};
|
||||
|
||||
class CEconItemView
|
||||
{
|
||||
public:
|
||||
DECLARE_SCHEMA_CLASS_INLINE(CEconItemView);
|
||||
|
||||
SCHEMA_FIELD(uint16, m_iItemDefinitionIndex)
|
||||
SCHEMA_FIELD(int32, m_iEntityQuality)
|
||||
SCHEMA_FIELD(uint32, m_iEntityLevel)
|
||||
SCHEMA_FIELD(uint64_t, m_iItemID)
|
||||
SCHEMA_FIELD(uint32, m_iItemIDHigh)
|
||||
SCHEMA_FIELD(uint32, m_iItemIDLow)
|
||||
SCHEMA_FIELD(uint32, m_iAccountID)
|
||||
SCHEMA_FIELD(uint32, m_iInventoryPosition)
|
||||
SCHEMA_FIELD(bool, m_bInitialized)
|
||||
SCHEMA_FIELD(CAttributeList, m_AttributeList)
|
||||
SCHEMA_FIELD(CAttributeList, m_NetworkedDynamicAttributes)
|
||||
SCHEMA_FIELD_POINTER(char, m_szCustomName)
|
||||
SCHEMA_FIELD_POINTER(char, m_szCustomNameOverride)
|
||||
};
|
||||
|
||||
class CAttributeContainer
|
||||
{
|
||||
public:
|
||||
DECLARE_SCHEMA_CLASS_INLINE(CAttributeContainer);
|
||||
|
||||
SCHEMA_FIELD(CEconItemView, m_Item)
|
||||
};
|
||||
|
||||
class CEconEntity : public CBaseModelEntity
|
||||
{
|
||||
public:
|
||||
DECLARE_SCHEMA_CLASS(CEconEntity)
|
||||
|
||||
SCHEMA_FIELD(CAttributeContainer, m_AttributeManager)
|
||||
SCHEMA_FIELD(uint32, m_OriginalOwnerXuidLow)
|
||||
SCHEMA_FIELD(uint32, m_OriginalOwnerXuidHigh)
|
||||
SCHEMA_FIELD(int32, m_nFallbackPaintKit)
|
||||
SCHEMA_FIELD(int32, m_nFallbackSeed)
|
||||
SCHEMA_FIELD(float, m_flFallbackWear)
|
||||
SCHEMA_FIELD(int32, m_nFallbackStatTrak)
|
||||
};
|
||||
|
||||
class CEconWearable : public CEconEntity
|
||||
{
|
||||
public:
|
||||
DECLARE_SCHEMA_CLASS(CEconWearable)
|
||||
|
||||
SCHEMA_FIELD(int32, m_nForceSkin)
|
||||
SCHEMA_FIELD(bool, m_bAlwaysAllow)
|
||||
};
|
||||
|
||||
class CBasePlayerWeaponVData : public CEntitySubclassVDataBase
|
||||
{
|
||||
public:
|
||||
DECLARE_SCHEMA_CLASS(CBasePlayerWeaponVData)
|
||||
SCHEMA_FIELD(int, m_iMaxClip1)
|
||||
SCHEMA_FIELD(int, m_iMaxClip2)
|
||||
SCHEMA_FIELD(int, m_iDefaultClip1)
|
||||
};
|
||||
|
||||
class CCSWeaponBaseVData : public CBasePlayerWeaponVData
|
||||
{
|
||||
public:
|
||||
DECLARE_SCHEMA_CLASS(CCSWeaponBaseVData)
|
||||
|
||||
SCHEMA_FIELD(CSWeaponType, m_WeaponType);
|
||||
SCHEMA_FIELD(CSWeaponCategory, m_WeaponCategory);
|
||||
SCHEMA_FIELD(gear_slot_t, m_GearSlot)
|
||||
SCHEMA_FIELD(int, m_nPrice)
|
||||
SCHEMA_FIELD(CUtlString, m_szName)
|
||||
SCHEMA_FIELD(int, m_nPrimaryReserveAmmoMax)
|
||||
SCHEMA_FIELD(int, m_nSecondaryReserveAmmoMax)
|
||||
SCHEMA_FIELD(int, m_nDamage)
|
||||
};
|
||||
|
||||
class CBasePlayerWeapon : public CEconEntity
|
||||
{
|
||||
public:
|
||||
DECLARE_SCHEMA_CLASS(CBasePlayerWeapon)
|
||||
|
||||
SCHEMA_FIELD(int, m_nNextPrimaryAttackTick);
|
||||
SCHEMA_FIELD(float, m_flNextPrimaryAttackTickRatio);
|
||||
SCHEMA_FIELD(int, m_nNextSecondaryAttackTick);
|
||||
SCHEMA_FIELD(float, m_flNextSecondaryAttackTickRatio);
|
||||
|
||||
SCHEMA_FIELD(int32_t, m_iClip1);
|
||||
SCHEMA_FIELD(int32_t, m_iClip2);
|
||||
SCHEMA_FIELD_POINTER(int, m_pReserveAmmo);
|
||||
|
||||
CCSWeaponBaseVData* GetWeaponVData() { return (CCSWeaponBaseVData*)GetVData(); }
|
||||
|
||||
const char* GetWeaponClassname() noexcept
|
||||
{
|
||||
const char* pszClassname = GetClassname();
|
||||
if (V_StringHasPrefixCaseSensitive(pszClassname, "item_"))
|
||||
return pszClassname;
|
||||
|
||||
switch (m_AttributeManager().m_Item().m_iItemDefinitionIndex)
|
||||
{
|
||||
case 23:
|
||||
return "weapon_mp5sd";
|
||||
case 41:
|
||||
return "weapon_knifegg";
|
||||
case 42:
|
||||
return "weapon_knife";
|
||||
case 59:
|
||||
return "weapon_knife_t";
|
||||
case 60:
|
||||
return "weapon_m4a1_silencer";
|
||||
case 61:
|
||||
return "weapon_usp_silencer";
|
||||
case 63:
|
||||
return "weapon_cz75a";
|
||||
case 64:
|
||||
return "weapon_revolver";
|
||||
default:
|
||||
return pszClassname;
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
class CCSWeaponBase : public CBasePlayerWeapon
|
||||
{
|
||||
public:
|
||||
DECLARE_SCHEMA_CLASS(CCSWeaponBase)
|
||||
|
||||
SCHEMA_FIELD(bool, m_bInReload);
|
||||
SCHEMA_FIELD(bool, m_bReloadVisuallyComplete);
|
||||
SCHEMA_FIELD(bool, m_bRequireUseToTouch);
|
||||
SCHEMA_FIELD(float, m_flDroppedAtTime);
|
||||
SCHEMA_FIELD(float, m_fAccuracyPenalty);
|
||||
SCHEMA_FIELD(float, m_flRecoilIndex);
|
||||
SCHEMA_FIELD(int, m_iRecoilIndex);
|
||||
};
|
||||
|
||||
class CWeaponBaseItem : public CCSWeaponBase
|
||||
{
|
||||
public:
|
||||
DECLARE_SCHEMA_CLASS(CWeaponBaseItem)
|
||||
};
|
||||
|
||||
class CCSWeaponBaseGun : public CCSWeaponBase
|
||||
{
|
||||
public:
|
||||
DECLARE_SCHEMA_CLASS(CCSWeaponBaseGun)
|
||||
};
|
||||
}
|
||||
26
src/schema/CChicken.h
Normal file
26
src/schema/CChicken.h
Normal file
|
|
@ -0,0 +1,26 @@
|
|||
//
|
||||
// Created by Michal Přikryl on 26.06.2025.
|
||||
// Copyright (c) 2025 slynxcz. All rights reserved.
|
||||
//
|
||||
#pragma once
|
||||
#include "CBaseEntity.h"
|
||||
|
||||
namespace TemplatePlugin {
|
||||
enum class ChickenActivity : uint32_t {
|
||||
IDLE = 0x0,
|
||||
SQUAT = 0x1,
|
||||
WALK = 0x2,
|
||||
RUN = 0x3,
|
||||
GLIDE = 0x4,
|
||||
LAND = 0x5,
|
||||
PANIC = 0x6
|
||||
};
|
||||
|
||||
class CChicken : public CBaseEntity
|
||||
{
|
||||
public:
|
||||
DECLARE_SCHEMA_CLASS(CChicken)
|
||||
|
||||
SCHEMA_FIELD(ChickenActivity, m_currentActivity)
|
||||
};
|
||||
}
|
||||
50
src/schema/CDynamicProp.h
Normal file
50
src/schema/CDynamicProp.h
Normal file
|
|
@ -0,0 +1,50 @@
|
|||
//
|
||||
// Created by Michal Přikryl on 01.11.2025.
|
||||
// Copyright (c) 2025 slynxcz. All rights reserved.
|
||||
//
|
||||
#pragma once
|
||||
#include "CBaseEntity.h"
|
||||
#include "globaltypes.h"
|
||||
#include "CBreakableProp.h"
|
||||
|
||||
namespace
|
||||
TemplatePlugin
|
||||
{
|
||||
enum AnimLoopMode_t : uint
|
||||
{
|
||||
ANIM_LOOP_MODE_INVALID = 0xFFFFFFFF,
|
||||
ANIM_LOOP_MODE_NOT_LOOPING = 0x0,
|
||||
ANIM_LOOP_MODE_LOOPING = 0x1,
|
||||
ANIM_LOOP_MODE_USE_SEQUENCE_SETTINGS = 0x2,
|
||||
ANIM_LOOP_MODE_COUNT = 0x3,
|
||||
};
|
||||
|
||||
class CDynamicProp : public CBreakableProp
|
||||
{
|
||||
public:
|
||||
DECLARE_SCHEMA_CLASS(CDynamicProp);
|
||||
|
||||
SCHEMA_FIELD(bool, m_bCreateNavObstacle)
|
||||
SCHEMA_FIELD(bool, m_bNavObstacleUpdatesOverridden)
|
||||
SCHEMA_FIELD(bool, m_bUseHitboxesForRenderBox)
|
||||
SCHEMA_FIELD(bool, m_bUseAnimGraph)
|
||||
SCHEMA_FIELD(CEntityIOOutput, m_pOutputAnimBegun)
|
||||
SCHEMA_FIELD(CEntityIOOutput, m_pOutputAnimOver)
|
||||
SCHEMA_FIELD(CEntityIOOutput, m_pOutputAnimLoopCycleOver)
|
||||
SCHEMA_FIELD(CEntityIOOutput, m_OnAnimReachedStart)
|
||||
SCHEMA_FIELD(CEntityIOOutput, m_OnAnimReachedEnd)
|
||||
SCHEMA_FIELD_POINTER(char, m_iszIdleAnim)
|
||||
SCHEMA_FIELD(AnimLoopMode_t, m_nIdleAnimLoopMode)
|
||||
SCHEMA_FIELD(bool, m_bRandomizeCycle)
|
||||
SCHEMA_FIELD(bool, m_bStartDisabled)
|
||||
SCHEMA_FIELD(bool, m_bFiredStartEndOutput)
|
||||
SCHEMA_FIELD(bool, m_bForceNpcExclude)
|
||||
SCHEMA_FIELD(bool, m_bCreateNonSolid)
|
||||
SCHEMA_FIELD(bool, m_bIsOverrideProp)
|
||||
SCHEMA_FIELD(int32, m_iInitialGlowState)
|
||||
SCHEMA_FIELD(int32, m_nGlowRange)
|
||||
SCHEMA_FIELD(int32, m_nGlowRangeMin)
|
||||
SCHEMA_FIELD(Color, m_glowColor)
|
||||
SCHEMA_FIELD(int32, m_nGlowTeam)
|
||||
};
|
||||
}
|
||||
20
src/schema/CEnvEntityMarker.h
Normal file
20
src/schema/CEnvEntityMarker.h
Normal file
|
|
@ -0,0 +1,20 @@
|
|||
//
|
||||
// Created by Michal Přikryl on 26.06.2025.
|
||||
// Copyright (c) 2025 slynxcz. All rights reserved.
|
||||
//
|
||||
#pragma once
|
||||
|
||||
#include "CBaseEntity.h"
|
||||
#include"schemasystem.h"
|
||||
|
||||
#define SF_TRIG_PUSH_ONCE 0x80
|
||||
|
||||
namespace TemplatePlugin {
|
||||
class CEnvEntityMaker : public CBaseEntity
|
||||
{
|
||||
public:
|
||||
DECLARE_SCHEMA_CLASS(CEnvEntityMaker);
|
||||
|
||||
SCHEMA_FIELD(CUtlSymbolLarge, m_iszTemplate)
|
||||
};
|
||||
}
|
||||
29
src/schema/CFuncBrush.h
Normal file
29
src/schema/CFuncBrush.h
Normal file
|
|
@ -0,0 +1,29 @@
|
|||
//
|
||||
// Created by Michal Přikryl on 07.11.2025.
|
||||
// Copyright (c) 2025 slynxcz. All rights reserved.
|
||||
#pragma once
|
||||
#include "CBaseModelEntity.h"
|
||||
#include "globaltypes.h"
|
||||
|
||||
namespace
|
||||
TemplatePlugin
|
||||
{
|
||||
enum BrushSolidities_e : uint
|
||||
{
|
||||
BRUSHSOLID_TOGGLE,
|
||||
BRUSHSOLID_NEVER,
|
||||
BRUSHSOLID_ALWAYS,
|
||||
};
|
||||
|
||||
class CFuncBrush : public CBaseModelEntity
|
||||
{
|
||||
public:
|
||||
DECLARE_SCHEMA_CLASS(CFuncBrush);
|
||||
SCHEMA_FIELD(BrushSolidities_e, m_iSolidity)
|
||||
SCHEMA_FIELD(int, m_iDisabled)
|
||||
SCHEMA_FIELD(bool, m_bSolidBsp)
|
||||
SCHEMA_FIELD_POINTER(char, m_iszExcludedClass)
|
||||
SCHEMA_FIELD(bool, m_bInvertExclusion)
|
||||
SCHEMA_FIELD(bool, m_bScriptedMovement)
|
||||
};
|
||||
}
|
||||
17
src/schema/CFuncVPhysicsClip.h
Normal file
17
src/schema/CFuncVPhysicsClip.h
Normal file
|
|
@ -0,0 +1,17 @@
|
|||
//
|
||||
// Created by Michal Přikryl on 07.11.2025.
|
||||
// Copyright (c) 2025 slynxcz. All rights reserved.
|
||||
#pragma once
|
||||
#include "CBaseModelEntity.h"
|
||||
#include "globaltypes.h"
|
||||
|
||||
namespace
|
||||
TemplatePlugin
|
||||
{
|
||||
class CFuncVPhysicsClip : public CBaseModelEntity
|
||||
{
|
||||
public:
|
||||
DECLARE_SCHEMA_CLASS(CFuncVPhysicsClip);
|
||||
SCHEMA_FIELD(int, m_bDisabled)
|
||||
};
|
||||
}
|
||||
125
src/schema/CGameRules.h
Normal file
125
src/schema/CGameRules.h
Normal file
|
|
@ -0,0 +1,125 @@
|
|||
//
|
||||
// Created by Michal Přikryl on 26.06.2025.
|
||||
// Copyright (c) 2025 slynxcz. All rights reserved.
|
||||
//
|
||||
#pragma once
|
||||
#include <platform.h>
|
||||
#include "CBaseEntity.h"
|
||||
|
||||
namespace TemplatePlugin {
|
||||
enum class RoundEndReason : uint32_t
|
||||
{
|
||||
Unknown = 0x0u,
|
||||
TargetBombed = 0x1u,
|
||||
TerroristsEscaped = 0x4u,
|
||||
CTsPreventEscape = 0x5u,
|
||||
EscapingTerroristsNeutralized = 0x6u,
|
||||
BombDefused = 0x7u,
|
||||
CTsWin = 0x8u,
|
||||
TerroristsWin = 0x9u,
|
||||
RoundDraw = 0xAu,
|
||||
AllHostageRescued = 0xBu,
|
||||
TargetSaved = 0xCu,
|
||||
HostagesNotRescued = 0xDu,
|
||||
TerroristsNotEscaped = 0xEu,
|
||||
GameCommencing = 0x10u,
|
||||
|
||||
TerroristsSurrender = 0x11u,
|
||||
CTsSurrender = 0x12u,
|
||||
|
||||
TerroristsPlanted = 0x13u,
|
||||
CTsReachedHostage = 0x14u,
|
||||
SurvivalWin = 0x15u,
|
||||
SurvivalDraw = 0x16u,
|
||||
|
||||
TerroristsPlanned = 0x13u
|
||||
};
|
||||
|
||||
class CGameRules
|
||||
{
|
||||
public:
|
||||
DECLARE_SCHEMA_CLASS(CGameRules)
|
||||
};
|
||||
|
||||
class CCSGameModeRules_Deathmatch : public CGameRules
|
||||
{
|
||||
public:
|
||||
DECLARE_SCHEMA_CLASS(CCSGameModeRules_Deathmatch)
|
||||
|
||||
SCHEMA_FIELD(GameTime_t, m_flDMBonusStartTime);
|
||||
SCHEMA_FIELD(float32, m_flDMBonusTimeLength);
|
||||
SCHEMA_FIELD(CUtlString, m_sDMBonusWeapon);
|
||||
};
|
||||
|
||||
class CCSGameRules;
|
||||
|
||||
class CCSGameRulesProxy : public CBaseEntity
|
||||
{
|
||||
public:
|
||||
DECLARE_SCHEMA_CLASS(CCSGameRulesProxy)
|
||||
|
||||
SCHEMA_FIELD(CCSGameRules *, m_pGameRules);
|
||||
};
|
||||
|
||||
class CCSGameRules : public CGameRules
|
||||
{
|
||||
public:
|
||||
DECLARE_SCHEMA_CLASS(CCSGameRules)
|
||||
|
||||
SCHEMA_FIELD(float, m_fMatchStartTime);
|
||||
SCHEMA_FIELD(float, m_flGameStartTime);
|
||||
SCHEMA_FIELD(int, m_totalRoundsPlayed);
|
||||
SCHEMA_FIELD(float, m_fRoundStartTime);
|
||||
SCHEMA_FIELD(float, m_flRestartRoundTime);
|
||||
SCHEMA_FIELD_POINTER(int, m_nEndMatchMapGroupVoteOptions)
|
||||
SCHEMA_FIELD(int, m_nEndMatchMapVoteWinner);
|
||||
SCHEMA_FIELD(int, m_iRoundTime);
|
||||
SCHEMA_FIELD(bool, m_bWarmupPeriod);
|
||||
SCHEMA_FIELD(float, m_fWarmupPeriodEnd);
|
||||
SCHEMA_FIELD(float, m_fWarmupPeriodStart);
|
||||
SCHEMA_FIELD(GamePhase, m_gamePhase);
|
||||
SCHEMA_FIELD(bool, m_bGameRestart);
|
||||
SCHEMA_FIELD(bool, m_bBombPlanted);
|
||||
SCHEMA_FIELD(int32_t, m_totaArenaoundsPlayed);
|
||||
SCHEMA_FIELD(int32_t, m_nOvertimePlaying);
|
||||
SCHEMA_FIELD(bool, m_bBuyTimeEnded);
|
||||
SCHEMA_FIELD(bool, m_bTCantBuy);
|
||||
SCHEMA_FIELD(bool, m_bCTCantBuy);
|
||||
SCHEMA_FIELD(bool, m_bSwitchingTeamsAtRoundReset);
|
||||
SCHEMA_FIELD(int, m_iRoundEndWinnerTeam);
|
||||
SCHEMA_FIELD(CUtlString, m_sRoundEndMessage);
|
||||
SCHEMA_FIELD(CUtlString, m_sRoundEndFunFactToken);
|
||||
SCHEMA_FIELD(bool, m_bIsValveDS);
|
||||
SCHEMA_FIELD(bool, m_bIsQuestEligible);
|
||||
SCHEMA_FIELD(int32, m_iSpectatorSlotCount);
|
||||
SCHEMA_FIELD(float, m_fWarmupNextChatNoticeTime);
|
||||
SCHEMA_FIELD_POINTER(CUtlVector<SpawnPoint*>, m_CTSpawnPoints);
|
||||
SCHEMA_FIELD_POINTER(CUtlVector<SpawnPoint*>, m_TerroristSpawnPoints);
|
||||
|
||||
using TerminateRoundFn = void(*)(CCSGameRules*, RoundEndReason, float, void*, uint8_t);
|
||||
TerminateRoundFn s_pTerminateRound = nullptr;
|
||||
|
||||
void TerminateRound(float delay, RoundEndReason roundEndReason) {
|
||||
if (!s_pTerminateRound) {
|
||||
TerminateRoundFn addr = DynLibUtils::CModule(shared::g_pServer).FindPattern(
|
||||
shared::g_pGameConfig->GetSignature("CCSGameRules_TerminateRound")).RCast<TerminateRoundFn>();
|
||||
|
||||
if (!addr)
|
||||
return;
|
||||
|
||||
s_pTerminateRound = addr;
|
||||
}
|
||||
s_pTerminateRound(this, roundEndReason, delay, nullptr, 0);
|
||||
}
|
||||
|
||||
static CCSGameRules* FindGameRules()
|
||||
{
|
||||
auto entities = UTIL_FindAllEntitiesByDesignerName<CCSGameRulesProxy>("cs_gamerules");
|
||||
if (entities.empty())
|
||||
return nullptr;
|
||||
|
||||
auto* proxy = entities.front();
|
||||
return proxy ? proxy->m_pGameRules() : nullptr;
|
||||
}
|
||||
};
|
||||
}
|
||||
38
src/schema/CParticleSystem.h
Normal file
38
src/schema/CParticleSystem.h
Normal file
|
|
@ -0,0 +1,38 @@
|
|||
//
|
||||
// Created by Michal Přikryl on 26.06.2025.
|
||||
// Copyright (c) 2025 slynxcz. All rights reserved.
|
||||
//
|
||||
#pragma once
|
||||
|
||||
#include "CBaseModelEntity.h"
|
||||
|
||||
namespace TemplatePlugin {
|
||||
class CParticleSystem : public CBaseModelEntity
|
||||
{
|
||||
public:
|
||||
DECLARE_SCHEMA_CLASS(CParticleSystem);
|
||||
|
||||
SCHEMA_FIELD(bool, m_bActive)
|
||||
SCHEMA_FIELD(bool, m_bStartActive)
|
||||
SCHEMA_FIELD(bool, m_bFrozen)
|
||||
SCHEMA_FIELD(float32, m_flFreezeTransitionDuration)
|
||||
SCHEMA_FIELD(int32, m_nStopType)
|
||||
SCHEMA_FIELD(bool, m_bAnimateDuringGameplayPause)
|
||||
SCHEMA_FIELD(CUtlSymbolLarge, m_iszEffectName)
|
||||
SCHEMA_FIELD(int, m_nTintCP)
|
||||
SCHEMA_FIELD(GameTime_t, m_flStartTime)
|
||||
SCHEMA_FIELD_POINTER(Color, m_clrTint)
|
||||
SCHEMA_FIELD_POINTER(CHandle<CBaseEntity>, m_hControlPointEnts)
|
||||
};
|
||||
|
||||
class CEnvParticleGlow : public CParticleSystem
|
||||
{
|
||||
public:
|
||||
DECLARE_SCHEMA_CLASS(CEnvParticleGlow);
|
||||
|
||||
SCHEMA_FIELD(float, m_flAlphaScale)
|
||||
SCHEMA_FIELD(float, m_flRadiusScale)
|
||||
SCHEMA_FIELD(float, m_flSelfIllumScale)
|
||||
SCHEMA_FIELD_POINTER(Color, m_ColorTint)
|
||||
};
|
||||
}
|
||||
27
src/schema/CPhysExplosion.h
Normal file
27
src/schema/CPhysExplosion.h
Normal file
|
|
@ -0,0 +1,27 @@
|
|||
//
|
||||
// Created by Michal Přikryl on 09.11.2025.
|
||||
// Copyright (c) 2025 slynxcz. All rights reserved.
|
||||
//
|
||||
#pragma once
|
||||
#include "CBaseEntity.h"
|
||||
#include "globaltypes.h"
|
||||
|
||||
namespace TemplatePlugin
|
||||
{
|
||||
class CPhysExplosion : public CBaseEntity
|
||||
{
|
||||
public:
|
||||
DECLARE_SCHEMA_CLASS(CPhysExplosion);
|
||||
|
||||
SCHEMA_FIELD(bool, m_bExplodeOnSpawn)
|
||||
SCHEMA_FIELD(float, m_flMagnitude)
|
||||
SCHEMA_FIELD(float, m_flDamage)
|
||||
SCHEMA_FIELD(float, m_radius)
|
||||
SCHEMA_FIELD_POINTER(char, m_targetEntityName)
|
||||
SCHEMA_FIELD(float, m_flInnerRadius)
|
||||
SCHEMA_FIELD(float, m_flPushScale)
|
||||
SCHEMA_FIELD(bool, m_bConvertToDebrisWhenPossible)
|
||||
SCHEMA_FIELD(bool, m_bAffectInvulnerableEnts)
|
||||
SCHEMA_FIELD(CEntityIOOutput, m_OnPushedPlayer)
|
||||
};
|
||||
}
|
||||
70
src/schema/CPhysicsProp.h
Normal file
70
src/schema/CPhysicsProp.h
Normal file
|
|
@ -0,0 +1,70 @@
|
|||
//
|
||||
// Created by Michal Přikryl on 01.11.2025.
|
||||
// Copyright (c) 2025 slynxcz. All rights reserved.
|
||||
//
|
||||
#pragma once
|
||||
#include "CBaseEntity.h"
|
||||
#include "globaltypes.h"
|
||||
#include "CBreakableProp.h"
|
||||
|
||||
namespace
|
||||
TemplatePlugin
|
||||
{
|
||||
enum DynamicContinuousContactBehavior_t : byte
|
||||
{
|
||||
DYNAMIC_CONTINUOUS_ALLOW_IF_REQUESTED_BY_OTHER_BODY = 0x0,
|
||||
DYNAMIC_CONTINUOUS_ALWAYS = 0x1,
|
||||
DYNAMIC_CONTINUOUS_NEVER = 0x2,
|
||||
};
|
||||
|
||||
enum CPhysicsPropCrateType_t : uint
|
||||
{
|
||||
CRATE_SPECIFIC_ITEM = 0x0,
|
||||
CRATE_TYPE_COUNT = 0x1,
|
||||
};
|
||||
|
||||
class CPhysicsProp : public CBreakableProp
|
||||
{
|
||||
public:
|
||||
DECLARE_SCHEMA_CLASS(CPhysicsProp);
|
||||
|
||||
SCHEMA_FIELD(CEntityIOOutput, m_MotionEnabled)
|
||||
SCHEMA_FIELD(CEntityIOOutput, m_OnAwakened)
|
||||
SCHEMA_FIELD(CEntityIOOutput, m_OnAwake)
|
||||
SCHEMA_FIELD(CEntityIOOutput, m_OnAsleep)
|
||||
SCHEMA_FIELD(CEntityIOOutput, m_OnPlayerUse)
|
||||
SCHEMA_FIELD(CEntityIOOutput, m_OnOutOfWorld)
|
||||
SCHEMA_FIELD(CEntityIOOutput, m_OnPlayerPickup)
|
||||
SCHEMA_FIELD(bool, m_bForceNavIgnore)
|
||||
SCHEMA_FIELD(bool, m_bNoNavmeshBlocker)
|
||||
SCHEMA_FIELD(bool, m_bForceNpcExclude)
|
||||
SCHEMA_FIELD(float, m_massScale)
|
||||
SCHEMA_FIELD(float, m_buoyancyScale)
|
||||
SCHEMA_FIELD(int32, m_damageType)
|
||||
SCHEMA_FIELD(int32, m_damageToEnableMotion)
|
||||
SCHEMA_FIELD(float, m_flForceToEnableMotion)
|
||||
SCHEMA_FIELD(bool, m_bThrownByPlayer)
|
||||
SCHEMA_FIELD(bool, m_bDroppedByPlayer)
|
||||
SCHEMA_FIELD(bool, m_bTouchedByPlayer)
|
||||
SCHEMA_FIELD(bool, m_bFirstCollisionAfterLaunch)
|
||||
SCHEMA_FIELD(bool, m_bHasBeenAwakened)
|
||||
SCHEMA_FIELD(bool, m_bIsOverrideProp)
|
||||
SCHEMA_FIELD(float, m_flLastBurn)
|
||||
SCHEMA_FIELD(DynamicContinuousContactBehavior_t, m_nDynamicContinuousContactBehavior)
|
||||
SCHEMA_FIELD(float, m_fNextCheckDisableMotionContactsTime)
|
||||
SCHEMA_FIELD(int32, m_iInitialGlowState)
|
||||
SCHEMA_FIELD(int32, m_nGlowRange)
|
||||
SCHEMA_FIELD(int32, m_nGlowRangeMin)
|
||||
SCHEMA_FIELD(Color, m_glowColor)
|
||||
SCHEMA_FIELD(bool, m_bShouldAutoConvertBackFromDebris)
|
||||
SCHEMA_FIELD(bool, m_bMuteImpactEffects)
|
||||
SCHEMA_FIELD(bool, m_bAcceptDamageFromHeldObjects)
|
||||
SCHEMA_FIELD(bool, m_bEnableUseOutput)
|
||||
SCHEMA_FIELD(CPhysicsPropCrateType_t, m_CrateType)
|
||||
SCHEMA_FIELD_POINTER(char, m_strItemClass)
|
||||
SCHEMA_FIELD_POINTER(int32, m_nItemCount)
|
||||
SCHEMA_FIELD(bool, m_bRemovableForAmmoBalancing)
|
||||
SCHEMA_FIELD(bool, m_bAwake)
|
||||
SCHEMA_FIELD(bool, m_bAttachedToReferenceFrame)
|
||||
};
|
||||
}
|
||||
18
src/schema/CPlantedC4.h
Normal file
18
src/schema/CPlantedC4.h
Normal file
|
|
@ -0,0 +1,18 @@
|
|||
//
|
||||
// Created by Michal Přikryl on 26.06.2025.
|
||||
// Copyright (c) 2025 slynxcz. All rights reserved.
|
||||
//
|
||||
#pragma once
|
||||
#include "CBaseModelEntity.h"
|
||||
#include "globaltypes.h"
|
||||
|
||||
namespace TemplatePlugin {
|
||||
class CPlantedC4 : public CBaseModelEntity
|
||||
{
|
||||
public:
|
||||
DECLARE_SCHEMA_CLASS(CPlantedC4)
|
||||
|
||||
SCHEMA_FIELD(GameTime_t, m_flC4Blow);
|
||||
SCHEMA_FIELD(GameTime_t, m_flDefuseCountDown);
|
||||
};
|
||||
}
|
||||
74
src/schema/CPointWorldText.h
Normal file
74
src/schema/CPointWorldText.h
Normal file
|
|
@ -0,0 +1,74 @@
|
|||
/**
|
||||
* =============================================================================
|
||||
* CS2Fixes
|
||||
* Copyright (C) 2023-2025 Source2ZE
|
||||
* =============================================================================
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it under
|
||||
* the terms of the GNU General Public License, version 3.0, as published by the
|
||||
* Free Software Foundation.
|
||||
*
|
||||
* This program 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
|
||||
* this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "CBaseModelEntity.h"
|
||||
|
||||
namespace TemplatePlugin {
|
||||
enum class PointWorldTextJustifyHorizontal_t : uint32_t
|
||||
{
|
||||
POINT_WORLD_TEXT_JUSTIFY_HORIZONTAL_LEFT = 0x0,
|
||||
POINT_WORLD_TEXT_JUSTIFY_HORIZONTAL_CENTER = 0x1,
|
||||
POINT_WORLD_TEXT_JUSTIFY_HORIZONTAL_RIGHT = 0x2,
|
||||
};
|
||||
|
||||
enum class PointWorldTextJustifyVertical_t : uint32_t
|
||||
{
|
||||
POINT_WORLD_TEXT_JUSTIFY_VERTICAL_BOTTOM = 0x0,
|
||||
POINT_WORLD_TEXT_JUSTIFY_VERTICAL_CENTER = 0x1,
|
||||
POINT_WORLD_TEXT_JUSTIFY_VERTICAL_TOP = 0x2,
|
||||
};
|
||||
|
||||
enum class PointWorldTextReorientMode_t : uint32_t
|
||||
{
|
||||
POINT_WORLD_TEXT_REORIENT_NONE = 0x0,
|
||||
POINT_WORLD_TEXT_REORIENT_AROUND_UP = 0x1,
|
||||
};
|
||||
|
||||
class CPointWorldText : public CBaseModelEntity
|
||||
{
|
||||
public:
|
||||
DECLARE_SCHEMA_CLASS(CPointWorldText)
|
||||
|
||||
SCHEMA_FIELD_POINTER(char, m_messageText) // char m_messageText[512]
|
||||
SCHEMA_FIELD_POINTER(char, m_FontName) // char m_FontName[64]
|
||||
SCHEMA_FIELD_POINTER(char, m_BackgroundMaterialName) // char m_BackgroundMaterialName[64]
|
||||
|
||||
SCHEMA_FIELD(bool, m_bEnabled)
|
||||
SCHEMA_FIELD(bool, m_bFullbright)
|
||||
SCHEMA_FIELD(float, m_flWorldUnitsPerPx)
|
||||
SCHEMA_FIELD(float, m_flFontSize)
|
||||
SCHEMA_FIELD(float, m_flDepthOffset)
|
||||
SCHEMA_FIELD(bool, m_bDrawBackground)
|
||||
SCHEMA_FIELD(float, m_flBackgroundBorderWidth)
|
||||
SCHEMA_FIELD(float, m_flBackgroundBorderHeight)
|
||||
SCHEMA_FIELD(float, m_flBackgroundWorldToUV)
|
||||
SCHEMA_FIELD(Color, m_Color)
|
||||
|
||||
SCHEMA_FIELD(PointWorldTextJustifyHorizontal_t, m_nJustifyHorizontal)
|
||||
SCHEMA_FIELD(PointWorldTextJustifyVertical_t, m_nJustifyVertical)
|
||||
SCHEMA_FIELD(PointWorldTextReorientMode_t, m_nReorientMode)
|
||||
|
||||
void SetMessage(const char* sMessage)
|
||||
{
|
||||
V_strncpy(m_messageText, sMessage, 512);
|
||||
}
|
||||
};
|
||||
}
|
||||
80
src/schema/CRecipientFilter.h
Normal file
80
src/schema/CRecipientFilter.h
Normal file
|
|
@ -0,0 +1,80 @@
|
|||
//
|
||||
// Created by Michal Přikryl on 17.08.2025.
|
||||
// Copyright (c) 2025 slynxcz. All rights reserved.
|
||||
//
|
||||
#pragma once
|
||||
#include "irecipientfilter.h"
|
||||
|
||||
class CRecipientFilter : public IRecipientFilter
|
||||
{
|
||||
public:
|
||||
CRecipientFilter(NetChannelBufType_t nBufType = BUF_RELIABLE, bool bInitMessage = false)
|
||||
: m_nBufType(nBufType), m_bInitMessage(bInitMessage)
|
||||
{
|
||||
}
|
||||
|
||||
CRecipientFilter(const IRecipientFilter* source, CPlayerSlot exceptSlot = -1)
|
||||
{
|
||||
m_Recipients = source->GetRecipients();
|
||||
m_nBufType = source->GetNetworkBufType();
|
||||
m_bInitMessage = source->IsInitMessage();
|
||||
|
||||
if (exceptSlot != -1)
|
||||
m_Recipients.Clear(exceptSlot.Get());
|
||||
}
|
||||
|
||||
~CRecipientFilter() override = default;
|
||||
|
||||
NetChannelBufType_t GetNetworkBufType() const override { return m_nBufType; }
|
||||
bool IsInitMessage() const override { return m_bInitMessage; }
|
||||
const CPlayerBitVec& GetRecipients() const override { return m_Recipients; }
|
||||
CPlayerSlot GetPredictedPlayerSlot() const override { return m_slotPlayerExcludedDueToPrediction; }
|
||||
virtual CPlayerSlot GetExcludedPlayerDueToPrediction() const { return m_slotPlayerExcludedDueToPrediction; }
|
||||
|
||||
void AddRecipient(CPlayerSlot slot)
|
||||
{
|
||||
if (slot.Get() >= 0 && slot.Get() < ABSOLUTE_PLAYER_LIMIT)
|
||||
m_Recipients.Set(slot.Get());
|
||||
}
|
||||
|
||||
void AddRecipientsFromMask(uint64 mask)
|
||||
{
|
||||
for (int i = 0; i < 64; ++i)
|
||||
{
|
||||
if (mask & (uint64{1} << i))
|
||||
AddRecipient(CPlayerSlot(i));
|
||||
}
|
||||
}
|
||||
|
||||
int GetRecipientCount() const
|
||||
{
|
||||
const auto& vec = GetRecipients();
|
||||
int count = 0;
|
||||
for (int i = 0; i < ABSOLUTE_PLAYER_LIMIT; ++i)
|
||||
{
|
||||
if (vec.Get(i))
|
||||
++count;
|
||||
}
|
||||
return count;
|
||||
}
|
||||
|
||||
protected:
|
||||
CPlayerBitVec m_Recipients;
|
||||
CPlayerSlot m_slotPlayerExcludedDueToPrediction = -1;
|
||||
NetChannelBufType_t m_nBufType = BUF_DEFAULT;
|
||||
bool m_bInitMessage = false;
|
||||
bool m_bDoNotSuppressPrediction = false; // unused
|
||||
};
|
||||
|
||||
class CSingleRecipientFilter : public CRecipientFilter
|
||||
{
|
||||
public:
|
||||
CSingleRecipientFilter(CPlayerSlot nRecipientSlot,
|
||||
NetChannelBufType_t nBufType = BUF_RELIABLE,
|
||||
bool bInitMessage = false)
|
||||
: CRecipientFilter(nBufType, bInitMessage)
|
||||
{
|
||||
if (nRecipientSlot.Get() >= 0 && nRecipientSlot.Get() < ABSOLUTE_PLAYER_LIMIT)
|
||||
m_Recipients.Set(nRecipientSlot.Get());
|
||||
}
|
||||
};
|
||||
28
src/schema/CSkyCamera.h
Normal file
28
src/schema/CSkyCamera.h
Normal file
|
|
@ -0,0 +1,28 @@
|
|||
//
|
||||
// Created by Michal Přikryl on 26.06.2025.
|
||||
// Copyright (c) 2025 slynxcz. All rights reserved.
|
||||
//
|
||||
#pragma once
|
||||
#include "CBaseEntity.h"
|
||||
#include "globaltypes.h"
|
||||
#include "CBaseModelEntity.h"
|
||||
|
||||
namespace TemplatePlugin {
|
||||
class CSkyCamera : public CBaseEntity
|
||||
{
|
||||
public:
|
||||
DECLARE_SCHEMA_CLASS(CSkyCamera)
|
||||
SCHEMA_FIELD(CUtlStringToken, m_skyboxSlotToken);
|
||||
};
|
||||
|
||||
class CEnvSky : public CBaseModelEntity
|
||||
{
|
||||
public:
|
||||
DECLARE_SCHEMA_CLASS(CEnvSky)
|
||||
|
||||
SCHEMA_FIELD(int, m_hSkyMaterial)
|
||||
SCHEMA_FIELD(int, m_hSkyMaterialLightingOnly)
|
||||
SCHEMA_FIELD(Color, m_vTintColor)
|
||||
SCHEMA_FIELD(float32, m_flBrightnessScale)
|
||||
};
|
||||
}
|
||||
40
src/schema/CSoundEventEntity.h
Normal file
40
src/schema/CSoundEventEntity.h
Normal file
|
|
@ -0,0 +1,40 @@
|
|||
//
|
||||
// Created by Michal Přikryl on 23.08.2025.
|
||||
// Copyright (c) 2025 slynxcz. All rights reserved.
|
||||
//
|
||||
#pragma once
|
||||
#include "CBaseEntity.h"
|
||||
|
||||
namespace TemplatePlugin {
|
||||
class CSoundEventEntity : public CBaseEntity {
|
||||
public:
|
||||
DECLARE_SCHEMA_CLASS(CSoundEventEntity)
|
||||
SCHEMA_FIELD(bool, m_bStartOnSpawn);
|
||||
|
||||
SCHEMA_FIELD(bool, m_bToLocalPlayer);
|
||||
|
||||
SCHEMA_FIELD(bool, m_bStopOnNew);
|
||||
|
||||
SCHEMA_FIELD(bool, m_bSaveRestore);
|
||||
|
||||
SCHEMA_FIELD(bool, m_bSavedIsPlaying);
|
||||
|
||||
SCHEMA_FIELD(float32, m_flSavedElapsedTime);
|
||||
|
||||
SCHEMA_FIELD(CUtlSymbolLarge, m_iszSourceEntityName);
|
||||
|
||||
SCHEMA_FIELD(CUtlSymbolLarge, m_iszAttachmentName);
|
||||
|
||||
SCHEMA_FIELD(char, m_onGUIDChanged);
|
||||
|
||||
SCHEMA_FIELD(CEntityIOOutput, m_onSoundFinished);
|
||||
|
||||
SCHEMA_FIELD(float32, m_flClientCullRadius);
|
||||
|
||||
SCHEMA_FIELD(CUtlSymbolLarge, m_iszSoundName);
|
||||
|
||||
SCHEMA_FIELD(CEntityHandle, m_hSource);
|
||||
|
||||
SCHEMA_FIELD(int32, m_nEntityIndexSelection);
|
||||
};
|
||||
}
|
||||
16
src/schema/CTeam.h
Normal file
16
src/schema/CTeam.h
Normal file
|
|
@ -0,0 +1,16 @@
|
|||
//
|
||||
// Created by Michal Přikryl on 26.06.2025.
|
||||
// Copyright (c) 2025 slynxcz. All rights reserved.
|
||||
//
|
||||
#pragma once
|
||||
#include "CBaseEntity.h"
|
||||
|
||||
namespace TemplatePlugin {
|
||||
class CTeam : public CBaseEntity
|
||||
{
|
||||
public:
|
||||
DECLARE_SCHEMA_CLASS(CTeam)
|
||||
|
||||
SCHEMA_FIELD(int32_t, m_iScore);
|
||||
};
|
||||
}
|
||||
84
src/schema/CTimer.cpp
Normal file
84
src/schema/CTimer.cpp
Normal file
|
|
@ -0,0 +1,84 @@
|
|||
//
|
||||
// Created by Michal Přikryl on 31.10.2025.
|
||||
// Copyright (c) 2025 slynxcz. All rights reserved.
|
||||
//
|
||||
#include "CTimer.h"
|
||||
|
||||
#include <Shared.h>
|
||||
|
||||
namespace
|
||||
TemplatePlugin
|
||||
{
|
||||
std::list<std::shared_ptr<CTimerBase>> g_timers;
|
||||
|
||||
void RunTimers()
|
||||
{
|
||||
auto iterator = g_timers.begin();
|
||||
|
||||
while (iterator != g_timers.end())
|
||||
{
|
||||
auto pTimer = *iterator;
|
||||
pTimer->Initialize();
|
||||
|
||||
// Timer execute
|
||||
if (pTimer->GetLastExecute() + pTimer->GetInterval() <= universal_time && !pTimer->Execute(true))
|
||||
iterator = g_timers.erase(iterator);
|
||||
else
|
||||
iterator++;
|
||||
}
|
||||
}
|
||||
|
||||
void RemoveAllTimers()
|
||||
{
|
||||
g_timers.clear();
|
||||
}
|
||||
|
||||
void RemoveTimers(uint64 iTimerFlag)
|
||||
{
|
||||
auto iterator = g_timers.begin();
|
||||
|
||||
while (iterator != g_timers.end())
|
||||
if ((*iterator)->IsTimerFlagSet(iTimerFlag))
|
||||
iterator = g_timers.erase(iterator);
|
||||
else
|
||||
iterator++;
|
||||
}
|
||||
|
||||
std::weak_ptr<CTimer> CTimer::Create(float flInitialInterval, uint64 nTimerFlags, std::function<float()> func)
|
||||
{
|
||||
auto pTimer = std::make_shared<CTimer>(flInitialInterval, nTimerFlags, func, _timer_constructor_tag{});
|
||||
|
||||
g_timers.push_back(pTimer);
|
||||
return pTimer;
|
||||
}
|
||||
|
||||
bool CTimer::Execute(bool bAutomaticExecute)
|
||||
{
|
||||
SetInterval(m_func());
|
||||
SetLastExecute(universal_time);
|
||||
|
||||
bool bContinue = GetInterval() >= 0;
|
||||
|
||||
// Only scan the timer list if this isn't an automatic execute (RunTimers() already has the iterator to erase)
|
||||
if (!bAutomaticExecute && !bContinue)
|
||||
Cancel();
|
||||
|
||||
return bContinue;
|
||||
}
|
||||
|
||||
void CTimer::Cancel()
|
||||
{
|
||||
auto iterator = g_timers.begin();
|
||||
|
||||
while (iterator != g_timers.end())
|
||||
{
|
||||
if (*iterator == shared_from_this())
|
||||
{
|
||||
g_timers.erase(iterator);
|
||||
break;
|
||||
}
|
||||
|
||||
iterator++;
|
||||
}
|
||||
}
|
||||
}
|
||||
76
src/schema/CTimer.h
Normal file
76
src/schema/CTimer.h
Normal file
|
|
@ -0,0 +1,76 @@
|
|||
//
|
||||
// Created by Michal Přikryl on 31.10.2025.
|
||||
// Copyright (c) 2025 slynxcz. All rights reserved.
|
||||
//
|
||||
#pragma once
|
||||
#include <functional>
|
||||
#include <list>
|
||||
#include <memory>
|
||||
#include <platform.h>
|
||||
#include <Shared.h>
|
||||
|
||||
#include "tasks.h"
|
||||
|
||||
// clang-format off
|
||||
#define TIMERFLAG_NONE (0)
|
||||
#define TIMERFLAG_MAP (1 << 0) // Only valid for this map, cancels on map change
|
||||
#define TIMERFLAG_ROUND (1 << 1) // Only valid for this round, cancels on new round
|
||||
|
||||
namespace TemplatePlugin {
|
||||
class CTimerBase
|
||||
{
|
||||
protected:
|
||||
CTimerBase(float flInitialInterval, uint64 nTimerFlags) :
|
||||
m_flInterval(flInitialInterval), m_nTimerFlags(nTimerFlags)
|
||||
{}
|
||||
|
||||
void SetInterval(float flInterval) { m_flInterval = flInterval; }
|
||||
void SetLastExecute(float flLastExecute) { m_flLastExecute = flLastExecute; }
|
||||
|
||||
public:
|
||||
virtual bool Execute(bool bAutomaticExecute = false) = 0;
|
||||
virtual void Cancel() = 0;
|
||||
|
||||
float GetInterval() { return m_flInterval; }
|
||||
float GetLastExecute() { return m_flLastExecute; }
|
||||
bool IsTimerFlagSet(uint64 iTimerFlag) { return !iTimerFlag || (m_nTimerFlags & iTimerFlag); }
|
||||
void Initialize()
|
||||
{
|
||||
if (m_flLastExecute == -1)
|
||||
m_flLastExecute = universal_time;
|
||||
}
|
||||
|
||||
private:
|
||||
float m_flInterval;
|
||||
float m_flLastExecute = -1;
|
||||
uint64 m_nTimerFlags;
|
||||
};
|
||||
|
||||
// Timer functions should return the time until next execution, or a negative value like -1.0f to stop
|
||||
// Having an interval of 0 is fine, in this case it will run on every game frame
|
||||
class CTimer : public CTimerBase, public std::enable_shared_from_this<CTimer>
|
||||
{
|
||||
private:
|
||||
// Silly workaround to achieve a "private constructor" only Create() can call
|
||||
struct _timer_constructor_tag
|
||||
{
|
||||
explicit _timer_constructor_tag() = default;
|
||||
};
|
||||
|
||||
public:
|
||||
CTimer(float flInitialInterval, uint64 nTimerFlags, std::function<float()> func, _timer_constructor_tag) :
|
||||
CTimerBase(flInitialInterval, nTimerFlags), m_func(func)
|
||||
{}
|
||||
|
||||
static std::weak_ptr<CTimer> Create(float flInitialInterval, uint64 nTimerFlags, std::function<float()> func);
|
||||
bool Execute(bool bAutomaticExecute) override;
|
||||
void Cancel() override;
|
||||
|
||||
private:
|
||||
std::function<float()> m_func;
|
||||
};
|
||||
|
||||
void RunTimers();
|
||||
void RemoveAllTimers();
|
||||
void RemoveTimers(uint64 iTimerFlag);
|
||||
}
|
||||
21
src/schema/CTriggerPush.h
Normal file
21
src/schema/CTriggerPush.h
Normal file
|
|
@ -0,0 +1,21 @@
|
|||
//
|
||||
// Created by Michal Přikryl on 26.06.2025.
|
||||
// Copyright (c) 2025 slynxcz. All rights reserved.
|
||||
//
|
||||
#pragma once
|
||||
|
||||
#include "CBaseTrigger.h"
|
||||
#include "schemasystem.h"
|
||||
|
||||
#define SF_TRIG_PUSH_ONCE 0x80
|
||||
|
||||
namespace TemplatePlugin {
|
||||
class CTriggerPush : public CBaseTrigger
|
||||
{
|
||||
public:
|
||||
DECLARE_SCHEMA_CLASS(CTriggerPush);
|
||||
|
||||
SCHEMA_FIELD(Vector, m_vecPushDirEntitySpace)
|
||||
SCHEMA_FIELD(bool, m_bTriggerOnStartTouch)
|
||||
};
|
||||
}
|
||||
33
src/schema/ccollisionproperty.h
Normal file
33
src/schema/ccollisionproperty.h
Normal file
|
|
@ -0,0 +1,33 @@
|
|||
//
|
||||
// Created by Michal Přikryl on 26.06.2025.
|
||||
// Copyright (c) 2025 slynxcz. All rights reserved.
|
||||
//
|
||||
#pragma once
|
||||
|
||||
#include "CBaseEntity.h"
|
||||
|
||||
namespace TemplatePlugin {
|
||||
struct VPhysicsCollisionAttribute_t
|
||||
{
|
||||
DECLARE_SCHEMA_CLASS_INLINE(VPhysicsCollisionAttribute_t)
|
||||
|
||||
SCHEMA_FIELD(uint8, m_nCollisionGroup)
|
||||
SCHEMA_FIELD(uint64_t, m_nInteractsAs)
|
||||
SCHEMA_FIELD(uint64_t, m_nInteractsWith)
|
||||
SCHEMA_FIELD(uint64_t, m_nInteractsExclude)
|
||||
SCHEMA_FIELD(uint16, m_nHierarchyId)
|
||||
};
|
||||
|
||||
class CCollisionProperty
|
||||
{
|
||||
public:
|
||||
DECLARE_SCHEMA_CLASS_INLINE(CCollisionProperty)
|
||||
|
||||
SCHEMA_FIELD(VPhysicsCollisionAttribute_t, m_collisionAttribute)
|
||||
SCHEMA_FIELD(SolidType_t, m_nSolidType)
|
||||
SCHEMA_FIELD(uint8, m_usSolidFlags)
|
||||
SCHEMA_FIELD(uint8, m_CollisionGroup)
|
||||
SCHEMA_FIELD(Vector, m_vecMins)
|
||||
SCHEMA_FIELD(Vector, m_vecMaxs)
|
||||
};
|
||||
}
|
||||
38
src/schema/cgameresourceserviceserver.h
Normal file
38
src/schema/cgameresourceserviceserver.h
Normal file
|
|
@ -0,0 +1,38 @@
|
|||
/**
|
||||
* =============================================================================
|
||||
* CS2Fixes
|
||||
* Copyright (C) 2023 Source2ZE
|
||||
* =============================================================================
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it under
|
||||
* the terms of the GNU General Public License, version 3.0, as published by the
|
||||
* Free Software Foundation.
|
||||
*
|
||||
* This program 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
|
||||
* this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
#include <cstdint>
|
||||
#include "TemplatePlugin.h"
|
||||
|
||||
class CGameEntitySystem;
|
||||
|
||||
class CGameResourceService
|
||||
{
|
||||
public:
|
||||
CGameEntitySystem* GetGameEntitySystem()
|
||||
{
|
||||
#ifdef WIN32
|
||||
static int offset = 88;
|
||||
#else
|
||||
static int offset = 80;
|
||||
#endif
|
||||
return *reinterpret_cast<CGameEntitySystem**>(reinterpret_cast<uintptr_t>(g_pGameResourceServiceServer) + offset);
|
||||
}
|
||||
};
|
||||
53
src/schema/ctakedamageinfo.cpp
Normal file
53
src/schema/ctakedamageinfo.cpp
Normal file
|
|
@ -0,0 +1,53 @@
|
|||
//
|
||||
// Created by Michal Přikryl on 23.09.2025.
|
||||
// Copyright (c) 2025 slynxcz. All rights reserved.
|
||||
//
|
||||
#include "ctakedamageinfo.h"
|
||||
#include "dynlibutils/module.h"
|
||||
#include "CCSPlayerController.h"
|
||||
#include <Shared.h>
|
||||
|
||||
namespace
|
||||
TemplatePlugin
|
||||
{
|
||||
CAttackerInfo::CAttackerInfo(CEntityInstance* attacker)
|
||||
{
|
||||
NeedInit = false;
|
||||
IsWorld = true;
|
||||
IsPawn = false;
|
||||
Attacker = attacker ? attacker->m_pEntity->GetRefEHandle().ToInt() : 0;
|
||||
|
||||
if (!attacker || (attacker->m_pEntity && attacker->m_pEntity->m_designerName.String() !=
|
||||
"cs_player_controller"))
|
||||
return;
|
||||
|
||||
if (auto* controller = static_cast<CCSPlayerController*>(attacker))
|
||||
{
|
||||
IsWorld = false;
|
||||
IsPawn = true;
|
||||
AttackerUserId = static_cast<unsigned short>(shared::g_pEngine->GetPlayerUserId(controller->GetPlayerSlot()).Get());
|
||||
TeamNum = controller->m_iTeamNum();
|
||||
TeamChecked = controller->m_iTeamNum();
|
||||
}
|
||||
}
|
||||
|
||||
HitGroup_t CTakeDamageInfo::GetHitGroup() const
|
||||
{
|
||||
const int off = shared::g_pGameConfig->GetOffset("CTakeDamageInfo_HitGroup");
|
||||
if (off <= 0)
|
||||
return HitGroup_t::HITGROUP_INVALID;
|
||||
|
||||
const uintptr_t base = reinterpret_cast<uintptr_t>(this);
|
||||
|
||||
const uintptr_t v4 = *reinterpret_cast<const uintptr_t*>(base + off);
|
||||
if (!v4)
|
||||
return HitGroup_t::HITGROUP_INVALID;
|
||||
|
||||
const uintptr_t v1 = *reinterpret_cast<const uintptr_t*>(v4 + 16);
|
||||
if (!v1)
|
||||
return HitGroup_t::HITGROUP_GENERIC;
|
||||
|
||||
const int32_t group = *reinterpret_cast<const int32_t*>(v1 + 56);
|
||||
return static_cast<HitGroup_t>(group);
|
||||
}
|
||||
}
|
||||
84
src/schema/ctakedamageinfo.h
Normal file
84
src/schema/ctakedamageinfo.h
Normal file
|
|
@ -0,0 +1,84 @@
|
|||
//
|
||||
// Created by Michal Přikryl on 23.09.2025.
|
||||
// Copyright (c) 2025 slynxcz. All rights reserved.
|
||||
//
|
||||
#pragma once
|
||||
#include <public/mathlib/vector.h>
|
||||
#include "ehandle.h"
|
||||
#include "schemasystem.h"
|
||||
#include "globaltypes.h"
|
||||
|
||||
namespace
|
||||
TemplatePlugin
|
||||
{
|
||||
class CBaseEntity;
|
||||
class CTakeDamageInfo;
|
||||
|
||||
#pragma pack(push, 1)
|
||||
struct CAttackerInfo
|
||||
{
|
||||
bool NeedInit = true; // 0x0
|
||||
bool IsPawn = false; // 0x1
|
||||
bool IsWorld = false; // 0x2
|
||||
std::uint8_t pad_3[1] = {}; // vyrovnání na 4 bajty
|
||||
std::uint32_t Attacker = 0; // 0x4
|
||||
std::uint16_t AttackerUserId = 0; // 0x8
|
||||
std::uint8_t pad_A[2] = {}; // vyrovnání na 0xC
|
||||
int TeamChecked = -1; // 0x0C
|
||||
int TeamNum = -1; // 0x10
|
||||
|
||||
CAttackerInfo() = default;
|
||||
explicit CAttackerInfo(CEntityInstance* attacker);
|
||||
};
|
||||
#pragma pack(pop)
|
||||
|
||||
struct CTakeDamageInfoContainer
|
||||
{
|
||||
CTakeDamageInfo* pInfo;
|
||||
};
|
||||
|
||||
class CTakeDamageInfo
|
||||
{
|
||||
public:
|
||||
DECLARE_SCHEMA_CLASS(CTakeDamageInfo)
|
||||
|
||||
SCHEMA_FIELD(Vector, m_vecDamageForce);
|
||||
SCHEMA_FIELD(Vector, m_vecDamagePosition);
|
||||
SCHEMA_FIELD(Vector, m_vecReportedPosition);
|
||||
SCHEMA_FIELD(Vector, m_vecDamageDirection);
|
||||
SCHEMA_FIELD(CHandle<CBaseEntity>, m_hInflictor);
|
||||
SCHEMA_FIELD(CHandle<CBaseEntity>, m_hAttacker);
|
||||
SCHEMA_FIELD(CHandle<CBaseEntity>, m_hAbility);
|
||||
SCHEMA_FIELD(float, m_flDamage);
|
||||
SCHEMA_FIELD(float, m_flTotalledDamage);
|
||||
SCHEMA_FIELD(int32_t, m_bitsDamageType);
|
||||
SCHEMA_FIELD(int32_t, m_iDamageCustom);
|
||||
SCHEMA_FIELD(int8_t, m_iAmmoType);
|
||||
SCHEMA_FIELD(float, m_flOriginalDamage);
|
||||
SCHEMA_FIELD(bool, m_bShouldBleed);
|
||||
SCHEMA_FIELD(bool, m_bShouldSpark);
|
||||
SCHEMA_FIELD(TakeDamageFlags_t, m_nDamageFlags);
|
||||
SCHEMA_FIELD_POINTER(char, m_sDamageSourceName);
|
||||
SCHEMA_FIELD(HitGroup_t, m_iHitGroupId);
|
||||
SCHEMA_FIELD(int32_t, m_nNumObjectsPenetrated);
|
||||
SCHEMA_FIELD(float, m_flFriendlyFireDamageReductionRatio);
|
||||
SCHEMA_FIELD(bool, m_bInTakeDamageFlow);
|
||||
|
||||
HitGroup_t GetHitGroup() const;
|
||||
};
|
||||
|
||||
class CTakeDamageResult
|
||||
{
|
||||
public:
|
||||
DECLARE_SCHEMA_CLASS(CTakeDamageResult)
|
||||
|
||||
SCHEMA_FIELD(CTakeDamageInfo*, m_pOriginatingInfo)
|
||||
SCHEMA_FIELD(int32, m_nHealthLost)
|
||||
SCHEMA_FIELD(int32, m_nHealthBefore)
|
||||
SCHEMA_FIELD(int32, m_nDamageDealt)
|
||||
SCHEMA_FIELD(float32, m_flPreModifiedDamage)
|
||||
SCHEMA_FIELD(int32, m_nTotalledHealthLost)
|
||||
SCHEMA_FIELD(int32, m_nTotalledDamageDealt)
|
||||
SCHEMA_FIELD(bool, m_bWasDamageSuppressed)
|
||||
};
|
||||
}
|
||||
482
src/schema/globaltypes.h
Normal file
482
src/schema/globaltypes.h
Normal file
|
|
@ -0,0 +1,482 @@
|
|||
//
|
||||
// Created by Michal Přikryl on 26.06.2025.
|
||||
// Copyright (c) 2025 slynxcz. All rights reserved.
|
||||
//
|
||||
#pragma once
|
||||
#include <platform.h>
|
||||
#include "soundflags.h"
|
||||
|
||||
// struct TransmitInfo
|
||||
// {
|
||||
// CBitVec<16384> *m_pTransmitEdict;
|
||||
// };
|
||||
|
||||
namespace TemplatePlugin {
|
||||
enum CSRoundEndReason {
|
||||
TargetBombed = 1, /**< Target Successfully Bombed! */
|
||||
VIPEscaped, /**< The VIP has escaped! - Doesn't exist on CS:GO */
|
||||
VIPKilled, /**< VIP has been assassinated! - Doesn't exist on CS:GO */
|
||||
TerroristsEscaped, /**< The terrorists have escaped! */
|
||||
CTStoppedEscape, /**< The CTs have prevented most of the terrorists from escaping! */
|
||||
TerroristsStopped, /**< Escaping terrorists have all been neutralized! */
|
||||
BombDefused, /**< The bomb has been defused! */
|
||||
CTWin, /**< Counter-Terrorists Win! */
|
||||
TerroristWin, /**< Terrorists Win! */
|
||||
Draw, /**< Round Draw! */
|
||||
HostagesRescued, /**< All Hostages have been rescued! */
|
||||
TargetSaved, /**< Target has been saved! */
|
||||
HostagesNotRescued, /**< Hostages have not been rescued! */
|
||||
TerroristsNotEscaped, /**< Terrorists have not escaped! */
|
||||
VIPNotEscaped, /**< VIP has not escaped! - Doesn't exist on CS:GO */
|
||||
GameStart, /**< Game Commencing! */
|
||||
TerroristsSurrender, /**< Terrorists Surrender */
|
||||
CTSurrender, /**< CTs Surrender */
|
||||
TerroristsPlanted, /**< Terrorists Planted the bomb */
|
||||
CTsReachedHostage, /**< CTs Reached the hostage */
|
||||
SurvivalWin,
|
||||
SurvivalDraw
|
||||
};
|
||||
|
||||
enum class CsTeam : uint8_t {
|
||||
None = 0,
|
||||
Spectator = 1,
|
||||
Terrorist = 2,
|
||||
CounterTerrorist = 3
|
||||
};
|
||||
|
||||
enum GamePhase : int32_t {
|
||||
GAMEPHASE_WARMUP_ROUND,
|
||||
GAMEPHASE_PLAYING_STANDARD,
|
||||
GAMEPHASE_PLAYING_FIArenaT_HALF,
|
||||
GAMEPHASE_PLAYING_SECOND_HALF,
|
||||
GAMEPHASE_HALFTIME,
|
||||
GAMEPHASE_MATCH_ENDED,
|
||||
GAMEPHASE_MAX
|
||||
};
|
||||
|
||||
enum InputBitMask_t : uint64_t {
|
||||
// MEnumeratorIsNotAFlag
|
||||
IN_NONE = 0x0,
|
||||
// MEnumeratorIsNotAFlag
|
||||
IN_ALL = 0xffffffffffffffff,
|
||||
IN_ATTACK = 0x1,
|
||||
IN_JUMP = 0x2,
|
||||
IN_DUCK = 0x4,
|
||||
IN_FORWARD = 0x8,
|
||||
IN_BACK = 0x10,
|
||||
IN_USE = 0x20,
|
||||
IN_TURNLEFT = 0x80,
|
||||
IN_TURNRIGHT = 0x100,
|
||||
IN_MOVELEFT = 0x200,
|
||||
IN_MOVERIGHT = 0x400,
|
||||
IN_ATTACK2 = 0x800,
|
||||
IN_RELOAD = 0x2000,
|
||||
IN_SPEED = 0x10000,
|
||||
IN_JOYAUTOSPRINT = 0x20000,
|
||||
// MEnumeratorIsNotAFlag
|
||||
IN_FIRST_MOD_SPECIFIC_BIT = 0x100000000,
|
||||
IN_USEORRELOAD = 0x100000000,
|
||||
IN_SCORE = 0x200000000,
|
||||
IN_ZOOM = 0x400000000,
|
||||
IN_LOOK_AT_WEAPON = 0x800000000,
|
||||
};
|
||||
|
||||
enum EInButtonState : uint32_t {
|
||||
IN_BUTTON_UP = 0x0,
|
||||
IN_BUTTON_DOWN = 0x1,
|
||||
IN_BUTTON_DOWN_UP = 0x2,
|
||||
IN_BUTTON_UP_DOWN = 0x3,
|
||||
IN_BUTTON_UP_DOWN_UP = 0x4,
|
||||
IN_BUTTON_DOWN_UP_DOWN = 0x5,
|
||||
IN_BUTTON_DOWN_UP_DOWN_UP = 0x6,
|
||||
IN_BUTTON_UP_DOWN_UP_DOWN = 0x7,
|
||||
IN_BUTTON_STATE_COUNT = 0x8,
|
||||
};
|
||||
|
||||
enum ParticleAttachment_t : uint32_t {
|
||||
PATTACH_INVALID = 0xffffffff,
|
||||
PATTACH_ABSORIGIN = 0x0, // Spawn at entity origin
|
||||
PATTACH_ABSORIGIN_FOLLOW = 0x1, // Spawn at and follow entity origin
|
||||
PATTACH_CUSTOMORIGIN = 0x2,
|
||||
PATTACH_CUSTOMORIGIN_FOLLOW = 0x3,
|
||||
PATTACH_POINT = 0x4, // Spawn at attachment point
|
||||
PATTACH_POINT_FOLLOW = 0x5, // Spawn at and follow attachment point
|
||||
PATTACH_EYES_FOLLOW = 0x6,
|
||||
PATTACH_OVERHEAD_FOLLOW = 0x7,
|
||||
PATTACH_WORLDORIGIN = 0x8,
|
||||
PATTACH_ROOTBONE_FOLLOW = 0x9,
|
||||
PATTACH_RENDERORIGIN_FOLLOW = 0xa,
|
||||
PATTACH_MAIN_VIEW = 0xb,
|
||||
PATTACH_WATERWAKE = 0xc,
|
||||
PATTACH_CENTER_FOLLOW = 0xd,
|
||||
PATTACH_CUSTOM_GAME_STATE_1 = 0xe,
|
||||
PATTACH_HEALTHBAR = 0xf,
|
||||
MAX_PATTACH_TYPES = 0x10,
|
||||
};
|
||||
|
||||
enum ObserverMode_t : uint8_t {
|
||||
OBS_MODE_NONE = 0x0,
|
||||
OBS_MODE_FIXED = 0x1,
|
||||
OBS_MODE_IN_EYE = 0x2,
|
||||
OBS_MODE_CHASE = 0x3,
|
||||
OBS_MODE_ROAMING = 0x4,
|
||||
OBS_MODE_DIRECTED = 0x5,
|
||||
NUM_OBSERVER_MODES = 0x6,
|
||||
};
|
||||
|
||||
typedef uint32 SoundEventGuid_t;
|
||||
|
||||
struct SndOpEventGuid_t {
|
||||
SoundEventGuid_t m_nGuid;
|
||||
uint64 m_hStackHash;
|
||||
};
|
||||
|
||||
// used with EmitSound_t
|
||||
enum gender_t : uint8 {
|
||||
GENDER_NONE = 0x0,
|
||||
GENDER_MALE = 0x1,
|
||||
GENDER_FEMALE = 0x2,
|
||||
GENDER_NAMVET = 0x3,
|
||||
GENDER_TEENGIRL = 0x4,
|
||||
GENDER_BIKER = 0x5,
|
||||
GENDER_MANAGER = 0x6,
|
||||
GENDER_GAMBLER = 0x7,
|
||||
GENDER_PRODUCER = 0x8,
|
||||
GENDER_COACH = 0x9,
|
||||
GENDER_MECHANIC = 0xA,
|
||||
GENDER_CEDA = 0xB,
|
||||
GENDER_CRAWLER = 0xC,
|
||||
GENDER_UNDISTRACTABLE = 0xD,
|
||||
GENDER_FALLEN = 0xE,
|
||||
GENDER_RIOT_CONTROL = 0xF,
|
||||
GENDER_CLOWN = 0x10,
|
||||
GENDER_JIMMY = 0x11,
|
||||
GENDER_HOSPITAL_PATIENT = 0x12,
|
||||
GENDER_BRIDE = 0x13,
|
||||
GENDER_LAST = 0x14,
|
||||
};
|
||||
|
||||
enum DamageTypes_t : uint32_t {
|
||||
DMG_GENERIC = 0x0,
|
||||
DMG_CRUSH = 0x1,
|
||||
DMG_BULLET = 0x2,
|
||||
DMG_SLASH = 0x4,
|
||||
DMG_BURN = 0x8,
|
||||
DMG_VEHICLE = 0x10,
|
||||
DMG_FALL = 0x20,
|
||||
DMG_BLAST = 0x40,
|
||||
DMG_CLUB = 0x80,
|
||||
DMG_SHOCK = 0x100,
|
||||
DMG_SONIC = 0x200,
|
||||
DMG_ENERGYBEAM = 0x400,
|
||||
DMG_DROWN = 0x4000,
|
||||
DMG_POISON = 0x8000,
|
||||
DMG_RADIATION = 0x10000,
|
||||
DMG_DROWNRECOVER = 0x20000,
|
||||
DMG_ACID = 0x40000,
|
||||
DMG_PHYSGUN = 0x100000,
|
||||
DMG_DISSOLVE = 0x200000,
|
||||
DMG_BLAST_SURFACE = 0x400000,
|
||||
DMG_BUCKSHOT = 0x1000000,
|
||||
DMG_LASTGENERICFLAG = 0x1000000,
|
||||
DMG_HEADSHOT = 0x2000000,
|
||||
DMG_DANGERZONE = 0x4000000,
|
||||
};
|
||||
|
||||
enum TakeDamageFlags_t : uint64_t
|
||||
{
|
||||
DFLAG_NONE = 0x0,
|
||||
DFLAG_SUPPRESS_HEALTH_CHANGES = 0x1,
|
||||
DFLAG_SUPPRESS_PHYSICS_FORCE = 0x2,
|
||||
DFLAG_SUPPRESS_EFFECTS = 0x4,
|
||||
DFLAG_PREVENT_DEATH = 0x8,
|
||||
DFLAG_FORCE_DEATH = 0x10,
|
||||
DFLAG_ALWAYS_GIB = 0x20,
|
||||
DFLAG_NEVER_GIB = 0x40,
|
||||
DFLAG_REMOVE_NO_RAGDOLL = 0x80,
|
||||
DFLAG_SUPPRESS_DAMAGE_MODIFICATION = 0x100,
|
||||
DFLAG_ALWAYS_FIRE_DAMAGE_EVENTS = 0x200,
|
||||
DFLAG_RADIUS_DMG = 0x400,
|
||||
DFLAG_FORCEREDUCEARMOR_DMG = 0x800,
|
||||
DFLAG_SUPPRESS_INTERRUPT_FLINCH = 0x1000,
|
||||
DFLAG_IGNORE_DESTRUCTIBLE_PARTS = 0x2000,
|
||||
DMG_LASTDFLAG = 0x2000,
|
||||
DFLAG_IGNORE_ARMOR = 0x4000,
|
||||
DFLAG_SUPPRESS_UTILREMOVE = 0x8000,
|
||||
};
|
||||
|
||||
struct EmitSound_t {
|
||||
EmitSound_t() : m_nChannel(0),
|
||||
m_pSoundName(0),
|
||||
m_flVolume(VOL_NORM),
|
||||
m_SoundLevel(SNDLVL_NONE),
|
||||
m_nFlags(0),
|
||||
m_nPitch(PITCH_NORM),
|
||||
m_pOrigin(0),
|
||||
m_flSoundTime(0.0f),
|
||||
m_pflSoundDuration(0),
|
||||
m_bEmitCloseCaption(true),
|
||||
m_bWarnOnMissingCloseCaption(false),
|
||||
m_bWarnOnDirectWaveReference(false),
|
||||
m_nSpeakerEntity(-1),
|
||||
m_nForceGuid(0),
|
||||
m_SpeakerGender(GENDER_NONE) {
|
||||
}
|
||||
|
||||
int m_nChannel;
|
||||
const char *m_pSoundName;
|
||||
float m_flVolume;
|
||||
soundlevel_t m_SoundLevel;
|
||||
int m_nFlags;
|
||||
int m_nPitch;
|
||||
const Vector *m_pOrigin;
|
||||
float m_flSoundTime;
|
||||
float *m_pflSoundDuration;
|
||||
bool m_bEmitCloseCaption;
|
||||
bool m_bWarnOnMissingCloseCaption;
|
||||
bool m_bWarnOnDirectWaveReference;
|
||||
CEntityIndex m_nSpeakerEntity;
|
||||
// CUtlVector<Vector, CUtlMemory<Vector, int> > m_UtlVecSoundOrigin;
|
||||
void *unk01;
|
||||
SoundEventGuid_t m_nForceGuid;
|
||||
gender_t m_SpeakerGender;
|
||||
};
|
||||
|
||||
struct GameTick_t {
|
||||
public:
|
||||
DECLARE_SCHEMA_CLASS_INLINE(GameTick_t)
|
||||
|
||||
SCHEMA_FIELD(int32_t, m_Value);
|
||||
};
|
||||
|
||||
struct AmmoIndex_t {
|
||||
public:
|
||||
DECLARE_SCHEMA_CLASS_INLINE(AmmoIndex_t)
|
||||
|
||||
SCHEMA_FIELD(int8_t, m_Value);
|
||||
};
|
||||
|
||||
class CNetworkTransmitComponent {
|
||||
public:
|
||||
DECLARE_SCHEMA_CLASS_INLINE(CNetworkTransmitComponent)
|
||||
};
|
||||
|
||||
class CNetworkVelocityVector {
|
||||
public:
|
||||
DECLARE_SCHEMA_CLASS_INLINE(CNetworkVelocityVector)
|
||||
|
||||
SCHEMA_FIELD(float, m_vecX)
|
||||
|
||||
SCHEMA_FIELD(float, m_vecY)
|
||||
|
||||
SCHEMA_FIELD(float, m_vecZ)
|
||||
};
|
||||
|
||||
class CNetworkOriginCellCoordQuantizedVector {
|
||||
public:
|
||||
DECLARE_SCHEMA_CLASS_INLINE(CNetworkOriginCellCoordQuantizedVector)
|
||||
|
||||
SCHEMA_FIELD(uint16, m_cellX)
|
||||
|
||||
SCHEMA_FIELD(uint16, m_cellY)
|
||||
|
||||
SCHEMA_FIELD(uint16, m_cellZ)
|
||||
|
||||
SCHEMA_FIELD(uint16, m_nOutsideWorld)
|
||||
|
||||
// These are actually CNetworkedQuantizedFloat but we don't have the definition for it...
|
||||
SCHEMA_FIELD(float, m_vecX)
|
||||
|
||||
SCHEMA_FIELD(float, m_vecY)
|
||||
|
||||
SCHEMA_FIELD(float, m_vecZ)
|
||||
};
|
||||
|
||||
class CInButtonState {
|
||||
public:
|
||||
DECLARE_SCHEMA_CLASS_INLINE(CInButtonState)
|
||||
|
||||
// m_pButtonStates[3]
|
||||
|
||||
// m_pButtonStates[0] is the mask of currently pressed buttons
|
||||
// m_pButtonStates[1] is the mask of buttons that changed in the current frame
|
||||
SCHEMA_FIELD_POINTER(uint64, m_pButtonStates)
|
||||
};
|
||||
|
||||
enum class PlayerButtons : uint64_t {
|
||||
Attack = (1ull << 0),
|
||||
Jump = (1ull << 1),
|
||||
Duck = (1ull << 2),
|
||||
Forward = (1ull << 3),
|
||||
Back = (1ull << 4),
|
||||
Use = (1ull << 5),
|
||||
Cancel = (1ull << 6),
|
||||
Left = (1ull << 7),
|
||||
Right = (1ull << 8),
|
||||
Moveleft = (1ull << 9),
|
||||
Moveright = (1ull << 10),
|
||||
Attack2 = (1ull << 11),
|
||||
Run = (1ull << 12),
|
||||
Reload = (1ull << 13),
|
||||
Alt1 = (1ull << 14),
|
||||
Alt2 = (1ull << 15),
|
||||
Speed = (1ull << 16),
|
||||
Walk = (1ull << 17),
|
||||
Zoom = (1ull << 18),
|
||||
Weapon1 = (1ull << 19),
|
||||
Weapon2 = (1ull << 20),
|
||||
Bullrush = (1ull << 21),
|
||||
Grenade1 = (1ull << 22),
|
||||
Grenade2 = (1ull << 23),
|
||||
Attack3 = (1ull << 24),
|
||||
Scoreboard = (1ull << 33),
|
||||
Inspect = (1ull << 35),
|
||||
};
|
||||
|
||||
inline std::string PlayerButtonsToString(uint64* buttons) {
|
||||
struct BtnName {
|
||||
uint64 flag;
|
||||
const char *name;
|
||||
};
|
||||
static constexpr BtnName names[] = {
|
||||
{(uint64) PlayerButtons::Attack, "Attack"},
|
||||
{(uint64) PlayerButtons::Jump, "Jump"},
|
||||
{(uint64) PlayerButtons::Duck, "Duck"},
|
||||
{(uint64) PlayerButtons::Forward, "Forward"},
|
||||
{(uint64) PlayerButtons::Back, "Back"},
|
||||
{(uint64) PlayerButtons::Use, "Use"},
|
||||
{(uint64) PlayerButtons::Cancel, "Cancel"},
|
||||
{(uint64) PlayerButtons::Left, "Left"},
|
||||
{(uint64) PlayerButtons::Right, "Right"},
|
||||
{(uint64) PlayerButtons::Moveleft, "Moveleft"},
|
||||
{(uint64) PlayerButtons::Moveright, "Moveright"},
|
||||
{(uint64) PlayerButtons::Attack2, "Attack2"},
|
||||
{(uint64) PlayerButtons::Run, "Run"},
|
||||
{(uint64) PlayerButtons::Reload, "Reload"},
|
||||
{(uint64) PlayerButtons::Alt1, "Alt1"},
|
||||
{(uint64) PlayerButtons::Alt2, "Alt2"},
|
||||
{(uint64) PlayerButtons::Speed, "Speed"},
|
||||
{(uint64) PlayerButtons::Walk, "Walk"},
|
||||
{(uint64) PlayerButtons::Zoom, "Zoom"},
|
||||
{(uint64) PlayerButtons::Weapon1, "Weapon1"},
|
||||
{(uint64) PlayerButtons::Weapon2, "Weapon2"},
|
||||
{(uint64) PlayerButtons::Bullrush, "Bullrush"},
|
||||
{(uint64) PlayerButtons::Grenade1, "Grenade1"},
|
||||
{(uint64) PlayerButtons::Grenade2, "Grenade2"},
|
||||
{(uint64) PlayerButtons::Attack3, "Attack3"},
|
||||
{(uint64) PlayerButtons::Scoreboard, "Scoreboard"},
|
||||
{(uint64) PlayerButtons::Inspect, "Inspect"},
|
||||
};
|
||||
|
||||
std::string out;
|
||||
for (const auto &btn: names) {
|
||||
if (*buttons & btn.flag) {
|
||||
if (!out.empty())
|
||||
out += " | ";
|
||||
out += btn.name;
|
||||
}
|
||||
}
|
||||
|
||||
if (out.empty())
|
||||
out = "NONE";
|
||||
|
||||
return out;
|
||||
}
|
||||
|
||||
enum class PlayerFlags : uint32_t {
|
||||
OnGround = (1u << 0), // At rest / on the ground
|
||||
Ducking = (1u << 1), // Player is fully crouched
|
||||
WaterJump = (1u << 2), // Jumping out of water
|
||||
OnTrain = (1u << 3), // Controlling a train
|
||||
InRain = (1u << 4), // Standing in rain
|
||||
Frozen = (1u << 5), // Frozen for 3rd person cam
|
||||
AtControls = (1u << 6), // Can't move, but key inputs go to other entity
|
||||
Client = (1u << 7), // Is a player
|
||||
FakeClient = (1u << 8), // Simulated server-side
|
||||
InWater = (1u << 9), // In water
|
||||
};
|
||||
|
||||
inline std::string PlayerFlagsToString(uint32_t flags) {
|
||||
struct FlagName {
|
||||
uint32_t flag;
|
||||
const char* name;
|
||||
};
|
||||
|
||||
static constexpr FlagName names[] = {
|
||||
{ (uint32_t)PlayerFlags::OnGround, "OnGround" },
|
||||
{ (uint32_t)PlayerFlags::Ducking, "Ducking" },
|
||||
{ (uint32_t)PlayerFlags::WaterJump, "WaterJump" },
|
||||
{ (uint32_t)PlayerFlags::OnTrain, "OnTrain" },
|
||||
{ (uint32_t)PlayerFlags::InRain, "InRain" },
|
||||
{ (uint32_t)PlayerFlags::Frozen, "Frozen" },
|
||||
{ (uint32_t)PlayerFlags::AtControls, "AtControls" },
|
||||
{ (uint32_t)PlayerFlags::Client, "Client" },
|
||||
{ (uint32_t)PlayerFlags::FakeClient, "FakeClient" },
|
||||
{ (uint32_t)PlayerFlags::InWater, "InWater" },
|
||||
};
|
||||
|
||||
std::string out;
|
||||
for (const auto& f : names) {
|
||||
if (flags & f.flag) {
|
||||
if (!out.empty())
|
||||
out += " | ";
|
||||
out += f.name;
|
||||
}
|
||||
}
|
||||
|
||||
if (out.empty())
|
||||
out = "NONE";
|
||||
|
||||
return out;
|
||||
}
|
||||
|
||||
class CGlowProperty {
|
||||
public:
|
||||
DECLARE_SCHEMA_CLASS_INLINE(CGlowProperty)
|
||||
|
||||
SCHEMA_FIELD(Vector, m_fGlowColor)
|
||||
|
||||
SCHEMA_FIELD(int, m_iGlowType)
|
||||
|
||||
SCHEMA_FIELD(int, m_iGlowTeam)
|
||||
|
||||
SCHEMA_FIELD(int, m_nGlowRange)
|
||||
|
||||
SCHEMA_FIELD(int, m_nGlowRangeMin)
|
||||
|
||||
SCHEMA_FIELD(Color, m_glowColorOverride)
|
||||
|
||||
SCHEMA_FIELD(bool, m_bFlashing)
|
||||
|
||||
SCHEMA_FIELD(bool, m_bGlowing)
|
||||
};
|
||||
|
||||
struct TraceHistory {
|
||||
Vector start;
|
||||
Vector end;
|
||||
Ray_t ray;
|
||||
bool didHit;
|
||||
Vector m_vStartPos; // start position
|
||||
Vector m_vEndPos; // final position
|
||||
Vector m_vHitNormal; // surface normal at impact
|
||||
Vector m_vHitPoint; // exact hit point if m_bExactHitPoint is true, otherwise equal to m_vEndPos
|
||||
|
||||
float m_flHitOffset; // surface normal hit offset
|
||||
float m_flFraction; // time completed, 1.0 = didn't hit anything
|
||||
|
||||
float32 error;
|
||||
Vector velocity;
|
||||
};
|
||||
|
||||
class CCheckTransmitInfoHack {
|
||||
public:
|
||||
CBitVec<16384> *m_pTransmitEntity;
|
||||
|
||||
private:
|
||||
[[maybe_unused]] int8_t m_pad8[568];
|
||||
|
||||
public:
|
||||
int32_t m_nPlayerSlot;
|
||||
bool m_bFullUpdate;
|
||||
};
|
||||
}
|
||||
45
src/schema/plat.h
Normal file
45
src/schema/plat.h
Normal file
|
|
@ -0,0 +1,45 @@
|
|||
/**
|
||||
* =============================================================================
|
||||
* CS2Fixes
|
||||
* Copyright (C) 2023 Source2ZE
|
||||
* =============================================================================
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it under
|
||||
* the terms of the GNU General Public License, version 3.0, as published by the
|
||||
* Free Software Foundation.
|
||||
*
|
||||
* This program 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
|
||||
* this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
#include <cstdint>
|
||||
#include "metamod_oslink.h"
|
||||
|
||||
struct Module
|
||||
{
|
||||
#ifndef _WIN32
|
||||
void* pHandle;
|
||||
#endif
|
||||
uint8_t* pBase;
|
||||
unsigned int nSize;
|
||||
};
|
||||
|
||||
#ifndef _WIN32
|
||||
int GetModuleInformation(HINSTANCE module, void** base, size_t* length);
|
||||
#endif
|
||||
|
||||
#ifdef _WIN32
|
||||
#define MODULE_PREFIX ""
|
||||
#define MODULE_EXT ".dll"
|
||||
#else
|
||||
#define MODULE_PREFIX "lib"
|
||||
#define MODULE_EXT ".so"
|
||||
#endif
|
||||
|
||||
void Plat_WriteMemory(void* pPatchAddress, uint8_t *pPatch, int iPatchSize);
|
||||
230
src/schema/schemasystem.cpp
Normal file
230
src/schema/schemasystem.cpp
Normal file
|
|
@ -0,0 +1,230 @@
|
|||
//
|
||||
// Created by Michal Přikryl on 26.06.2025.
|
||||
// Copyright (c) 2025 slynxcz. All rights reserved.
|
||||
//
|
||||
#include "schemasystem.h"
|
||||
#include "platform.h"
|
||||
#include "schemasystem/schemasystem.h"
|
||||
#include "tier1/utlmap.h"
|
||||
#include <entity2/entityidentity.h>
|
||||
#include <entity2/entityinstance.h>
|
||||
#include <edict.h>
|
||||
#include "CBaseEntity.h"
|
||||
#include "tier0/memdbgon.h"
|
||||
|
||||
#ifdef _WIN32
|
||||
#define MODULE_PREFIX ""
|
||||
#define MODULE_EXT ".dll"
|
||||
#else
|
||||
#define MODULE_PREFIX "lib"
|
||||
#define MODULE_EXT ".so"
|
||||
#endif
|
||||
|
||||
namespace
|
||||
TemplatePlugin
|
||||
{
|
||||
using SchemaKeyValueMap_t = std::map<uint32_t, SchemaKey>;
|
||||
using SchemaTableMap_t = std::map<uint32_t, SchemaKeyValueMap_t>;
|
||||
|
||||
static constexpr uint32_t g_ChainKey = hash_32_fnv1a_const("__m_pChainEntity");
|
||||
|
||||
static bool IsFieldNetworked(SchemaClassFieldData_t& field)
|
||||
{
|
||||
for (int i = 0; i < field.m_nStaticMetadataCount; i++)
|
||||
{
|
||||
static auto networkEnabled = hash_32_fnv1a_const("MNetworkEnable");
|
||||
if (networkEnabled == hash_32_fnv1a_const(field.m_pStaticMetadata[i].m_pszName))
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
// Try to recursively find __m_pChainEntity in base classes
|
||||
// (e.g. CCSGameRules -> CTeamplayRules -> CMultiplayRules -> CGameRules, in this case it's in CGameRules)
|
||||
static void InitChainOffset(SchemaClassInfoData_t* pClassInfo, SchemaKeyValueMap_t& keyValueMap)
|
||||
{
|
||||
short fieldsSize = pClassInfo->m_nFieldCount;
|
||||
SchemaClassFieldData_t* pFields = pClassInfo->m_pFields;
|
||||
|
||||
for (int i = 0; i < fieldsSize; ++i)
|
||||
{
|
||||
SchemaClassFieldData_t& field = pFields[i];
|
||||
|
||||
if (hash_32_fnv1a_const(field.m_pszName) != g_ChainKey)
|
||||
continue;
|
||||
|
||||
std::pair<uint32_t, SchemaKey> keyValuePair;
|
||||
keyValuePair.first = g_ChainKey;
|
||||
keyValuePair.second.offset = field.m_nSingleInheritanceOffset;
|
||||
keyValuePair.second.networked = IsFieldNetworked(field);
|
||||
|
||||
keyValueMap.insert(keyValuePair);
|
||||
return;
|
||||
}
|
||||
|
||||
// Not the base class yet, keep looking
|
||||
if (pClassInfo->m_nBaseClassCount)
|
||||
return InitChainOffset(pClassInfo->m_pBaseClasses[0].m_pClass, keyValueMap);
|
||||
}
|
||||
|
||||
static void InitSchemaKeyValueMap(SchemaClassInfoData_t* pClassInfo, SchemaKeyValueMap_t& keyValueMap)
|
||||
{
|
||||
short fieldsSize = pClassInfo->m_nFieldCount;
|
||||
SchemaClassFieldData_t* pFields = pClassInfo->m_pFields;
|
||||
|
||||
for (int i = 0; i < fieldsSize; ++i)
|
||||
{
|
||||
SchemaClassFieldData_t& field = pFields[i];
|
||||
|
||||
std::pair<uint32_t, SchemaKey> keyValuePair;
|
||||
keyValuePair.first = hash_32_fnv1a_const(field.m_pszName);
|
||||
keyValuePair.second.offset = field.m_nSingleInheritanceOffset;
|
||||
keyValuePair.second.networked = IsFieldNetworked(field);
|
||||
|
||||
keyValueMap.insert(keyValuePair);
|
||||
}
|
||||
|
||||
// If this is a child class there might be a parent class with __m_pChainEntity
|
||||
if (keyValueMap.find(g_ChainKey) == keyValueMap.end() && pClassInfo->m_nBaseClassCount)
|
||||
InitChainOffset(pClassInfo->m_pBaseClasses[0].m_pClass, keyValueMap);
|
||||
}
|
||||
|
||||
static bool InitSchemaFieldsForClass(SchemaTableMap_t& tableMap, const char* className, uint32_t classKey)
|
||||
{
|
||||
CSchemaSystemTypeScope* pType = shared::g_pSchemaSystem->FindTypeScopeForModule(MODULE_PREFIX "server" MODULE_EXT);
|
||||
|
||||
if (!pType)
|
||||
return false;
|
||||
|
||||
SchemaClassInfoData_t* pClassInfo = pType->FindDeclaredClass(className).Get();
|
||||
|
||||
if (!pClassInfo)
|
||||
{
|
||||
SchemaKeyValueMap_t map;
|
||||
tableMap.insert(std::make_pair(classKey, map));
|
||||
|
||||
Warning("InitSchemaFieldsForClass(): '%s' was not found!\n", className);
|
||||
return false;
|
||||
}
|
||||
|
||||
SchemaKeyValueMap_t& keyValueMap = tableMap.insert(std::make_pair(classKey, SchemaKeyValueMap_t())).first->
|
||||
second;
|
||||
|
||||
InitSchemaKeyValueMap(pClassInfo, keyValueMap);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
int16_t schema::FindChainOffset(const char* className, uint32_t classNameHash)
|
||||
{
|
||||
return schema::GetOffset(className, classNameHash, "__m_pChainEntity", g_ChainKey).offset;
|
||||
}
|
||||
|
||||
int16_t schema::FindChainOffset(const char* className)
|
||||
{
|
||||
CSchemaSystemTypeScope* pType = shared::g_pSchemaSystem->FindTypeScopeForModule(MODULE_PREFIX "server" MODULE_EXT);
|
||||
|
||||
if (!pType)
|
||||
return false;
|
||||
|
||||
SchemaClassInfoData_t* pClassInfo = pType->FindDeclaredClass(className).Get();
|
||||
|
||||
do
|
||||
{
|
||||
SchemaClassFieldData_t* pFields = pClassInfo->m_pFields;
|
||||
short fieldsSize = pClassInfo->m_nFieldCount;
|
||||
for (int i = 0; i < fieldsSize; ++i)
|
||||
{
|
||||
SchemaClassFieldData_t& field = pFields[i];
|
||||
|
||||
if (V_strcmp(field.m_pszName, "__m_pChainEntity") == 0)
|
||||
{
|
||||
return field.m_nSingleInheritanceOffset;
|
||||
}
|
||||
}
|
||||
}
|
||||
while ((pClassInfo = pClassInfo->m_pBaseClasses ? pClassInfo->m_pBaseClasses->m_pClass : nullptr) != nullptr);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
SchemaKey schema::GetOffset(const char* className, uint32_t classKey, const char* memberName, uint32_t memberKey)
|
||||
{
|
||||
static SchemaTableMap_t schemaTableMap;
|
||||
|
||||
if (schemaTableMap.find(classKey) == schemaTableMap.end())
|
||||
{
|
||||
if (InitSchemaFieldsForClass(schemaTableMap, className, classKey))
|
||||
return GetOffset(className, classKey, memberName, memberKey);
|
||||
|
||||
return {0, 0};
|
||||
}
|
||||
|
||||
SchemaKeyValueMap_t tableMap = schemaTableMap[classKey];
|
||||
|
||||
if (tableMap.find(memberKey) == tableMap.end())
|
||||
{
|
||||
if (memberKey != g_ChainKey)
|
||||
Warning("schema::GetOffset(): '%s' was not found in '%s'!\n", memberName, className);
|
||||
|
||||
return {0, 0};
|
||||
}
|
||||
|
||||
return tableMap[memberKey];
|
||||
}
|
||||
|
||||
int32_t schema::GetServerOffset(const char* pszClassName, const char* pszPropName)
|
||||
{
|
||||
SchemaClassInfoData_t* pClassInfo = shared::g_pSchemaSystem->FindTypeScopeForModule(MODULE_PREFIX "server" MODULE_EXT)->
|
||||
FindDeclaredClass(pszClassName).Get();
|
||||
if (pClassInfo)
|
||||
{
|
||||
for (int i = 0; i < pClassInfo->m_nFieldCount; i++)
|
||||
{
|
||||
auto& pFieldData = pClassInfo->m_pFields[i];
|
||||
|
||||
if (std::strcmp(pFieldData.m_pszName, pszPropName) == 0)
|
||||
{
|
||||
return pFieldData.m_nSingleInheritanceOffset;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
int32 schema::GetClassSize(const char* className) {
|
||||
CSchemaSystemTypeScope *pType = shared::g_pSchemaSystem->FindTypeScopeForModule(
|
||||
MODULE_PREFIX "server" MODULE_EXT);
|
||||
|
||||
SchemaClassInfoData_t *pClassInfo = pType->FindDeclaredClass(className).Get();
|
||||
if (!pClassInfo) return -1;
|
||||
|
||||
return pClassInfo->m_nSize;
|
||||
}
|
||||
|
||||
void NetworkVarStateChanged(uintptr_t pNetworkVar, uint32_t nOffset, uint32 nNetworkStateChangedOffset)
|
||||
{
|
||||
NetworkStateChangedData data(nOffset);
|
||||
CALL_VIRTUAL(void, nNetworkStateChangedOffset, (void*)pNetworkVar, &data);
|
||||
}
|
||||
|
||||
void EntityNetworkStateChanged(uintptr_t pEntity, uint nOffset)
|
||||
{
|
||||
NetworkStateChangedData data(nOffset);
|
||||
reinterpret_cast<CEntityInstance*>(pEntity)->NetworkStateChanged(data);
|
||||
}
|
||||
|
||||
void ChainNetworkStateChanged(uintptr_t pNetworkVarChainer, uint nLocalOffset)
|
||||
{
|
||||
CEntityInstance* pEntity = reinterpret_cast<CNetworkVarChainer2*>(pNetworkVarChainer)->m_pEntity;
|
||||
|
||||
if (pEntity)
|
||||
// NetworkStateChanged_t WENDER SDK
|
||||
// NetworkStateChangedData HL2SDK-CS@
|
||||
pEntity->NetworkStateChanged(NetworkStateChangedData(nLocalOffset, -1,
|
||||
reinterpret_cast<CNetworkVarChainer2*>(
|
||||
pNetworkVarChainer)->m_PathIndex));
|
||||
}
|
||||
}
|
||||
289
src/schema/schemasystem.h
Normal file
289
src/schema/schemasystem.h
Normal file
|
|
@ -0,0 +1,289 @@
|
|||
/**
|
||||
* =============================================================================
|
||||
* CS2Fixes
|
||||
* Copyright (C) 2023-2025 Source2ZE
|
||||
* =============================================================================
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it under
|
||||
* the terms of the GNU General Public License, version 3.0, as published by the
|
||||
* Free Software Foundation.
|
||||
*
|
||||
* This program 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
|
||||
* this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#ifdef _WIN32
|
||||
#pragma warning(push)
|
||||
#pragma warning(disable : 4005)
|
||||
#endif
|
||||
|
||||
#include <type_traits>
|
||||
|
||||
#ifdef _WIN32
|
||||
#pragma warning(pop)
|
||||
#endif
|
||||
|
||||
#include <entity2/entityidentity.h>
|
||||
#include <entity2/entityinstance.h>
|
||||
#include "const.h"
|
||||
#include "stdint.h"
|
||||
#include "tier0/dbg.h"
|
||||
#include "virtual.h"
|
||||
#undef schema
|
||||
|
||||
namespace
|
||||
TemplatePlugin
|
||||
{
|
||||
struct SchemaKey
|
||||
{
|
||||
int32 offset;
|
||||
bool networked;
|
||||
};
|
||||
|
||||
class CNetworkVarChainer2
|
||||
{
|
||||
public:
|
||||
CEntityInstance* m_pEntity;
|
||||
|
||||
private:
|
||||
uint8 pad_0000[24];
|
||||
|
||||
public:
|
||||
ChangeAccessorFieldPathIndex_t m_PathIndex;
|
||||
|
||||
private:
|
||||
uint8 pad_0024[4];
|
||||
};
|
||||
|
||||
void EntityNetworkStateChanged(uintptr_t pEntity, uint nOffset);
|
||||
void ChainNetworkStateChanged(uintptr_t pNetworkVarChainer, uint nOffset);
|
||||
void NetworkVarStateChanged(uintptr_t pNetworkVar, uint32_t nOffset, uint32 nNetworkStateChangedOffset);
|
||||
|
||||
namespace schema
|
||||
{
|
||||
int16_t FindChainOffset(const char* className, uint32_t classNameHash);
|
||||
int16_t FindChainOffset(const char* className);
|
||||
SchemaKey GetOffset(const char* className, uint32_t classKey, const char* memberName, uint32_t memberKey);
|
||||
int32_t GetServerOffset(const char* pszClassName, const char* pszPropName);
|
||||
int32_t GetClassSize(const char* className);
|
||||
} // namespace schema
|
||||
|
||||
constexpr uint32_t val_32_const = 0x811c9dc5;
|
||||
constexpr uint32_t prime_32_const = 0x1000193;
|
||||
constexpr uint64_t val_64_const = 0xcbf29ce484222325;
|
||||
constexpr uint64_t prime_64_const = 0x100000001b3;
|
||||
|
||||
inline constexpr uint32_t hash_32_fnv1a_const(const char* const str, const uint32_t value = val_32_const) noexcept
|
||||
{
|
||||
return (str[0] == '\0') ? value : hash_32_fnv1a_const(&str[1], (value ^ uint32_t(str[0])) * prime_32_const);
|
||||
}
|
||||
|
||||
inline constexpr uint64_t hash_64_fnv1a_const(const char* const str, const uint64_t value = val_64_const) noexcept
|
||||
{
|
||||
return (str[0] == '\0') ? value : hash_64_fnv1a_const(&str[1], (value ^ uint64_t(str[0])) * prime_64_const);
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
inline constexpr bool schema_writable_v =
|
||||
std::is_pointer_v<T> ||
|
||||
std::is_trivially_copyable_v<T> ||
|
||||
std::is_same_v<T, Vector> ||
|
||||
std::is_same_v<T, QAngle> ||
|
||||
std::is_same_v<T, Color>;
|
||||
|
||||
#define SCHEMA_FIELD_OFFSET(type, varName, extra_offset) \
|
||||
class varName##_prop \
|
||||
{ \
|
||||
public: \
|
||||
std::add_lvalue_reference_t<type> Get() \
|
||||
{ \
|
||||
static const auto m_key = schema::GetOffset(m_className, m_classNameHash, #varName, m_varNameHash); \
|
||||
static const auto m_offset = offsetof(ThisClass, varName); \
|
||||
\
|
||||
uintptr_t pThisClass = ((uintptr_t)this - m_offset); \
|
||||
\
|
||||
return *reinterpret_cast<std::add_pointer_t<type>>(pThisClass + m_key.offset + extra_offset); \
|
||||
} \
|
||||
template <typename T = type> \
|
||||
std::enable_if_t<std::is_pointer_v<T>, void> \
|
||||
Set(T val) \
|
||||
{ \
|
||||
static const auto m_key = schema::GetOffset(m_className, m_classNameHash, #varName, m_varNameHash); \
|
||||
static const auto m_offset = offsetof(ThisClass, varName); \
|
||||
\
|
||||
uintptr_t pThisClass = ((uintptr_t)this - m_offset); \
|
||||
\
|
||||
NetworkStateChanged(); \
|
||||
*reinterpret_cast<T*>(pThisClass + m_key.offset + extra_offset) = val; \
|
||||
} \
|
||||
template <typename T = type> \
|
||||
std::enable_if_t<!std::is_pointer_v<T> && std::is_trivially_copyable_v<T>, void> \
|
||||
Set(T val) \
|
||||
{ \
|
||||
static const auto m_key = schema::GetOffset(m_className, m_classNameHash, #varName, m_varNameHash); \
|
||||
static const auto m_offset = offsetof(ThisClass, varName); \
|
||||
\
|
||||
uintptr_t pThisClass = ((uintptr_t)this - m_offset); \
|
||||
\
|
||||
NetworkStateChanged(); \
|
||||
*reinterpret_cast<T*>(pThisClass + m_key.offset + extra_offset) = val; \
|
||||
} \
|
||||
template <typename T = type> \
|
||||
std::enable_if_t<!std::is_pointer_v<T> && !std::is_trivially_copyable_v<T>, void> \
|
||||
Set(const T& val) \
|
||||
{ \
|
||||
static const auto m_key = schema::GetOffset(m_className, m_classNameHash, #varName, m_varNameHash); \
|
||||
static const auto m_offset = offsetof(ThisClass, varName); \
|
||||
\
|
||||
uintptr_t pThisClass = ((uintptr_t)this - m_offset); \
|
||||
\
|
||||
NetworkStateChanged(); \
|
||||
std::memcpy( \
|
||||
reinterpret_cast<void*>(pThisClass + m_key.offset + extra_offset), \
|
||||
&val, \
|
||||
sizeof(type) \
|
||||
); \
|
||||
} \
|
||||
void NetworkStateChanged() \
|
||||
{ \
|
||||
static const auto m_key = schema::GetOffset(m_className, m_classNameHash, #varName, m_varNameHash); \
|
||||
static const auto m_chain = schema::FindChainOffset(m_className, m_classNameHash); \
|
||||
static const auto m_offset = offsetof(ThisClass, varName); \
|
||||
\
|
||||
uintptr_t pThisClass = ((uintptr_t)this - m_offset); \
|
||||
\
|
||||
if (m_chain != 0 && m_key.networked) \
|
||||
{ \
|
||||
ChainNetworkStateChanged(pThisClass + m_chain, m_key.offset + extra_offset); \
|
||||
} \
|
||||
else if (m_key.networked) \
|
||||
{ \
|
||||
if (!m_networkStateChangedOffset) \
|
||||
EntityNetworkStateChanged(pThisClass, m_key.offset + extra_offset); \
|
||||
else \
|
||||
NetworkVarStateChanged(pThisClass, m_key.offset + extra_offset, m_networkStateChangedOffset); \
|
||||
} \
|
||||
} \
|
||||
operator std::add_lvalue_reference_t<type>() \
|
||||
{ \
|
||||
return Get(); \
|
||||
} \
|
||||
std::add_lvalue_reference_t<type> operator()() \
|
||||
{ \
|
||||
return Get(); \
|
||||
} \
|
||||
std::add_lvalue_reference_t<type> operator->() \
|
||||
{ \
|
||||
return Get(); \
|
||||
} \
|
||||
template <typename T = type> \
|
||||
std::enable_if_t<schema_writable_v<T>, void> \
|
||||
operator()(T val) \
|
||||
{ \
|
||||
Set(val); \
|
||||
} \
|
||||
template <typename T = type> \
|
||||
std::enable_if_t<schema_writable_v<T>, varName##_prop&> \
|
||||
operator=(T val) \
|
||||
{ \
|
||||
Set(val); \
|
||||
return *this; \
|
||||
} \
|
||||
private: \
|
||||
/*Prevent accidentally copying this wrapper class instead of the underlying field*/ \
|
||||
varName##_prop(const varName##_prop&) = delete; \
|
||||
static constexpr auto m_varNameHash = hash_32_fnv1a_const(#varName); \
|
||||
} varName;
|
||||
|
||||
#define SCHEMA_FIELD_POINTER_OFFSET(type, varName, extra_offset) \
|
||||
class varName##_prop \
|
||||
{ \
|
||||
public: \
|
||||
type* Get() \
|
||||
{ \
|
||||
static const auto m_key = schema::GetOffset(m_className, m_classNameHash, #varName, m_varNameHash); \
|
||||
static const auto m_offset = offsetof(ThisClass, varName); \
|
||||
\
|
||||
uintptr_t pThisClass = ((uintptr_t)this - m_offset); \
|
||||
\
|
||||
return reinterpret_cast<std::add_pointer_t<type>>(pThisClass + m_key.offset + extra_offset); \
|
||||
} \
|
||||
void NetworkStateChanged() /*Call this after editing the field*/ \
|
||||
{ \
|
||||
static const auto m_key = schema::GetOffset(m_className, m_classNameHash, #varName, m_varNameHash); \
|
||||
static const auto m_chain = schema::FindChainOffset(m_className, m_classNameHash); \
|
||||
static const auto m_offset = offsetof(ThisClass, varName); \
|
||||
\
|
||||
uintptr_t pThisClass = ((uintptr_t)this - m_offset); \
|
||||
\
|
||||
if (m_chain != 0 && m_key.networked) \
|
||||
{ \
|
||||
ChainNetworkStateChanged(pThisClass + m_chain, m_key.offset + extra_offset); \
|
||||
} \
|
||||
else if (m_key.networked) \
|
||||
{ \
|
||||
if (!m_networkStateChangedOffset) \
|
||||
EntityNetworkStateChanged(pThisClass, m_key.offset + extra_offset); \
|
||||
else \
|
||||
NetworkVarStateChanged(pThisClass, m_key.offset + extra_offset, m_networkStateChangedOffset); \
|
||||
} \
|
||||
} \
|
||||
operator type*() \
|
||||
{ \
|
||||
return Get(); \
|
||||
} \
|
||||
type* operator()() \
|
||||
{ \
|
||||
return Get(); \
|
||||
} \
|
||||
type* operator->() \
|
||||
{ \
|
||||
return Get(); \
|
||||
} \
|
||||
private: \
|
||||
/*Prevent accidentally copying this wrapper class instead of the underlying field*/ \
|
||||
varName##_prop(const varName##_prop&) = delete; \
|
||||
static constexpr auto m_varNameHash = hash_32_fnv1a_const(#varName); \
|
||||
} varName;
|
||||
|
||||
// Use this when you want the member's value itself
|
||||
#define SCHEMA_FIELD(type, varName) \
|
||||
SCHEMA_FIELD_OFFSET(type, varName, 0)
|
||||
|
||||
// Use this when you want a pointer to a member
|
||||
#define SCHEMA_FIELD_POINTER(type, varName) \
|
||||
SCHEMA_FIELD_POINTER_OFFSET(type, varName, 0)
|
||||
|
||||
// If the class needs a specific offset for its NetworkStateChanged (like CEconItemView), use this and provide the offset
|
||||
#define DECLARE_SCHEMA_CLASS_BASE(ClassName, offset) \
|
||||
private: \
|
||||
typedef ClassName ThisClass; \
|
||||
static constexpr const char* m_className = #ClassName; \
|
||||
static constexpr uint32_t m_classNameHash = hash_32_fnv1a_const(#ClassName);\
|
||||
static constexpr int m_networkStateChangedOffset = offset; \
|
||||
public:
|
||||
|
||||
#define SCHEMA_FIELD_OLD(type, className, propName) \
|
||||
std::add_lvalue_reference_t<type> propName() \
|
||||
{ \
|
||||
static const int32_t offset = schema::GetServerOffset(#className, #propName); \
|
||||
if(offset == -1) \
|
||||
std::runtime_error("Failed to find " #propName " in " #className); \
|
||||
return *reinterpret_cast<std::add_pointer_t<type>>(reinterpret_cast<intptr_t>(this) + offset); \
|
||||
}
|
||||
|
||||
#define DECLARE_SCHEMA_CLASS(className) DECLARE_SCHEMA_CLASS_BASE(className, 0)
|
||||
|
||||
// Use this for non-entity classes such as CCollisionProperty or CGlowProperty
|
||||
// The only difference is that their NetworkStateChanged function is index 1 on their vtable rather than being CEntityInstance::NetworkStateChanged
|
||||
// Though some classes like CGameRules will instead use their CNetworkVarChainer as a link back to the parent entity
|
||||
#define DECLARE_SCHEMA_CLASS_INLINE(className) DECLARE_SCHEMA_CLASS_BASE(className, 1)
|
||||
|
||||
}
|
||||
445
src/schema/serversideclient.h
Normal file
445
src/schema/serversideclient.h
Normal file
|
|
@ -0,0 +1,445 @@
|
|||
//
|
||||
// Created by Michal Přikryl on 26.06.2025.
|
||||
// Copyright (c) 2025 slynxcz. All rights reserved.
|
||||
//
|
||||
#pragma once
|
||||
|
||||
#include "playerslot.h"
|
||||
#include "steam/steamclientpublic.h"
|
||||
#include "utlstring.h"
|
||||
#include "inetchannel.h"
|
||||
#include "networkbasetypes.pb.h"
|
||||
#include <inetchannel.h>
|
||||
#include <playerslot.h>
|
||||
#include "circularbuffer.h"
|
||||
#include "networksystem/inetworksystem.h"
|
||||
#include "threadtools.h"
|
||||
#include "tier1/netadr.h"
|
||||
#include <entity2/entityidentity.h>
|
||||
#include <networksystem/inetworksystem.h>
|
||||
#include <steam/steamclientpublic.h>
|
||||
#include <tier1/utlstring.h>
|
||||
#include <network_connection.pb.h>
|
||||
#include <netmessages.pb.h>
|
||||
|
||||
namespace
|
||||
TemplatePlugin
|
||||
{
|
||||
class CHLTVServer;
|
||||
class INetMessage;
|
||||
class CNetworkGameServerBase;
|
||||
class CNetworkGameServer;
|
||||
class CFrameSnapshot;
|
||||
|
||||
class CMsg_CVars;
|
||||
class CNETMsg_StringCmd_t;
|
||||
class CNETMsg_Tick_t;
|
||||
class CNETMsg_SpawnGroup_LoadCompleted_t;
|
||||
class CCLCMsg_ClientInfo_t;
|
||||
class CCLCMsg_BaselineAck_t;
|
||||
class CCLCMsg_LoadingProgress_t;
|
||||
class CCLCMsg_SplitPlayerConnect_t;
|
||||
class CCLCMsg_SplitPlayerDisconnect_t;
|
||||
class CCLCMsg_CmdKeyValues_t;
|
||||
class CCLCMsg_Move_t;
|
||||
class CCLCMsg_VoiceData_t;
|
||||
class CCLCMsg_FileCRCCheck_t;
|
||||
class CCLCMsg_RespondCvarValue_t;
|
||||
class NetMessagePacketStart_t;
|
||||
class NetMessagePacketEnd_t;
|
||||
class NetMessageConnectionClosed_t;
|
||||
class NetMessageConnectionCrashed_t;
|
||||
class NetMessageSplitscreenUserChanged_t;
|
||||
|
||||
struct HltvReplayStats_t
|
||||
{
|
||||
enum FailEnum_t
|
||||
{
|
||||
FAILURE_ALREADY_IN_REPLAY,
|
||||
FAILURE_TOO_FREQUENT,
|
||||
FAILURE_NO_FRAME,
|
||||
FAILURE_NO_FRAME2,
|
||||
FAILURE_CANNOT_MATCH_DELAY,
|
||||
FAILURE_FRAME_NOT_READY,
|
||||
NUM_FAILURES
|
||||
};
|
||||
|
||||
uint nClients;
|
||||
uint nStartRequests;
|
||||
uint nSuccessfulStarts;
|
||||
uint nStopRequests;
|
||||
uint nAbortStopRequests;
|
||||
uint nUserCancels;
|
||||
uint nFullReplays;
|
||||
uint nNetAbortReplays;
|
||||
uint nFailedReplays[NUM_FAILURES];
|
||||
}; // sizeof 56
|
||||
COMPILE_TIME_ASSERT(sizeof(HltvReplayStats_t) == 56);
|
||||
|
||||
struct Spike_t
|
||||
{
|
||||
public:
|
||||
CUtlString m_szDesc;
|
||||
int m_nBits;
|
||||
};
|
||||
|
||||
COMPILE_TIME_ASSERT(sizeof(Spike_t) == 16);
|
||||
|
||||
class CNetworkStatTrace
|
||||
{
|
||||
public:
|
||||
CUtlVector<Spike_t> m_Records;
|
||||
int m_nMinWarningBytes;
|
||||
int m_nStartBit;
|
||||
int m_nCurBit;
|
||||
};
|
||||
|
||||
COMPILE_TIME_ASSERT(sizeof(CNetworkStatTrace) == 40);
|
||||
|
||||
enum CopiedLockState_t : int32
|
||||
{
|
||||
CLS_NOCOPY = 0,
|
||||
CLS_UNLOCKED = 1,
|
||||
CLS_LOCKED_BY_COPYING_THREAD = 2,
|
||||
};
|
||||
|
||||
template <class MUTEX, CopiedLockState_t L = CLS_UNLOCKED>
|
||||
class CCopyableLock : public MUTEX
|
||||
{
|
||||
typedef MUTEX BaseClass;
|
||||
|
||||
public:
|
||||
// ...
|
||||
};
|
||||
|
||||
class CUtlSignaller_Base
|
||||
{
|
||||
public:
|
||||
using Delegate_t = CUtlDelegate<void(CUtlSlot*)>;
|
||||
|
||||
CUtlSignaller_Base(const Delegate_t& other) :
|
||||
m_SlotDeletionDelegate(other)
|
||||
{
|
||||
}
|
||||
|
||||
CUtlSignaller_Base(Delegate_t&& other) :
|
||||
m_SlotDeletionDelegate(Move(other))
|
||||
{
|
||||
}
|
||||
|
||||
private:
|
||||
Delegate_t m_SlotDeletionDelegate;
|
||||
};
|
||||
|
||||
class CUtlSlot
|
||||
{
|
||||
public:
|
||||
using MTElement_t = CUtlSignaller_Base*;
|
||||
|
||||
CUtlSlot() :
|
||||
m_ConnectedSignallers(0, 1)
|
||||
{
|
||||
}
|
||||
|
||||
private:
|
||||
CCopyableLock<CThreadFastMutex> m_Mutex;
|
||||
CUtlVector<MTElement_t> m_ConnectedSignallers;
|
||||
};
|
||||
|
||||
class CServerSideClientBase : public CUtlSlot, public INetworkChannelNotify,
|
||||
public INetworkMessageProcessingPreFilter
|
||||
{
|
||||
public:
|
||||
virtual ~CServerSideClientBase() = 0;
|
||||
|
||||
public:
|
||||
CPlayerSlot GetPlayerSlot() const { return m_nClientSlot; }
|
||||
CPlayerUserId GetUserID() const { return m_UserID; }
|
||||
CEntityIndex GetEntityIndex() const { return m_nEntityIndex; }
|
||||
CSteamID GetClientSteamID() const { return m_SteamID; }
|
||||
const char* GetClientName() const { return m_Name; }
|
||||
INetChannel* GetNetChannel() const { return m_NetChannel; }
|
||||
const netadr_t* GetRemoteAddress() const { return &m_nAddr.GetAddress(); }
|
||||
CNetworkGameServerBase* GetServer() const { return m_Server; }
|
||||
|
||||
virtual void Connect(int socket, const char* pszName, int nUserID, INetChannel* pNetChannel,
|
||||
uint8 nConnectionTypeFlags,
|
||||
uint32 uChallengeNumber) = 0;
|
||||
// bool bFakePlayer = !nConnectionTypeFlags || (nConnectionTypeFlags & 8) != 0;
|
||||
virtual void Inactivate(const char* pszAddons) = 0;
|
||||
virtual void Reactivate(CPlayerSlot nSlot) = 0;
|
||||
virtual void SetServer(CNetworkGameServer* pNetServer) = 0;
|
||||
virtual void Reconnect() = 0;
|
||||
virtual void Disconnect(ENetworkDisconnectionReason reason, const char* pszInternalReason) = 0;
|
||||
virtual bool CheckConnect() = 0;
|
||||
virtual void Create(CPlayerSlot& nSlot, CSteamID nSteamID, const char* pszName) = 0;
|
||||
virtual void SetRate(int nRate) = 0;
|
||||
virtual void SetUpdateRate(float fUpdateRate) = 0;
|
||||
virtual int GetRate() = 0;
|
||||
|
||||
virtual void Clear() = 0;
|
||||
|
||||
virtual bool ExecuteStringCommand(const CNETMsg_StringCmd_t& msg) = 0;
|
||||
// "false" trigger an anti spam counter to kick a client.
|
||||
virtual bool SendNetMessage(const CNetMessage* pData, NetChannelBufType_t bufType = BUF_DEFAULT) = 0;
|
||||
|
||||
// "Client %d(%s) tried to send a RebroadcastSourceId msg.\n"
|
||||
virtual bool FilterMessage(const CNetMessage* pData, INetChannel* pChannel) = 0;
|
||||
// On Windows, this function is in a separate virtual table
|
||||
|
||||
public:
|
||||
virtual void ClientPrintf(PRINTF_FORMAT_STRING const char*, ...) = 0;
|
||||
|
||||
bool IsConnected() const { return m_nSignonState >= SIGNONSTATE_CONNECTED; }
|
||||
bool IsInGame() const { return m_nSignonState == SIGNONSTATE_FULL; }
|
||||
bool IsSpawned() const { return m_nSignonState >= SIGNONSTATE_NEW; }
|
||||
bool IsActive() const { return m_nSignonState == SIGNONSTATE_FULL; }
|
||||
virtual bool IsFakeClient() const { return m_bFakePlayer; }
|
||||
bool IsHLTV() const { return m_bIsHLTV; }
|
||||
virtual bool IsHumanPlayer() const { return false; }
|
||||
|
||||
// Is an actual human player or splitscreen player (not a bot and not a HLTV slot)
|
||||
virtual bool IsHearingClient(CPlayerSlot nSlot) const { return false; }
|
||||
virtual bool IsProximityHearingClient() const = 0;
|
||||
virtual bool IsLowViolenceClient() const { return m_bLowViolence; }
|
||||
|
||||
virtual bool IsSplitScreenUser() const { return m_bSplitScreenUser; }
|
||||
|
||||
public: // Message Handlers
|
||||
virtual bool ProcessTick(const CNETMsg_Tick_t& msg) = 0;
|
||||
virtual bool ProcessStringCmd(const CNETMsg_StringCmd_t& msg) = 0;
|
||||
|
||||
public:
|
||||
virtual bool ApplyConVars(const CMsg_CVars& list) = 0;
|
||||
|
||||
private:
|
||||
virtual bool unk_28() = 0;
|
||||
|
||||
public:
|
||||
virtual bool ProcessSpawnGroup_LoadCompleted(const CNETMsg_SpawnGroup_LoadCompleted_t& msg) = 0;
|
||||
virtual bool ProcessClientInfo(const CCLCMsg_ClientInfo_t& msg) = 0;
|
||||
virtual bool ProcessBaselineAck(const CCLCMsg_BaselineAck_t& msg) = 0;
|
||||
virtual bool ProcessLoadingProgress(const CCLCMsg_LoadingProgress_t& msg) = 0;
|
||||
virtual bool ProcessSplitPlayerConnect(const CCLCMsg_SplitPlayerConnect_t& msg) = 0;
|
||||
virtual bool ProcessSplitPlayerDisconnect(const CCLCMsg_SplitPlayerDisconnect_t& msg) = 0;
|
||||
virtual bool ProcessCmdKeyValues(const CCLCMsg_CmdKeyValues_t& msg) = 0;
|
||||
|
||||
private:
|
||||
virtual bool unk_36() = 0;
|
||||
virtual bool unk_37() = 0;
|
||||
|
||||
public:
|
||||
virtual bool ProcessMove(const CCLCMsg_Move_t& msg) = 0;
|
||||
virtual bool ProcessVoiceData(const CCLCMsg_VoiceData_t& msg) = 0;
|
||||
virtual bool ProcessRespondCvarValue(const CCLCMsg_RespondCvarValue_t& msg) = 0;
|
||||
|
||||
virtual bool ProcessPacketStart(const NetMessagePacketStart_t& msg) = 0;
|
||||
virtual bool ProcessPacketEnd(const NetMessagePacketEnd_t& msg) = 0;
|
||||
virtual bool ProcessConnectionClosed(const NetMessageConnectionClosed_t& msg) = 0;
|
||||
virtual bool ProcessConnectionCrashed(const NetMessageConnectionCrashed_t& msg) = 0;
|
||||
|
||||
public:
|
||||
virtual bool ProcessChangeSplitscreenUser(const NetMessageSplitscreenUserChanged_t& msg) = 0;
|
||||
|
||||
private:
|
||||
virtual bool unk_47() = 0;
|
||||
virtual bool unk_48() = 0;
|
||||
virtual bool unk_49() = 0;
|
||||
|
||||
public:
|
||||
virtual void ConnectionStart(INetChannel* pNetChannel) = 0;
|
||||
|
||||
private: // SpawnGroup something.
|
||||
virtual void unk_51() = 0;
|
||||
virtual void unk_52() = 0;
|
||||
|
||||
public:
|
||||
virtual void ExecuteDelayedCall(void*) = 0;
|
||||
|
||||
virtual bool UpdateAcknowledgedFramecount(int tick) = 0;
|
||||
|
||||
void ForceFullUpdate()
|
||||
{
|
||||
// For some reason, it doesn't work.
|
||||
// UpdateAcknowledgedFramecount(-1);
|
||||
m_nDeltaTick = -1;
|
||||
}
|
||||
|
||||
virtual bool ShouldSendMessages() = 0;
|
||||
virtual void UpdateSendState() = 0;
|
||||
|
||||
virtual const CMsgPlayerInfo& GetPlayerInfo() const { return m_playerInfo; }
|
||||
|
||||
virtual void UpdateUserSettings() = 0;
|
||||
virtual void ResetUserSettings() = 0;
|
||||
|
||||
private:
|
||||
virtual void unk_60() = 0;
|
||||
|
||||
public:
|
||||
virtual void SendSignonData() = 0;
|
||||
virtual void SpawnPlayer() = 0;
|
||||
virtual void ActivatePlayer() = 0;
|
||||
|
||||
virtual void SetName(const char* name) = 0;
|
||||
virtual void SetUserCVar(const char* cvar, const char* value) = 0;
|
||||
|
||||
SignonState_t GetSignonState() const { return m_nSignonState; }
|
||||
|
||||
virtual void FreeBaselines() = 0;
|
||||
|
||||
bool IsFullyAuthenticated(void) { return m_bFullyAuthenticated; }
|
||||
void SetFullyAuthenticated(void) { m_bFullyAuthenticated = true; }
|
||||
|
||||
virtual CServerSideClientBase* GetSplitScreenOwner() { return m_pAttachedTo; }
|
||||
|
||||
virtual int GetNumPlayers() = 0;
|
||||
|
||||
virtual void ShouldReceiveStringTableUserData() = 0;
|
||||
|
||||
private:
|
||||
virtual void unk_70(CPlayerSlot nSlot) = 0;
|
||||
virtual void unk_71() = 0;
|
||||
virtual void unk_72() = 0;
|
||||
|
||||
public:
|
||||
virtual int GetHltvLastSendTick() = 0;
|
||||
|
||||
private:
|
||||
virtual void unk_74() = 0;
|
||||
virtual void unk_75() = 0;
|
||||
virtual void unk_76() = 0;
|
||||
|
||||
public:
|
||||
virtual void Await() = 0;
|
||||
|
||||
virtual void MarkToKick() = 0;
|
||||
virtual void UnmarkToKick() = 0;
|
||||
|
||||
virtual bool ProcessSignonStateMsg(int state) = 0;
|
||||
virtual void PerformDisconnection(ENetworkDisconnectionReason reason) = 0;
|
||||
|
||||
public:
|
||||
CUtlString m_UserIDString;
|
||||
CUtlString m_Name;
|
||||
CPlayerSlot m_nClientSlot;
|
||||
CEntityIndex m_nEntityIndex;
|
||||
CNetworkGameServerBase* m_Server;
|
||||
INetChannel* m_NetChannel;
|
||||
// CServerSideClientBase::Connect( name='%s', userid=%d, fake=%d, connectiontypeflags=%d, chan->addr=%s )
|
||||
uint8 m_nConnectionTypeFlags;
|
||||
uint8 m_nAsyncDisconnectFlags; // check in Disconnect function, 1 add to queue, 2 disconnect now
|
||||
bool m_bMarkedToKick;
|
||||
SignonState_t m_nSignonState;
|
||||
bool m_bSplitScreenUser;
|
||||
bool m_bSplitAllowFastDisconnect;
|
||||
int m_nSplitScreenPlayerSlot;
|
||||
CServerSideClientBase* m_SplitScreenUsers[4];
|
||||
CServerSideClientBase* m_pAttachedTo;
|
||||
bool m_bSplitPlayerDisconnecting;
|
||||
int m_nDisconnectionTypeFlags;
|
||||
bool m_bFakePlayer;
|
||||
bool m_bSendingSnapshot;
|
||||
|
||||
private:
|
||||
[[maybe_unused]] char pad162[0x6];
|
||||
|
||||
public:
|
||||
CPlayerUserId m_UserID = -1;
|
||||
bool m_bReceivedPacket; // true, if client received a packet after the last send packet
|
||||
CSteamID m_SteamID;
|
||||
CSteamID m_DisconnectedSteamID;
|
||||
CSteamID m_AuthTicketSteamID; // Auth ticket
|
||||
CSteamID m_nFriendsID;
|
||||
ns_address m_nAddr;
|
||||
ns_address m_nAddr2;
|
||||
KeyValues* m_ConVars;
|
||||
bool m_bUnk0;
|
||||
|
||||
private:
|
||||
[[maybe_unused]] char pad281[0x28];
|
||||
|
||||
public:
|
||||
bool m_bConVarsChanged;
|
||||
bool m_bIsHLTV;
|
||||
|
||||
private:
|
||||
[[maybe_unused]] char pad323[0xD];
|
||||
|
||||
public:
|
||||
uint32 m_nSendtableCRC;
|
||||
uint32 m_uChallengeNumber;
|
||||
int m_nSignonTick;
|
||||
int m_nDeltaTick;
|
||||
int m_UnkVariable3;
|
||||
int m_nStringTableAckTick;
|
||||
int m_UnkVariable4;
|
||||
CFrameSnapshot* m_pLastSnapshot; // last send snapshot
|
||||
CUtlVector<void*> m_vecLoadedSpawnGroups;
|
||||
CMsgPlayerInfo m_playerInfo;
|
||||
CFrameSnapshot* m_pBaseline;
|
||||
int m_nBaselineUpdateTick;
|
||||
CBitVec<MAX_EDICTS> m_BaselinesSent;
|
||||
int m_nBaselineUsed; // 0/1 toggling flag, singaling client what baseline to use
|
||||
int m_nLoadingProgress; // 0..100 progress, only valid during loading
|
||||
|
||||
// This is used when we send out a nodelta packet to put the client in a state where we wait
|
||||
// until we get an ack from them on this packet.
|
||||
// This is for 3 reasons:
|
||||
// 1. A client requesting a nodelta packet means they're screwed so no point in deluging them with data.
|
||||
// Better to send the uncompressed data at a slow rate until we hear back from them (if at all).
|
||||
// 2. Since the nodelta packet deletes all client entities, we can't ever delta from a packet previous to it.
|
||||
// 3. It can eat up a lot of CPU on the server to keep building nodelta packets while waiting for
|
||||
// a client to get back on its feet.
|
||||
int m_nForceWaitForTick = -1;
|
||||
|
||||
CCircularBuffer m_UnkBuffer = {1024};
|
||||
bool m_bLowViolence = false; // true if client is in low-violence mode (L4D server needs to know)
|
||||
bool m_bSomethingWithAddressType = true;
|
||||
bool m_bFullyAuthenticated = false;
|
||||
bool m_bUnk1 = false;
|
||||
int m_nUnk;
|
||||
|
||||
// The datagram is written to after every frame, but only cleared
|
||||
// when it is sent out to the client. overflow is tolerated.
|
||||
|
||||
// Time when we should send next world state update ( datagram )
|
||||
float m_fNextMessageTime = 0.0f;
|
||||
float m_fAuthenticatedTime = -1.0f;
|
||||
|
||||
// Default time to wait for next message
|
||||
float m_fSnapshotInterval = 0.0f;
|
||||
|
||||
private:
|
||||
[[maybe_unused]] char pad2572[0x8];
|
||||
[[maybe_unused]] char m_packetmsg[0x15C]; // CSVCMsg_PacketEntities_t
|
||||
#ifdef __linux__
|
||||
[[maybe_unused]] char pad2928[0x8];
|
||||
#endif
|
||||
|
||||
public:
|
||||
CNetworkStatTrace m_Trace;
|
||||
|
||||
private:
|
||||
[[maybe_unused]] char pad2976[0x8];
|
||||
|
||||
public:
|
||||
// SV: Player %s kicked for too many failed console commands
|
||||
int m_spamCommandsCount = 0; // if the value is greater than 16, the player will be kicked with reason 39
|
||||
int m_unknown = 0;
|
||||
double m_lastExecutedCommand = 0.0; // if command executed more than once per second, ++m_spamCommandCount
|
||||
|
||||
private:
|
||||
[[maybe_unused]] char pad3000[0x8];
|
||||
|
||||
public:
|
||||
CCommand* m_pCommand;
|
||||
};
|
||||
#ifdef __linux__
|
||||
COMPILE_TIME_ASSERT(sizeof(CServerSideClientBase) == 3016);
|
||||
#endif
|
||||
|
||||
class CServerSideClient : public CServerSideClientBase
|
||||
{
|
||||
};
|
||||
}
|
||||
410
src/schema/services.h
Normal file
410
src/schema/services.h
Normal file
|
|
@ -0,0 +1,410 @@
|
|||
/**
|
||||
* =============================================================================
|
||||
* CS2Fixes
|
||||
* Copyright (C) 2023-2025 Source2ZE
|
||||
* =============================================================================
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it under
|
||||
* the terms of the GNU General Public License, version 3.0, as published by the
|
||||
* Free Software Foundation.
|
||||
*
|
||||
* This program 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
|
||||
* this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "globaltypes.h"
|
||||
#include "CCSWeaponBase.h"
|
||||
#include <platform.h>
|
||||
#include <unordered_map>
|
||||
|
||||
#define AMMO_OFFSET_HEGRENADE 13
|
||||
#define AMMO_OFFSET_FLASHBANG 14
|
||||
#define AMMO_OFFSET_SMOKEGRENADE 15
|
||||
#define AMMO_OFFSET_MOLOTOV 16
|
||||
#define AMMO_OFFSET_DECOY 17
|
||||
|
||||
namespace TemplatePlugin {
|
||||
class CCSPlayerController;
|
||||
class CCSPlayerPawn;
|
||||
extern bool g_bAwsChangingTeam;
|
||||
|
||||
struct CSPerRoundStats_t {
|
||||
DECLARE_SCHEMA_CLASS_INLINE(CSPerRoundStats_t)
|
||||
|
||||
SCHEMA_FIELD(int32_t, m_iKills);
|
||||
SCHEMA_FIELD(int32_t, m_iDeaths);
|
||||
SCHEMA_FIELD(int32_t, m_iAssists);
|
||||
SCHEMA_FIELD(int32_t, m_iDamage);
|
||||
SCHEMA_FIELD(int32_t, m_iHeadShotKills);
|
||||
SCHEMA_FIELD(int32_t, m_iUtilityDamage);
|
||||
SCHEMA_FIELD(int32_t, m_iEnemiesFlashed);
|
||||
SCHEMA_FIELD(int32_t, m_iObjective);
|
||||
SCHEMA_FIELD(int32_t, m_iCashEarned);
|
||||
SCHEMA_FIELD(int32_t, m_iEquipmentValue);
|
||||
SCHEMA_FIELD(int32_t, m_iKillReward);
|
||||
SCHEMA_FIELD(int32_t, m_iMoneySaved);
|
||||
};
|
||||
|
||||
struct CSMatchStats_t : public CSPerRoundStats_t {
|
||||
public:
|
||||
DECLARE_SCHEMA_CLASS_INLINE(CSMatchStats_t)
|
||||
|
||||
SCHEMA_FIELD(int32_t, m_iEntryWins);
|
||||
};
|
||||
|
||||
class CPlayerControllerComponent {
|
||||
virtual ~CPlayerControllerComponent() = 0;
|
||||
|
||||
public:
|
||||
DECLARE_SCHEMA_CLASS(CPlayerControllerComponent)
|
||||
|
||||
CCSPlayerController* __m_pChainEntity;
|
||||
CCSPlayerController* GetController() { return __m_pChainEntity; }
|
||||
};
|
||||
|
||||
class CPlayerPawnComponent {
|
||||
virtual ~CPlayerPawnComponent() = 0;
|
||||
|
||||
virtual void unk_01() = 0;
|
||||
|
||||
virtual void unk_02() = 0;
|
||||
|
||||
virtual void unk_03() = 0;
|
||||
|
||||
virtual void unk_04() = 0;
|
||||
|
||||
virtual void unk_05() = 0;
|
||||
|
||||
virtual void unk_06() = 0;
|
||||
|
||||
virtual void unk_07() = 0;
|
||||
|
||||
virtual void unk_08() = 0;
|
||||
|
||||
virtual void unk_09() = 0;
|
||||
|
||||
virtual void unk_10() = 0;
|
||||
|
||||
virtual void unk_11() = 0;
|
||||
|
||||
virtual void unk_12() = 0;
|
||||
|
||||
virtual void unk_13() = 0;
|
||||
|
||||
virtual void unk_14() = 0;
|
||||
|
||||
virtual void unk_15() = 0;
|
||||
|
||||
virtual void unk_16() = 0;
|
||||
|
||||
virtual void unk_17() = 0;
|
||||
|
||||
public:
|
||||
DECLARE_SCHEMA_CLASS(CPlayerPawnComponent);
|
||||
|
||||
SCHEMA_FIELD(CCSPlayerPawn*, __m_pChainEntity)
|
||||
|
||||
CCSPlayerPawn *GetPawn() { return __m_pChainEntity; }
|
||||
};
|
||||
|
||||
class CPlayer_MovementServices : public CPlayerPawnComponent {
|
||||
virtual ~CPlayer_MovementServices() = 0;
|
||||
|
||||
public:
|
||||
DECLARE_SCHEMA_CLASS(CPlayer_MovementServices);
|
||||
|
||||
SCHEMA_FIELD(CInButtonState, m_nButtons)
|
||||
|
||||
SCHEMA_FIELD(uint64_t, m_nQueuedButtonDownMask)
|
||||
|
||||
SCHEMA_FIELD(uint64_t, m_nQueuedButtonChangeMask)
|
||||
|
||||
SCHEMA_FIELD(uint64_t, m_nButtonDoublePressed)
|
||||
|
||||
// m_pButtonPressedCmdNumber[64]
|
||||
SCHEMA_FIELD_POINTER(uint32_t, m_pButtonPressedCmdNumber)
|
||||
|
||||
SCHEMA_FIELD(uint32_t, m_nLastCommandNumberProcessed)
|
||||
|
||||
SCHEMA_FIELD(uint64_t, m_nToggleButtonDownMask)
|
||||
|
||||
SCHEMA_FIELD(float, m_flMaxspeed)
|
||||
};
|
||||
|
||||
class CPlayer_MovementServices_Humanoid : public CPlayer_MovementServices {
|
||||
virtual ~CPlayer_MovementServices_Humanoid() = 0;
|
||||
|
||||
public:
|
||||
DECLARE_SCHEMA_CLASS(CPlayer_MovementServices_Humanoid);
|
||||
|
||||
SCHEMA_FIELD(float, m_flFallVelocity)
|
||||
|
||||
SCHEMA_FIELD(float, m_bInCrouch)
|
||||
|
||||
SCHEMA_FIELD(uint32_t, m_nCrouchState)
|
||||
|
||||
SCHEMA_FIELD(bool, m_bInDuckJump)
|
||||
|
||||
SCHEMA_FIELD(float, m_flSurfaceFriction)
|
||||
};
|
||||
|
||||
class CCSPlayer_MovementServices : public CPlayer_MovementServices_Humanoid {
|
||||
virtual ~CCSPlayer_MovementServices() = 0;
|
||||
|
||||
public:
|
||||
DECLARE_SCHEMA_CLASS(CCSPlayer_MovementServices);
|
||||
|
||||
SCHEMA_FIELD(float, m_flMaxFallVelocity)
|
||||
|
||||
SCHEMA_FIELD(float, m_flJumpVel)
|
||||
|
||||
SCHEMA_FIELD(float, m_flJumpPressedTime)
|
||||
|
||||
SCHEMA_FIELD(float, m_flStamina)
|
||||
|
||||
SCHEMA_FIELD(float, m_flDuckSpeed)
|
||||
|
||||
SCHEMA_FIELD(bool, m_bDuckOverride)
|
||||
};
|
||||
|
||||
class CPlayer_WeaponServices : public CPlayerPawnComponent {
|
||||
virtual ~CPlayer_WeaponServices() = 0;
|
||||
|
||||
public:
|
||||
DECLARE_SCHEMA_CLASS(CPlayer_WeaponServices);
|
||||
|
||||
SCHEMA_FIELD_POINTER(CUtlVector<CHandle<CBasePlayerWeapon>>, m_hMyWeapons)
|
||||
|
||||
SCHEMA_FIELD(CHandle<CBasePlayerWeapon>, m_hActiveWeapon)
|
||||
|
||||
SCHEMA_FIELD_POINTER(uint16_t, m_iAmmo)
|
||||
};
|
||||
|
||||
class CCSPlayer_WeaponServices : public CPlayer_WeaponServices {
|
||||
virtual ~CCSPlayer_WeaponServices() = 0;
|
||||
|
||||
public:
|
||||
DECLARE_SCHEMA_CLASS(CCSPlayer_WeaponServices);
|
||||
|
||||
SCHEMA_FIELD(GameTime_t, m_flNextAttack)
|
||||
|
||||
SCHEMA_FIELD(bool, m_bIsLookingAtWeapon)
|
||||
|
||||
SCHEMA_FIELD(bool, m_bIsHoldingLookAtWeapon)
|
||||
|
||||
SCHEMA_FIELD(CHandle<CBasePlayerWeapon>, m_hSavedWeapon)
|
||||
|
||||
SCHEMA_FIELD(int32_t, m_nTimeToMelee)
|
||||
|
||||
SCHEMA_FIELD(int32_t, m_nTimeToSecondary)
|
||||
|
||||
SCHEMA_FIELD(int32_t, m_nTimeToPrimary)
|
||||
|
||||
SCHEMA_FIELD(int32_t, m_nTimeToSniperRifle)
|
||||
|
||||
SCHEMA_FIELD(bool, m_bIsBeingGivenItem)
|
||||
|
||||
SCHEMA_FIELD(bool, m_bIsPickingUpItemWithUse)
|
||||
|
||||
SCHEMA_FIELD(bool, m_bPickedUpWeapon)
|
||||
|
||||
void DropWeapon(CBasePlayerWeapon *pWeapon, Vector *pVecTarget = nullptr, Vector *pVelocity = nullptr) {
|
||||
static int offset = shared::g_pGameConfig->GetOffset("CCSPlayer_WeaponServices_DropWeapon");
|
||||
CALL_VIRTUAL(void, offset, this, pWeapon, pVecTarget, pVelocity);
|
||||
}
|
||||
|
||||
void SelectItem(CBasePlayerWeapon *pWeapon, int unk1 = 0) {
|
||||
static int offset = shared::g_pGameConfig->GetOffset("CCSPlayer_WeaponServices_SelectItem");
|
||||
CALL_VIRTUAL(void, offset, this, pWeapon, unk1);
|
||||
}
|
||||
};
|
||||
|
||||
class CCSPlayerController_ActionTrackingServices : public CPlayerControllerComponent {
|
||||
virtual ~CCSPlayerController_ActionTrackingServices() = 0;
|
||||
|
||||
public:
|
||||
DECLARE_SCHEMA_CLASS(CCSPlayerController_ActionTrackingServices)
|
||||
|
||||
SCHEMA_FIELD(CSMatchStats_t, m_matchStats)
|
||||
SCHEMA_FIELD(int, m_iNumRoundKills);
|
||||
};
|
||||
|
||||
class CCSPlayerController_InGameMoneyServices : public CPlayerControllerComponent {
|
||||
virtual ~CCSPlayerController_InGameMoneyServices() = 0;
|
||||
|
||||
public:
|
||||
DECLARE_SCHEMA_CLASS(CCSPlayerController_InGameMoneyServices);
|
||||
|
||||
SCHEMA_FIELD(bool, m_bReceivesMoneyNextRound); // ReceivesMoneyNextRound
|
||||
SCHEMA_FIELD(int, m_iMoneyEarnedForNextRound); // MoneyEarnedForNextRound
|
||||
SCHEMA_FIELD(int, m_iAccount); // Account
|
||||
SCHEMA_FIELD(int, m_iStartAccount); // StartAccount
|
||||
SCHEMA_FIELD(int, m_iTotalCashSpent); // TotalCashSpent
|
||||
SCHEMA_FIELD(int, m_iCashSpentThisRound); // CashSpentThisRound
|
||||
};
|
||||
|
||||
class CCSPlayerController_InventoryServices : public CPlayerControllerComponent {
|
||||
virtual ~CCSPlayerController_InventoryServices() = 0;
|
||||
|
||||
public:
|
||||
DECLARE_SCHEMA_CLASS(CCSPlayerController_InventoryServices);
|
||||
|
||||
SCHEMA_FIELD(int32_t, m_nPersonaDataXpTrailLevel)
|
||||
SCHEMA_FIELD(int32_t, m_nPersonaDataPublicLevel)
|
||||
SCHEMA_FIELD(uint16_t, m_unMusicID)
|
||||
SCHEMA_FIELD_POINTER(int, m_rank)
|
||||
};
|
||||
|
||||
class CPlayer_ItemServices : public CPlayerPawnComponent {
|
||||
virtual ~CPlayer_ItemServices() = 0;
|
||||
|
||||
public:
|
||||
DECLARE_SCHEMA_CLASS(CPlayer_ItemServices);
|
||||
};
|
||||
|
||||
class CCSPlayer_ItemServices : public CPlayer_ItemServices {
|
||||
virtual ~CCSPlayer_ItemServices() = 0;
|
||||
|
||||
public:
|
||||
DECLARE_SCHEMA_CLASS(CCSPlayer_ItemServices);
|
||||
|
||||
SCHEMA_FIELD(bool, m_bHasDefuser)
|
||||
SCHEMA_FIELD(bool, m_bHasHelmet)
|
||||
|
||||
private:
|
||||
virtual CBasePlayerWeapon *_GiveNamedItem(const char *pchName) = 0;
|
||||
|
||||
public:
|
||||
virtual bool GiveNamedItemBool(const char *pchName) = 0;
|
||||
|
||||
virtual CBasePlayerWeapon *GiveNamedItem(const char *pchName) = 0;
|
||||
|
||||
// Recommended to use CCSPlayer_WeaponServices::DropWeapon instead (parameter is ignored here)
|
||||
virtual void DropActiveWeapon(CBasePlayerWeapon *pWeapon) = 0;
|
||||
|
||||
virtual void StripPlayerWeapons(bool removeSuit) = 0;
|
||||
|
||||
// Custom functions
|
||||
[[nodiscard]] static bool IsAwsProcessing() noexcept { return g_bAwsChangingTeam; }
|
||||
static void ResetAwsProcessing() { g_bAwsChangingTeam = false; }
|
||||
|
||||
[[nodiscard]] static gear_slot_t GetItemGearSlot(const char *item) noexcept;
|
||||
|
||||
CBasePlayerWeapon *GiveNamedItemAws(const char *item) noexcept;
|
||||
|
||||
void RemoveWeapons() {
|
||||
CALL_VIRTUAL(void, shared::g_pGameConfig->GetOffset("CCSPlayer_ItemServices_RemoveWeapons"), this);
|
||||
}
|
||||
};
|
||||
|
||||
// We need an exactly sized class to be able to iterate the vector, our schema system implementation can't do this
|
||||
class WeaponPurchaseCount_t {
|
||||
private:
|
||||
virtual void unk00() {
|
||||
};
|
||||
|
||||
virtual void unk01() {
|
||||
};
|
||||
|
||||
virtual void unk02() {
|
||||
};
|
||||
|
||||
virtual void unk03() {
|
||||
};
|
||||
|
||||
virtual void unk04() {
|
||||
};
|
||||
|
||||
CCSPlayerPawn *m_pPawn;
|
||||
uint64_t unk2 = 0; // 0x10
|
||||
uint64_t unk3 = 0; // 0x18
|
||||
uint64_t unk4 = 0; // 0x20
|
||||
uint64_t unk5 = -1; // 0x28
|
||||
|
||||
public:
|
||||
WeaponPurchaseCount_t(CCSPlayerPawn *pPawn, uint16 nItemDefIndex, uint16 nCount) : m_pPawn(pPawn),
|
||||
m_nItemDefIndex(nItemDefIndex), m_nCount(nCount) {
|
||||
// Since we're constructing a new object, the vtable pointer will be incorrect so fix it
|
||||
static const auto pVTable = DynLibUtils::CModule(shared::g_pEntitySystem).GetVirtualTableByName("WeaponPurchaseCount_t");
|
||||
((void **) this)[0] = pVTable;
|
||||
}
|
||||
|
||||
uint16_t m_nItemDefIndex; // 0x30
|
||||
uint16_t m_nCount; // 0x32
|
||||
private:
|
||||
uint32_t unk6 = 0;
|
||||
};
|
||||
|
||||
struct WeaponPurchaseTracker_t {
|
||||
public:
|
||||
DECLARE_SCHEMA_CLASS_INLINE(WeaponPurchaseTracker_t)
|
||||
|
||||
SCHEMA_FIELD_POINTER(CUtlVector<WeaponPurchaseCount_t>, m_weaponPurchases)
|
||||
};
|
||||
|
||||
class CCSPlayer_ActionTrackingServices : CPlayerPawnComponent {
|
||||
virtual ~CCSPlayer_ActionTrackingServices() = 0;
|
||||
|
||||
public:
|
||||
DECLARE_SCHEMA_CLASS(CCSPlayer_ActionTrackingServices)
|
||||
|
||||
SCHEMA_FIELD(WeaponPurchaseTracker_t, m_weaponPurchasesThisRound)
|
||||
};
|
||||
|
||||
class CPlayer_ObserverServices : public CPlayerPawnComponent {
|
||||
virtual ~CPlayer_ObserverServices() = 0;
|
||||
|
||||
public:
|
||||
DECLARE_SCHEMA_CLASS(CPlayer_ObserverServices)
|
||||
|
||||
SCHEMA_FIELD(ObserverMode_t, m_iObserverMode)
|
||||
|
||||
SCHEMA_FIELD(CHandle<CBaseEntity>, m_hObserverTarget)
|
||||
|
||||
SCHEMA_FIELD(ObserverMode_t, m_iObserverLastMode)
|
||||
|
||||
SCHEMA_FIELD(bool, m_bForcedObserverMode)
|
||||
};
|
||||
|
||||
class CPlayer_CameraServices : public CPlayerPawnComponent {
|
||||
virtual ~CPlayer_CameraServices() = 0;
|
||||
|
||||
public:
|
||||
DECLARE_SCHEMA_CLASS(CPlayer_CameraServices)
|
||||
|
||||
SCHEMA_FIELD(CHandle<CBaseEntity>, m_hViewEntity)
|
||||
};
|
||||
|
||||
class CCSPlayerBase_CameraServices : public CPlayer_CameraServices {
|
||||
public:
|
||||
virtual ~CCSPlayerBase_CameraServices() = 0;
|
||||
|
||||
DECLARE_SCHEMA_CLASS(CCSPlayerBase_CameraServices)
|
||||
|
||||
SCHEMA_FIELD(CHandle<CBaseEntity>, m_hZoomOwner)
|
||||
|
||||
SCHEMA_FIELD(uint, m_iFOV)
|
||||
};
|
||||
|
||||
class CCSPlayer_CameraServices : public CCSPlayerBase_CameraServices {
|
||||
virtual ~CCSPlayer_CameraServices() = 0;
|
||||
};
|
||||
|
||||
class CCSPlayer_PingServices : public CPlayerPawnComponent {
|
||||
virtual ~CCSPlayer_PingServices() = 0;
|
||||
|
||||
public:
|
||||
DECLARE_SCHEMA_CLASS(CCSPlayer_PingServices);
|
||||
|
||||
SCHEMA_FIELD_POINTER(GameTime_t, m_flPlayerPingTokens)
|
||||
|
||||
SCHEMA_FIELD(CHandle<CBaseEntity>, m_hPlayerPing)
|
||||
};
|
||||
}
|
||||
18
src/schema/vfunc.h
Normal file
18
src/schema/vfunc.h
Normal file
|
|
@ -0,0 +1,18 @@
|
|||
//
|
||||
// Created by Michal Přikryl on 26.06.2025.
|
||||
// Copyright (c) 2025 slynxcz. All rights reserved.
|
||||
//
|
||||
#pragma once
|
||||
|
||||
#include <cstdint>
|
||||
|
||||
namespace TemplatePlugin
|
||||
{
|
||||
template <typename T, typename... Args>
|
||||
inline T CallVFunc(void* base, int index, Args... args)
|
||||
{
|
||||
using Fn = T(*)(void*, Args...);
|
||||
void** vtable = *reinterpret_cast<void***>(base);
|
||||
return reinterpret_cast<Fn>(vtable[index])(base, args...);
|
||||
}
|
||||
}
|
||||
64
src/schema/virtual.h
Normal file
64
src/schema/virtual.h
Normal file
|
|
@ -0,0 +1,64 @@
|
|||
//
|
||||
// Created by Michal Přikryl on 20.06.2025.
|
||||
// Copyright (c) 2025 slynxcz. All rights reserved.
|
||||
//
|
||||
#pragma once
|
||||
#include "platform.h"
|
||||
|
||||
#define CALL_VIRTUAL(retType, idx, ...) vmt::CallVirtual<retType>(idx, __VA_ARGS__)
|
||||
#define CALL_VIRTUAL_OVERRIDE_VTBL(retType, idx, vtable, classPtr, ...) vmt::CallVirtualOverrideVTable<retType>(idx, vtable, classPtr, __VA_ARGS__)
|
||||
|
||||
namespace vmt {
|
||||
template <typename T = void*> inline T GetVMethod(uint32 uIndex, void* pClass)
|
||||
{
|
||||
if (!pClass)
|
||||
{
|
||||
return T();
|
||||
}
|
||||
|
||||
void** pVTable = *static_cast<void***>(pClass);
|
||||
if (!pVTable)
|
||||
{
|
||||
return T();
|
||||
}
|
||||
|
||||
return reinterpret_cast<T>(pVTable[uIndex]);
|
||||
}
|
||||
|
||||
template <typename T, typename... Args> inline T CallVirtual(uint32 uIndex, void* pClass, Args... args)
|
||||
{
|
||||
#ifdef _WIN32
|
||||
auto pFunc = GetVMethod<T(__thiscall*)(void*, Args...)>(uIndex, pClass);
|
||||
#else
|
||||
auto pFunc = GetVMethod<T (*)(void*, Args...)>(uIndex, pClass);
|
||||
#endif
|
||||
if (!pFunc)
|
||||
{
|
||||
return T();
|
||||
}
|
||||
|
||||
return pFunc(pClass, args...);
|
||||
}
|
||||
|
||||
template<typename T, typename... Args>
|
||||
inline T CallVirtualOverrideVTable(uint32 uIndex, void **pVTable, void *pClass, Args... args)
|
||||
{
|
||||
if (!pVTable)
|
||||
{
|
||||
Warning("Tried getting virtual function from a null vtable.\n");
|
||||
return T();
|
||||
}
|
||||
#ifdef _WIN32
|
||||
auto pFunc = reinterpret_cast<T(__thiscall *)(void *, Args...)>(pVTable[uIndex]);
|
||||
#else
|
||||
auto pFunc = reinterpret_cast<T(__cdecl *)(void *, Args...)>(pVTable[uIndex]);
|
||||
#endif
|
||||
if (!pFunc)
|
||||
{
|
||||
Warning("Tried calling a null virtual function.\n");
|
||||
return T();
|
||||
}
|
||||
|
||||
return pFunc(pClass, args...);
|
||||
}
|
||||
} // namespace vmt
|
||||
160
src/tasks.cpp
Normal file
160
src/tasks.cpp
Normal file
|
|
@ -0,0 +1,160 @@
|
|||
//
|
||||
// Created by Michal Přikryl on 10.07.2025.
|
||||
// Copyright (c) 2025 slynxcz. All rights reserved.
|
||||
//
|
||||
#include "tasks.h"
|
||||
#include <algorithm>
|
||||
#include <chrono>
|
||||
#include <mutex>
|
||||
#include <queue>
|
||||
|
||||
namespace TemplatePlugin {
|
||||
double universal_time = 0.0;
|
||||
double last_tick_time = 0.0;
|
||||
double timer_next_think = 0.0;
|
||||
|
||||
namespace {
|
||||
std::vector<Timer *> once_off_timers;
|
||||
std::vector<Timer *> repeat_timers;
|
||||
std::mutex nextFrameMutex;
|
||||
std::queue<std::function<void()> > nextFrameQueue;
|
||||
}
|
||||
void Tasks::NextFrame(std::function<void()> &&task) {
|
||||
std::lock_guard lock(nextFrameMutex);
|
||||
nextFrameQueue.emplace(std::move(task));
|
||||
}
|
||||
|
||||
Timer::Timer(float interval, double execTime, TimerCallback callback, int flags)
|
||||
: Interval(interval), ExecTime(execTime), Callback(std::move(callback)), Flags(flags) {
|
||||
}
|
||||
|
||||
void Tasks::Init() {
|
||||
universal_time = 0.0;
|
||||
last_tick_time = 0.0;
|
||||
timer_next_think = 0.0;
|
||||
}
|
||||
|
||||
void Tasks::Shutdown() {
|
||||
for (auto *timer: once_off_timers)
|
||||
delete timer;
|
||||
for (auto *timer: repeat_timers)
|
||||
delete timer;
|
||||
once_off_timers.clear();
|
||||
repeat_timers.clear();
|
||||
std::lock_guard lock(nextFrameMutex);
|
||||
std::queue<std::function<void()> > empty;
|
||||
std::swap(nextFrameQueue, empty);
|
||||
}
|
||||
|
||||
void Tasks::Tick(bool simulating) {
|
||||
std::queue<std::function<void()>> localQueue;
|
||||
{
|
||||
std::lock_guard lock(nextFrameMutex);
|
||||
std::swap(localQueue, nextFrameQueue);
|
||||
}
|
||||
|
||||
while (!localQueue.empty()) {
|
||||
try {
|
||||
localQueue.front()();
|
||||
} catch (...) {
|
||||
}
|
||||
localQueue.pop();
|
||||
}
|
||||
|
||||
double now = std::chrono::duration_cast<std::chrono::duration<float> >(
|
||||
std::chrono::steady_clock::now().time_since_epoch()).count();
|
||||
|
||||
if (simulating)
|
||||
universal_time += now - last_tick_time;
|
||||
else
|
||||
universal_time += 0.015;
|
||||
|
||||
last_tick_time = now;
|
||||
|
||||
if (universal_time < timer_next_think)
|
||||
return;
|
||||
|
||||
for (int i = static_cast<int>(once_off_timers.size()) - 1; i >= 0; --i) {
|
||||
Timer *timer = once_off_timers[i];
|
||||
if (universal_time >= timer->ExecTime) {
|
||||
timer->InExec = true;
|
||||
try {
|
||||
timer->Callback();
|
||||
} catch (...) {
|
||||
}
|
||||
delete timer;
|
||||
once_off_timers.erase(once_off_timers.begin() + i);
|
||||
}
|
||||
}
|
||||
|
||||
for (int i = static_cast<int>(repeat_timers.size()) - 1; i >= 0; --i) {
|
||||
Timer *timer = repeat_timers[i];
|
||||
if (universal_time >= timer->ExecTime) {
|
||||
timer->InExec = true;
|
||||
try {
|
||||
timer->Callback();
|
||||
} catch (...) {
|
||||
}
|
||||
|
||||
if (timer->KillMe) {
|
||||
delete timer;
|
||||
repeat_timers.erase(repeat_timers.begin() + i);
|
||||
continue;
|
||||
}
|
||||
|
||||
timer->InExec = false;
|
||||
timer->ExecTime = universal_time + timer->Interval;
|
||||
}
|
||||
}
|
||||
|
||||
timer_next_think = universal_time + 0.1;
|
||||
}
|
||||
|
||||
Timer *Tasks::AddTimer(float interval, TimerCallback callback, int flags) {
|
||||
Timer *timer = new Timer(interval, universal_time + interval, std::move(callback), flags);
|
||||
|
||||
if (flags & TIMER_FLAG_REPEAT)
|
||||
repeat_timers.push_back(timer);
|
||||
else
|
||||
once_off_timers.push_back(timer);
|
||||
|
||||
return timer;
|
||||
}
|
||||
|
||||
void Tasks::KillTimer(Timer *timer) {
|
||||
if (!timer) return;
|
||||
|
||||
auto killFrom = [](std::vector<Timer *> &list, Timer *target) {
|
||||
auto it = std::remove_if(list.begin(), list.end(), [=](Timer *t) { return t == target; });
|
||||
if (it != list.end()) {
|
||||
delete target;
|
||||
list.erase(it, list.end());
|
||||
}
|
||||
};
|
||||
|
||||
if (timer->InExec) {
|
||||
timer->KillMe = true;
|
||||
return;
|
||||
}
|
||||
|
||||
if (timer->Flags & TIMER_FLAG_REPEAT)
|
||||
killFrom(repeat_timers, timer);
|
||||
else
|
||||
killFrom(once_off_timers, timer);
|
||||
}
|
||||
|
||||
void Tasks::RemoveMapChangeTimers() {
|
||||
auto removeFrom = [](std::vector<Timer*>& list) {
|
||||
for (int i = static_cast<int>(list.size()) - 1; i >= 0; --i) {
|
||||
Timer* t = list[i];
|
||||
if (t->Flags & TIMER_FLAG_NO_MAPCHANGE) {
|
||||
delete t;
|
||||
list.erase(list.begin() + i);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
removeFrom(once_off_timers);
|
||||
removeFrom(repeat_timers);
|
||||
}
|
||||
}
|
||||
43
src/tasks.h
Normal file
43
src/tasks.h
Normal file
|
|
@ -0,0 +1,43 @@
|
|||
//
|
||||
// Created by Michal Přikryl on 10.07.2025.
|
||||
// Copyright (c) 2025 slynxcz. All rights reserved.
|
||||
//
|
||||
#pragma once
|
||||
|
||||
#include <functional>
|
||||
|
||||
namespace TemplatePlugin {
|
||||
using TimerCallback = std::function<void()>;
|
||||
|
||||
enum TimerFlags {
|
||||
TIMER_FLAG_REPEAT = 1 << 0,
|
||||
TIMER_FLAG_NO_MAPCHANGE = 1 << 1,
|
||||
};
|
||||
|
||||
extern double universal_time;
|
||||
extern double last_tick_time;
|
||||
extern double timer_next_think;
|
||||
|
||||
class Timer {
|
||||
public:
|
||||
Timer(float interval, double execTime, TimerCallback callback, int flags);
|
||||
~Timer() = default;
|
||||
|
||||
float Interval;
|
||||
double ExecTime;
|
||||
TimerCallback Callback;
|
||||
int Flags;
|
||||
bool InExec = false;
|
||||
bool KillMe = false;
|
||||
};
|
||||
|
||||
namespace Tasks {
|
||||
void Init();
|
||||
void Shutdown();
|
||||
void Tick(bool simulating = true);
|
||||
void NextFrame(std::function<void()> &&task);
|
||||
Timer* AddTimer(float interval, TimerCallback callback, int flags = 0);
|
||||
void KillTimer(Timer* timer);
|
||||
void RemoveMapChangeTimers();
|
||||
}
|
||||
}
|
||||
126
src/vectorextends.h
Normal file
126
src/vectorextends.h
Normal file
|
|
@ -0,0 +1,126 @@
|
|||
//
|
||||
// Created by Michal Přikryl on 07.08.2025.
|
||||
// Copyright (c) 2025 slynxcz. All rights reserved.
|
||||
//
|
||||
#pragma once
|
||||
|
||||
#include <cmath>
|
||||
#include <algorithm>
|
||||
#include <vector.h>
|
||||
|
||||
namespace TemplatePlugin::VectorExtends
|
||||
{
|
||||
inline const Vector VectorZero{0.0f, 0.0f, 0.0f};
|
||||
inline const QAngle RotationZero{0.0f, 0.0f, 0.0f};
|
||||
inline const Vector StaticTeleportVector{9999999.0f, 8888888.0f, 777777.0f};
|
||||
|
||||
inline Vector Clone(const Vector& vector)
|
||||
{
|
||||
return Vector{vector.x, vector.y, vector.z};
|
||||
}
|
||||
|
||||
inline QAngle QClone(const QAngle& angle)
|
||||
{
|
||||
return QAngle{angle.x, angle.y, angle.z};
|
||||
}
|
||||
|
||||
inline Vector Adds(const Vector& vector, const Vector& other)
|
||||
{
|
||||
return Vector{vector.x + other.x, vector.y + other.y, vector.z + other.z};
|
||||
}
|
||||
|
||||
inline Vector Scale(const Vector& vector, float scale)
|
||||
{
|
||||
return Vector{vector.x * scale, vector.y * scale, vector.z * scale};
|
||||
}
|
||||
|
||||
inline Vector Normalize(const Vector& vector)
|
||||
{
|
||||
float length = vector.Length();
|
||||
return Vector{vector.x / length, vector.y / length, vector.z / length};
|
||||
}
|
||||
|
||||
inline float Distance(const Vector& vector, const Vector& other)
|
||||
{
|
||||
return std::sqrt(
|
||||
std::pow(vector.x - other.x, 2.0f) +
|
||||
std::pow(vector.y - other.y, 2.0f) +
|
||||
std::pow(vector.z - other.z, 2.0f)
|
||||
);
|
||||
}
|
||||
|
||||
inline float DistanceSquared(const Vector& vector, const Vector& other)
|
||||
{
|
||||
return
|
||||
std::pow(vector.x - other.x, 2.0f) +
|
||||
std::pow(vector.y - other.y, 2.0f) +
|
||||
std::pow(vector.z - other.z, 2.0f);
|
||||
}
|
||||
|
||||
inline Vector MakeVectorFromPoints(const Vector& pt1, const Vector& pt2)
|
||||
{
|
||||
return Vector{pt2.x - pt1.x, pt2.y - pt1.y, pt2.z - pt1.z};
|
||||
}
|
||||
|
||||
inline Vector SubtractVectors(const Vector& vec1, const Vector& vec2)
|
||||
{
|
||||
return Vector{vec1.x - vec2.x, vec1.y - vec2.y, vec1.z - vec2.z};
|
||||
}
|
||||
|
||||
inline Vector NegateVector(const Vector& vec)
|
||||
{
|
||||
return Vector{-vec.x, -vec.y, -vec.z};
|
||||
}
|
||||
|
||||
inline float DegToRad(float degrees)
|
||||
{
|
||||
return degrees * (static_cast<float>(M_PI) / 180.0f);
|
||||
}
|
||||
|
||||
inline float RadToDeg(float radians)
|
||||
{
|
||||
return radians * (180.0f / static_cast<float>(M_PI));
|
||||
}
|
||||
|
||||
inline bool IsInsideBox(const Vector& playerVector, const Vector& corner1, const Vector& corner2, float height = 0.0f)
|
||||
{
|
||||
float minX = std::min(corner1.x, corner2.x);
|
||||
float minY = std::min(corner1.y, corner2.y);
|
||||
float minZ = std::min(corner1.z, corner2.z);
|
||||
|
||||
float maxX = std::max(corner1.x, corner2.x);
|
||||
float maxY = std::max(corner1.y, corner2.y);
|
||||
float maxZ = std::max(corner1.z, corner2.z);
|
||||
|
||||
return playerVector.x >= minX && playerVector.x <= maxX &&
|
||||
playerVector.y >= minY && playerVector.y <= maxY &&
|
||||
playerVector.z >= minZ && playerVector.z <= maxZ + height;
|
||||
}
|
||||
|
||||
inline bool IsInsideField(const Vector& playerVector, const Vector& corner1, const Vector& corner2)
|
||||
{
|
||||
float minX = std::min(corner1.x, corner2.x);
|
||||
float minY = std::min(corner1.y, corner2.y);
|
||||
|
||||
float maxX = std::max(corner1.x, corner2.x);
|
||||
float maxY = std::max(corner1.y, corner2.y);
|
||||
|
||||
return playerVector.x >= minX && playerVector.x <= maxX &&
|
||||
playerVector.y >= minY && playerVector.y <= maxY;
|
||||
}
|
||||
|
||||
inline float ArcCosine(float value)
|
||||
{
|
||||
return std::acos(value);
|
||||
}
|
||||
|
||||
inline float GetVectorDotProduct(const Vector& vec1, const Vector& vec2)
|
||||
{
|
||||
return vec1.x * vec2.x + vec1.y * vec2.y + vec1.z * vec2.z;
|
||||
}
|
||||
|
||||
inline float Dot(const Vector& vec1, const Vector& vec2)
|
||||
{
|
||||
return vec1.x * vec2.x + vec1.y * vec2.y + vec1.z * vec2.z;
|
||||
}
|
||||
}
|
||||
21
vendor/dynlibutils/LICENSE
vendored
Normal file
21
vendor/dynlibutils/LICENSE
vendored
Normal file
|
|
@ -0,0 +1,21 @@
|
|||
MIT License
|
||||
|
||||
Copyright (c) 2023 komashchenko (Phoenix)
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all
|
||||
copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
SOFTWARE.
|
||||
9
vendor/dynlibutils/README.md
vendored
Normal file
9
vendor/dynlibutils/README.md
vendored
Normal file
|
|
@ -0,0 +1,9 @@
|
|||
DynLibUtils is a library for interacting with dynamically loaded libraries (DLL, SO).
|
||||
Allows to get library sections, find pattern in memory and VirtualTable address by name.
|
||||
|
||||
This library is designed to simplify development for CS2 server, supports Windows/Linux x86_64.
|
||||
|
||||
Usage
|
||||
------------
|
||||
|
||||
Copy the source and header files to your project and add [`module.cpp`](module.cpp) in your build.
|
||||
152
vendor/dynlibutils/memaddr.h
vendored
Normal file
152
vendor/dynlibutils/memaddr.h
vendored
Normal file
|
|
@ -0,0 +1,152 @@
|
|||
// DynLibUtils
|
||||
// Copyright (C) 2023 komashchenko (Phoenix)
|
||||
// https://github.com/komashchenko/DynLibUtils
|
||||
|
||||
#ifndef DYNLIBUTILS_MEMADDR_H
|
||||
#define DYNLIBUTILS_MEMADDR_H
|
||||
#ifdef _WIN32
|
||||
#pragma once
|
||||
#endif
|
||||
|
||||
#include <cstdint>
|
||||
#include <cstddef>
|
||||
#include <utility>
|
||||
|
||||
namespace DynLibUtils {
|
||||
|
||||
class CMemory
|
||||
{
|
||||
public:
|
||||
CMemory() : m_ptr(0) {}
|
||||
CMemory(const CMemory&) noexcept = default;
|
||||
CMemory& operator= (const CMemory&) noexcept = default;
|
||||
CMemory(CMemory&& other) noexcept : m_ptr(std::exchange(other.m_ptr, 0)) {}
|
||||
CMemory(const uintptr_t ptr) : m_ptr(ptr) {}
|
||||
CMemory(const void* ptr) : m_ptr(reinterpret_cast<uintptr_t>(ptr)) {}
|
||||
|
||||
inline operator uintptr_t() const noexcept
|
||||
{
|
||||
return m_ptr;
|
||||
}
|
||||
|
||||
inline operator void*() const noexcept
|
||||
{
|
||||
return reinterpret_cast<void*>(m_ptr);
|
||||
}
|
||||
|
||||
explicit inline operator bool() const noexcept
|
||||
{
|
||||
return m_ptr != 0;
|
||||
}
|
||||
|
||||
inline bool operator!= (const CMemory& addr) const noexcept
|
||||
{
|
||||
return m_ptr != addr.m_ptr;
|
||||
}
|
||||
|
||||
inline bool operator== (const CMemory& addr) const noexcept
|
||||
{
|
||||
return m_ptr == addr.m_ptr;
|
||||
}
|
||||
|
||||
inline bool operator== (const uintptr_t& addr) const noexcept
|
||||
{
|
||||
return m_ptr == addr;
|
||||
}
|
||||
|
||||
[[nodiscard]] inline uintptr_t GetPtr() const noexcept
|
||||
{
|
||||
return m_ptr;
|
||||
}
|
||||
|
||||
template<class T> [[nodiscard]] inline T GetValue() const noexcept
|
||||
{
|
||||
return *reinterpret_cast<T*>(m_ptr);
|
||||
}
|
||||
|
||||
template<typename T> [[nodiscard]] inline T CCast() const noexcept
|
||||
{
|
||||
return (T)m_ptr;
|
||||
}
|
||||
|
||||
template<typename T> [[nodiscard]] inline T RCast() const noexcept
|
||||
{
|
||||
return reinterpret_cast<T>(m_ptr);
|
||||
}
|
||||
|
||||
template<typename T> [[nodiscard]] inline T UCast() const noexcept
|
||||
{
|
||||
union { uintptr_t m_ptr; T cptr; } cast;
|
||||
return cast.m_ptr = m_ptr, cast.cptr;
|
||||
}
|
||||
|
||||
[[nodiscard]] inline CMemory Offset(ptrdiff_t offset) const noexcept
|
||||
{
|
||||
return m_ptr + offset;
|
||||
}
|
||||
|
||||
inline CMemory& OffsetSelf(ptrdiff_t offset) noexcept
|
||||
{
|
||||
m_ptr += offset;
|
||||
return *this;
|
||||
}
|
||||
|
||||
[[nodiscard]] inline CMemory Deref(int deref = 1) const
|
||||
{
|
||||
uintptr_t reference = m_ptr;
|
||||
|
||||
while (deref--)
|
||||
{
|
||||
if (reference)
|
||||
reference = *reinterpret_cast<uintptr_t*>(reference);
|
||||
}
|
||||
|
||||
return reference;
|
||||
}
|
||||
|
||||
inline CMemory& DerefSelf(int deref = 1)
|
||||
{
|
||||
while (deref--)
|
||||
{
|
||||
if (m_ptr)
|
||||
m_ptr = *reinterpret_cast<uintptr_t*>(m_ptr);
|
||||
}
|
||||
|
||||
return *this;
|
||||
}
|
||||
|
||||
[[nodiscard]] inline CMemory FollowNearCall(const ptrdiff_t opcodeOffset = 0x1, const ptrdiff_t nextInstructionOffset = 0x5) const
|
||||
{
|
||||
return ResolveRelativeAddress(opcodeOffset, nextInstructionOffset);
|
||||
}
|
||||
|
||||
inline CMemory& FollowNearCallSelf(const ptrdiff_t opcodeOffset = 0x1, const ptrdiff_t nextInstructionOffset = 0x5)
|
||||
{
|
||||
return ResolveRelativeAddressSelf(opcodeOffset, nextInstructionOffset);
|
||||
}
|
||||
|
||||
[[nodiscard]] inline CMemory ResolveRelativeAddress(const ptrdiff_t registerOffset = 0x0, const ptrdiff_t nextInstructionOffset = 0x4) const
|
||||
{
|
||||
const uintptr_t skipRegister = m_ptr + registerOffset;
|
||||
const int32_t relativeAddress = *reinterpret_cast<int32_t*>(skipRegister);
|
||||
const uintptr_t nextInstruction = m_ptr + nextInstructionOffset;
|
||||
return nextInstruction + relativeAddress;
|
||||
}
|
||||
|
||||
inline CMemory& ResolveRelativeAddressSelf(const ptrdiff_t registerOffset = 0x0, const ptrdiff_t nextInstructionOffset = 0x4)
|
||||
{
|
||||
const uintptr_t skipRegister = m_ptr + registerOffset;
|
||||
const int32_t relativeAddress = *reinterpret_cast<int32_t*>(skipRegister);
|
||||
const uintptr_t nextInstruction = m_ptr + nextInstructionOffset;
|
||||
m_ptr = nextInstruction + relativeAddress;
|
||||
|
||||
return *this;
|
||||
}
|
||||
|
||||
private:
|
||||
uintptr_t m_ptr;
|
||||
};
|
||||
|
||||
} // namespace DynLibUtils
|
||||
|
||||
#endif // DYNLIBUTILS_MEMADDR_H
|
||||
203
vendor/dynlibutils/module.cpp
vendored
Normal file
203
vendor/dynlibutils/module.cpp
vendored
Normal file
|
|
@ -0,0 +1,203 @@
|
|||
// DynLibUtils
|
||||
// Copyright (C) 2023 komashchenko (Phoenix)
|
||||
// https://github.com/komashchenko/DynLibUtils
|
||||
|
||||
#include "module.h"
|
||||
#include "memaddr.h"
|
||||
#include <cstring>
|
||||
#include <cmath>
|
||||
#include <emmintrin.h>
|
||||
|
||||
using namespace DynLibUtils;
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose: constructor
|
||||
// Input : szModuleName (without extension .dll/.so)
|
||||
//-----------------------------------------------------------------------------
|
||||
CModule::CModule(const std::string_view szModuleName) : m_pModuleHandle(nullptr)
|
||||
{
|
||||
InitFromName(szModuleName);
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose: constructor
|
||||
// Input : pModuleMemory
|
||||
//-----------------------------------------------------------------------------
|
||||
CModule::CModule(const CMemory pModuleMemory) : m_pModuleHandle(nullptr)
|
||||
{
|
||||
InitFromMemory(pModuleMemory);
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose: Converts a string pattern with wildcards to an array of bytes and mask
|
||||
// Input : svInput
|
||||
// Output : std::pair<std::vector<uint8_t>, std::string>
|
||||
//-----------------------------------------------------------------------------
|
||||
std::pair<std::vector<uint8_t>, std::string> CModule::PatternToMaskedBytes(const std::string_view svInput)
|
||||
{
|
||||
char* pszPatternStart = const_cast<char*>(svInput.data());
|
||||
char* pszPatternEnd = pszPatternStart + svInput.size();
|
||||
std::vector<uint8_t> vBytes;
|
||||
std::string svMask;
|
||||
|
||||
for (char* pszCurrentByte = pszPatternStart; pszCurrentByte < pszPatternEnd; ++pszCurrentByte)
|
||||
{
|
||||
if (*pszCurrentByte == '?')
|
||||
{
|
||||
++pszCurrentByte;
|
||||
if (*pszCurrentByte == '?')
|
||||
{
|
||||
++pszCurrentByte; // Skip double wildcard.
|
||||
}
|
||||
|
||||
vBytes.push_back(0); // Push the byte back as invalid.
|
||||
svMask += '?';
|
||||
}
|
||||
else
|
||||
{
|
||||
vBytes.push_back(static_cast<uint8_t>(strtoul(pszCurrentByte, &pszCurrentByte, 16)));
|
||||
svMask += 'x';
|
||||
}
|
||||
}
|
||||
|
||||
return std::make_pair(std::move(vBytes), std::move(svMask));
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose: Finds an array of bytes in process memory using SIMD instructions
|
||||
// Input : *pPattern
|
||||
// szMask
|
||||
// pStartAddress
|
||||
// *pModuleSection
|
||||
// Output : CMemory
|
||||
//-----------------------------------------------------------------------------
|
||||
CMemory CModule::FindPattern(const CMemory pPattern, const std::string_view szMask, const CMemory pStartAddress, const ModuleSections_t* pModuleSection) const
|
||||
{
|
||||
const uint8_t* pattern = pPattern.RCast<const uint8_t*>();
|
||||
const ModuleSections_t* section = pModuleSection ? pModuleSection : &m_ExecutableCode;
|
||||
if (!section->IsSectionValid())
|
||||
return CMemory();
|
||||
|
||||
const uintptr_t nBase = section->m_pSectionBase;
|
||||
const size_t nSize = section->m_nSectionSize;
|
||||
|
||||
const size_t nMaskLen = szMask.length();
|
||||
const uint8_t* pData = reinterpret_cast<uint8_t*>(nBase);
|
||||
const uint8_t* pEnd = pData + nSize - nMaskLen;
|
||||
|
||||
if(pStartAddress)
|
||||
{
|
||||
const uint8_t* startAddress = pStartAddress.RCast<uint8_t*>();
|
||||
if(pData > startAddress || startAddress > pEnd)
|
||||
return CMemory();
|
||||
|
||||
pData = startAddress;
|
||||
}
|
||||
|
||||
int nMasks[64]; // 64*16 = enough masks for 1024 bytes.
|
||||
const uint8_t iNumMasks = static_cast<uint8_t>(std::ceil(static_cast<float>(nMaskLen) / 16.f));
|
||||
|
||||
memset(nMasks, 0, iNumMasks * sizeof(int));
|
||||
for (uint8_t i = 0; i < iNumMasks; ++i)
|
||||
{
|
||||
for (int8_t j = static_cast<int8_t>(std::min<size_t>(nMaskLen - i * 16, 16)) - 1; j >= 0; --j)
|
||||
{
|
||||
if (szMask[i * 16 + j] == 'x')
|
||||
{
|
||||
nMasks[i] |= 1 << j;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
const __m128i xmm1 = _mm_loadu_si128(reinterpret_cast<const __m128i*>(pattern));
|
||||
__m128i xmm2, xmm3, msks;
|
||||
for (; pData != pEnd; _mm_prefetch(reinterpret_cast<const char*>(++pData + 64), _MM_HINT_NTA))
|
||||
{
|
||||
xmm2 = _mm_loadu_si128(reinterpret_cast<const __m128i*>(pData));
|
||||
msks = _mm_cmpeq_epi8(xmm1, xmm2);
|
||||
if ((_mm_movemask_epi8(msks) & nMasks[0]) == nMasks[0])
|
||||
{
|
||||
bool bFound = true;
|
||||
for (uint8_t i = 1; i < iNumMasks; ++i)
|
||||
{
|
||||
xmm2 = _mm_loadu_si128(reinterpret_cast<const __m128i*>((pData + i * 16)));
|
||||
xmm3 = _mm_loadu_si128(reinterpret_cast<const __m128i*>((pattern + i * 16)));
|
||||
msks = _mm_cmpeq_epi8(xmm2, xmm3);
|
||||
if ((_mm_movemask_epi8(msks) & nMasks[i]) != nMasks[i])
|
||||
{
|
||||
bFound = false;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (bFound)
|
||||
return pData;
|
||||
}
|
||||
}
|
||||
|
||||
return CMemory();
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose: Finds a string pattern in process memory using SIMD instructions
|
||||
// Input : svPattern
|
||||
// pStartAddress
|
||||
// *pModuleSection
|
||||
// Output : CMemory
|
||||
//-----------------------------------------------------------------------------
|
||||
CMemory CModule::FindPattern(const std::string_view svPattern, const CMemory pStartAddress, const ModuleSections_t* pModuleSection) const
|
||||
{
|
||||
const std::pair patternInfo = PatternToMaskedBytes(svPattern);
|
||||
return FindPattern(patternInfo.first.data(), patternInfo.second, pStartAddress, pModuleSection);
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose: Gets a module section by name (example: '.rdata', '.text')
|
||||
// Input : svModuleName
|
||||
// Output : ModuleSections_t
|
||||
//-----------------------------------------------------------------------------
|
||||
CModule::ModuleSections_t CModule::GetSectionByName(const std::string_view svSectionName) const
|
||||
{
|
||||
for (const ModuleSections_t& section : m_vModuleSections)
|
||||
{
|
||||
if (section.m_svSectionName == svSectionName)
|
||||
return section;
|
||||
}
|
||||
|
||||
return ModuleSections_t();
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose: Returns the module handle
|
||||
//-----------------------------------------------------------------------------
|
||||
void* CModule::GetModuleHandle() const noexcept
|
||||
{
|
||||
return m_pModuleHandle;
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose: Returns the module path
|
||||
//-----------------------------------------------------------------------------
|
||||
std::string_view CModule::GetModulePath() const
|
||||
{
|
||||
return m_sModulePath;
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose: Returns the module name
|
||||
//-----------------------------------------------------------------------------
|
||||
std::string_view CModule::GetModuleName() const
|
||||
{
|
||||
std::string_view svModulePath(m_sModulePath);
|
||||
return svModulePath.substr(svModulePath.find_last_of("/\\") + 1);
|
||||
}
|
||||
|
||||
#ifndef DYNLIBUTILS_SEPARATE_SOURCE_FILES
|
||||
#if defined _WIN32 && _M_X64
|
||||
#include "module_windows.cpp"
|
||||
#elif defined __linux__ && __x86_64__
|
||||
#include "module_linux.cpp"
|
||||
#else
|
||||
#error "Unsupported platform"
|
||||
#endif
|
||||
#endif
|
||||
77
vendor/dynlibutils/module.h
vendored
Normal file
77
vendor/dynlibutils/module.h
vendored
Normal file
|
|
@ -0,0 +1,77 @@
|
|||
// DynLibUtils
|
||||
// Copyright (C) 2023 komashchenko (Phoenix)
|
||||
// https://github.com/komashchenko/DynLibUtils
|
||||
|
||||
#ifndef DYNLIBUTILS_MODULE_H
|
||||
#define DYNLIBUTILS_MODULE_H
|
||||
#ifdef _WIN32
|
||||
#pragma once
|
||||
#endif
|
||||
|
||||
#include "memaddr.h"
|
||||
#include <vector>
|
||||
#include <string>
|
||||
#include <string_view>
|
||||
#include <utility>
|
||||
|
||||
namespace DynLibUtils {
|
||||
|
||||
class CModule
|
||||
{
|
||||
public:
|
||||
struct ModuleSections_t
|
||||
{
|
||||
ModuleSections_t() : m_nSectionSize(0) {}
|
||||
ModuleSections_t(const ModuleSections_t&) = default;
|
||||
ModuleSections_t& operator= (const ModuleSections_t&) = default;
|
||||
ModuleSections_t(ModuleSections_t&& other) noexcept : m_svSectionName(std::move(other.m_svSectionName)), m_pSectionBase(std::move(other.m_pSectionBase)), m_nSectionSize(std::exchange(other.m_nSectionSize, 0)) {}
|
||||
ModuleSections_t(const std::string_view svSectionName, uintptr_t pSectionBase, size_t nSectionSize) : m_svSectionName(svSectionName), m_pSectionBase(pSectionBase), m_nSectionSize(nSectionSize) {}
|
||||
|
||||
[[nodiscard]] inline bool IsSectionValid() const noexcept
|
||||
{
|
||||
return m_pSectionBase;
|
||||
}
|
||||
|
||||
std::string m_svSectionName; // Name of section.
|
||||
CMemory m_pSectionBase; // Start address of section.
|
||||
size_t m_nSectionSize; // Size of section.
|
||||
};
|
||||
|
||||
CModule() : m_pModuleHandle(nullptr) {}
|
||||
~CModule();
|
||||
CModule (const CModule&) = delete;
|
||||
CModule& operator= (const CModule&) = delete;
|
||||
CModule(CModule&& other) noexcept : m_ExecutableCode(std::move(other.m_ExecutableCode)), m_sModulePath(std::move(other.m_sModulePath)), m_pModuleHandle(std::exchange(other.m_pModuleHandle, nullptr)), m_vModuleSections(std::move(other.m_vModuleSections)) {}
|
||||
explicit CModule(const std::string_view svModuleName);
|
||||
explicit CModule(const char* pszModuleName) : CModule(std::string_view(pszModuleName)) {}
|
||||
explicit CModule(const std::string& sModuleName) : CModule(std::string_view(sModuleName)) {}
|
||||
CModule(const CMemory pModuleMemory);
|
||||
|
||||
bool InitFromName(const std::string_view svModuleName, bool bExtension = false);
|
||||
bool InitFromMemory(const CMemory pModuleMemory);
|
||||
|
||||
[[nodiscard]] static std::pair<std::vector<uint8_t>, std::string> PatternToMaskedBytes(const std::string_view svInput);
|
||||
[[nodiscard]] CMemory FindPattern(const CMemory pPattern, const std::string_view szMask, const CMemory pStartAddress = nullptr, const ModuleSections_t* pModuleSection = nullptr) const;
|
||||
[[nodiscard]] CMemory FindPattern(const std::string_view svPattern, const CMemory pStartAddress = nullptr, const ModuleSections_t* pModuleSection = nullptr) const;
|
||||
|
||||
[[nodiscard]] CMemory GetVirtualTableByName(const std::string_view svTableName, bool bDecorated = false) const;
|
||||
[[nodiscard]] CMemory GetFunctionByName(const std::string_view svFunctionName) const noexcept;
|
||||
|
||||
[[nodiscard]] ModuleSections_t GetSectionByName(const std::string_view svSectionName) const;
|
||||
[[nodiscard]] void* GetModuleHandle() const noexcept;
|
||||
[[nodiscard]] CMemory GetModuleBase() const noexcept;
|
||||
[[nodiscard]] std::string_view GetModulePath() const;
|
||||
[[nodiscard]] std::string_view GetModuleName() const;
|
||||
|
||||
private:
|
||||
bool Init(const std::string_view svModelePath);
|
||||
|
||||
ModuleSections_t m_ExecutableCode;
|
||||
std::string m_sModulePath;
|
||||
void* m_pModuleHandle;
|
||||
std::vector<ModuleSections_t> m_vModuleSections;
|
||||
};
|
||||
|
||||
} // namespace DynLibUtils
|
||||
|
||||
#endif // DYNLIBUTILS_MODULE_H
|
||||
Some files were not shown because too many files have changed in this diff Show more
Loading…
Add table
Add a link
Reference in a new issue