commit 3dd53cf457848adcb29573d2dbd9483bdd755918 Author: Michal <88426022+SlynxCZ@users.noreply.github.com> Date: Sun Jan 11 18:57:42 2026 +0400 Initial commit diff --git a/.clang-tidy b/.clang-tidy new file mode 100644 index 0000000..1688d77 --- /dev/null +++ b/.clang-tidy @@ -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 \ No newline at end of file diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml new file mode 100644 index 0000000..5e02c64 --- /dev/null +++ b/.github/workflows/main.yml @@ -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" diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..1d140b9 --- /dev/null +++ b/.gitignore @@ -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/ diff --git a/.gitmodules b/.gitmodules new file mode 100644 index 0000000..7ef8ded --- /dev/null +++ b/.gitmodules @@ -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 diff --git a/CMakeLists.txt b/CMakeLists.txt new file mode 100644 index 0000000..e82e3ba --- /dev/null +++ b/CMakeLists.txt @@ -0,0 +1,128 @@ +cmake_minimum_required(VERSION 3.18) +project(TemplatePlugin C CXX ASM) + +set(CMAKE_MSVC_RUNTIME_LIBRARY "MultiThreaded$<$: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 $ + COMMENT "Stripping symbols from $" + ) + 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} +) diff --git a/LICENSE b/LICENSE new file mode 100644 index 0000000..f288702 --- /dev/null +++ b/LICENSE @@ -0,0 +1,674 @@ + GNU GENERAL PUBLIC LICENSE + Version 3, 29 June 2007 + + Copyright (C) 2007 Free Software Foundation, Inc. + 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. + + + Copyright (C) + + 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 . + +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: + + Copyright (C) + 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 +. + + 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 +. diff --git a/configs/addons/TemplatePlugin/gamedata.json b/configs/addons/TemplatePlugin/gamedata.json new file mode 100644 index 0000000..3e28462 --- /dev/null +++ b/configs/addons/TemplatePlugin/gamedata.json @@ -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" + } + } +} diff --git a/configs/addons/metamod/TemplatePlugin.vdf b/configs/addons/metamod/TemplatePlugin.vdf new file mode 100644 index 0000000..69a7a3b --- /dev/null +++ b/configs/addons/metamod/TemplatePlugin.vdf @@ -0,0 +1,5 @@ +"Metamod Plugin" +{ + "alias" "NadeKingChallenges" + "file" "addons/NadeKingChallenges/bin/linuxsteamrt64/NadeKingChallenges" +} diff --git a/docker/Dockerfile b/docker/Dockerfile new file mode 100644 index 0000000..152fee3 --- /dev/null +++ b/docker/Dockerfile @@ -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"] \ No newline at end of file diff --git a/docker/docker-compose.yml b/docker/docker-compose.yml new file mode 100644 index 0000000..93a41cd --- /dev/null +++ b/docker/docker-compose.yml @@ -0,0 +1,8 @@ +services: + builder: + image: cmake-builder + build: + context: .. + dockerfile: docker/Dockerfile + volumes: + - ..:/app/source \ No newline at end of file diff --git a/docker/docker-entrypoint.sh b/docker/docker-entrypoint.sh new file mode 100644 index 0000000..bdc7cef --- /dev/null +++ b/docker/docker-entrypoint.sh @@ -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)" \ No newline at end of file diff --git a/makefiles/linux.base.cmake b/makefiles/linux.base.cmake new file mode 100644 index 0000000..5451c3a --- /dev/null +++ b/makefiles/linux.base.cmake @@ -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 +) diff --git a/makefiles/metamod/TemplatePlugin.vdf.in b/makefiles/metamod/TemplatePlugin.vdf.in new file mode 100644 index 0000000..2a923ef --- /dev/null +++ b/makefiles/metamod/TemplatePlugin.vdf.in @@ -0,0 +1,5 @@ +"Metamod Plugin" +{ + "alias" "NadeKingChallenges" + "file" "addons/NadeKingChallenges/bin/${PROJECT_VDF_PLATFORM}/NadeKingChallenges" +} \ No newline at end of file diff --git a/makefiles/metamod/configure_metamod.cmake b/makefiles/metamod/configure_metamod.cmake new file mode 100644 index 0000000..c81f466 --- /dev/null +++ b/makefiles/metamod/configure_metamod.cmake @@ -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 +) diff --git a/makefiles/protobuf.cmake b/makefiles/protobuf.cmake new file mode 100644 index 0000000..d9f0734 --- /dev/null +++ b/makefiles/protobuf.cmake @@ -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) \ No newline at end of file diff --git a/makefiles/shared.cmake b/makefiles/shared.cmake new file mode 100644 index 0000000..4721f91 --- /dev/null +++ b/makefiles/shared.cmake @@ -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) \ No newline at end of file diff --git a/makefiles/windows.base.cmake b/makefiles/windows.base.cmake new file mode 100644 index 0000000..bf443c0 --- /dev/null +++ b/makefiles/windows.base.cmake @@ -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 +) \ No newline at end of file diff --git a/src/EntityData.h b/src/EntityData.h new file mode 100644 index 0000000..ca57767 --- /dev/null +++ b/src/EntityData.h @@ -0,0 +1,86 @@ +// +// Created by Michal Přikryl on 15.09.2025. +// Copyright (c) 2025 slynxcz. All rights reserved. +// +#pragma once +#include +#include +#include "schema/CCSPlayerController.h" + +namespace TemplatePlugin { + enum class EntityType { + None = 0, + }; + + template + 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, CHandle)> OnTouch; + std::function, CHandle)> OnUse; + + std::unique_ptr > CustomData; + + CHandle GrabHolder = nullptr; + float GrabDistance = 0.0f; + + CHandle 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 &h) const noexcept { + return std::hash()(h.GetEntryIndex()); + } + }; + + struct HandleEqual { + bool operator()(const CHandle &a, const CHandle &b) const noexcept { + return a.GetEntryIndex() == b.GetEntryIndex(); + } + }; + + inline std::unordered_map, EntityData_t, HandleHasher, HandleEqual> EntityData; +} diff --git a/src/PlayersData.cpp b/src/PlayersData.cpp new file mode 100644 index 0000000..73e7843 --- /dev/null +++ b/src/PlayersData.cpp @@ -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(); + } +} diff --git a/src/PlayersData.h b/src/PlayersData.h new file mode 100644 index 0000000..efc5c56 --- /dev/null +++ b/src/PlayersData.h @@ -0,0 +1,30 @@ +// +// Created by Michal Přikryl on 12.07.2025. +// Copyright (c) 2025 slynxcz. All rights reserved. +// +#pragma once +#include +#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 players_; + }; +} diff --git a/src/RayTrace.cpp b/src/RayTrace.cpp new file mode 100644 index 0000000..5a782bc --- /dev/null +++ b/src/RayTrace.cpp @@ -0,0 +1,139 @@ +// +// Created by Michal Přikryl on 30.08.2025. +// Copyright (c) 2025 slynxcz. All rights reserved. +// +#include "RayTrace.h" +#include +#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(pCNavPhysicsInterfaceVTable); + s_TraceShape = reinterpret_cast(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("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 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 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(*opts->InteractsWith); + if (opts->InteractsExclude) filter.m_nInteractsExclude = static_cast(*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 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(*opts->InteractsWith); + if (opts->InteractsExclude) filter.m_nInteractsExclude = static_cast(*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; + } +} diff --git a/src/RayTrace.h b/src/RayTrace.h new file mode 100644 index 0000000..a1027e9 --- /dev/null +++ b/src/RayTrace.h @@ -0,0 +1,126 @@ +// +// Created by Michal Přikryl on 30.08.2025. +// Copyright (c) 2025 slynxcz. All rights reserved. +// +#pragma once +#include +#include +#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( + static_cast(a) | static_cast(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(entityToIgnore), + entityToIgnore ? entityToIgnore->m_hOwnerEntity.Get() : nullptr, + entityToIgnore ? entityToIgnore->m_pCollision()->m_collisionAttribute().m_nHierarchyId() : static_cast(0xFFFFFFFF), + 0x2c3011, + COLLISION_GROUP_DEFAULT, true) + { + } + + CTraceFilterEx() : CTraceFilter(0x2c3011, COLLISION_GROUP_DEFAULT, true) + { + } + }; + + + struct TraceOptions + { + std::optional InteractsWith{static_cast(0x2c3011)}; + std::optional InteractsExclude{}; + bool DrawBeam{false}; + }; + + struct TraceResult + { + Vector EndPos{}; + CEntityInstance* HitEntity{}; + float Fraction{}; + bool AllSolid{}; + Vector Normal{}; + }; + + bool Initialize(); + + std::optional TraceShape( + const Vector& origin, + const QAngle& viewangles, + CBaseEntity* ignorePlayer = nullptr, + const TraceOptions* opts = nullptr); + + std::optional TraceEndShape( + const Vector& origin, + const Vector& endOrigin, + CBaseEntity* ignorePlayer = nullptr, + const TraceOptions* opts = nullptr); + + std::optional TraceShapeEx( + const Vector& vecStart, + const Vector& vecEnd, + CTraceFilter& filterInc, + Ray_t rayInc); +} diff --git a/src/Shared.cpp b/src/Shared.cpp new file mode 100644 index 0000000..ceb211a --- /dev/null +++ b/src/Shared.cpp @@ -0,0 +1,62 @@ +// +// Created by Michal Přikryl on 20.09.2025. +// Copyright (c) 2025 slynxcz. All rights reserved. +// +#include "Shared.h" +#include +#include +#include +#include +#include + +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; +} diff --git a/src/Shared.h b/src/Shared.h new file mode 100644 index 0000000..e43671e --- /dev/null +++ b/src/Shared.h @@ -0,0 +1,55 @@ +// +// Created by Michal Přikryl on 20.09.2025. +// Copyright (c) 2025 slynxcz. All rights reserved. +// +#pragma once +#include +#include +#include +#include +#include +#include +#include +#include "schema/cgameresourceserviceserver.h" +#include + +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 diff --git a/src/TemplatePlugin.cpp b/src/TemplatePlugin.cpp new file mode 100644 index 0000000..9498dd4 --- /dev/null +++ b/src/TemplatePlugin.cpp @@ -0,0 +1,133 @@ +#include "TemplatePlugin.h" +#include "path.h" +#include "Shared.h" +#include "dynlibutils/module.h" +#include +#include "igameevents.h" +#include +#include "game_system.h" +#include "schemasystem/schemasystem.h" +#include "schema/CCSPlayerController.h" +#include "schema/cgameresourceserviceserver.h" +#include "schema/plat.h" +#include +#include +#include +#include +#include +#include +#include +#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((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"; } +} diff --git a/src/TemplatePlugin.h b/src/TemplatePlugin.h new file mode 100644 index 0000000..10de363 --- /dev/null +++ b/src/TemplatePlugin.h @@ -0,0 +1,30 @@ +#ifndef _INCLUDE_METAMOD_SOURCE_STUB_PLUGIN_H_ +#define _INCLUDE_METAMOD_SOURCE_STUB_PLUGIN_H_ + +#include +#include +#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(); diff --git a/src/colors.h b/src/colors.h new file mode 100644 index 0000000..b113b61 --- /dev/null +++ b/src/colors.h @@ -0,0 +1,137 @@ +#pragma once +#include +#include +#include +#include +#include +#include + +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(rf + m), + static_cast(gf + m), + static_cast(bf + m), + static_cast(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(r * 255); + int ig = static_cast(g * 255); + int ib = static_cast(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(a * 255) << 24) | + (static_cast(b * 255) << 16) | + (static_cast(g * 255) << 8) | + (static_cast(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(r * 255.0f), + static_cast(g * 255.0f), + static_cast(b * 255.0f), + static_cast(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(now.time_since_epoch()).count(); + + double hue = fmod((ms % 1000) / 1000.0 * 360.0, 360.0); + return FromHSV(hue, 1.0, 1.0); + } + }; +} \ No newline at end of file diff --git a/src/commands/Commands.cpp b/src/commands/Commands.cpp new file mode 100644 index 0000000..d2a859d --- /dev/null +++ b/src/commands/Commands.cpp @@ -0,0 +1,14 @@ +// +// Created by Michal Přikryl on 21.11.2025. +// Copyright (c) 2025 slynxcz. All rights reserved. +// +#include "Commands.h" +#include + +namespace TemplatePlugin::Commands +{ + void InitCommands() + { + + } +} diff --git a/src/commands/Commands.h b/src/commands/Commands.h new file mode 100644 index 0000000..73e837f --- /dev/null +++ b/src/commands/Commands.h @@ -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(); +} \ No newline at end of file diff --git a/src/detours.cpp b/src/detours.cpp new file mode 100644 index 0000000..3b5ec21 --- /dev/null +++ b/src/detours.cpp @@ -0,0 +1,369 @@ +// +// Created by Michal Přikryl on 09.07.2025. +// Copyright (c) 2025 slynxcz. All rights reserved. +// +#include +#include +#include +#include +#include +#include "schema/CCSPlayerController.h" +#include "detours.h" + +#include +#include + +#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 > registeredCommands; + static std::unordered_map > consoleListeners; + static std::unordered_map > gameEvents; + static EventManager eventManager; + static std::vector eventStack; + static std::vector entitySpawnedListeners; + static std::vector entityCreatedListeners; + static std::vector entityDeletedListeners; + static std::vector entityParentChangerListeners; + static std::unordered_set registeredNames; + static std::unordered_map 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{}(k.entity) ^ (std::hash{}(k.output) << 1) + ^ (std::hash{}(static_cast(k.mode)) << 2); + } + }; + static std::unordered_map, 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 & + 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 & + 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( + 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(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(thisResult) > static_cast(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() == handler.target(); + }), + 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(r) > static_cast(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); + } + } +} diff --git a/src/detours.h b/src/detours.h new file mode 100644 index 0000000..26c76b0 --- /dev/null +++ b/src/detours.h @@ -0,0 +1,293 @@ +// +// Created by Michal Přikryl on 20.06.2025. +// Copyright (c) 2025 slynxcz. All rights reserved. +// +#pragma once + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#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> signatureHooks; + static std::mutex signatureHooksMutex; + static std::vector hookHandles; + extern std::unordered_map 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& handler); + + void RegisterConsoleCommand(const std::string& name, + const std::function& 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 + inline void* ToVoidArg(T&& v) + { + return const_cast(reinterpret_cast(&v)); + } + + template + inline void* ToVoidArg(T* v) + { + return const_cast(reinterpret_cast(v)); + } + + template + auto DispatchSignatureCall(const std::string& name, Fn original, Args... args) + -> decltype(original(args...)) + { + using Ret = decltype(original(args...)); + std::vector 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 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 + 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(addr); + SignatureStorage::name = sigName; + + auto detour = [](Args... args) -> R + { + auto orig = SignatureStorage::original; + return DispatchSignatureCall(SignatureStorage::name, orig, args...); + }; + + auto hook = funchook_create(); + using FnType = R(*)(Args...); + + if (funchook_prepare( + hook, + reinterpret_cast(ppOriginal), + reinterpret_cast(static_cast(detour)) + ) != 0 || + funchook_install(hook, 0) != 0) + { + FP_ERROR("Failed to hook '{}'", sigName); + return; + } + + SignatureStorage::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& fn) + { + return [fn](const CCommandContext& ctx, const CCommand& args, HookMode mode) -> HookResult + { + fn(ctx, args, mode); + return HookResult::Continue; + }; + } +} diff --git a/src/detourtypes.h b/src/detourtypes.h new file mode 100644 index 0000000..e0e2ebd --- /dev/null +++ b/src/detourtypes.h @@ -0,0 +1,207 @@ +// +// Created by Michal Přikryl on 23.08.2025. +// Copyright (c) 2025 slynxcz. All rights reserved. +// +#pragma once +#include +#include +#include +#include +#include + +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 + T GetParam(size_t index) const + { + if (index >= argCount) + throw std::out_of_range("arg index"); + + if constexpr (std::is_pointer_v) + { + return reinterpret_cast(args[index]); + } + else + { + return *reinterpret_cast(args[index]); + } + } + + template + void SetParam(size_t index, const T& value) + { + if (index >= argCount) + throw std::out_of_range("arg index"); + + if constexpr (std::is_pointer_v) + { + if constexpr (std::is_pointer_v>) + { + **reinterpret_cast(args[index]) = *value; + } + else + { + args[index] = const_cast>(value); + } + } + else + { + *reinterpret_cast(args[index]) = value; + } + } + + template + T GetReturn() const + { + if (!returnValue) + return T{}; + + if constexpr (std::is_pointer_v) + { + return *reinterpret_cast(returnValue); + } + else + { + return *reinterpret_cast(returnValue); + } + } + + template + void SetReturn(const T& value) + { + if (!returnValue) + return; + + if constexpr (std::is_pointer_v) + { + *reinterpret_cast(returnValue) = value; + } + else + { + *reinterpret_cast(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; + using GameEventHandler = std::function; + using EntityEventHandler = void(*)(CEntityInstance*); + using EntityParentChangedHandler = void(*)(CEntityInstance*, CEntityInstance*); + using EntityOutputHandler = std::function; + using SignatureHandler = std::function; + 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 + struct SignatureStorage; + + template + struct SignatureStorage + { + static inline std::string name; + + static inline R (*original)(Args...) = nullptr; + }; +} diff --git a/src/events/Events.cpp b/src/events/Events.cpp new file mode 100644 index 0000000..355b0e6 --- /dev/null +++ b/src/events/Events.cpp @@ -0,0 +1,13 @@ +// +// Created by Michal Přikryl on 21.11.2025. +// Copyright (c) 2025 slynxcz. All rights reserved. +// +#include "Events.h" +#include + +namespace TemplatePlugin::Events +{ + void InitEvents() + { + } +} diff --git a/src/events/Events.h b/src/events/Events.h new file mode 100644 index 0000000..01be4f0 --- /dev/null +++ b/src/events/Events.h @@ -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(); +} \ No newline at end of file diff --git a/src/game_system.cpp b/src/game_system.cpp new file mode 100644 index 0000000..bd59872 --- /dev/null +++ b/src/game_system.cpp @@ -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 + +#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(result.GetPtr()) + 3; + uint32 offset = *(uint32*)ptr; + ptr += 4; + + CBaseGameSystemFactory::sm_pFirst = (CBaseGameSystemFactory**)(ptr + offset); + CGameSystem::sm_Factory = new CGameSystemStaticFactory("Template_GameSystem", &g_GameSystem); + + return true; +} + +GS_EVENT_MEMBER(CGameSystem, BuildGameSessionManifest) +{ + IEntityResourceManifest* pResourceManifest = msg->m_pResourceManifest; + + m_exportResourceManifest = pResourceManifest; +} diff --git a/src/game_system.h b/src/game_system.h new file mode 100644 index 0000000..3473e6b --- /dev/null +++ b/src/game_system.h @@ -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; +}; \ No newline at end of file diff --git a/src/gameconfig.cpp b/src/gameconfig.cpp new file mode 100644 index 0000000..ae628c3 --- /dev/null +++ b/src/gameconfig.cpp @@ -0,0 +1,102 @@ +// +// Created by Michal Přikryl on 20.06.2025. +// Copyright (c) 2025 slynxcz. All rights reserved. +// +#include "gameconfig.h" +#include +#include + +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(); + } + if (auto signature = v["signatures"][platform]; signature.is_string()) + { + m_umSignatures[k] = signature.get(); + } + } + if (v.contains("offsets")) + { + if (auto offset = v["offsets"][platform]; offset.is_number_integer()) + { + m_umOffsets[k] = offset.get(); + } + } + if (v.contains("patches")) + { + if (auto patch = v["patches"][platform]; patch.is_string()) + { + m_umPatches[k] = patch.get(); + } + } + } + } + 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; + } +} diff --git a/src/gameconfig.h b/src/gameconfig.h new file mode 100644 index 0000000..42226f3 --- /dev/null +++ b/src/gameconfig.h @@ -0,0 +1,41 @@ +// +// Created by Michal Přikryl on 20.06.2025. +// Copyright (c) 2025 slynxcz. All rights reserved. +// +#pragma once +#include +#include +#include + +#undef snprintf +#include + +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 m_umOffsets; + std::unordered_map m_umSignatures; + std::unordered_map m_umAddresses; + std::unordered_map m_umLibraries; + std::unordered_map m_umPatches; + }; + +} // namespace Core \ No newline at end of file diff --git a/src/hooks/Hooks.cpp b/src/hooks/Hooks.cpp new file mode 100644 index 0000000..3975652 --- /dev/null +++ b/src/hooks/Hooks.cpp @@ -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() + { + } +} diff --git a/src/hooks/Hooks.h b/src/hooks/Hooks.h new file mode 100644 index 0000000..0451e29 --- /dev/null +++ b/src/hooks/Hooks.h @@ -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(); +} diff --git a/src/listeners/Listeners.cpp b/src/listeners/Listeners.cpp new file mode 100644 index 0000000..94def8c --- /dev/null +++ b/src/listeners/Listeners.cpp @@ -0,0 +1,86 @@ +// +// Created by Michal Přikryl on 10.07.2025. +// Copyright (c) 2025 slynxcz. All rights reserved. +// +#include "Listeners.h" +#include +#include +#include +#include +#include +#include +#include +#include + +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(); + 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); + } +} diff --git a/src/listeners/Listeners.h b/src/listeners/Listeners.h new file mode 100644 index 0000000..00a4500 --- /dev/null +++ b/src/listeners/Listeners.h @@ -0,0 +1,23 @@ +// +// Created by Michal Přikryl on 09.07.2025. +// Copyright (c) 2025 slynxcz. All rights reserved. +// +#pragma once +#include +#include +#include + +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; +} diff --git a/src/log.cpp b/src/log.cpp new file mode 100644 index 0000000..785156a --- /dev/null +++ b/src/log.cpp @@ -0,0 +1,49 @@ +// +// Created by Michal Přikryl on 22.12.2025. +// Copyright (c) 2025 slynxcz. All rights reserved. +// +#include "log.h" + +#include +#include +#include + +#if defined(_WIN32) +#include +#endif + +namespace TemplatePlugin { + std::shared_ptr 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 sinks; + + auto color_sink = std::make_shared(); + color_sink->set_pattern("%^[%T.%e] %n: %v%$"); + + auto file_sink = std::make_shared("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("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(); + } +} diff --git a/src/log.h b/src/log.h new file mode 100644 index 0000000..a680df4 --- /dev/null +++ b/src/log.h @@ -0,0 +1,28 @@ +// +// Created by Michal Přikryl on 22.12.2025. +// Copyright (c) 2025 slynxcz. All rights reserved. +// +#pragma once + +#include +#include + +namespace TemplatePlugin { + class Log { + public: + static void Init(); + static void Close(); + + static std::shared_ptr& GetLogger() { return m_FP_logger; } + + private: + static std::shared_ptr 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__) diff --git a/src/path.h b/src/path.h new file mode 100644 index 0000000..462763c --- /dev/null +++ b/src/path.h @@ -0,0 +1,29 @@ +// +// Created by Michal Přikryl on 19.06.2025. +// Copyright (c) 2025 slynxcz. All rights reserved. +// +#pragma once + +#include +#include +#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 \ No newline at end of file diff --git a/src/prints.cpp b/src/prints.cpp new file mode 100644 index 0000000..8f3e1b1 --- /dev/null +++ b/src/prints.cpp @@ -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 +#include +#include +#include "usermessages.pb.h" +#include "tier0/memdbgon.h" + +namespace TemplatePlugin::Prints +{ + std::string ReplaceColorTags(const std::string &input) { + static const std::vector > 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(); + data->set_dest(static_cast(dest)); + data->add_param(msg); + + CPlayerBitVec recipients; + recipients.Set(slot.Get()); + + shared::g_pGameEventSystem->PostEventAbstract( + CSplitScreenSlot(-1), false, ABSOLUTE_PLAYER_LIMIT, + reinterpret_cast(recipients.Base()), pNetMsg, data, + 0, BUF_RELIABLE + ); + + delete data; + } +} diff --git a/src/prints.h b/src/prints.h new file mode 100644 index 0000000..53952b5 --- /dev/null +++ b/src/prints.h @@ -0,0 +1,35 @@ +// +// Created by Michal Přikryl on 10.07.2025. +// Copyright (c) 2025 slynxcz. All rights reserved. +// +#pragma once +#include +#include +#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 + std::string FormatMessage(fmt::format_string fmtStr, Args &&... args) { + std::string formatted = fmt::format(fmtStr, std::forward(args)...); + return ReplaceFormatTags(formatted); + } + + inline const char* PrefixCl() { return "[[DARKRED]][!][[DEFAULT]] "; } + + void ChatToPlayer(CCSPlayerController* player, const std::string& msg); +} diff --git a/src/schema/CBaseAnimGraph.h b/src/schema/CBaseAnimGraph.h new file mode 100644 index 0000000..adda6c7 --- /dev/null +++ b/src/schema/CBaseAnimGraph.h @@ -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, m_Transforms) + SCHEMA_FIELD(CHandle, 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) + }; +} diff --git a/src/schema/CBaseButton.h b/src/schema/CBaseButton.h new file mode 100644 index 0000000..8280d03 --- /dev/null +++ b/src/schema/CBaseButton.h @@ -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, m_hConstraint) + SCHEMA_FIELD(CHandle, m_hConstraintParent) + SCHEMA_FIELD(bool, m_bForceNpcExclude) + SCHEMA_FIELD_POINTER(char, m_sGlowEntity) + SCHEMA_FIELD(CHandle, m_glowEntity) + SCHEMA_FIELD(bool, m_usable) + SCHEMA_FIELD_POINTER(char, m_szDisplayText) + }; +} diff --git a/src/schema/CBaseEntity.h b/src/schema/CBaseEntity.h new file mode 100644 index 0000000..856b7a2 --- /dev/null +++ b/src/schema/CBaseEntity.h @@ -0,0 +1,485 @@ +// +// Created by Michal Přikryl on 26.06.2025. +// Copyright (c) 2025 slynxcz. All rights reserved. +// +#pragma once +#include +#include +#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 + 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(); + + if (!addr) + return nullptr; + + g_UTIL_CreateEntityByName = addr; + } + return reinterpret_cast(g_UTIL_CreateEntityByName(name, -1)); + } + + template + inline std::vector UTIL_FindAllEntitiesByDesignerName(const char* designerName) + { + std::vector 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, 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, m_hOwnerEntity) + + SCHEMA_FIELD(CHandle, 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(this)->m_fFlags() & mask) == mask; + } + + uint32_t GetFlags() const + { + return const_cast(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 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(); + 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(); + + 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(); + + 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); + }; +} diff --git a/src/schema/CBaseFilter.h b/src/schema/CBaseFilter.h new file mode 100644 index 0000000..ae3a1f0 --- /dev/null +++ b/src/schema/CBaseFilter.h @@ -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) + }; +} diff --git a/src/schema/CBaseGrenade.h b/src/schema/CBaseGrenade.h new file mode 100644 index 0000000..b244a24 --- /dev/null +++ b/src/schema/CBaseGrenade.h @@ -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, 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); + }; +} \ No newline at end of file diff --git a/src/schema/CBaseModelEntity.h b/src/schema/CBaseModelEntity.h new file mode 100644 index 0000000..eb1f6d8 --- /dev/null +++ b/src/schema/CBaseModelEntity.h @@ -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(); + + 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); + }; +} diff --git a/src/schema/CBasePlayerController.h b/src/schema/CBasePlayerController.h new file mode 100644 index 0000000..ad1f2b6 --- /dev/null +++ b/src/schema/CBasePlayerController.h @@ -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, 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(); + if (!addr) + return; + CBasePlayerController_SetPawn = addr; + } + + CBasePlayerController_SetPawn(this, pawn, true, false, false, false); + } + }; +} diff --git a/src/schema/CBasePlayerPawn.h b/src/schema/CBasePlayerPawn.h new file mode 100644 index 0000000..9f17c1e --- /dev/null +++ b/src/schema/CBasePlayerPawn.h @@ -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>, 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, 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(); } + }; +} diff --git a/src/schema/CBaseProp.h b/src/schema/CBaseProp.h new file mode 100644 index 0000000..e08aa04 --- /dev/null +++ b/src/schema/CBaseProp.h @@ -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) + }; +} diff --git a/src/schema/CBaseTrigger.h b/src/schema/CBaseTrigger.h new file mode 100644 index 0000000..1db5cca --- /dev/null +++ b/src/schema/CBaseTrigger.h @@ -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>, 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); + }; +} diff --git a/src/schema/CBreakableProp.h b/src/schema/CBreakableProp.h new file mode 100644 index 0000000..1d3188c --- /dev/null +++ b/src/schema/CBreakableProp.h @@ -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, 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, m_hPhysicsAttacker) + SCHEMA_FIELD(float, m_flLastPhysicsInfluenceTime) + SCHEMA_FIELD(float, m_flDefaultFadeScale) + SCHEMA_FIELD(CHandle, m_hLastAttacker) + SCHEMA_FIELD_POINTER(char, m_iszPuntSound) + SCHEMA_FIELD(bool, m_bUsePuntSound) + SCHEMA_FIELD(bool, m_bOriginalBlockLOS) + }; +} diff --git a/src/schema/CC4.h b/src/schema/CC4.h new file mode 100644 index 0000000..0b32628 --- /dev/null +++ b/src/schema/CC4.h @@ -0,0 +1,18 @@ +// +// Created by Michal Přikryl on 26.06.2025. +// Copyright (c) 2025 slynxcz. All rights reserved. +// +#pragma once +#include +#include "CGameRules.h" +#include "schemasystem.h" + +namespace TemplatePlugin { + class CC4 + { + public: + DECLARE_SCHEMA_CLASS(CC4); + + SCHEMA_FIELD(GameTime_t, m_fArmedTime); + }; +} diff --git a/src/schema/CCSPlayerController.h b/src/schema/CCSPlayerController.h new file mode 100644 index 0000000..64d2a51 --- /dev/null +++ b/src/schema/CCSPlayerController.h @@ -0,0 +1,727 @@ +// +// Created by Michal Přikryl on 26.06.2025. +// Copyright (c) 2025 slynxcz. All rights reserved. +// +#pragma once +#include +#include +#include +#include +#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, m_hPlayerPawn); + + SCHEMA_FIELD(int32, m_DesiredObserverMode); + + SCHEMA_FIELD(int16_t, m_nPawnCharacterDefIndex); + + SCHEMA_FIELD(CHandle, m_hObserverPawn); + + SCHEMA_FIELD(CHandle, 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(pawn->m_hController().Get()); + } + + static CCSPlayerController* FromIndex(int iIndex) + { + return static_cast(shared::g_pEntitySystem-> + GetEntityInstance(CEntityIndex(iIndex))); + } + + static CCSPlayerController* FromSlot(int iSlot) + { + return static_cast(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(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(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(CsTeam::None) || teamNum > static_cast(CsTeam::CounterTerrorist)) + return CsTeam::None; + + return static_cast(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(); + + 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(infoMem) + 0x98, &attackerInfo, sizeof(CAttackerInfo)); + + auto* info = reinterpret_cast(infoMem); + auto* result = reinterpret_cast(resultMem); + + info->m_hInflictor() = attackerPawn->GetHandle(); + info->m_hAttacker() = attackerPawn->GetHandle(); + info->m_flDamage() = static_cast(damage); + info->m_flFriendlyFireDamageReductionRatio() = static_cast(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(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(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 GetWeapons() + { + std::vector 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(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(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(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 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& 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 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& 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; + } + } + } + } + }; +} diff --git a/src/schema/CCSPlayerPawn.h b/src/schema/CCSPlayerPawn.h new file mode 100644 index 0000000..3513dbb --- /dev/null +++ b/src/schema/CCSPlayerPawn.h @@ -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, 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); + }; +} diff --git a/src/schema/CCSWeaponBase.h b/src/schema/CCSWeaponBase.h new file mode 100644 index 0000000..03a4c2e --- /dev/null +++ b/src/schema/CCSWeaponBase.h @@ -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, 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, 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) + }; +} \ No newline at end of file diff --git a/src/schema/CChicken.h b/src/schema/CChicken.h new file mode 100644 index 0000000..1c6a51e --- /dev/null +++ b/src/schema/CChicken.h @@ -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) + }; +} \ No newline at end of file diff --git a/src/schema/CDynamicProp.h b/src/schema/CDynamicProp.h new file mode 100644 index 0000000..85ab43a --- /dev/null +++ b/src/schema/CDynamicProp.h @@ -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) + }; +} diff --git a/src/schema/CEnvEntityMarker.h b/src/schema/CEnvEntityMarker.h new file mode 100644 index 0000000..a6044fd --- /dev/null +++ b/src/schema/CEnvEntityMarker.h @@ -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) + }; +} \ No newline at end of file diff --git a/src/schema/CFuncBrush.h b/src/schema/CFuncBrush.h new file mode 100644 index 0000000..1d7fa23 --- /dev/null +++ b/src/schema/CFuncBrush.h @@ -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) + }; +} diff --git a/src/schema/CFuncVPhysicsClip.h b/src/schema/CFuncVPhysicsClip.h new file mode 100644 index 0000000..9c22b88 --- /dev/null +++ b/src/schema/CFuncVPhysicsClip.h @@ -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) + }; +} diff --git a/src/schema/CGameRules.h b/src/schema/CGameRules.h new file mode 100644 index 0000000..7d3b243 --- /dev/null +++ b/src/schema/CGameRules.h @@ -0,0 +1,125 @@ +// +// Created by Michal Přikryl on 26.06.2025. +// Copyright (c) 2025 slynxcz. All rights reserved. +// +#pragma once +#include +#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, m_CTSpawnPoints); + SCHEMA_FIELD_POINTER(CUtlVector, 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(); + + if (!addr) + return; + + s_pTerminateRound = addr; + } + s_pTerminateRound(this, roundEndReason, delay, nullptr, 0); + } + + static CCSGameRules* FindGameRules() + { + auto entities = UTIL_FindAllEntitiesByDesignerName("cs_gamerules"); + if (entities.empty()) + return nullptr; + + auto* proxy = entities.front(); + return proxy ? proxy->m_pGameRules() : nullptr; + } + }; +} \ No newline at end of file diff --git a/src/schema/CParticleSystem.h b/src/schema/CParticleSystem.h new file mode 100644 index 0000000..22fda5a --- /dev/null +++ b/src/schema/CParticleSystem.h @@ -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, 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) + }; +} \ No newline at end of file diff --git a/src/schema/CPhysExplosion.h b/src/schema/CPhysExplosion.h new file mode 100644 index 0000000..d2a93cb --- /dev/null +++ b/src/schema/CPhysExplosion.h @@ -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) + }; +} diff --git a/src/schema/CPhysicsProp.h b/src/schema/CPhysicsProp.h new file mode 100644 index 0000000..3e503ae --- /dev/null +++ b/src/schema/CPhysicsProp.h @@ -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) + }; +} diff --git a/src/schema/CPlantedC4.h b/src/schema/CPlantedC4.h new file mode 100644 index 0000000..e9d6a19 --- /dev/null +++ b/src/schema/CPlantedC4.h @@ -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); + }; +} \ No newline at end of file diff --git a/src/schema/CPointWorldText.h b/src/schema/CPointWorldText.h new file mode 100644 index 0000000..bd73c91 --- /dev/null +++ b/src/schema/CPointWorldText.h @@ -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 . + */ + +#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); + } + }; +} \ No newline at end of file diff --git a/src/schema/CRecipientFilter.h b/src/schema/CRecipientFilter.h new file mode 100644 index 0000000..bbd295e --- /dev/null +++ b/src/schema/CRecipientFilter.h @@ -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()); + } +}; \ No newline at end of file diff --git a/src/schema/CSkyCamera.h b/src/schema/CSkyCamera.h new file mode 100644 index 0000000..4ee5577 --- /dev/null +++ b/src/schema/CSkyCamera.h @@ -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) + }; +} \ No newline at end of file diff --git a/src/schema/CSoundEventEntity.h b/src/schema/CSoundEventEntity.h new file mode 100644 index 0000000..5cb9f80 --- /dev/null +++ b/src/schema/CSoundEventEntity.h @@ -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); + }; +} \ No newline at end of file diff --git a/src/schema/CTeam.h b/src/schema/CTeam.h new file mode 100644 index 0000000..8a68242 --- /dev/null +++ b/src/schema/CTeam.h @@ -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); + }; +} \ No newline at end of file diff --git a/src/schema/CTimer.cpp b/src/schema/CTimer.cpp new file mode 100644 index 0000000..5b388a6 --- /dev/null +++ b/src/schema/CTimer.cpp @@ -0,0 +1,84 @@ +// +// Created by Michal Přikryl on 31.10.2025. +// Copyright (c) 2025 slynxcz. All rights reserved. +// +#include "CTimer.h" + +#include + +namespace +TemplatePlugin +{ + std::list> 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::Create(float flInitialInterval, uint64 nTimerFlags, std::function func) + { + auto pTimer = std::make_shared(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++; + } + } +} diff --git a/src/schema/CTimer.h b/src/schema/CTimer.h new file mode 100644 index 0000000..8cb6f44 --- /dev/null +++ b/src/schema/CTimer.h @@ -0,0 +1,76 @@ +// +// Created by Michal Přikryl on 31.10.2025. +// Copyright (c) 2025 slynxcz. All rights reserved. +// +#pragma once +#include +#include +#include +#include +#include + +#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 + { + 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 func, _timer_constructor_tag) : + CTimerBase(flInitialInterval, nTimerFlags), m_func(func) + {} + + static std::weak_ptr Create(float flInitialInterval, uint64 nTimerFlags, std::function func); + bool Execute(bool bAutomaticExecute) override; + void Cancel() override; + + private: + std::function m_func; + }; + + void RunTimers(); + void RemoveAllTimers(); + void RemoveTimers(uint64 iTimerFlag); +} diff --git a/src/schema/CTriggerPush.h b/src/schema/CTriggerPush.h new file mode 100644 index 0000000..7b52b4b --- /dev/null +++ b/src/schema/CTriggerPush.h @@ -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) + }; +} \ No newline at end of file diff --git a/src/schema/ccollisionproperty.h b/src/schema/ccollisionproperty.h new file mode 100644 index 0000000..3e31ea4 --- /dev/null +++ b/src/schema/ccollisionproperty.h @@ -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) + }; +} \ No newline at end of file diff --git a/src/schema/cgameresourceserviceserver.h b/src/schema/cgameresourceserviceserver.h new file mode 100644 index 0000000..15b4b0f --- /dev/null +++ b/src/schema/cgameresourceserviceserver.h @@ -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 . + */ + +#pragma once +#include +#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(reinterpret_cast(g_pGameResourceServiceServer) + offset); + } +}; \ No newline at end of file diff --git a/src/schema/ctakedamageinfo.cpp b/src/schema/ctakedamageinfo.cpp new file mode 100644 index 0000000..493cf76 --- /dev/null +++ b/src/schema/ctakedamageinfo.cpp @@ -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 + +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(attacker)) + { + IsWorld = false; + IsPawn = true; + AttackerUserId = static_cast(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(this); + + const uintptr_t v4 = *reinterpret_cast(base + off); + if (!v4) + return HitGroup_t::HITGROUP_INVALID; + + const uintptr_t v1 = *reinterpret_cast(v4 + 16); + if (!v1) + return HitGroup_t::HITGROUP_GENERIC; + + const int32_t group = *reinterpret_cast(v1 + 56); + return static_cast(group); + } +} diff --git a/src/schema/ctakedamageinfo.h b/src/schema/ctakedamageinfo.h new file mode 100644 index 0000000..1e911b7 --- /dev/null +++ b/src/schema/ctakedamageinfo.h @@ -0,0 +1,84 @@ +// +// Created by Michal Přikryl on 23.09.2025. +// Copyright (c) 2025 slynxcz. All rights reserved. +// +#pragma once +#include +#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, m_hInflictor); + SCHEMA_FIELD(CHandle, m_hAttacker); + SCHEMA_FIELD(CHandle, 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) + }; +} diff --git a/src/schema/globaltypes.h b/src/schema/globaltypes.h new file mode 100644 index 0000000..0e42bf8 --- /dev/null +++ b/src/schema/globaltypes.h @@ -0,0 +1,482 @@ +// +// Created by Michal Přikryl on 26.06.2025. +// Copyright (c) 2025 slynxcz. All rights reserved. +// +#pragma once +#include +#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 > 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; + }; +} diff --git a/src/schema/plat.h b/src/schema/plat.h new file mode 100644 index 0000000..12101b9 --- /dev/null +++ b/src/schema/plat.h @@ -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 . + */ + +#pragma once +#include +#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); \ No newline at end of file diff --git a/src/schema/schemasystem.cpp b/src/schema/schemasystem.cpp new file mode 100644 index 0000000..4461c98 --- /dev/null +++ b/src/schema/schemasystem.cpp @@ -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 +#include +#include +#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; + using SchemaTableMap_t = std::map; + + 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 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 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(pEntity)->NetworkStateChanged(data); + } + + void ChainNetworkStateChanged(uintptr_t pNetworkVarChainer, uint nLocalOffset) + { + CEntityInstance* pEntity = reinterpret_cast(pNetworkVarChainer)->m_pEntity; + + if (pEntity) + // NetworkStateChanged_t WENDER SDK + // NetworkStateChangedData HL2SDK-CS@ + pEntity->NetworkStateChanged(NetworkStateChangedData(nLocalOffset, -1, + reinterpret_cast( + pNetworkVarChainer)->m_PathIndex)); + } +} diff --git a/src/schema/schemasystem.h b/src/schema/schemasystem.h new file mode 100644 index 0000000..e5e22e3 --- /dev/null +++ b/src/schema/schemasystem.h @@ -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 . + */ + +#pragma once + +#ifdef _WIN32 + #pragma warning(push) + #pragma warning(disable : 4005) +#endif + +#include + +#ifdef _WIN32 + #pragma warning(pop) +#endif + +#include +#include +#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 + inline constexpr bool schema_writable_v = + std::is_pointer_v || + std::is_trivially_copyable_v || + std::is_same_v || + std::is_same_v || + std::is_same_v; + +#define SCHEMA_FIELD_OFFSET(type, varName, extra_offset) \ + class varName##_prop \ + { \ + public: \ + std::add_lvalue_reference_t 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>(pThisClass + m_key.offset + extra_offset); \ + } \ + template \ + std::enable_if_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(pThisClass + m_key.offset + extra_offset) = val; \ + } \ + template \ + std::enable_if_t && std::is_trivially_copyable_v, 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(pThisClass + m_key.offset + extra_offset) = val; \ + } \ + template \ + std::enable_if_t && !std::is_trivially_copyable_v, 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(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() \ + { \ + return Get(); \ + } \ + std::add_lvalue_reference_t operator()() \ + { \ + return Get(); \ + } \ + std::add_lvalue_reference_t operator->() \ + { \ + return Get(); \ + } \ + template \ + std::enable_if_t, void> \ + operator()(T val) \ + { \ + Set(val); \ + } \ + template \ + std::enable_if_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>(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 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>(reinterpret_cast(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) + +} diff --git a/src/schema/serversideclient.h b/src/schema/serversideclient.h new file mode 100644 index 0000000..eaf384e --- /dev/null +++ b/src/schema/serversideclient.h @@ -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 +#include +#include "circularbuffer.h" +#include "networksystem/inetworksystem.h" +#include "threadtools.h" +#include "tier1/netadr.h" +#include +#include +#include +#include +#include +#include + +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 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 CCopyableLock : public MUTEX + { + typedef MUTEX BaseClass; + + public: + // ... + }; + + class CUtlSignaller_Base + { + public: + using Delegate_t = CUtlDelegate; + + 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 m_Mutex; + CUtlVector 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 m_vecLoadedSpawnGroups; + CMsgPlayerInfo m_playerInfo; + CFrameSnapshot* m_pBaseline; + int m_nBaselineUpdateTick; + CBitVec 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 + { + }; +} diff --git a/src/schema/services.h b/src/schema/services.h new file mode 100644 index 0000000..ddae2cb --- /dev/null +++ b/src/schema/services.h @@ -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 . + */ + +#pragma once + +#include "globaltypes.h" +#include "CCSWeaponBase.h" +#include +#include + +#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>, m_hMyWeapons) + + SCHEMA_FIELD(CHandle, 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, 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, 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, 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, m_hViewEntity) + }; + + class CCSPlayerBase_CameraServices : public CPlayer_CameraServices { + public: + virtual ~CCSPlayerBase_CameraServices() = 0; + + DECLARE_SCHEMA_CLASS(CCSPlayerBase_CameraServices) + + SCHEMA_FIELD(CHandle, 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, m_hPlayerPing) + }; +} diff --git a/src/schema/vfunc.h b/src/schema/vfunc.h new file mode 100644 index 0000000..108201c --- /dev/null +++ b/src/schema/vfunc.h @@ -0,0 +1,18 @@ +// +// Created by Michal Přikryl on 26.06.2025. +// Copyright (c) 2025 slynxcz. All rights reserved. +// +#pragma once + +#include + +namespace TemplatePlugin +{ + template + inline T CallVFunc(void* base, int index, Args... args) + { + using Fn = T(*)(void*, Args...); + void** vtable = *reinterpret_cast(base); + return reinterpret_cast(vtable[index])(base, args...); + } +} diff --git a/src/schema/virtual.h b/src/schema/virtual.h new file mode 100644 index 0000000..8bf71c7 --- /dev/null +++ b/src/schema/virtual.h @@ -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(idx, __VA_ARGS__) +#define CALL_VIRTUAL_OVERRIDE_VTBL(retType, idx, vtable, classPtr, ...) vmt::CallVirtualOverrideVTable(idx, vtable, classPtr, __VA_ARGS__) + +namespace vmt { + template inline T GetVMethod(uint32 uIndex, void* pClass) + { + if (!pClass) + { + return T(); + } + + void** pVTable = *static_cast(pClass); + if (!pVTable) + { + return T(); + } + + return reinterpret_cast(pVTable[uIndex]); + } + + template inline T CallVirtual(uint32 uIndex, void* pClass, Args... args) + { +#ifdef _WIN32 + auto pFunc = GetVMethod(uIndex, pClass); +#else + auto pFunc = GetVMethod(uIndex, pClass); +#endif + if (!pFunc) + { + return T(); + } + + return pFunc(pClass, args...); + } + + template + 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(pVTable[uIndex]); +#else + auto pFunc = reinterpret_cast(pVTable[uIndex]); +#endif + if (!pFunc) + { + Warning("Tried calling a null virtual function.\n"); + return T(); + } + + return pFunc(pClass, args...); + } +} // namespace vmt \ No newline at end of file diff --git a/src/tasks.cpp b/src/tasks.cpp new file mode 100644 index 0000000..9e641ff --- /dev/null +++ b/src/tasks.cpp @@ -0,0 +1,160 @@ +// +// Created by Michal Přikryl on 10.07.2025. +// Copyright (c) 2025 slynxcz. All rights reserved. +// +#include "tasks.h" +#include +#include +#include +#include + +namespace TemplatePlugin { + double universal_time = 0.0; + double last_tick_time = 0.0; + double timer_next_think = 0.0; + + namespace { + std::vector once_off_timers; + std::vector repeat_timers; + std::mutex nextFrameMutex; + std::queue > nextFrameQueue; + } + void Tasks::NextFrame(std::function &&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 > empty; + std::swap(nextFrameQueue, empty); + } + + void Tasks::Tick(bool simulating) { + std::queue> 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::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(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(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 &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& list) { + for (int i = static_cast(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); + } +} diff --git a/src/tasks.h b/src/tasks.h new file mode 100644 index 0000000..edaf544 --- /dev/null +++ b/src/tasks.h @@ -0,0 +1,43 @@ +// +// Created by Michal Přikryl on 10.07.2025. +// Copyright (c) 2025 slynxcz. All rights reserved. +// +#pragma once + +#include + +namespace TemplatePlugin { + using TimerCallback = std::function; + + 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 &&task); + Timer* AddTimer(float interval, TimerCallback callback, int flags = 0); + void KillTimer(Timer* timer); + void RemoveMapChangeTimers(); + } +} diff --git a/src/vectorextends.h b/src/vectorextends.h new file mode 100644 index 0000000..1a5b00e --- /dev/null +++ b/src/vectorextends.h @@ -0,0 +1,126 @@ +// +// Created by Michal Přikryl on 07.08.2025. +// Copyright (c) 2025 slynxcz. All rights reserved. +// +#pragma once + +#include +#include +#include + +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(M_PI) / 180.0f); + } + + inline float RadToDeg(float radians) + { + return radians * (180.0f / static_cast(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; + } +} \ No newline at end of file diff --git a/vendor/dynlibutils/LICENSE b/vendor/dynlibutils/LICENSE new file mode 100644 index 0000000..4be4c90 --- /dev/null +++ b/vendor/dynlibutils/LICENSE @@ -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. diff --git a/vendor/dynlibutils/README.md b/vendor/dynlibutils/README.md new file mode 100644 index 0000000..985e870 --- /dev/null +++ b/vendor/dynlibutils/README.md @@ -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. diff --git a/vendor/dynlibutils/memaddr.h b/vendor/dynlibutils/memaddr.h new file mode 100644 index 0000000..748410b --- /dev/null +++ b/vendor/dynlibutils/memaddr.h @@ -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 +#include +#include + +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(ptr)) {} + + inline operator uintptr_t() const noexcept + { + return m_ptr; + } + + inline operator void*() const noexcept + { + return reinterpret_cast(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 [[nodiscard]] inline T GetValue() const noexcept + { + return *reinterpret_cast(m_ptr); + } + + template [[nodiscard]] inline T CCast() const noexcept + { + return (T)m_ptr; + } + + template [[nodiscard]] inline T RCast() const noexcept + { + return reinterpret_cast(m_ptr); + } + + template [[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(reference); + } + + return reference; + } + + inline CMemory& DerefSelf(int deref = 1) + { + while (deref--) + { + if (m_ptr) + m_ptr = *reinterpret_cast(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(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(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 diff --git a/vendor/dynlibutils/module.cpp b/vendor/dynlibutils/module.cpp new file mode 100644 index 0000000..6d4dc2d --- /dev/null +++ b/vendor/dynlibutils/module.cpp @@ -0,0 +1,203 @@ +// DynLibUtils +// Copyright (C) 2023 komashchenko (Phoenix) +// https://github.com/komashchenko/DynLibUtils + +#include "module.h" +#include "memaddr.h" +#include +#include +#include + +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::string> +//----------------------------------------------------------------------------- +std::pair, std::string> CModule::PatternToMaskedBytes(const std::string_view svInput) +{ + char* pszPatternStart = const_cast(svInput.data()); + char* pszPatternEnd = pszPatternStart + svInput.size(); + std::vector 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(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 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(nBase); + const uint8_t* pEnd = pData + nSize - nMaskLen; + + if(pStartAddress) + { + const uint8_t* startAddress = pStartAddress.RCast(); + 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(std::ceil(static_cast(nMaskLen) / 16.f)); + + memset(nMasks, 0, iNumMasks * sizeof(int)); + for (uint8_t i = 0; i < iNumMasks; ++i) + { + for (int8_t j = static_cast(std::min(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(pattern)); + __m128i xmm2, xmm3, msks; + for (; pData != pEnd; _mm_prefetch(reinterpret_cast(++pData + 64), _MM_HINT_NTA)) + { + xmm2 = _mm_loadu_si128(reinterpret_cast(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((pData + i * 16))); + xmm3 = _mm_loadu_si128(reinterpret_cast((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 diff --git a/vendor/dynlibutils/module.h b/vendor/dynlibutils/module.h new file mode 100644 index 0000000..17ad729 --- /dev/null +++ b/vendor/dynlibutils/module.h @@ -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 +#include +#include +#include + +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::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 m_vModuleSections; +}; + +} // namespace DynLibUtils + +#endif // DYNLIBUTILS_MODULE_H diff --git a/vendor/dynlibutils/module_linux.cpp b/vendor/dynlibutils/module_linux.cpp new file mode 100644 index 0000000..bf87f44 --- /dev/null +++ b/vendor/dynlibutils/module_linux.cpp @@ -0,0 +1,219 @@ +// DynLibUtils +// Copyright (C) 2023 komashchenko (Phoenix) +// https://github.com/komashchenko/DynLibUtils + +#include "module.h" +#include "memaddr.h" +#include +#include +#include +#include +#include +#include + +using namespace DynLibUtils; + +CModule::~CModule() +{ + if (m_pModuleHandle) + dlclose(m_pModuleHandle); +} + +//----------------------------------------------------------------------------- +// Purpose: Initializes the module from module name +// Input : svModuleName +// bExtension +// Output : bool +//----------------------------------------------------------------------------- +bool CModule::InitFromName(const std::string_view svModuleName, bool bExtension) +{ + if (m_pModuleHandle) + return false; + + if (svModuleName.empty()) + return false; + + std::string sModuleName(svModuleName); + if (!bExtension) + sModuleName.append(".so"); + + struct dl_data + { + ElfW(Addr) addr; + const char* moduleName; + const char* modulePath; + } dldata{ 0, sModuleName.c_str(), {} }; + + dl_iterate_phdr([](dl_phdr_info* info, size_t /* size */, void* data) + { + dl_data* dldata = reinterpret_cast(data); + + if (std::strstr(info->dlpi_name, dldata->moduleName) != nullptr) + { + dldata->addr = info->dlpi_addr; + dldata->modulePath = info->dlpi_name; + } + + return 0; + }, &dldata); + + if (!dldata.addr) + return false; + + if (!Init(dldata.modulePath)) + return false; + + return true; +} + +//----------------------------------------------------------------------------- +// Purpose: Initializes the module from module memory +// Input : pModuleMemory +// Output : bool +//----------------------------------------------------------------------------- +bool CModule::InitFromMemory(const CMemory pModuleMemory) +{ + if (m_pModuleHandle) + return false; + + if (!pModuleMemory) + return false; + + Dl_info info; + if (!dladdr(pModuleMemory, &info) || !info.dli_fbase || !info.dli_fname) + return false; + + if (!Init(info.dli_fname)) + return false; + + return true; +} + +//----------------------------------------------------------------------------- +// Purpose: Initializes a module descriptors +//----------------------------------------------------------------------------- +bool CModule::Init(const std::string_view svModelePath) +{ + void* handle = dlopen(svModelePath.data(), RTLD_LAZY | RTLD_NOLOAD); + if (!handle) + return false; + + link_map* lmap; + if (dlinfo(handle, RTLD_DI_LINKMAP, &lmap) != 0) + { + dlclose(handle); + return false; + } + + int fd = open(lmap->l_name, O_RDONLY); + if (fd == -1) + { + dlclose(handle); + return false; + } + + struct stat st; + if (fstat(fd, &st) == 0) + { + void* map = mmap(nullptr, st.st_size, PROT_READ, MAP_PRIVATE, fd, 0); + if (map != MAP_FAILED) + { + ElfW(Ehdr)* ehdr = static_cast(map); + ElfW(Shdr)* shdrs = reinterpret_cast(reinterpret_cast(ehdr) + ehdr->e_shoff); + const char* strTab = reinterpret_cast(reinterpret_cast(ehdr) + shdrs[ehdr->e_shstrndx].sh_offset); + + for (auto i = 0; i < ehdr->e_shnum; ++i) // Loop through the sections. + { + ElfW(Shdr)* shdr = reinterpret_cast(reinterpret_cast(shdrs) + i * ehdr->e_shentsize); + if (*(strTab + shdr->sh_name) == '\0') + continue; + + m_vModuleSections.emplace_back(strTab + shdr->sh_name, static_cast(lmap->l_addr + shdr->sh_addr), shdr->sh_size); + } + + munmap(map, st.st_size); + } + } + + close(fd); + + m_pModuleHandle = handle; + m_sModulePath.assign(svModelePath); + + m_ExecutableCode = GetSectionByName(".text"); + + return true; +} + +//----------------------------------------------------------------------------- +// Purpose: Gets an address of a virtual method table by rtti type descriptor name +// Input : svTableName +// bDecorated +// Output : CMemory +//----------------------------------------------------------------------------- +CMemory CModule::GetVirtualTableByName(const std::string_view svTableName, bool bDecorated) const +{ + if (svTableName.empty()) + return CMemory(); + + CModule::ModuleSections_t readOnlyData = GetSectionByName(".rodata"), readOnlyRelocations = GetSectionByName(".data.rel.ro"); + if (!readOnlyData.IsSectionValid() || !readOnlyRelocations.IsSectionValid()) + return CMemory(); + + std::string sDecoratedTableName(bDecorated ? svTableName : std::to_string(svTableName.length()) + std::string(svTableName)); + std::string sMask(sDecoratedTableName.length() + 1, 'x'); + + CMemory typeInfoName = FindPattern(sDecoratedTableName.data(), sMask, nullptr, &readOnlyData); + if (!typeInfoName) + return CMemory(); + + CMemory referenceTypeName = FindPattern(&typeInfoName, "xxxxxxxx", nullptr, &readOnlyRelocations); // Get reference to type name. + if (!referenceTypeName) + return CMemory(); + + CMemory typeInfo = referenceTypeName.Offset(-0x8); // Offset -0x8 to typeinfo. + + for (const auto& sectionName : { std::string_view(".data.rel.ro"), std::string_view(".data.rel.ro.local") }) + { + CModule::ModuleSections_t section = GetSectionByName(sectionName); + if (!section.IsSectionValid()) + continue; + + CMemory reference; + while ((reference = FindPattern(&typeInfo, "xxxxxxxx", reference, §ion))) // Get reference typeinfo in vtable + { + if (reference.Offset(-0x8).GetValue() == 0) // Offset to this. + { + return reference.Offset(0x8); + } + + reference.OffsetSelf(0x8); + } + } + + return CMemory(); +} + +//----------------------------------------------------------------------------- +// Purpose: Gets an address of a virtual method table by rtti type descriptor name +// Input : svFunctionName +// Output : CMemory +//----------------------------------------------------------------------------- +CMemory CModule::GetFunctionByName(const std::string_view svFunctionName) const noexcept +{ + if (!m_pModuleHandle) + return CMemory(); + + if (svFunctionName.empty()) + return CMemory(); + + return dlsym(m_pModuleHandle, svFunctionName.data()); +} + +//----------------------------------------------------------------------------- +// Purpose: Returns the module base +//----------------------------------------------------------------------------- +CMemory CModule::GetModuleBase() const noexcept +{ + return static_cast(m_pModuleHandle)->l_addr; +} diff --git a/vendor/dynlibutils/module_windows.cpp b/vendor/dynlibutils/module_windows.cpp new file mode 100644 index 0000000..cbc2852 --- /dev/null +++ b/vendor/dynlibutils/module_windows.cpp @@ -0,0 +1,196 @@ +// DynLibUtils +// Copyright (C) 2023 komashchenko (Phoenix) +// https://github.com/komashchenko/DynLibUtils + +#include "module.h" +#include "memaddr.h" +#include +#include +#include + +using namespace DynLibUtils; + +CModule::~CModule() +{ + if (m_pModuleHandle) + FreeLibrary(reinterpret_cast(m_pModuleHandle)); +} + +static std::string GetModulePath(HMODULE hModule) +{ + std::string modulePath(MAX_PATH, '\0'); + while (true) + { + size_t len = GetModuleFileNameA(hModule, modulePath.data(), static_cast(modulePath.length())); + if (len == 0) + { + modulePath.clear(); + break; + } + + if (len < modulePath.length()) + { + modulePath.resize(len); + break; + } + else + modulePath.resize(modulePath.length() * 2); + } + + return modulePath; +} + +//----------------------------------------------------------------------------- +// Purpose: Initializes the module from module name +// Input : svModuleName +// bExtension +// Output : bool +//----------------------------------------------------------------------------- +bool CModule::InitFromName(const std::string_view svModuleName, bool bExtension) +{ + if (m_pModuleHandle) + return false; + + if (svModuleName.empty()) + return false; + + std::string sModuleName(svModuleName); + if (!bExtension) + sModuleName.append(".dll"); + + HMODULE handle = GetModuleHandleA(sModuleName.c_str()); + if (!handle) + return false; + + std::string modulePath = ::GetModulePath(handle); + if(modulePath.empty()) + return false; + + if (!Init(modulePath)) + return false; + + return true; +} + +//----------------------------------------------------------------------------- +// Purpose: Initializes the module from module memory +// Input : pModuleMemory +// Output : bool +//----------------------------------------------------------------------------- +bool CModule::InitFromMemory(const CMemory pModuleMemory) +{ + if (m_pModuleHandle) + return false; + + if (!pModuleMemory) + return false; + + MEMORY_BASIC_INFORMATION mbi; + if (!VirtualQuery(pModuleMemory, &mbi, sizeof(mbi))) + return false; + + std::string modulePath = ::GetModulePath(reinterpret_cast(mbi.AllocationBase)); + if (modulePath.empty()) + return false; + + if (!Init(modulePath)) + return false; + + return true; +} + +//----------------------------------------------------------------------------- +// Purpose: Initializes a module descriptors +//----------------------------------------------------------------------------- +bool CModule::Init(const std::string_view svModelePath) +{ + HMODULE handle = LoadLibraryExA(svModelePath.data(), nullptr, DONT_RESOLVE_DLL_REFERENCES); + if (!handle) + return false; + + IMAGE_DOS_HEADER* pDOSHeader = reinterpret_cast(handle); + IMAGE_NT_HEADERS64* pNTHeaders = reinterpret_cast(reinterpret_cast(handle) + pDOSHeader->e_lfanew); + + const IMAGE_SECTION_HEADER* hSection = IMAGE_FIRST_SECTION(pNTHeaders); // Get first image section. + + for (WORD i = 0; i < pNTHeaders->FileHeader.NumberOfSections; ++i) // Loop through the sections. + { + const IMAGE_SECTION_HEADER& hCurrentSection = hSection[i]; // Get current section. + m_vModuleSections.emplace_back(reinterpret_cast(hCurrentSection.Name), static_cast(reinterpret_cast(handle) + hCurrentSection.VirtualAddress), hCurrentSection.SizeOfRawData); // Push back a struct with the section data. + } + + m_pModuleHandle = handle; + m_sModulePath.assign(svModelePath); + + m_ExecutableCode = GetSectionByName(".text"); + + return true; +} + +//----------------------------------------------------------------------------- +// Purpose: Gets an address of a virtual method table by rtti type descriptor name +// Input : svTableName +// bDecorated +// Output : CMemory +//----------------------------------------------------------------------------- +CMemory CModule::GetVirtualTableByName(const std::string_view svTableName, bool bDecorated) const +{ + if(svTableName.empty()) + return CMemory(); + + CModule::ModuleSections_t runTimeData = GetSectionByName(".data"), readOnlyData = GetSectionByName(".rdata"); + if(!runTimeData.IsSectionValid() || !readOnlyData.IsSectionValid()) + return CMemory(); + + std::string sDecoratedTableName(bDecorated ? svTableName : ".?AV" + std::string(svTableName) + "@@"); + std::string sMask(sDecoratedTableName.length() + 1, 'x'); + + CMemory typeDescriptorName = FindPattern(sDecoratedTableName.data(), sMask, nullptr, &runTimeData); + if (!typeDescriptorName) + return CMemory(); + + CMemory rttiTypeDescriptor = typeDescriptorName.Offset(-0x10); + const uintptr_t rttiTDRva = rttiTypeDescriptor - GetModuleBase(); // The RTTI gets referenced by a 4-Byte RVA address. We need to scan for that address. + + CMemory reference; + while ((reference = FindPattern(&rttiTDRva, "xxxx", reference, &readOnlyData))) // Get reference typeinfo in vtable + { + // Check if we got a RTTI Object Locator for this reference by checking if -0xC is 1, which is the 'signature' field which is always 1 on x64. + // Check that offset of this vtable is 0 + if (reference.Offset(-0xC).GetValue() == 1 && reference.Offset(-0x8).GetValue() == 0) + { + CMemory referenceOffset = reference.Offset(-0xC); + CMemory rttiCompleteObjectLocator = FindPattern(&referenceOffset, "xxxxxxxx", nullptr, &readOnlyData); + if (rttiCompleteObjectLocator) + return rttiCompleteObjectLocator.Offset(0x8); + } + + reference.OffsetSelf(0x4); + } + + return CMemory(); +} + +//----------------------------------------------------------------------------- +// Purpose: Gets an address of a virtual method table by rtti type descriptor name +// Input : svFunctionName +// Output : CMemory +//----------------------------------------------------------------------------- +CMemory CModule::GetFunctionByName(const std::string_view svFunctionName) const noexcept +{ + if(!m_pModuleHandle) + return CMemory(); + + if (svFunctionName.empty()) + return CMemory(); + + return GetProcAddress(reinterpret_cast(m_pModuleHandle), svFunctionName.data()); +} + +//----------------------------------------------------------------------------- +// Purpose: Returns the module base +//----------------------------------------------------------------------------- +CMemory CModule::GetModuleBase() const noexcept +{ + return m_pModuleHandle; +} diff --git a/vendor/funchook b/vendor/funchook new file mode 160000 index 0000000..b499170 --- /dev/null +++ b/vendor/funchook @@ -0,0 +1 @@ +Subproject commit b4991704add411ecbc492dae020f375124d51f45 diff --git a/vendor/nlohmann/json.hpp b/vendor/nlohmann/json.hpp new file mode 100644 index 0000000..5a2d171 --- /dev/null +++ b/vendor/nlohmann/json.hpp @@ -0,0 +1,24596 @@ +// __ _____ _____ _____ +// __| | __| | | | JSON for Modern C++ +// | | |__ | | | | | | version 3.11.2 +// |_____|_____|_____|_|___| https://github.com/nlohmann/json +// +// SPDX-FileCopyrightText: 2013-2022 Niels Lohmann +// SPDX-License-Identifier: MIT + +/****************************************************************************\ + * Note on documentation: The source files contain links to the online * + * documentation of the public API at https://json.nlohmann.me. This URL * + * contains the most recent documentation and should also be applicable to * + * previous versions; documentation for deprecated functions is not * + * removed, but marked deprecated. See "Generate documentation" section in * + * file docs/README.md. * +\****************************************************************************/ + +#ifndef INCLUDE_NLOHMANN_JSON_HPP_ +#define INCLUDE_NLOHMANN_JSON_HPP_ + +#include // all_of, find, for_each +#include // nullptr_t, ptrdiff_t, size_t +#include // hash, less +#include // initializer_list +#ifndef JSON_NO_IO + #include // istream, ostream +#endif // JSON_NO_IO +#include // random_access_iterator_tag +#include // unique_ptr +#include // accumulate +#include // string, stoi, to_string +#include // declval, forward, move, pair, swap +#include // vector + +// #include +// __ _____ _____ _____ +// __| | __| | | | JSON for Modern C++ +// | | |__ | | | | | | version 3.11.2 +// |_____|_____|_____|_|___| https://github.com/nlohmann/json +// +// SPDX-FileCopyrightText: 2013-2022 Niels Lohmann +// SPDX-License-Identifier: MIT + + + +#include + +// #include +// __ _____ _____ _____ +// __| | __| | | | JSON for Modern C++ +// | | |__ | | | | | | version 3.11.2 +// |_____|_____|_____|_|___| https://github.com/nlohmann/json +// +// SPDX-FileCopyrightText: 2013-2022 Niels Lohmann +// SPDX-License-Identifier: MIT + + + +// This file contains all macro definitions affecting or depending on the ABI + +#ifndef JSON_SKIP_LIBRARY_VERSION_CHECK + #if defined(NLOHMANN_JSON_VERSION_MAJOR) && defined(NLOHMANN_JSON_VERSION_MINOR) && defined(NLOHMANN_JSON_VERSION_PATCH) + #if NLOHMANN_JSON_VERSION_MAJOR != 3 || NLOHMANN_JSON_VERSION_MINOR != 11 || NLOHMANN_JSON_VERSION_PATCH != 2 + #warning "Already included a different version of the library!" + #endif + #endif +#endif + +#define NLOHMANN_JSON_VERSION_MAJOR 3 // NOLINT(modernize-macro-to-enum) +#define NLOHMANN_JSON_VERSION_MINOR 11 // NOLINT(modernize-macro-to-enum) +#define NLOHMANN_JSON_VERSION_PATCH 2 // NOLINT(modernize-macro-to-enum) + +#ifndef JSON_DIAGNOSTICS + #define JSON_DIAGNOSTICS 0 +#endif + +#ifndef JSON_USE_LEGACY_DISCARDED_VALUE_COMPARISON + #define JSON_USE_LEGACY_DISCARDED_VALUE_COMPARISON 0 +#endif + +#if JSON_DIAGNOSTICS + #define NLOHMANN_JSON_ABI_TAG_DIAGNOSTICS _diag +#else + #define NLOHMANN_JSON_ABI_TAG_DIAGNOSTICS +#endif + +#if JSON_USE_LEGACY_DISCARDED_VALUE_COMPARISON + #define NLOHMANN_JSON_ABI_TAG_LEGACY_DISCARDED_VALUE_COMPARISON _ldvcmp +#else + #define NLOHMANN_JSON_ABI_TAG_LEGACY_DISCARDED_VALUE_COMPARISON +#endif + +#ifndef NLOHMANN_JSON_NAMESPACE_NO_VERSION + #define NLOHMANN_JSON_NAMESPACE_NO_VERSION 0 +#endif + +// Construct the namespace ABI tags component +#define NLOHMANN_JSON_ABI_TAGS_CONCAT_EX(a, b) json_abi ## a ## b +#define NLOHMANN_JSON_ABI_TAGS_CONCAT(a, b) \ + NLOHMANN_JSON_ABI_TAGS_CONCAT_EX(a, b) + +#define NLOHMANN_JSON_ABI_TAGS \ + NLOHMANN_JSON_ABI_TAGS_CONCAT( \ + NLOHMANN_JSON_ABI_TAG_DIAGNOSTICS, \ + NLOHMANN_JSON_ABI_TAG_LEGACY_DISCARDED_VALUE_COMPARISON) + +// Construct the namespace version component +#define NLOHMANN_JSON_NAMESPACE_VERSION_CONCAT_EX(major, minor, patch) \ + _v ## major ## _ ## minor ## _ ## patch +#define NLOHMANN_JSON_NAMESPACE_VERSION_CONCAT(major, minor, patch) \ + NLOHMANN_JSON_NAMESPACE_VERSION_CONCAT_EX(major, minor, patch) + +#if NLOHMANN_JSON_NAMESPACE_NO_VERSION +#define NLOHMANN_JSON_NAMESPACE_VERSION +#else +#define NLOHMANN_JSON_NAMESPACE_VERSION \ + NLOHMANN_JSON_NAMESPACE_VERSION_CONCAT(NLOHMANN_JSON_VERSION_MAJOR, \ + NLOHMANN_JSON_VERSION_MINOR, \ + NLOHMANN_JSON_VERSION_PATCH) +#endif + +// Combine namespace components +#define NLOHMANN_JSON_NAMESPACE_CONCAT_EX(a, b) a ## b +#define NLOHMANN_JSON_NAMESPACE_CONCAT(a, b) \ + NLOHMANN_JSON_NAMESPACE_CONCAT_EX(a, b) + +#ifndef NLOHMANN_JSON_NAMESPACE +#define NLOHMANN_JSON_NAMESPACE \ + nlohmann::NLOHMANN_JSON_NAMESPACE_CONCAT( \ + NLOHMANN_JSON_ABI_TAGS, \ + NLOHMANN_JSON_NAMESPACE_VERSION) +#endif + +#ifndef NLOHMANN_JSON_NAMESPACE_BEGIN +#define NLOHMANN_JSON_NAMESPACE_BEGIN \ + namespace nlohmann \ + { \ + inline namespace NLOHMANN_JSON_NAMESPACE_CONCAT( \ + NLOHMANN_JSON_ABI_TAGS, \ + NLOHMANN_JSON_NAMESPACE_VERSION) \ + { +#endif + +#ifndef NLOHMANN_JSON_NAMESPACE_END +#define NLOHMANN_JSON_NAMESPACE_END \ + } /* namespace (inline namespace) NOLINT(readability/namespace) */ \ + } // namespace nlohmann +#endif + +// #include +// __ _____ _____ _____ +// __| | __| | | | JSON for Modern C++ +// | | |__ | | | | | | version 3.11.2 +// |_____|_____|_____|_|___| https://github.com/nlohmann/json +// +// SPDX-FileCopyrightText: 2013-2022 Niels Lohmann +// SPDX-License-Identifier: MIT + + + +#include // transform +#include // array +#include // forward_list +#include // inserter, front_inserter, end +#include // map +#include // string +#include // tuple, make_tuple +#include // is_arithmetic, is_same, is_enum, underlying_type, is_convertible +#include // unordered_map +#include // pair, declval +#include // valarray + +// #include +// __ _____ _____ _____ +// __| | __| | | | JSON for Modern C++ +// | | |__ | | | | | | version 3.11.2 +// |_____|_____|_____|_|___| https://github.com/nlohmann/json +// +// SPDX-FileCopyrightText: 2013-2022 Niels Lohmann +// SPDX-License-Identifier: MIT + + + +#include // nullptr_t +#include // exception +#include // runtime_error +#include // to_string +#include // vector + +// #include +// __ _____ _____ _____ +// __| | __| | | | JSON for Modern C++ +// | | |__ | | | | | | version 3.11.2 +// |_____|_____|_____|_|___| https://github.com/nlohmann/json +// +// SPDX-FileCopyrightText: 2013-2022 Niels Lohmann +// SPDX-License-Identifier: MIT + + + +#include // array +#include // size_t +#include // uint8_t +#include // string + +// #include +// __ _____ _____ _____ +// __| | __| | | | JSON for Modern C++ +// | | |__ | | | | | | version 3.11.2 +// |_____|_____|_____|_|___| https://github.com/nlohmann/json +// +// SPDX-FileCopyrightText: 2013-2022 Niels Lohmann +// SPDX-License-Identifier: MIT + + + +#include // declval, pair +// #include +// __ _____ _____ _____ +// __| | __| | | | JSON for Modern C++ +// | | |__ | | | | | | version 3.11.2 +// |_____|_____|_____|_|___| https://github.com/nlohmann/json +// +// SPDX-FileCopyrightText: 2013-2022 Niels Lohmann +// SPDX-License-Identifier: MIT + + + +#include + +// #include +// __ _____ _____ _____ +// __| | __| | | | JSON for Modern C++ +// | | |__ | | | | | | version 3.11.2 +// |_____|_____|_____|_|___| https://github.com/nlohmann/json +// +// SPDX-FileCopyrightText: 2013-2022 Niels Lohmann +// SPDX-License-Identifier: MIT + + + +// #include + + +NLOHMANN_JSON_NAMESPACE_BEGIN +namespace detail +{ + +template struct make_void +{ + using type = void; +}; +template using void_t = typename make_void::type; + +} // namespace detail +NLOHMANN_JSON_NAMESPACE_END + + +NLOHMANN_JSON_NAMESPACE_BEGIN +namespace detail +{ + +// https://en.cppreference.com/w/cpp/experimental/is_detected +struct nonesuch +{ + nonesuch() = delete; + ~nonesuch() = delete; + nonesuch(nonesuch const&) = delete; + nonesuch(nonesuch const&&) = delete; + void operator=(nonesuch const&) = delete; + void operator=(nonesuch&&) = delete; +}; + +template class Op, + class... Args> +struct detector +{ + using value_t = std::false_type; + using type = Default; +}; + +template class Op, class... Args> +struct detector>, Op, Args...> +{ + using value_t = std::true_type; + using type = Op; +}; + +template class Op, class... Args> +using is_detected = typename detector::value_t; + +template class Op, class... Args> +struct is_detected_lazy : is_detected { }; + +template class Op, class... Args> +using detected_t = typename detector::type; + +template class Op, class... Args> +using detected_or = detector; + +template class Op, class... Args> +using detected_or_t = typename detected_or::type; + +template class Op, class... Args> +using is_detected_exact = std::is_same>; + +template class Op, class... Args> +using is_detected_convertible = + std::is_convertible, To>; + +} // namespace detail +NLOHMANN_JSON_NAMESPACE_END + +// #include + + +// __ _____ _____ _____ +// __| | __| | | | JSON for Modern C++ +// | | |__ | | | | | | version 3.11.2 +// |_____|_____|_____|_|___| https://github.com/nlohmann/json +// +// SPDX-FileCopyrightText: 2013-2022 Niels Lohmann +// SPDX-FileCopyrightText: 2016-2021 Evan Nemerson +// SPDX-License-Identifier: MIT + +/* Hedley - https://nemequ.github.io/hedley + * Created by Evan Nemerson + */ + +#if !defined(JSON_HEDLEY_VERSION) || (JSON_HEDLEY_VERSION < 15) +#if defined(JSON_HEDLEY_VERSION) + #undef JSON_HEDLEY_VERSION +#endif +#define JSON_HEDLEY_VERSION 15 + +#if defined(JSON_HEDLEY_STRINGIFY_EX) + #undef JSON_HEDLEY_STRINGIFY_EX +#endif +#define JSON_HEDLEY_STRINGIFY_EX(x) #x + +#if defined(JSON_HEDLEY_STRINGIFY) + #undef JSON_HEDLEY_STRINGIFY +#endif +#define JSON_HEDLEY_STRINGIFY(x) JSON_HEDLEY_STRINGIFY_EX(x) + +#if defined(JSON_HEDLEY_CONCAT_EX) + #undef JSON_HEDLEY_CONCAT_EX +#endif +#define JSON_HEDLEY_CONCAT_EX(a,b) a##b + +#if defined(JSON_HEDLEY_CONCAT) + #undef JSON_HEDLEY_CONCAT +#endif +#define JSON_HEDLEY_CONCAT(a,b) JSON_HEDLEY_CONCAT_EX(a,b) + +#if defined(JSON_HEDLEY_CONCAT3_EX) + #undef JSON_HEDLEY_CONCAT3_EX +#endif +#define JSON_HEDLEY_CONCAT3_EX(a,b,c) a##b##c + +#if defined(JSON_HEDLEY_CONCAT3) + #undef JSON_HEDLEY_CONCAT3 +#endif +#define JSON_HEDLEY_CONCAT3(a,b,c) JSON_HEDLEY_CONCAT3_EX(a,b,c) + +#if defined(JSON_HEDLEY_VERSION_ENCODE) + #undef JSON_HEDLEY_VERSION_ENCODE +#endif +#define JSON_HEDLEY_VERSION_ENCODE(major,minor,revision) (((major) * 1000000) + ((minor) * 1000) + (revision)) + +#if defined(JSON_HEDLEY_VERSION_DECODE_MAJOR) + #undef JSON_HEDLEY_VERSION_DECODE_MAJOR +#endif +#define JSON_HEDLEY_VERSION_DECODE_MAJOR(version) ((version) / 1000000) + +#if defined(JSON_HEDLEY_VERSION_DECODE_MINOR) + #undef JSON_HEDLEY_VERSION_DECODE_MINOR +#endif +#define JSON_HEDLEY_VERSION_DECODE_MINOR(version) (((version) % 1000000) / 1000) + +#if defined(JSON_HEDLEY_VERSION_DECODE_REVISION) + #undef JSON_HEDLEY_VERSION_DECODE_REVISION +#endif +#define JSON_HEDLEY_VERSION_DECODE_REVISION(version) ((version) % 1000) + +#if defined(JSON_HEDLEY_GNUC_VERSION) + #undef JSON_HEDLEY_GNUC_VERSION +#endif +#if defined(__GNUC__) && defined(__GNUC_PATCHLEVEL__) + #define JSON_HEDLEY_GNUC_VERSION JSON_HEDLEY_VERSION_ENCODE(__GNUC__, __GNUC_MINOR__, __GNUC_PATCHLEVEL__) +#elif defined(__GNUC__) + #define JSON_HEDLEY_GNUC_VERSION JSON_HEDLEY_VERSION_ENCODE(__GNUC__, __GNUC_MINOR__, 0) +#endif + +#if defined(JSON_HEDLEY_GNUC_VERSION_CHECK) + #undef JSON_HEDLEY_GNUC_VERSION_CHECK +#endif +#if defined(JSON_HEDLEY_GNUC_VERSION) + #define JSON_HEDLEY_GNUC_VERSION_CHECK(major,minor,patch) (JSON_HEDLEY_GNUC_VERSION >= JSON_HEDLEY_VERSION_ENCODE(major, minor, patch)) +#else + #define JSON_HEDLEY_GNUC_VERSION_CHECK(major,minor,patch) (0) +#endif + +#if defined(JSON_HEDLEY_MSVC_VERSION) + #undef JSON_HEDLEY_MSVC_VERSION +#endif +#if defined(_MSC_FULL_VER) && (_MSC_FULL_VER >= 140000000) && !defined(__ICL) + #define JSON_HEDLEY_MSVC_VERSION JSON_HEDLEY_VERSION_ENCODE(_MSC_FULL_VER / 10000000, (_MSC_FULL_VER % 10000000) / 100000, (_MSC_FULL_VER % 100000) / 100) +#elif defined(_MSC_FULL_VER) && !defined(__ICL) + #define JSON_HEDLEY_MSVC_VERSION JSON_HEDLEY_VERSION_ENCODE(_MSC_FULL_VER / 1000000, (_MSC_FULL_VER % 1000000) / 10000, (_MSC_FULL_VER % 10000) / 10) +#elif defined(_MSC_VER) && !defined(__ICL) + #define JSON_HEDLEY_MSVC_VERSION JSON_HEDLEY_VERSION_ENCODE(_MSC_VER / 100, _MSC_VER % 100, 0) +#endif + +#if defined(JSON_HEDLEY_MSVC_VERSION_CHECK) + #undef JSON_HEDLEY_MSVC_VERSION_CHECK +#endif +#if !defined(JSON_HEDLEY_MSVC_VERSION) + #define JSON_HEDLEY_MSVC_VERSION_CHECK(major,minor,patch) (0) +#elif defined(_MSC_VER) && (_MSC_VER >= 1400) + #define JSON_HEDLEY_MSVC_VERSION_CHECK(major,minor,patch) (_MSC_FULL_VER >= ((major * 10000000) + (minor * 100000) + (patch))) +#elif defined(_MSC_VER) && (_MSC_VER >= 1200) + #define JSON_HEDLEY_MSVC_VERSION_CHECK(major,minor,patch) (_MSC_FULL_VER >= ((major * 1000000) + (minor * 10000) + (patch))) +#else + #define JSON_HEDLEY_MSVC_VERSION_CHECK(major,minor,patch) (_MSC_VER >= ((major * 100) + (minor))) +#endif + +#if defined(JSON_HEDLEY_INTEL_VERSION) + #undef JSON_HEDLEY_INTEL_VERSION +#endif +#if defined(__INTEL_COMPILER) && defined(__INTEL_COMPILER_UPDATE) && !defined(__ICL) + #define JSON_HEDLEY_INTEL_VERSION JSON_HEDLEY_VERSION_ENCODE(__INTEL_COMPILER / 100, __INTEL_COMPILER % 100, __INTEL_COMPILER_UPDATE) +#elif defined(__INTEL_COMPILER) && !defined(__ICL) + #define JSON_HEDLEY_INTEL_VERSION JSON_HEDLEY_VERSION_ENCODE(__INTEL_COMPILER / 100, __INTEL_COMPILER % 100, 0) +#endif + +#if defined(JSON_HEDLEY_INTEL_VERSION_CHECK) + #undef JSON_HEDLEY_INTEL_VERSION_CHECK +#endif +#if defined(JSON_HEDLEY_INTEL_VERSION) + #define JSON_HEDLEY_INTEL_VERSION_CHECK(major,minor,patch) (JSON_HEDLEY_INTEL_VERSION >= JSON_HEDLEY_VERSION_ENCODE(major, minor, patch)) +#else + #define JSON_HEDLEY_INTEL_VERSION_CHECK(major,minor,patch) (0) +#endif + +#if defined(JSON_HEDLEY_INTEL_CL_VERSION) + #undef JSON_HEDLEY_INTEL_CL_VERSION +#endif +#if defined(__INTEL_COMPILER) && defined(__INTEL_COMPILER_UPDATE) && defined(__ICL) + #define JSON_HEDLEY_INTEL_CL_VERSION JSON_HEDLEY_VERSION_ENCODE(__INTEL_COMPILER, __INTEL_COMPILER_UPDATE, 0) +#endif + +#if defined(JSON_HEDLEY_INTEL_CL_VERSION_CHECK) + #undef JSON_HEDLEY_INTEL_CL_VERSION_CHECK +#endif +#if defined(JSON_HEDLEY_INTEL_CL_VERSION) + #define JSON_HEDLEY_INTEL_CL_VERSION_CHECK(major,minor,patch) (JSON_HEDLEY_INTEL_CL_VERSION >= JSON_HEDLEY_VERSION_ENCODE(major, minor, patch)) +#else + #define JSON_HEDLEY_INTEL_CL_VERSION_CHECK(major,minor,patch) (0) +#endif + +#if defined(JSON_HEDLEY_PGI_VERSION) + #undef JSON_HEDLEY_PGI_VERSION +#endif +#if defined(__PGI) && defined(__PGIC__) && defined(__PGIC_MINOR__) && defined(__PGIC_PATCHLEVEL__) + #define JSON_HEDLEY_PGI_VERSION JSON_HEDLEY_VERSION_ENCODE(__PGIC__, __PGIC_MINOR__, __PGIC_PATCHLEVEL__) +#endif + +#if defined(JSON_HEDLEY_PGI_VERSION_CHECK) + #undef JSON_HEDLEY_PGI_VERSION_CHECK +#endif +#if defined(JSON_HEDLEY_PGI_VERSION) + #define JSON_HEDLEY_PGI_VERSION_CHECK(major,minor,patch) (JSON_HEDLEY_PGI_VERSION >= JSON_HEDLEY_VERSION_ENCODE(major, minor, patch)) +#else + #define JSON_HEDLEY_PGI_VERSION_CHECK(major,minor,patch) (0) +#endif + +#if defined(JSON_HEDLEY_SUNPRO_VERSION) + #undef JSON_HEDLEY_SUNPRO_VERSION +#endif +#if defined(__SUNPRO_C) && (__SUNPRO_C > 0x1000) + #define JSON_HEDLEY_SUNPRO_VERSION JSON_HEDLEY_VERSION_ENCODE((((__SUNPRO_C >> 16) & 0xf) * 10) + ((__SUNPRO_C >> 12) & 0xf), (((__SUNPRO_C >> 8) & 0xf) * 10) + ((__SUNPRO_C >> 4) & 0xf), (__SUNPRO_C & 0xf) * 10) +#elif defined(__SUNPRO_C) + #define JSON_HEDLEY_SUNPRO_VERSION JSON_HEDLEY_VERSION_ENCODE((__SUNPRO_C >> 8) & 0xf, (__SUNPRO_C >> 4) & 0xf, (__SUNPRO_C) & 0xf) +#elif defined(__SUNPRO_CC) && (__SUNPRO_CC > 0x1000) + #define JSON_HEDLEY_SUNPRO_VERSION JSON_HEDLEY_VERSION_ENCODE((((__SUNPRO_CC >> 16) & 0xf) * 10) + ((__SUNPRO_CC >> 12) & 0xf), (((__SUNPRO_CC >> 8) & 0xf) * 10) + ((__SUNPRO_CC >> 4) & 0xf), (__SUNPRO_CC & 0xf) * 10) +#elif defined(__SUNPRO_CC) + #define JSON_HEDLEY_SUNPRO_VERSION JSON_HEDLEY_VERSION_ENCODE((__SUNPRO_CC >> 8) & 0xf, (__SUNPRO_CC >> 4) & 0xf, (__SUNPRO_CC) & 0xf) +#endif + +#if defined(JSON_HEDLEY_SUNPRO_VERSION_CHECK) + #undef JSON_HEDLEY_SUNPRO_VERSION_CHECK +#endif +#if defined(JSON_HEDLEY_SUNPRO_VERSION) + #define JSON_HEDLEY_SUNPRO_VERSION_CHECK(major,minor,patch) (JSON_HEDLEY_SUNPRO_VERSION >= JSON_HEDLEY_VERSION_ENCODE(major, minor, patch)) +#else + #define JSON_HEDLEY_SUNPRO_VERSION_CHECK(major,minor,patch) (0) +#endif + +#if defined(JSON_HEDLEY_EMSCRIPTEN_VERSION) + #undef JSON_HEDLEY_EMSCRIPTEN_VERSION +#endif +#if defined(__EMSCRIPTEN__) + #define JSON_HEDLEY_EMSCRIPTEN_VERSION JSON_HEDLEY_VERSION_ENCODE(__EMSCRIPTEN_major__, __EMSCRIPTEN_minor__, __EMSCRIPTEN_tiny__) +#endif + +#if defined(JSON_HEDLEY_EMSCRIPTEN_VERSION_CHECK) + #undef JSON_HEDLEY_EMSCRIPTEN_VERSION_CHECK +#endif +#if defined(JSON_HEDLEY_EMSCRIPTEN_VERSION) + #define JSON_HEDLEY_EMSCRIPTEN_VERSION_CHECK(major,minor,patch) (JSON_HEDLEY_EMSCRIPTEN_VERSION >= JSON_HEDLEY_VERSION_ENCODE(major, minor, patch)) +#else + #define JSON_HEDLEY_EMSCRIPTEN_VERSION_CHECK(major,minor,patch) (0) +#endif + +#if defined(JSON_HEDLEY_ARM_VERSION) + #undef JSON_HEDLEY_ARM_VERSION +#endif +#if defined(__CC_ARM) && defined(__ARMCOMPILER_VERSION) + #define JSON_HEDLEY_ARM_VERSION JSON_HEDLEY_VERSION_ENCODE(__ARMCOMPILER_VERSION / 1000000, (__ARMCOMPILER_VERSION % 1000000) / 10000, (__ARMCOMPILER_VERSION % 10000) / 100) +#elif defined(__CC_ARM) && defined(__ARMCC_VERSION) + #define JSON_HEDLEY_ARM_VERSION JSON_HEDLEY_VERSION_ENCODE(__ARMCC_VERSION / 1000000, (__ARMCC_VERSION % 1000000) / 10000, (__ARMCC_VERSION % 10000) / 100) +#endif + +#if defined(JSON_HEDLEY_ARM_VERSION_CHECK) + #undef JSON_HEDLEY_ARM_VERSION_CHECK +#endif +#if defined(JSON_HEDLEY_ARM_VERSION) + #define JSON_HEDLEY_ARM_VERSION_CHECK(major,minor,patch) (JSON_HEDLEY_ARM_VERSION >= JSON_HEDLEY_VERSION_ENCODE(major, minor, patch)) +#else + #define JSON_HEDLEY_ARM_VERSION_CHECK(major,minor,patch) (0) +#endif + +#if defined(JSON_HEDLEY_IBM_VERSION) + #undef JSON_HEDLEY_IBM_VERSION +#endif +#if defined(__ibmxl__) + #define JSON_HEDLEY_IBM_VERSION JSON_HEDLEY_VERSION_ENCODE(__ibmxl_version__, __ibmxl_release__, __ibmxl_modification__) +#elif defined(__xlC__) && defined(__xlC_ver__) + #define JSON_HEDLEY_IBM_VERSION JSON_HEDLEY_VERSION_ENCODE(__xlC__ >> 8, __xlC__ & 0xff, (__xlC_ver__ >> 8) & 0xff) +#elif defined(__xlC__) + #define JSON_HEDLEY_IBM_VERSION JSON_HEDLEY_VERSION_ENCODE(__xlC__ >> 8, __xlC__ & 0xff, 0) +#endif + +#if defined(JSON_HEDLEY_IBM_VERSION_CHECK) + #undef JSON_HEDLEY_IBM_VERSION_CHECK +#endif +#if defined(JSON_HEDLEY_IBM_VERSION) + #define JSON_HEDLEY_IBM_VERSION_CHECK(major,minor,patch) (JSON_HEDLEY_IBM_VERSION >= JSON_HEDLEY_VERSION_ENCODE(major, minor, patch)) +#else + #define JSON_HEDLEY_IBM_VERSION_CHECK(major,minor,patch) (0) +#endif + +#if defined(JSON_HEDLEY_TI_VERSION) + #undef JSON_HEDLEY_TI_VERSION +#endif +#if \ + defined(__TI_COMPILER_VERSION__) && \ + ( \ + defined(__TMS470__) || defined(__TI_ARM__) || \ + defined(__MSP430__) || \ + defined(__TMS320C2000__) \ + ) +#if (__TI_COMPILER_VERSION__ >= 16000000) + #define JSON_HEDLEY_TI_VERSION JSON_HEDLEY_VERSION_ENCODE(__TI_COMPILER_VERSION__ / 1000000, (__TI_COMPILER_VERSION__ % 1000000) / 1000, (__TI_COMPILER_VERSION__ % 1000)) +#endif +#endif + +#if defined(JSON_HEDLEY_TI_VERSION_CHECK) + #undef JSON_HEDLEY_TI_VERSION_CHECK +#endif +#if defined(JSON_HEDLEY_TI_VERSION) + #define JSON_HEDLEY_TI_VERSION_CHECK(major,minor,patch) (JSON_HEDLEY_TI_VERSION >= JSON_HEDLEY_VERSION_ENCODE(major, minor, patch)) +#else + #define JSON_HEDLEY_TI_VERSION_CHECK(major,minor,patch) (0) +#endif + +#if defined(JSON_HEDLEY_TI_CL2000_VERSION) + #undef JSON_HEDLEY_TI_CL2000_VERSION +#endif +#if defined(__TI_COMPILER_VERSION__) && defined(__TMS320C2000__) + #define JSON_HEDLEY_TI_CL2000_VERSION JSON_HEDLEY_VERSION_ENCODE(__TI_COMPILER_VERSION__ / 1000000, (__TI_COMPILER_VERSION__ % 1000000) / 1000, (__TI_COMPILER_VERSION__ % 1000)) +#endif + +#if defined(JSON_HEDLEY_TI_CL2000_VERSION_CHECK) + #undef JSON_HEDLEY_TI_CL2000_VERSION_CHECK +#endif +#if defined(JSON_HEDLEY_TI_CL2000_VERSION) + #define JSON_HEDLEY_TI_CL2000_VERSION_CHECK(major,minor,patch) (JSON_HEDLEY_TI_CL2000_VERSION >= JSON_HEDLEY_VERSION_ENCODE(major, minor, patch)) +#else + #define JSON_HEDLEY_TI_CL2000_VERSION_CHECK(major,minor,patch) (0) +#endif + +#if defined(JSON_HEDLEY_TI_CL430_VERSION) + #undef JSON_HEDLEY_TI_CL430_VERSION +#endif +#if defined(__TI_COMPILER_VERSION__) && defined(__MSP430__) + #define JSON_HEDLEY_TI_CL430_VERSION JSON_HEDLEY_VERSION_ENCODE(__TI_COMPILER_VERSION__ / 1000000, (__TI_COMPILER_VERSION__ % 1000000) / 1000, (__TI_COMPILER_VERSION__ % 1000)) +#endif + +#if defined(JSON_HEDLEY_TI_CL430_VERSION_CHECK) + #undef JSON_HEDLEY_TI_CL430_VERSION_CHECK +#endif +#if defined(JSON_HEDLEY_TI_CL430_VERSION) + #define JSON_HEDLEY_TI_CL430_VERSION_CHECK(major,minor,patch) (JSON_HEDLEY_TI_CL430_VERSION >= JSON_HEDLEY_VERSION_ENCODE(major, minor, patch)) +#else + #define JSON_HEDLEY_TI_CL430_VERSION_CHECK(major,minor,patch) (0) +#endif + +#if defined(JSON_HEDLEY_TI_ARMCL_VERSION) + #undef JSON_HEDLEY_TI_ARMCL_VERSION +#endif +#if defined(__TI_COMPILER_VERSION__) && (defined(__TMS470__) || defined(__TI_ARM__)) + #define JSON_HEDLEY_TI_ARMCL_VERSION JSON_HEDLEY_VERSION_ENCODE(__TI_COMPILER_VERSION__ / 1000000, (__TI_COMPILER_VERSION__ % 1000000) / 1000, (__TI_COMPILER_VERSION__ % 1000)) +#endif + +#if defined(JSON_HEDLEY_TI_ARMCL_VERSION_CHECK) + #undef JSON_HEDLEY_TI_ARMCL_VERSION_CHECK +#endif +#if defined(JSON_HEDLEY_TI_ARMCL_VERSION) + #define JSON_HEDLEY_TI_ARMCL_VERSION_CHECK(major,minor,patch) (JSON_HEDLEY_TI_ARMCL_VERSION >= JSON_HEDLEY_VERSION_ENCODE(major, minor, patch)) +#else + #define JSON_HEDLEY_TI_ARMCL_VERSION_CHECK(major,minor,patch) (0) +#endif + +#if defined(JSON_HEDLEY_TI_CL6X_VERSION) + #undef JSON_HEDLEY_TI_CL6X_VERSION +#endif +#if defined(__TI_COMPILER_VERSION__) && defined(__TMS320C6X__) + #define JSON_HEDLEY_TI_CL6X_VERSION JSON_HEDLEY_VERSION_ENCODE(__TI_COMPILER_VERSION__ / 1000000, (__TI_COMPILER_VERSION__ % 1000000) / 1000, (__TI_COMPILER_VERSION__ % 1000)) +#endif + +#if defined(JSON_HEDLEY_TI_CL6X_VERSION_CHECK) + #undef JSON_HEDLEY_TI_CL6X_VERSION_CHECK +#endif +#if defined(JSON_HEDLEY_TI_CL6X_VERSION) + #define JSON_HEDLEY_TI_CL6X_VERSION_CHECK(major,minor,patch) (JSON_HEDLEY_TI_CL6X_VERSION >= JSON_HEDLEY_VERSION_ENCODE(major, minor, patch)) +#else + #define JSON_HEDLEY_TI_CL6X_VERSION_CHECK(major,minor,patch) (0) +#endif + +#if defined(JSON_HEDLEY_TI_CL7X_VERSION) + #undef JSON_HEDLEY_TI_CL7X_VERSION +#endif +#if defined(__TI_COMPILER_VERSION__) && defined(__C7000__) + #define JSON_HEDLEY_TI_CL7X_VERSION JSON_HEDLEY_VERSION_ENCODE(__TI_COMPILER_VERSION__ / 1000000, (__TI_COMPILER_VERSION__ % 1000000) / 1000, (__TI_COMPILER_VERSION__ % 1000)) +#endif + +#if defined(JSON_HEDLEY_TI_CL7X_VERSION_CHECK) + #undef JSON_HEDLEY_TI_CL7X_VERSION_CHECK +#endif +#if defined(JSON_HEDLEY_TI_CL7X_VERSION) + #define JSON_HEDLEY_TI_CL7X_VERSION_CHECK(major,minor,patch) (JSON_HEDLEY_TI_CL7X_VERSION >= JSON_HEDLEY_VERSION_ENCODE(major, minor, patch)) +#else + #define JSON_HEDLEY_TI_CL7X_VERSION_CHECK(major,minor,patch) (0) +#endif + +#if defined(JSON_HEDLEY_TI_CLPRU_VERSION) + #undef JSON_HEDLEY_TI_CLPRU_VERSION +#endif +#if defined(__TI_COMPILER_VERSION__) && defined(__PRU__) + #define JSON_HEDLEY_TI_CLPRU_VERSION JSON_HEDLEY_VERSION_ENCODE(__TI_COMPILER_VERSION__ / 1000000, (__TI_COMPILER_VERSION__ % 1000000) / 1000, (__TI_COMPILER_VERSION__ % 1000)) +#endif + +#if defined(JSON_HEDLEY_TI_CLPRU_VERSION_CHECK) + #undef JSON_HEDLEY_TI_CLPRU_VERSION_CHECK +#endif +#if defined(JSON_HEDLEY_TI_CLPRU_VERSION) + #define JSON_HEDLEY_TI_CLPRU_VERSION_CHECK(major,minor,patch) (JSON_HEDLEY_TI_CLPRU_VERSION >= JSON_HEDLEY_VERSION_ENCODE(major, minor, patch)) +#else + #define JSON_HEDLEY_TI_CLPRU_VERSION_CHECK(major,minor,patch) (0) +#endif + +#if defined(JSON_HEDLEY_CRAY_VERSION) + #undef JSON_HEDLEY_CRAY_VERSION +#endif +#if defined(_CRAYC) + #if defined(_RELEASE_PATCHLEVEL) + #define JSON_HEDLEY_CRAY_VERSION JSON_HEDLEY_VERSION_ENCODE(_RELEASE_MAJOR, _RELEASE_MINOR, _RELEASE_PATCHLEVEL) + #else + #define JSON_HEDLEY_CRAY_VERSION JSON_HEDLEY_VERSION_ENCODE(_RELEASE_MAJOR, _RELEASE_MINOR, 0) + #endif +#endif + +#if defined(JSON_HEDLEY_CRAY_VERSION_CHECK) + #undef JSON_HEDLEY_CRAY_VERSION_CHECK +#endif +#if defined(JSON_HEDLEY_CRAY_VERSION) + #define JSON_HEDLEY_CRAY_VERSION_CHECK(major,minor,patch) (JSON_HEDLEY_CRAY_VERSION >= JSON_HEDLEY_VERSION_ENCODE(major, minor, patch)) +#else + #define JSON_HEDLEY_CRAY_VERSION_CHECK(major,minor,patch) (0) +#endif + +#if defined(JSON_HEDLEY_IAR_VERSION) + #undef JSON_HEDLEY_IAR_VERSION +#endif +#if defined(__IAR_SYSTEMS_ICC__) + #if __VER__ > 1000 + #define JSON_HEDLEY_IAR_VERSION JSON_HEDLEY_VERSION_ENCODE((__VER__ / 1000000), ((__VER__ / 1000) % 1000), (__VER__ % 1000)) + #else + #define JSON_HEDLEY_IAR_VERSION JSON_HEDLEY_VERSION_ENCODE(__VER__ / 100, __VER__ % 100, 0) + #endif +#endif + +#if defined(JSON_HEDLEY_IAR_VERSION_CHECK) + #undef JSON_HEDLEY_IAR_VERSION_CHECK +#endif +#if defined(JSON_HEDLEY_IAR_VERSION) + #define JSON_HEDLEY_IAR_VERSION_CHECK(major,minor,patch) (JSON_HEDLEY_IAR_VERSION >= JSON_HEDLEY_VERSION_ENCODE(major, minor, patch)) +#else + #define JSON_HEDLEY_IAR_VERSION_CHECK(major,minor,patch) (0) +#endif + +#if defined(JSON_HEDLEY_TINYC_VERSION) + #undef JSON_HEDLEY_TINYC_VERSION +#endif +#if defined(__TINYC__) + #define JSON_HEDLEY_TINYC_VERSION JSON_HEDLEY_VERSION_ENCODE(__TINYC__ / 1000, (__TINYC__ / 100) % 10, __TINYC__ % 100) +#endif + +#if defined(JSON_HEDLEY_TINYC_VERSION_CHECK) + #undef JSON_HEDLEY_TINYC_VERSION_CHECK +#endif +#if defined(JSON_HEDLEY_TINYC_VERSION) + #define JSON_HEDLEY_TINYC_VERSION_CHECK(major,minor,patch) (JSON_HEDLEY_TINYC_VERSION >= JSON_HEDLEY_VERSION_ENCODE(major, minor, patch)) +#else + #define JSON_HEDLEY_TINYC_VERSION_CHECK(major,minor,patch) (0) +#endif + +#if defined(JSON_HEDLEY_DMC_VERSION) + #undef JSON_HEDLEY_DMC_VERSION +#endif +#if defined(__DMC__) + #define JSON_HEDLEY_DMC_VERSION JSON_HEDLEY_VERSION_ENCODE(__DMC__ >> 8, (__DMC__ >> 4) & 0xf, __DMC__ & 0xf) +#endif + +#if defined(JSON_HEDLEY_DMC_VERSION_CHECK) + #undef JSON_HEDLEY_DMC_VERSION_CHECK +#endif +#if defined(JSON_HEDLEY_DMC_VERSION) + #define JSON_HEDLEY_DMC_VERSION_CHECK(major,minor,patch) (JSON_HEDLEY_DMC_VERSION >= JSON_HEDLEY_VERSION_ENCODE(major, minor, patch)) +#else + #define JSON_HEDLEY_DMC_VERSION_CHECK(major,minor,patch) (0) +#endif + +#if defined(JSON_HEDLEY_COMPCERT_VERSION) + #undef JSON_HEDLEY_COMPCERT_VERSION +#endif +#if defined(__COMPCERT_VERSION__) + #define JSON_HEDLEY_COMPCERT_VERSION JSON_HEDLEY_VERSION_ENCODE(__COMPCERT_VERSION__ / 10000, (__COMPCERT_VERSION__ / 100) % 100, __COMPCERT_VERSION__ % 100) +#endif + +#if defined(JSON_HEDLEY_COMPCERT_VERSION_CHECK) + #undef JSON_HEDLEY_COMPCERT_VERSION_CHECK +#endif +#if defined(JSON_HEDLEY_COMPCERT_VERSION) + #define JSON_HEDLEY_COMPCERT_VERSION_CHECK(major,minor,patch) (JSON_HEDLEY_COMPCERT_VERSION >= JSON_HEDLEY_VERSION_ENCODE(major, minor, patch)) +#else + #define JSON_HEDLEY_COMPCERT_VERSION_CHECK(major,minor,patch) (0) +#endif + +#if defined(JSON_HEDLEY_PELLES_VERSION) + #undef JSON_HEDLEY_PELLES_VERSION +#endif +#if defined(__POCC__) + #define JSON_HEDLEY_PELLES_VERSION JSON_HEDLEY_VERSION_ENCODE(__POCC__ / 100, __POCC__ % 100, 0) +#endif + +#if defined(JSON_HEDLEY_PELLES_VERSION_CHECK) + #undef JSON_HEDLEY_PELLES_VERSION_CHECK +#endif +#if defined(JSON_HEDLEY_PELLES_VERSION) + #define JSON_HEDLEY_PELLES_VERSION_CHECK(major,minor,patch) (JSON_HEDLEY_PELLES_VERSION >= JSON_HEDLEY_VERSION_ENCODE(major, minor, patch)) +#else + #define JSON_HEDLEY_PELLES_VERSION_CHECK(major,minor,patch) (0) +#endif + +#if defined(JSON_HEDLEY_MCST_LCC_VERSION) + #undef JSON_HEDLEY_MCST_LCC_VERSION +#endif +#if defined(__LCC__) && defined(__LCC_MINOR__) + #define JSON_HEDLEY_MCST_LCC_VERSION JSON_HEDLEY_VERSION_ENCODE(__LCC__ / 100, __LCC__ % 100, __LCC_MINOR__) +#endif + +#if defined(JSON_HEDLEY_MCST_LCC_VERSION_CHECK) + #undef JSON_HEDLEY_MCST_LCC_VERSION_CHECK +#endif +#if defined(JSON_HEDLEY_MCST_LCC_VERSION) + #define JSON_HEDLEY_MCST_LCC_VERSION_CHECK(major,minor,patch) (JSON_HEDLEY_MCST_LCC_VERSION >= JSON_HEDLEY_VERSION_ENCODE(major, minor, patch)) +#else + #define JSON_HEDLEY_MCST_LCC_VERSION_CHECK(major,minor,patch) (0) +#endif + +#if defined(JSON_HEDLEY_GCC_VERSION) + #undef JSON_HEDLEY_GCC_VERSION +#endif +#if \ + defined(JSON_HEDLEY_GNUC_VERSION) && \ + !defined(__clang__) && \ + !defined(JSON_HEDLEY_INTEL_VERSION) && \ + !defined(JSON_HEDLEY_PGI_VERSION) && \ + !defined(JSON_HEDLEY_ARM_VERSION) && \ + !defined(JSON_HEDLEY_CRAY_VERSION) && \ + !defined(JSON_HEDLEY_TI_VERSION) && \ + !defined(JSON_HEDLEY_TI_ARMCL_VERSION) && \ + !defined(JSON_HEDLEY_TI_CL430_VERSION) && \ + !defined(JSON_HEDLEY_TI_CL2000_VERSION) && \ + !defined(JSON_HEDLEY_TI_CL6X_VERSION) && \ + !defined(JSON_HEDLEY_TI_CL7X_VERSION) && \ + !defined(JSON_HEDLEY_TI_CLPRU_VERSION) && \ + !defined(__COMPCERT__) && \ + !defined(JSON_HEDLEY_MCST_LCC_VERSION) + #define JSON_HEDLEY_GCC_VERSION JSON_HEDLEY_GNUC_VERSION +#endif + +#if defined(JSON_HEDLEY_GCC_VERSION_CHECK) + #undef JSON_HEDLEY_GCC_VERSION_CHECK +#endif +#if defined(JSON_HEDLEY_GCC_VERSION) + #define JSON_HEDLEY_GCC_VERSION_CHECK(major,minor,patch) (JSON_HEDLEY_GCC_VERSION >= JSON_HEDLEY_VERSION_ENCODE(major, minor, patch)) +#else + #define JSON_HEDLEY_GCC_VERSION_CHECK(major,minor,patch) (0) +#endif + +#if defined(JSON_HEDLEY_HAS_ATTRIBUTE) + #undef JSON_HEDLEY_HAS_ATTRIBUTE +#endif +#if \ + defined(__has_attribute) && \ + ( \ + (!defined(JSON_HEDLEY_IAR_VERSION) || JSON_HEDLEY_IAR_VERSION_CHECK(8,5,9)) \ + ) +# define JSON_HEDLEY_HAS_ATTRIBUTE(attribute) __has_attribute(attribute) +#else +# define JSON_HEDLEY_HAS_ATTRIBUTE(attribute) (0) +#endif + +#if defined(JSON_HEDLEY_GNUC_HAS_ATTRIBUTE) + #undef JSON_HEDLEY_GNUC_HAS_ATTRIBUTE +#endif +#if defined(__has_attribute) + #define JSON_HEDLEY_GNUC_HAS_ATTRIBUTE(attribute,major,minor,patch) JSON_HEDLEY_HAS_ATTRIBUTE(attribute) +#else + #define JSON_HEDLEY_GNUC_HAS_ATTRIBUTE(attribute,major,minor,patch) JSON_HEDLEY_GNUC_VERSION_CHECK(major,minor,patch) +#endif + +#if defined(JSON_HEDLEY_GCC_HAS_ATTRIBUTE) + #undef JSON_HEDLEY_GCC_HAS_ATTRIBUTE +#endif +#if defined(__has_attribute) + #define JSON_HEDLEY_GCC_HAS_ATTRIBUTE(attribute,major,minor,patch) JSON_HEDLEY_HAS_ATTRIBUTE(attribute) +#else + #define JSON_HEDLEY_GCC_HAS_ATTRIBUTE(attribute,major,minor,patch) JSON_HEDLEY_GCC_VERSION_CHECK(major,minor,patch) +#endif + +#if defined(JSON_HEDLEY_HAS_CPP_ATTRIBUTE) + #undef JSON_HEDLEY_HAS_CPP_ATTRIBUTE +#endif +#if \ + defined(__has_cpp_attribute) && \ + defined(__cplusplus) && \ + (!defined(JSON_HEDLEY_SUNPRO_VERSION) || JSON_HEDLEY_SUNPRO_VERSION_CHECK(5,15,0)) + #define JSON_HEDLEY_HAS_CPP_ATTRIBUTE(attribute) __has_cpp_attribute(attribute) +#else + #define JSON_HEDLEY_HAS_CPP_ATTRIBUTE(attribute) (0) +#endif + +#if defined(JSON_HEDLEY_HAS_CPP_ATTRIBUTE_NS) + #undef JSON_HEDLEY_HAS_CPP_ATTRIBUTE_NS +#endif +#if !defined(__cplusplus) || !defined(__has_cpp_attribute) + #define JSON_HEDLEY_HAS_CPP_ATTRIBUTE_NS(ns,attribute) (0) +#elif \ + !defined(JSON_HEDLEY_PGI_VERSION) && \ + !defined(JSON_HEDLEY_IAR_VERSION) && \ + (!defined(JSON_HEDLEY_SUNPRO_VERSION) || JSON_HEDLEY_SUNPRO_VERSION_CHECK(5,15,0)) && \ + (!defined(JSON_HEDLEY_MSVC_VERSION) || JSON_HEDLEY_MSVC_VERSION_CHECK(19,20,0)) + #define JSON_HEDLEY_HAS_CPP_ATTRIBUTE_NS(ns,attribute) JSON_HEDLEY_HAS_CPP_ATTRIBUTE(ns::attribute) +#else + #define JSON_HEDLEY_HAS_CPP_ATTRIBUTE_NS(ns,attribute) (0) +#endif + +#if defined(JSON_HEDLEY_GNUC_HAS_CPP_ATTRIBUTE) + #undef JSON_HEDLEY_GNUC_HAS_CPP_ATTRIBUTE +#endif +#if defined(__has_cpp_attribute) && defined(__cplusplus) + #define JSON_HEDLEY_GNUC_HAS_CPP_ATTRIBUTE(attribute,major,minor,patch) __has_cpp_attribute(attribute) +#else + #define JSON_HEDLEY_GNUC_HAS_CPP_ATTRIBUTE(attribute,major,minor,patch) JSON_HEDLEY_GNUC_VERSION_CHECK(major,minor,patch) +#endif + +#if defined(JSON_HEDLEY_GCC_HAS_CPP_ATTRIBUTE) + #undef JSON_HEDLEY_GCC_HAS_CPP_ATTRIBUTE +#endif +#if defined(__has_cpp_attribute) && defined(__cplusplus) + #define JSON_HEDLEY_GCC_HAS_CPP_ATTRIBUTE(attribute,major,minor,patch) __has_cpp_attribute(attribute) +#else + #define JSON_HEDLEY_GCC_HAS_CPP_ATTRIBUTE(attribute,major,minor,patch) JSON_HEDLEY_GCC_VERSION_CHECK(major,minor,patch) +#endif + +#if defined(JSON_HEDLEY_HAS_BUILTIN) + #undef JSON_HEDLEY_HAS_BUILTIN +#endif +#if defined(__has_builtin) + #define JSON_HEDLEY_HAS_BUILTIN(builtin) __has_builtin(builtin) +#else + #define JSON_HEDLEY_HAS_BUILTIN(builtin) (0) +#endif + +#if defined(JSON_HEDLEY_GNUC_HAS_BUILTIN) + #undef JSON_HEDLEY_GNUC_HAS_BUILTIN +#endif +#if defined(__has_builtin) + #define JSON_HEDLEY_GNUC_HAS_BUILTIN(builtin,major,minor,patch) __has_builtin(builtin) +#else + #define JSON_HEDLEY_GNUC_HAS_BUILTIN(builtin,major,minor,patch) JSON_HEDLEY_GNUC_VERSION_CHECK(major,minor,patch) +#endif + +#if defined(JSON_HEDLEY_GCC_HAS_BUILTIN) + #undef JSON_HEDLEY_GCC_HAS_BUILTIN +#endif +#if defined(__has_builtin) + #define JSON_HEDLEY_GCC_HAS_BUILTIN(builtin,major,minor,patch) __has_builtin(builtin) +#else + #define JSON_HEDLEY_GCC_HAS_BUILTIN(builtin,major,minor,patch) JSON_HEDLEY_GCC_VERSION_CHECK(major,minor,patch) +#endif + +#if defined(JSON_HEDLEY_HAS_FEATURE) + #undef JSON_HEDLEY_HAS_FEATURE +#endif +#if defined(__has_feature) + #define JSON_HEDLEY_HAS_FEATURE(feature) __has_feature(feature) +#else + #define JSON_HEDLEY_HAS_FEATURE(feature) (0) +#endif + +#if defined(JSON_HEDLEY_GNUC_HAS_FEATURE) + #undef JSON_HEDLEY_GNUC_HAS_FEATURE +#endif +#if defined(__has_feature) + #define JSON_HEDLEY_GNUC_HAS_FEATURE(feature,major,minor,patch) __has_feature(feature) +#else + #define JSON_HEDLEY_GNUC_HAS_FEATURE(feature,major,minor,patch) JSON_HEDLEY_GNUC_VERSION_CHECK(major,minor,patch) +#endif + +#if defined(JSON_HEDLEY_GCC_HAS_FEATURE) + #undef JSON_HEDLEY_GCC_HAS_FEATURE +#endif +#if defined(__has_feature) + #define JSON_HEDLEY_GCC_HAS_FEATURE(feature,major,minor,patch) __has_feature(feature) +#else + #define JSON_HEDLEY_GCC_HAS_FEATURE(feature,major,minor,patch) JSON_HEDLEY_GCC_VERSION_CHECK(major,minor,patch) +#endif + +#if defined(JSON_HEDLEY_HAS_EXTENSION) + #undef JSON_HEDLEY_HAS_EXTENSION +#endif +#if defined(__has_extension) + #define JSON_HEDLEY_HAS_EXTENSION(extension) __has_extension(extension) +#else + #define JSON_HEDLEY_HAS_EXTENSION(extension) (0) +#endif + +#if defined(JSON_HEDLEY_GNUC_HAS_EXTENSION) + #undef JSON_HEDLEY_GNUC_HAS_EXTENSION +#endif +#if defined(__has_extension) + #define JSON_HEDLEY_GNUC_HAS_EXTENSION(extension,major,minor,patch) __has_extension(extension) +#else + #define JSON_HEDLEY_GNUC_HAS_EXTENSION(extension,major,minor,patch) JSON_HEDLEY_GNUC_VERSION_CHECK(major,minor,patch) +#endif + +#if defined(JSON_HEDLEY_GCC_HAS_EXTENSION) + #undef JSON_HEDLEY_GCC_HAS_EXTENSION +#endif +#if defined(__has_extension) + #define JSON_HEDLEY_GCC_HAS_EXTENSION(extension,major,minor,patch) __has_extension(extension) +#else + #define JSON_HEDLEY_GCC_HAS_EXTENSION(extension,major,minor,patch) JSON_HEDLEY_GCC_VERSION_CHECK(major,minor,patch) +#endif + +#if defined(JSON_HEDLEY_HAS_DECLSPEC_ATTRIBUTE) + #undef JSON_HEDLEY_HAS_DECLSPEC_ATTRIBUTE +#endif +#if defined(__has_declspec_attribute) + #define JSON_HEDLEY_HAS_DECLSPEC_ATTRIBUTE(attribute) __has_declspec_attribute(attribute) +#else + #define JSON_HEDLEY_HAS_DECLSPEC_ATTRIBUTE(attribute) (0) +#endif + +#if defined(JSON_HEDLEY_GNUC_HAS_DECLSPEC_ATTRIBUTE) + #undef JSON_HEDLEY_GNUC_HAS_DECLSPEC_ATTRIBUTE +#endif +#if defined(__has_declspec_attribute) + #define JSON_HEDLEY_GNUC_HAS_DECLSPEC_ATTRIBUTE(attribute,major,minor,patch) __has_declspec_attribute(attribute) +#else + #define JSON_HEDLEY_GNUC_HAS_DECLSPEC_ATTRIBUTE(attribute,major,minor,patch) JSON_HEDLEY_GNUC_VERSION_CHECK(major,minor,patch) +#endif + +#if defined(JSON_HEDLEY_GCC_HAS_DECLSPEC_ATTRIBUTE) + #undef JSON_HEDLEY_GCC_HAS_DECLSPEC_ATTRIBUTE +#endif +#if defined(__has_declspec_attribute) + #define JSON_HEDLEY_GCC_HAS_DECLSPEC_ATTRIBUTE(attribute,major,minor,patch) __has_declspec_attribute(attribute) +#else + #define JSON_HEDLEY_GCC_HAS_DECLSPEC_ATTRIBUTE(attribute,major,minor,patch) JSON_HEDLEY_GCC_VERSION_CHECK(major,minor,patch) +#endif + +#if defined(JSON_HEDLEY_HAS_WARNING) + #undef JSON_HEDLEY_HAS_WARNING +#endif +#if defined(__has_warning) + #define JSON_HEDLEY_HAS_WARNING(warning) __has_warning(warning) +#else + #define JSON_HEDLEY_HAS_WARNING(warning) (0) +#endif + +#if defined(JSON_HEDLEY_GNUC_HAS_WARNING) + #undef JSON_HEDLEY_GNUC_HAS_WARNING +#endif +#if defined(__has_warning) + #define JSON_HEDLEY_GNUC_HAS_WARNING(warning,major,minor,patch) __has_warning(warning) +#else + #define JSON_HEDLEY_GNUC_HAS_WARNING(warning,major,minor,patch) JSON_HEDLEY_GNUC_VERSION_CHECK(major,minor,patch) +#endif + +#if defined(JSON_HEDLEY_GCC_HAS_WARNING) + #undef JSON_HEDLEY_GCC_HAS_WARNING +#endif +#if defined(__has_warning) + #define JSON_HEDLEY_GCC_HAS_WARNING(warning,major,minor,patch) __has_warning(warning) +#else + #define JSON_HEDLEY_GCC_HAS_WARNING(warning,major,minor,patch) JSON_HEDLEY_GCC_VERSION_CHECK(major,minor,patch) +#endif + +#if \ + (defined(__STDC_VERSION__) && (__STDC_VERSION__ >= 199901L)) || \ + defined(__clang__) || \ + JSON_HEDLEY_GCC_VERSION_CHECK(3,0,0) || \ + JSON_HEDLEY_INTEL_VERSION_CHECK(13,0,0) || \ + JSON_HEDLEY_IAR_VERSION_CHECK(8,0,0) || \ + JSON_HEDLEY_PGI_VERSION_CHECK(18,4,0) || \ + JSON_HEDLEY_ARM_VERSION_CHECK(4,1,0) || \ + JSON_HEDLEY_TI_VERSION_CHECK(15,12,0) || \ + JSON_HEDLEY_TI_ARMCL_VERSION_CHECK(4,7,0) || \ + JSON_HEDLEY_TI_CL430_VERSION_CHECK(2,0,1) || \ + JSON_HEDLEY_TI_CL2000_VERSION_CHECK(6,1,0) || \ + JSON_HEDLEY_TI_CL6X_VERSION_CHECK(7,0,0) || \ + JSON_HEDLEY_TI_CL7X_VERSION_CHECK(1,2,0) || \ + JSON_HEDLEY_TI_CLPRU_VERSION_CHECK(2,1,0) || \ + JSON_HEDLEY_CRAY_VERSION_CHECK(5,0,0) || \ + JSON_HEDLEY_TINYC_VERSION_CHECK(0,9,17) || \ + JSON_HEDLEY_SUNPRO_VERSION_CHECK(8,0,0) || \ + (JSON_HEDLEY_IBM_VERSION_CHECK(10,1,0) && defined(__C99_PRAGMA_OPERATOR)) + #define JSON_HEDLEY_PRAGMA(value) _Pragma(#value) +#elif JSON_HEDLEY_MSVC_VERSION_CHECK(15,0,0) + #define JSON_HEDLEY_PRAGMA(value) __pragma(value) +#else + #define JSON_HEDLEY_PRAGMA(value) +#endif + +#if defined(JSON_HEDLEY_DIAGNOSTIC_PUSH) + #undef JSON_HEDLEY_DIAGNOSTIC_PUSH +#endif +#if defined(JSON_HEDLEY_DIAGNOSTIC_POP) + #undef JSON_HEDLEY_DIAGNOSTIC_POP +#endif +#if defined(__clang__) + #define JSON_HEDLEY_DIAGNOSTIC_PUSH _Pragma("clang diagnostic push") + #define JSON_HEDLEY_DIAGNOSTIC_POP _Pragma("clang diagnostic pop") +#elif JSON_HEDLEY_INTEL_VERSION_CHECK(13,0,0) + #define JSON_HEDLEY_DIAGNOSTIC_PUSH _Pragma("warning(push)") + #define JSON_HEDLEY_DIAGNOSTIC_POP _Pragma("warning(pop)") +#elif JSON_HEDLEY_GCC_VERSION_CHECK(4,6,0) + #define JSON_HEDLEY_DIAGNOSTIC_PUSH _Pragma("GCC diagnostic push") + #define JSON_HEDLEY_DIAGNOSTIC_POP _Pragma("GCC diagnostic pop") +#elif \ + JSON_HEDLEY_MSVC_VERSION_CHECK(15,0,0) || \ + JSON_HEDLEY_INTEL_CL_VERSION_CHECK(2021,1,0) + #define JSON_HEDLEY_DIAGNOSTIC_PUSH __pragma(warning(push)) + #define JSON_HEDLEY_DIAGNOSTIC_POP __pragma(warning(pop)) +#elif JSON_HEDLEY_ARM_VERSION_CHECK(5,6,0) + #define JSON_HEDLEY_DIAGNOSTIC_PUSH _Pragma("push") + #define JSON_HEDLEY_DIAGNOSTIC_POP _Pragma("pop") +#elif \ + JSON_HEDLEY_TI_VERSION_CHECK(15,12,0) || \ + JSON_HEDLEY_TI_ARMCL_VERSION_CHECK(5,2,0) || \ + JSON_HEDLEY_TI_CL430_VERSION_CHECK(4,4,0) || \ + JSON_HEDLEY_TI_CL6X_VERSION_CHECK(8,1,0) || \ + JSON_HEDLEY_TI_CL7X_VERSION_CHECK(1,2,0) || \ + JSON_HEDLEY_TI_CLPRU_VERSION_CHECK(2,1,0) + #define JSON_HEDLEY_DIAGNOSTIC_PUSH _Pragma("diag_push") + #define JSON_HEDLEY_DIAGNOSTIC_POP _Pragma("diag_pop") +#elif JSON_HEDLEY_PELLES_VERSION_CHECK(2,90,0) + #define JSON_HEDLEY_DIAGNOSTIC_PUSH _Pragma("warning(push)") + #define JSON_HEDLEY_DIAGNOSTIC_POP _Pragma("warning(pop)") +#else + #define JSON_HEDLEY_DIAGNOSTIC_PUSH + #define JSON_HEDLEY_DIAGNOSTIC_POP +#endif + +/* JSON_HEDLEY_DIAGNOSTIC_DISABLE_CPP98_COMPAT_WRAP_ is for + HEDLEY INTERNAL USE ONLY. API subject to change without notice. */ +#if defined(JSON_HEDLEY_DIAGNOSTIC_DISABLE_CPP98_COMPAT_WRAP_) + #undef JSON_HEDLEY_DIAGNOSTIC_DISABLE_CPP98_COMPAT_WRAP_ +#endif +#if defined(__cplusplus) +# if JSON_HEDLEY_HAS_WARNING("-Wc++98-compat") +# if JSON_HEDLEY_HAS_WARNING("-Wc++17-extensions") +# if JSON_HEDLEY_HAS_WARNING("-Wc++1z-extensions") +# define JSON_HEDLEY_DIAGNOSTIC_DISABLE_CPP98_COMPAT_WRAP_(xpr) \ + JSON_HEDLEY_DIAGNOSTIC_PUSH \ + _Pragma("clang diagnostic ignored \"-Wc++98-compat\"") \ + _Pragma("clang diagnostic ignored \"-Wc++17-extensions\"") \ + _Pragma("clang diagnostic ignored \"-Wc++1z-extensions\"") \ + xpr \ + JSON_HEDLEY_DIAGNOSTIC_POP +# else +# define JSON_HEDLEY_DIAGNOSTIC_DISABLE_CPP98_COMPAT_WRAP_(xpr) \ + JSON_HEDLEY_DIAGNOSTIC_PUSH \ + _Pragma("clang diagnostic ignored \"-Wc++98-compat\"") \ + _Pragma("clang diagnostic ignored \"-Wc++17-extensions\"") \ + xpr \ + JSON_HEDLEY_DIAGNOSTIC_POP +# endif +# else +# define JSON_HEDLEY_DIAGNOSTIC_DISABLE_CPP98_COMPAT_WRAP_(xpr) \ + JSON_HEDLEY_DIAGNOSTIC_PUSH \ + _Pragma("clang diagnostic ignored \"-Wc++98-compat\"") \ + xpr \ + JSON_HEDLEY_DIAGNOSTIC_POP +# endif +# endif +#endif +#if !defined(JSON_HEDLEY_DIAGNOSTIC_DISABLE_CPP98_COMPAT_WRAP_) + #define JSON_HEDLEY_DIAGNOSTIC_DISABLE_CPP98_COMPAT_WRAP_(x) x +#endif + +#if defined(JSON_HEDLEY_CONST_CAST) + #undef JSON_HEDLEY_CONST_CAST +#endif +#if defined(__cplusplus) +# define JSON_HEDLEY_CONST_CAST(T, expr) (const_cast(expr)) +#elif \ + JSON_HEDLEY_HAS_WARNING("-Wcast-qual") || \ + JSON_HEDLEY_GCC_VERSION_CHECK(4,6,0) || \ + JSON_HEDLEY_INTEL_VERSION_CHECK(13,0,0) +# define JSON_HEDLEY_CONST_CAST(T, expr) (__extension__ ({ \ + JSON_HEDLEY_DIAGNOSTIC_PUSH \ + JSON_HEDLEY_DIAGNOSTIC_DISABLE_CAST_QUAL \ + ((T) (expr)); \ + JSON_HEDLEY_DIAGNOSTIC_POP \ + })) +#else +# define JSON_HEDLEY_CONST_CAST(T, expr) ((T) (expr)) +#endif + +#if defined(JSON_HEDLEY_REINTERPRET_CAST) + #undef JSON_HEDLEY_REINTERPRET_CAST +#endif +#if defined(__cplusplus) + #define JSON_HEDLEY_REINTERPRET_CAST(T, expr) (reinterpret_cast(expr)) +#else + #define JSON_HEDLEY_REINTERPRET_CAST(T, expr) ((T) (expr)) +#endif + +#if defined(JSON_HEDLEY_STATIC_CAST) + #undef JSON_HEDLEY_STATIC_CAST +#endif +#if defined(__cplusplus) + #define JSON_HEDLEY_STATIC_CAST(T, expr) (static_cast(expr)) +#else + #define JSON_HEDLEY_STATIC_CAST(T, expr) ((T) (expr)) +#endif + +#if defined(JSON_HEDLEY_CPP_CAST) + #undef JSON_HEDLEY_CPP_CAST +#endif +#if defined(__cplusplus) +# if JSON_HEDLEY_HAS_WARNING("-Wold-style-cast") +# define JSON_HEDLEY_CPP_CAST(T, expr) \ + JSON_HEDLEY_DIAGNOSTIC_PUSH \ + _Pragma("clang diagnostic ignored \"-Wold-style-cast\"") \ + ((T) (expr)) \ + JSON_HEDLEY_DIAGNOSTIC_POP +# elif JSON_HEDLEY_IAR_VERSION_CHECK(8,3,0) +# define JSON_HEDLEY_CPP_CAST(T, expr) \ + JSON_HEDLEY_DIAGNOSTIC_PUSH \ + _Pragma("diag_suppress=Pe137") \ + JSON_HEDLEY_DIAGNOSTIC_POP +# else +# define JSON_HEDLEY_CPP_CAST(T, expr) ((T) (expr)) +# endif +#else +# define JSON_HEDLEY_CPP_CAST(T, expr) (expr) +#endif + +#if defined(JSON_HEDLEY_DIAGNOSTIC_DISABLE_DEPRECATED) + #undef JSON_HEDLEY_DIAGNOSTIC_DISABLE_DEPRECATED +#endif +#if JSON_HEDLEY_HAS_WARNING("-Wdeprecated-declarations") + #define JSON_HEDLEY_DIAGNOSTIC_DISABLE_DEPRECATED _Pragma("clang diagnostic ignored \"-Wdeprecated-declarations\"") +#elif JSON_HEDLEY_INTEL_VERSION_CHECK(13,0,0) + #define JSON_HEDLEY_DIAGNOSTIC_DISABLE_DEPRECATED _Pragma("warning(disable:1478 1786)") +#elif JSON_HEDLEY_INTEL_CL_VERSION_CHECK(2021,1,0) + #define JSON_HEDLEY_DIAGNOSTIC_DISABLE_DEPRECATED __pragma(warning(disable:1478 1786)) +#elif JSON_HEDLEY_PGI_VERSION_CHECK(20,7,0) + #define JSON_HEDLEY_DIAGNOSTIC_DISABLE_DEPRECATED _Pragma("diag_suppress 1215,1216,1444,1445") +#elif JSON_HEDLEY_PGI_VERSION_CHECK(17,10,0) + #define JSON_HEDLEY_DIAGNOSTIC_DISABLE_DEPRECATED _Pragma("diag_suppress 1215,1444") +#elif JSON_HEDLEY_GCC_VERSION_CHECK(4,3,0) + #define JSON_HEDLEY_DIAGNOSTIC_DISABLE_DEPRECATED _Pragma("GCC diagnostic ignored \"-Wdeprecated-declarations\"") +#elif JSON_HEDLEY_MSVC_VERSION_CHECK(15,0,0) + #define JSON_HEDLEY_DIAGNOSTIC_DISABLE_DEPRECATED __pragma(warning(disable:4996)) +#elif JSON_HEDLEY_MCST_LCC_VERSION_CHECK(1,25,10) + #define JSON_HEDLEY_DIAGNOSTIC_DISABLE_DEPRECATED _Pragma("diag_suppress 1215,1444") +#elif \ + JSON_HEDLEY_TI_VERSION_CHECK(15,12,0) || \ + (JSON_HEDLEY_TI_ARMCL_VERSION_CHECK(4,8,0) && defined(__TI_GNU_ATTRIBUTE_SUPPORT__)) || \ + JSON_HEDLEY_TI_ARMCL_VERSION_CHECK(5,2,0) || \ + (JSON_HEDLEY_TI_CL2000_VERSION_CHECK(6,0,0) && defined(__TI_GNU_ATTRIBUTE_SUPPORT__)) || \ + JSON_HEDLEY_TI_CL2000_VERSION_CHECK(6,4,0) || \ + (JSON_HEDLEY_TI_CL430_VERSION_CHECK(4,0,0) && defined(__TI_GNU_ATTRIBUTE_SUPPORT__)) || \ + JSON_HEDLEY_TI_CL430_VERSION_CHECK(4,3,0) || \ + (JSON_HEDLEY_TI_CL6X_VERSION_CHECK(7,2,0) && defined(__TI_GNU_ATTRIBUTE_SUPPORT__)) || \ + JSON_HEDLEY_TI_CL6X_VERSION_CHECK(7,5,0) || \ + JSON_HEDLEY_TI_CL7X_VERSION_CHECK(1,2,0) || \ + JSON_HEDLEY_TI_CLPRU_VERSION_CHECK(2,1,0) + #define JSON_HEDLEY_DIAGNOSTIC_DISABLE_DEPRECATED _Pragma("diag_suppress 1291,1718") +#elif JSON_HEDLEY_SUNPRO_VERSION_CHECK(5,13,0) && !defined(__cplusplus) + #define JSON_HEDLEY_DIAGNOSTIC_DISABLE_DEPRECATED _Pragma("error_messages(off,E_DEPRECATED_ATT,E_DEPRECATED_ATT_MESS)") +#elif JSON_HEDLEY_SUNPRO_VERSION_CHECK(5,13,0) && defined(__cplusplus) + #define JSON_HEDLEY_DIAGNOSTIC_DISABLE_DEPRECATED _Pragma("error_messages(off,symdeprecated,symdeprecated2)") +#elif JSON_HEDLEY_IAR_VERSION_CHECK(8,0,0) + #define JSON_HEDLEY_DIAGNOSTIC_DISABLE_DEPRECATED _Pragma("diag_suppress=Pe1444,Pe1215") +#elif JSON_HEDLEY_PELLES_VERSION_CHECK(2,90,0) + #define JSON_HEDLEY_DIAGNOSTIC_DISABLE_DEPRECATED _Pragma("warn(disable:2241)") +#else + #define JSON_HEDLEY_DIAGNOSTIC_DISABLE_DEPRECATED +#endif + +#if defined(JSON_HEDLEY_DIAGNOSTIC_DISABLE_UNKNOWN_PRAGMAS) + #undef JSON_HEDLEY_DIAGNOSTIC_DISABLE_UNKNOWN_PRAGMAS +#endif +#if JSON_HEDLEY_HAS_WARNING("-Wunknown-pragmas") + #define JSON_HEDLEY_DIAGNOSTIC_DISABLE_UNKNOWN_PRAGMAS _Pragma("clang diagnostic ignored \"-Wunknown-pragmas\"") +#elif JSON_HEDLEY_INTEL_VERSION_CHECK(13,0,0) + #define JSON_HEDLEY_DIAGNOSTIC_DISABLE_UNKNOWN_PRAGMAS _Pragma("warning(disable:161)") +#elif JSON_HEDLEY_INTEL_CL_VERSION_CHECK(2021,1,0) + #define JSON_HEDLEY_DIAGNOSTIC_DISABLE_UNKNOWN_PRAGMAS __pragma(warning(disable:161)) +#elif JSON_HEDLEY_PGI_VERSION_CHECK(17,10,0) + #define JSON_HEDLEY_DIAGNOSTIC_DISABLE_UNKNOWN_PRAGMAS _Pragma("diag_suppress 1675") +#elif JSON_HEDLEY_GCC_VERSION_CHECK(4,3,0) + #define JSON_HEDLEY_DIAGNOSTIC_DISABLE_UNKNOWN_PRAGMAS _Pragma("GCC diagnostic ignored \"-Wunknown-pragmas\"") +#elif JSON_HEDLEY_MSVC_VERSION_CHECK(15,0,0) + #define JSON_HEDLEY_DIAGNOSTIC_DISABLE_UNKNOWN_PRAGMAS __pragma(warning(disable:4068)) +#elif \ + JSON_HEDLEY_TI_VERSION_CHECK(16,9,0) || \ + JSON_HEDLEY_TI_CL6X_VERSION_CHECK(8,0,0) || \ + JSON_HEDLEY_TI_CL7X_VERSION_CHECK(1,2,0) || \ + JSON_HEDLEY_TI_CLPRU_VERSION_CHECK(2,3,0) + #define JSON_HEDLEY_DIAGNOSTIC_DISABLE_UNKNOWN_PRAGMAS _Pragma("diag_suppress 163") +#elif JSON_HEDLEY_TI_CL6X_VERSION_CHECK(8,0,0) + #define JSON_HEDLEY_DIAGNOSTIC_DISABLE_UNKNOWN_PRAGMAS _Pragma("diag_suppress 163") +#elif JSON_HEDLEY_IAR_VERSION_CHECK(8,0,0) + #define JSON_HEDLEY_DIAGNOSTIC_DISABLE_UNKNOWN_PRAGMAS _Pragma("diag_suppress=Pe161") +#elif JSON_HEDLEY_MCST_LCC_VERSION_CHECK(1,25,10) + #define JSON_HEDLEY_DIAGNOSTIC_DISABLE_UNKNOWN_PRAGMAS _Pragma("diag_suppress 161") +#else + #define JSON_HEDLEY_DIAGNOSTIC_DISABLE_UNKNOWN_PRAGMAS +#endif + +#if defined(JSON_HEDLEY_DIAGNOSTIC_DISABLE_UNKNOWN_CPP_ATTRIBUTES) + #undef JSON_HEDLEY_DIAGNOSTIC_DISABLE_UNKNOWN_CPP_ATTRIBUTES +#endif +#if JSON_HEDLEY_HAS_WARNING("-Wunknown-attributes") + #define JSON_HEDLEY_DIAGNOSTIC_DISABLE_UNKNOWN_CPP_ATTRIBUTES _Pragma("clang diagnostic ignored \"-Wunknown-attributes\"") +#elif JSON_HEDLEY_GCC_VERSION_CHECK(4,6,0) + #define JSON_HEDLEY_DIAGNOSTIC_DISABLE_UNKNOWN_CPP_ATTRIBUTES _Pragma("GCC diagnostic ignored \"-Wdeprecated-declarations\"") +#elif JSON_HEDLEY_INTEL_VERSION_CHECK(17,0,0) + #define JSON_HEDLEY_DIAGNOSTIC_DISABLE_UNKNOWN_CPP_ATTRIBUTES _Pragma("warning(disable:1292)") +#elif JSON_HEDLEY_INTEL_CL_VERSION_CHECK(2021,1,0) + #define JSON_HEDLEY_DIAGNOSTIC_DISABLE_UNKNOWN_CPP_ATTRIBUTES __pragma(warning(disable:1292)) +#elif JSON_HEDLEY_MSVC_VERSION_CHECK(19,0,0) + #define JSON_HEDLEY_DIAGNOSTIC_DISABLE_UNKNOWN_CPP_ATTRIBUTES __pragma(warning(disable:5030)) +#elif JSON_HEDLEY_PGI_VERSION_CHECK(20,7,0) + #define JSON_HEDLEY_DIAGNOSTIC_DISABLE_UNKNOWN_CPP_ATTRIBUTES _Pragma("diag_suppress 1097,1098") +#elif JSON_HEDLEY_PGI_VERSION_CHECK(17,10,0) + #define JSON_HEDLEY_DIAGNOSTIC_DISABLE_UNKNOWN_CPP_ATTRIBUTES _Pragma("diag_suppress 1097") +#elif JSON_HEDLEY_SUNPRO_VERSION_CHECK(5,14,0) && defined(__cplusplus) + #define JSON_HEDLEY_DIAGNOSTIC_DISABLE_UNKNOWN_CPP_ATTRIBUTES _Pragma("error_messages(off,attrskipunsup)") +#elif \ + JSON_HEDLEY_TI_VERSION_CHECK(18,1,0) || \ + JSON_HEDLEY_TI_CL6X_VERSION_CHECK(8,3,0) || \ + JSON_HEDLEY_TI_CL7X_VERSION_CHECK(1,2,0) + #define JSON_HEDLEY_DIAGNOSTIC_DISABLE_UNKNOWN_CPP_ATTRIBUTES _Pragma("diag_suppress 1173") +#elif JSON_HEDLEY_IAR_VERSION_CHECK(8,0,0) + #define JSON_HEDLEY_DIAGNOSTIC_DISABLE_UNKNOWN_CPP_ATTRIBUTES _Pragma("diag_suppress=Pe1097") +#elif JSON_HEDLEY_MCST_LCC_VERSION_CHECK(1,25,10) + #define JSON_HEDLEY_DIAGNOSTIC_DISABLE_UNKNOWN_CPP_ATTRIBUTES _Pragma("diag_suppress 1097") +#else + #define JSON_HEDLEY_DIAGNOSTIC_DISABLE_UNKNOWN_CPP_ATTRIBUTES +#endif + +#if defined(JSON_HEDLEY_DIAGNOSTIC_DISABLE_CAST_QUAL) + #undef JSON_HEDLEY_DIAGNOSTIC_DISABLE_CAST_QUAL +#endif +#if JSON_HEDLEY_HAS_WARNING("-Wcast-qual") + #define JSON_HEDLEY_DIAGNOSTIC_DISABLE_CAST_QUAL _Pragma("clang diagnostic ignored \"-Wcast-qual\"") +#elif JSON_HEDLEY_INTEL_VERSION_CHECK(13,0,0) + #define JSON_HEDLEY_DIAGNOSTIC_DISABLE_CAST_QUAL _Pragma("warning(disable:2203 2331)") +#elif JSON_HEDLEY_GCC_VERSION_CHECK(3,0,0) + #define JSON_HEDLEY_DIAGNOSTIC_DISABLE_CAST_QUAL _Pragma("GCC diagnostic ignored \"-Wcast-qual\"") +#else + #define JSON_HEDLEY_DIAGNOSTIC_DISABLE_CAST_QUAL +#endif + +#if defined(JSON_HEDLEY_DIAGNOSTIC_DISABLE_UNUSED_FUNCTION) + #undef JSON_HEDLEY_DIAGNOSTIC_DISABLE_UNUSED_FUNCTION +#endif +#if JSON_HEDLEY_HAS_WARNING("-Wunused-function") + #define JSON_HEDLEY_DIAGNOSTIC_DISABLE_UNUSED_FUNCTION _Pragma("clang diagnostic ignored \"-Wunused-function\"") +#elif JSON_HEDLEY_GCC_VERSION_CHECK(3,4,0) + #define JSON_HEDLEY_DIAGNOSTIC_DISABLE_UNUSED_FUNCTION _Pragma("GCC diagnostic ignored \"-Wunused-function\"") +#elif JSON_HEDLEY_MSVC_VERSION_CHECK(1,0,0) + #define JSON_HEDLEY_DIAGNOSTIC_DISABLE_UNUSED_FUNCTION __pragma(warning(disable:4505)) +#elif JSON_HEDLEY_MCST_LCC_VERSION_CHECK(1,25,10) + #define JSON_HEDLEY_DIAGNOSTIC_DISABLE_UNUSED_FUNCTION _Pragma("diag_suppress 3142") +#else + #define JSON_HEDLEY_DIAGNOSTIC_DISABLE_UNUSED_FUNCTION +#endif + +#if defined(JSON_HEDLEY_DEPRECATED) + #undef JSON_HEDLEY_DEPRECATED +#endif +#if defined(JSON_HEDLEY_DEPRECATED_FOR) + #undef JSON_HEDLEY_DEPRECATED_FOR +#endif +#if \ + JSON_HEDLEY_MSVC_VERSION_CHECK(14,0,0) || \ + JSON_HEDLEY_INTEL_CL_VERSION_CHECK(2021,1,0) + #define JSON_HEDLEY_DEPRECATED(since) __declspec(deprecated("Since " # since)) + #define JSON_HEDLEY_DEPRECATED_FOR(since, replacement) __declspec(deprecated("Since " #since "; use " #replacement)) +#elif \ + (JSON_HEDLEY_HAS_EXTENSION(attribute_deprecated_with_message) && !defined(JSON_HEDLEY_IAR_VERSION)) || \ + JSON_HEDLEY_GCC_VERSION_CHECK(4,5,0) || \ + JSON_HEDLEY_INTEL_VERSION_CHECK(13,0,0) || \ + JSON_HEDLEY_ARM_VERSION_CHECK(5,6,0) || \ + JSON_HEDLEY_SUNPRO_VERSION_CHECK(5,13,0) || \ + JSON_HEDLEY_PGI_VERSION_CHECK(17,10,0) || \ + JSON_HEDLEY_TI_VERSION_CHECK(18,1,0) || \ + JSON_HEDLEY_TI_ARMCL_VERSION_CHECK(18,1,0) || \ + JSON_HEDLEY_TI_CL6X_VERSION_CHECK(8,3,0) || \ + JSON_HEDLEY_TI_CL7X_VERSION_CHECK(1,2,0) || \ + JSON_HEDLEY_TI_CLPRU_VERSION_CHECK(2,3,0) || \ + JSON_HEDLEY_MCST_LCC_VERSION_CHECK(1,25,10) + #define JSON_HEDLEY_DEPRECATED(since) __attribute__((__deprecated__("Since " #since))) + #define JSON_HEDLEY_DEPRECATED_FOR(since, replacement) __attribute__((__deprecated__("Since " #since "; use " #replacement))) +#elif defined(__cplusplus) && (__cplusplus >= 201402L) + #define JSON_HEDLEY_DEPRECATED(since) JSON_HEDLEY_DIAGNOSTIC_DISABLE_CPP98_COMPAT_WRAP_([[deprecated("Since " #since)]]) + #define JSON_HEDLEY_DEPRECATED_FOR(since, replacement) JSON_HEDLEY_DIAGNOSTIC_DISABLE_CPP98_COMPAT_WRAP_([[deprecated("Since " #since "; use " #replacement)]]) +#elif \ + JSON_HEDLEY_HAS_ATTRIBUTE(deprecated) || \ + JSON_HEDLEY_GCC_VERSION_CHECK(3,1,0) || \ + JSON_HEDLEY_ARM_VERSION_CHECK(4,1,0) || \ + JSON_HEDLEY_TI_VERSION_CHECK(15,12,0) || \ + (JSON_HEDLEY_TI_ARMCL_VERSION_CHECK(4,8,0) && defined(__TI_GNU_ATTRIBUTE_SUPPORT__)) || \ + JSON_HEDLEY_TI_ARMCL_VERSION_CHECK(5,2,0) || \ + (JSON_HEDLEY_TI_CL2000_VERSION_CHECK(6,0,0) && defined(__TI_GNU_ATTRIBUTE_SUPPORT__)) || \ + JSON_HEDLEY_TI_CL2000_VERSION_CHECK(6,4,0) || \ + (JSON_HEDLEY_TI_CL430_VERSION_CHECK(4,0,0) && defined(__TI_GNU_ATTRIBUTE_SUPPORT__)) || \ + JSON_HEDLEY_TI_CL430_VERSION_CHECK(4,3,0) || \ + (JSON_HEDLEY_TI_CL6X_VERSION_CHECK(7,2,0) && defined(__TI_GNU_ATTRIBUTE_SUPPORT__)) || \ + JSON_HEDLEY_TI_CL6X_VERSION_CHECK(7,5,0) || \ + JSON_HEDLEY_TI_CL7X_VERSION_CHECK(1,2,0) || \ + JSON_HEDLEY_TI_CLPRU_VERSION_CHECK(2,1,0) || \ + JSON_HEDLEY_MCST_LCC_VERSION_CHECK(1,25,10) || \ + JSON_HEDLEY_IAR_VERSION_CHECK(8,10,0) + #define JSON_HEDLEY_DEPRECATED(since) __attribute__((__deprecated__)) + #define JSON_HEDLEY_DEPRECATED_FOR(since, replacement) __attribute__((__deprecated__)) +#elif \ + JSON_HEDLEY_MSVC_VERSION_CHECK(13,10,0) || \ + JSON_HEDLEY_PELLES_VERSION_CHECK(6,50,0) || \ + JSON_HEDLEY_INTEL_CL_VERSION_CHECK(2021,1,0) + #define JSON_HEDLEY_DEPRECATED(since) __declspec(deprecated) + #define JSON_HEDLEY_DEPRECATED_FOR(since, replacement) __declspec(deprecated) +#elif JSON_HEDLEY_IAR_VERSION_CHECK(8,0,0) + #define JSON_HEDLEY_DEPRECATED(since) _Pragma("deprecated") + #define JSON_HEDLEY_DEPRECATED_FOR(since, replacement) _Pragma("deprecated") +#else + #define JSON_HEDLEY_DEPRECATED(since) + #define JSON_HEDLEY_DEPRECATED_FOR(since, replacement) +#endif + +#if defined(JSON_HEDLEY_UNAVAILABLE) + #undef JSON_HEDLEY_UNAVAILABLE +#endif +#if \ + JSON_HEDLEY_HAS_ATTRIBUTE(warning) || \ + JSON_HEDLEY_GCC_VERSION_CHECK(4,3,0) || \ + JSON_HEDLEY_INTEL_VERSION_CHECK(13,0,0) || \ + JSON_HEDLEY_MCST_LCC_VERSION_CHECK(1,25,10) + #define JSON_HEDLEY_UNAVAILABLE(available_since) __attribute__((__warning__("Not available until " #available_since))) +#else + #define JSON_HEDLEY_UNAVAILABLE(available_since) +#endif + +#if defined(JSON_HEDLEY_WARN_UNUSED_RESULT) + #undef JSON_HEDLEY_WARN_UNUSED_RESULT +#endif +#if defined(JSON_HEDLEY_WARN_UNUSED_RESULT_MSG) + #undef JSON_HEDLEY_WARN_UNUSED_RESULT_MSG +#endif +#if \ + JSON_HEDLEY_HAS_ATTRIBUTE(warn_unused_result) || \ + JSON_HEDLEY_GCC_VERSION_CHECK(3,4,0) || \ + JSON_HEDLEY_INTEL_VERSION_CHECK(13,0,0) || \ + JSON_HEDLEY_TI_VERSION_CHECK(15,12,0) || \ + (JSON_HEDLEY_TI_ARMCL_VERSION_CHECK(4,8,0) && defined(__TI_GNU_ATTRIBUTE_SUPPORT__)) || \ + JSON_HEDLEY_TI_ARMCL_VERSION_CHECK(5,2,0) || \ + (JSON_HEDLEY_TI_CL2000_VERSION_CHECK(6,0,0) && defined(__TI_GNU_ATTRIBUTE_SUPPORT__)) || \ + JSON_HEDLEY_TI_CL2000_VERSION_CHECK(6,4,0) || \ + (JSON_HEDLEY_TI_CL430_VERSION_CHECK(4,0,0) && defined(__TI_GNU_ATTRIBUTE_SUPPORT__)) || \ + JSON_HEDLEY_TI_CL430_VERSION_CHECK(4,3,0) || \ + (JSON_HEDLEY_TI_CL6X_VERSION_CHECK(7,2,0) && defined(__TI_GNU_ATTRIBUTE_SUPPORT__)) || \ + JSON_HEDLEY_TI_CL6X_VERSION_CHECK(7,5,0) || \ + JSON_HEDLEY_TI_CL7X_VERSION_CHECK(1,2,0) || \ + JSON_HEDLEY_TI_CLPRU_VERSION_CHECK(2,1,0) || \ + (JSON_HEDLEY_SUNPRO_VERSION_CHECK(5,15,0) && defined(__cplusplus)) || \ + JSON_HEDLEY_PGI_VERSION_CHECK(17,10,0) || \ + JSON_HEDLEY_MCST_LCC_VERSION_CHECK(1,25,10) + #define JSON_HEDLEY_WARN_UNUSED_RESULT __attribute__((__warn_unused_result__)) + #define JSON_HEDLEY_WARN_UNUSED_RESULT_MSG(msg) __attribute__((__warn_unused_result__)) +#elif (JSON_HEDLEY_HAS_CPP_ATTRIBUTE(nodiscard) >= 201907L) + #define JSON_HEDLEY_WARN_UNUSED_RESULT JSON_HEDLEY_DIAGNOSTIC_DISABLE_CPP98_COMPAT_WRAP_([[nodiscard]]) + #define JSON_HEDLEY_WARN_UNUSED_RESULT_MSG(msg) JSON_HEDLEY_DIAGNOSTIC_DISABLE_CPP98_COMPAT_WRAP_([[nodiscard(msg)]]) +#elif JSON_HEDLEY_HAS_CPP_ATTRIBUTE(nodiscard) + #define JSON_HEDLEY_WARN_UNUSED_RESULT JSON_HEDLEY_DIAGNOSTIC_DISABLE_CPP98_COMPAT_WRAP_([[nodiscard]]) + #define JSON_HEDLEY_WARN_UNUSED_RESULT_MSG(msg) JSON_HEDLEY_DIAGNOSTIC_DISABLE_CPP98_COMPAT_WRAP_([[nodiscard]]) +#elif defined(_Check_return_) /* SAL */ + #define JSON_HEDLEY_WARN_UNUSED_RESULT _Check_return_ + #define JSON_HEDLEY_WARN_UNUSED_RESULT_MSG(msg) _Check_return_ +#else + #define JSON_HEDLEY_WARN_UNUSED_RESULT + #define JSON_HEDLEY_WARN_UNUSED_RESULT_MSG(msg) +#endif + +#if defined(JSON_HEDLEY_SENTINEL) + #undef JSON_HEDLEY_SENTINEL +#endif +#if \ + JSON_HEDLEY_HAS_ATTRIBUTE(sentinel) || \ + JSON_HEDLEY_GCC_VERSION_CHECK(4,0,0) || \ + JSON_HEDLEY_INTEL_VERSION_CHECK(13,0,0) || \ + JSON_HEDLEY_ARM_VERSION_CHECK(5,4,0) || \ + JSON_HEDLEY_MCST_LCC_VERSION_CHECK(1,25,10) + #define JSON_HEDLEY_SENTINEL(position) __attribute__((__sentinel__(position))) +#else + #define JSON_HEDLEY_SENTINEL(position) +#endif + +#if defined(JSON_HEDLEY_NO_RETURN) + #undef JSON_HEDLEY_NO_RETURN +#endif +#if JSON_HEDLEY_IAR_VERSION_CHECK(8,0,0) + #define JSON_HEDLEY_NO_RETURN __noreturn +#elif \ + JSON_HEDLEY_INTEL_VERSION_CHECK(13,0,0) || \ + JSON_HEDLEY_MCST_LCC_VERSION_CHECK(1,25,10) + #define JSON_HEDLEY_NO_RETURN __attribute__((__noreturn__)) +#elif defined(__STDC_VERSION__) && __STDC_VERSION__ >= 201112L + #define JSON_HEDLEY_NO_RETURN _Noreturn +#elif defined(__cplusplus) && (__cplusplus >= 201103L) + #define JSON_HEDLEY_NO_RETURN JSON_HEDLEY_DIAGNOSTIC_DISABLE_CPP98_COMPAT_WRAP_([[noreturn]]) +#elif \ + JSON_HEDLEY_HAS_ATTRIBUTE(noreturn) || \ + JSON_HEDLEY_GCC_VERSION_CHECK(3,2,0) || \ + JSON_HEDLEY_SUNPRO_VERSION_CHECK(5,11,0) || \ + JSON_HEDLEY_ARM_VERSION_CHECK(4,1,0) || \ + JSON_HEDLEY_IBM_VERSION_CHECK(10,1,0) || \ + JSON_HEDLEY_TI_VERSION_CHECK(15,12,0) || \ + (JSON_HEDLEY_TI_ARMCL_VERSION_CHECK(4,8,0) && defined(__TI_GNU_ATTRIBUTE_SUPPORT__)) || \ + JSON_HEDLEY_TI_ARMCL_VERSION_CHECK(5,2,0) || \ + (JSON_HEDLEY_TI_CL2000_VERSION_CHECK(6,0,0) && defined(__TI_GNU_ATTRIBUTE_SUPPORT__)) || \ + JSON_HEDLEY_TI_CL2000_VERSION_CHECK(6,4,0) || \ + (JSON_HEDLEY_TI_CL430_VERSION_CHECK(4,0,0) && defined(__TI_GNU_ATTRIBUTE_SUPPORT__)) || \ + JSON_HEDLEY_TI_CL430_VERSION_CHECK(4,3,0) || \ + (JSON_HEDLEY_TI_CL6X_VERSION_CHECK(7,2,0) && defined(__TI_GNU_ATTRIBUTE_SUPPORT__)) || \ + JSON_HEDLEY_TI_CL6X_VERSION_CHECK(7,5,0) || \ + JSON_HEDLEY_TI_CL7X_VERSION_CHECK(1,2,0) || \ + JSON_HEDLEY_TI_CLPRU_VERSION_CHECK(2,1,0) || \ + JSON_HEDLEY_IAR_VERSION_CHECK(8,10,0) + #define JSON_HEDLEY_NO_RETURN __attribute__((__noreturn__)) +#elif JSON_HEDLEY_SUNPRO_VERSION_CHECK(5,10,0) + #define JSON_HEDLEY_NO_RETURN _Pragma("does_not_return") +#elif \ + JSON_HEDLEY_MSVC_VERSION_CHECK(13,10,0) || \ + JSON_HEDLEY_INTEL_CL_VERSION_CHECK(2021,1,0) + #define JSON_HEDLEY_NO_RETURN __declspec(noreturn) +#elif JSON_HEDLEY_TI_CL6X_VERSION_CHECK(6,0,0) && defined(__cplusplus) + #define JSON_HEDLEY_NO_RETURN _Pragma("FUNC_NEVER_RETURNS;") +#elif JSON_HEDLEY_COMPCERT_VERSION_CHECK(3,2,0) + #define JSON_HEDLEY_NO_RETURN __attribute((noreturn)) +#elif JSON_HEDLEY_PELLES_VERSION_CHECK(9,0,0) + #define JSON_HEDLEY_NO_RETURN __declspec(noreturn) +#else + #define JSON_HEDLEY_NO_RETURN +#endif + +#if defined(JSON_HEDLEY_NO_ESCAPE) + #undef JSON_HEDLEY_NO_ESCAPE +#endif +#if JSON_HEDLEY_HAS_ATTRIBUTE(noescape) + #define JSON_HEDLEY_NO_ESCAPE __attribute__((__noescape__)) +#else + #define JSON_HEDLEY_NO_ESCAPE +#endif + +#if defined(JSON_HEDLEY_UNREACHABLE) + #undef JSON_HEDLEY_UNREACHABLE +#endif +#if defined(JSON_HEDLEY_UNREACHABLE_RETURN) + #undef JSON_HEDLEY_UNREACHABLE_RETURN +#endif +#if defined(JSON_HEDLEY_ASSUME) + #undef JSON_HEDLEY_ASSUME +#endif +#if \ + JSON_HEDLEY_MSVC_VERSION_CHECK(13,10,0) || \ + JSON_HEDLEY_INTEL_VERSION_CHECK(13,0,0) || \ + JSON_HEDLEY_INTEL_CL_VERSION_CHECK(2021,1,0) + #define JSON_HEDLEY_ASSUME(expr) __assume(expr) +#elif JSON_HEDLEY_HAS_BUILTIN(__builtin_assume) + #define JSON_HEDLEY_ASSUME(expr) __builtin_assume(expr) +#elif \ + JSON_HEDLEY_TI_CL2000_VERSION_CHECK(6,2,0) || \ + JSON_HEDLEY_TI_CL6X_VERSION_CHECK(4,0,0) + #if defined(__cplusplus) + #define JSON_HEDLEY_ASSUME(expr) std::_nassert(expr) + #else + #define JSON_HEDLEY_ASSUME(expr) _nassert(expr) + #endif +#endif +#if \ + (JSON_HEDLEY_HAS_BUILTIN(__builtin_unreachable) && (!defined(JSON_HEDLEY_ARM_VERSION))) || \ + JSON_HEDLEY_GCC_VERSION_CHECK(4,5,0) || \ + JSON_HEDLEY_PGI_VERSION_CHECK(18,10,0) || \ + JSON_HEDLEY_INTEL_VERSION_CHECK(13,0,0) || \ + JSON_HEDLEY_IBM_VERSION_CHECK(13,1,5) || \ + JSON_HEDLEY_CRAY_VERSION_CHECK(10,0,0) || \ + JSON_HEDLEY_MCST_LCC_VERSION_CHECK(1,25,10) + #define JSON_HEDLEY_UNREACHABLE() __builtin_unreachable() +#elif defined(JSON_HEDLEY_ASSUME) + #define JSON_HEDLEY_UNREACHABLE() JSON_HEDLEY_ASSUME(0) +#endif +#if !defined(JSON_HEDLEY_ASSUME) + #if defined(JSON_HEDLEY_UNREACHABLE) + #define JSON_HEDLEY_ASSUME(expr) JSON_HEDLEY_STATIC_CAST(void, ((expr) ? 1 : (JSON_HEDLEY_UNREACHABLE(), 1))) + #else + #define JSON_HEDLEY_ASSUME(expr) JSON_HEDLEY_STATIC_CAST(void, expr) + #endif +#endif +#if defined(JSON_HEDLEY_UNREACHABLE) + #if \ + JSON_HEDLEY_TI_CL2000_VERSION_CHECK(6,2,0) || \ + JSON_HEDLEY_TI_CL6X_VERSION_CHECK(4,0,0) + #define JSON_HEDLEY_UNREACHABLE_RETURN(value) return (JSON_HEDLEY_STATIC_CAST(void, JSON_HEDLEY_ASSUME(0)), (value)) + #else + #define JSON_HEDLEY_UNREACHABLE_RETURN(value) JSON_HEDLEY_UNREACHABLE() + #endif +#else + #define JSON_HEDLEY_UNREACHABLE_RETURN(value) return (value) +#endif +#if !defined(JSON_HEDLEY_UNREACHABLE) + #define JSON_HEDLEY_UNREACHABLE() JSON_HEDLEY_ASSUME(0) +#endif + +JSON_HEDLEY_DIAGNOSTIC_PUSH +#if JSON_HEDLEY_HAS_WARNING("-Wpedantic") + #pragma clang diagnostic ignored "-Wpedantic" +#endif +#if JSON_HEDLEY_HAS_WARNING("-Wc++98-compat-pedantic") && defined(__cplusplus) + #pragma clang diagnostic ignored "-Wc++98-compat-pedantic" +#endif +#if JSON_HEDLEY_GCC_HAS_WARNING("-Wvariadic-macros",4,0,0) + #if defined(__clang__) + #pragma clang diagnostic ignored "-Wvariadic-macros" + #elif defined(JSON_HEDLEY_GCC_VERSION) + #pragma GCC diagnostic ignored "-Wvariadic-macros" + #endif +#endif +#if defined(JSON_HEDLEY_NON_NULL) + #undef JSON_HEDLEY_NON_NULL +#endif +#if \ + JSON_HEDLEY_HAS_ATTRIBUTE(nonnull) || \ + JSON_HEDLEY_GCC_VERSION_CHECK(3,3,0) || \ + JSON_HEDLEY_INTEL_VERSION_CHECK(13,0,0) || \ + JSON_HEDLEY_ARM_VERSION_CHECK(4,1,0) + #define JSON_HEDLEY_NON_NULL(...) __attribute__((__nonnull__(__VA_ARGS__))) +#else + #define JSON_HEDLEY_NON_NULL(...) +#endif +JSON_HEDLEY_DIAGNOSTIC_POP + +#if defined(JSON_HEDLEY_PRINTF_FORMAT) + #undef JSON_HEDLEY_PRINTF_FORMAT +#endif +#if defined(__MINGW32__) && JSON_HEDLEY_GCC_HAS_ATTRIBUTE(format,4,4,0) && !defined(__USE_MINGW_ANSI_STDIO) + #define JSON_HEDLEY_PRINTF_FORMAT(string_idx,first_to_check) __attribute__((__format__(ms_printf, string_idx, first_to_check))) +#elif defined(__MINGW32__) && JSON_HEDLEY_GCC_HAS_ATTRIBUTE(format,4,4,0) && defined(__USE_MINGW_ANSI_STDIO) + #define JSON_HEDLEY_PRINTF_FORMAT(string_idx,first_to_check) __attribute__((__format__(gnu_printf, string_idx, first_to_check))) +#elif \ + JSON_HEDLEY_HAS_ATTRIBUTE(format) || \ + JSON_HEDLEY_GCC_VERSION_CHECK(3,1,0) || \ + JSON_HEDLEY_INTEL_VERSION_CHECK(13,0,0) || \ + JSON_HEDLEY_ARM_VERSION_CHECK(5,6,0) || \ + JSON_HEDLEY_IBM_VERSION_CHECK(10,1,0) || \ + JSON_HEDLEY_TI_VERSION_CHECK(15,12,0) || \ + (JSON_HEDLEY_TI_ARMCL_VERSION_CHECK(4,8,0) && defined(__TI_GNU_ATTRIBUTE_SUPPORT__)) || \ + JSON_HEDLEY_TI_ARMCL_VERSION_CHECK(5,2,0) || \ + (JSON_HEDLEY_TI_CL2000_VERSION_CHECK(6,0,0) && defined(__TI_GNU_ATTRIBUTE_SUPPORT__)) || \ + JSON_HEDLEY_TI_CL2000_VERSION_CHECK(6,4,0) || \ + (JSON_HEDLEY_TI_CL430_VERSION_CHECK(4,0,0) && defined(__TI_GNU_ATTRIBUTE_SUPPORT__)) || \ + JSON_HEDLEY_TI_CL430_VERSION_CHECK(4,3,0) || \ + (JSON_HEDLEY_TI_CL6X_VERSION_CHECK(7,2,0) && defined(__TI_GNU_ATTRIBUTE_SUPPORT__)) || \ + JSON_HEDLEY_TI_CL6X_VERSION_CHECK(7,5,0) || \ + JSON_HEDLEY_TI_CL7X_VERSION_CHECK(1,2,0) || \ + JSON_HEDLEY_TI_CLPRU_VERSION_CHECK(2,1,0) || \ + JSON_HEDLEY_MCST_LCC_VERSION_CHECK(1,25,10) + #define JSON_HEDLEY_PRINTF_FORMAT(string_idx,first_to_check) __attribute__((__format__(__printf__, string_idx, first_to_check))) +#elif JSON_HEDLEY_PELLES_VERSION_CHECK(6,0,0) + #define JSON_HEDLEY_PRINTF_FORMAT(string_idx,first_to_check) __declspec(vaformat(printf,string_idx,first_to_check)) +#else + #define JSON_HEDLEY_PRINTF_FORMAT(string_idx,first_to_check) +#endif + +#if defined(JSON_HEDLEY_CONSTEXPR) + #undef JSON_HEDLEY_CONSTEXPR +#endif +#if defined(__cplusplus) + #if __cplusplus >= 201103L + #define JSON_HEDLEY_CONSTEXPR JSON_HEDLEY_DIAGNOSTIC_DISABLE_CPP98_COMPAT_WRAP_(constexpr) + #endif +#endif +#if !defined(JSON_HEDLEY_CONSTEXPR) + #define JSON_HEDLEY_CONSTEXPR +#endif + +#if defined(JSON_HEDLEY_PREDICT) + #undef JSON_HEDLEY_PREDICT +#endif +#if defined(JSON_HEDLEY_LIKELY) + #undef JSON_HEDLEY_LIKELY +#endif +#if defined(JSON_HEDLEY_UNLIKELY) + #undef JSON_HEDLEY_UNLIKELY +#endif +#if defined(JSON_HEDLEY_UNPREDICTABLE) + #undef JSON_HEDLEY_UNPREDICTABLE +#endif +#if JSON_HEDLEY_HAS_BUILTIN(__builtin_unpredictable) + #define JSON_HEDLEY_UNPREDICTABLE(expr) __builtin_unpredictable((expr)) +#endif +#if \ + (JSON_HEDLEY_HAS_BUILTIN(__builtin_expect_with_probability) && !defined(JSON_HEDLEY_PGI_VERSION)) || \ + JSON_HEDLEY_GCC_VERSION_CHECK(9,0,0) || \ + JSON_HEDLEY_MCST_LCC_VERSION_CHECK(1,25,10) +# define JSON_HEDLEY_PREDICT(expr, value, probability) __builtin_expect_with_probability( (expr), (value), (probability)) +# define JSON_HEDLEY_PREDICT_TRUE(expr, probability) __builtin_expect_with_probability(!!(expr), 1 , (probability)) +# define JSON_HEDLEY_PREDICT_FALSE(expr, probability) __builtin_expect_with_probability(!!(expr), 0 , (probability)) +# define JSON_HEDLEY_LIKELY(expr) __builtin_expect (!!(expr), 1 ) +# define JSON_HEDLEY_UNLIKELY(expr) __builtin_expect (!!(expr), 0 ) +#elif \ + (JSON_HEDLEY_HAS_BUILTIN(__builtin_expect) && !defined(JSON_HEDLEY_INTEL_CL_VERSION)) || \ + JSON_HEDLEY_GCC_VERSION_CHECK(3,0,0) || \ + JSON_HEDLEY_INTEL_VERSION_CHECK(13,0,0) || \ + (JSON_HEDLEY_SUNPRO_VERSION_CHECK(5,15,0) && defined(__cplusplus)) || \ + JSON_HEDLEY_ARM_VERSION_CHECK(4,1,0) || \ + JSON_HEDLEY_IBM_VERSION_CHECK(10,1,0) || \ + JSON_HEDLEY_TI_VERSION_CHECK(15,12,0) || \ + JSON_HEDLEY_TI_ARMCL_VERSION_CHECK(4,7,0) || \ + JSON_HEDLEY_TI_CL430_VERSION_CHECK(3,1,0) || \ + JSON_HEDLEY_TI_CL2000_VERSION_CHECK(6,1,0) || \ + JSON_HEDLEY_TI_CL6X_VERSION_CHECK(6,1,0) || \ + JSON_HEDLEY_TI_CL7X_VERSION_CHECK(1,2,0) || \ + JSON_HEDLEY_TI_CLPRU_VERSION_CHECK(2,1,0) || \ + JSON_HEDLEY_TINYC_VERSION_CHECK(0,9,27) || \ + JSON_HEDLEY_CRAY_VERSION_CHECK(8,1,0) || \ + JSON_HEDLEY_MCST_LCC_VERSION_CHECK(1,25,10) +# define JSON_HEDLEY_PREDICT(expr, expected, probability) \ + (((probability) >= 0.9) ? __builtin_expect((expr), (expected)) : (JSON_HEDLEY_STATIC_CAST(void, expected), (expr))) +# define JSON_HEDLEY_PREDICT_TRUE(expr, probability) \ + (__extension__ ({ \ + double hedley_probability_ = (probability); \ + ((hedley_probability_ >= 0.9) ? __builtin_expect(!!(expr), 1) : ((hedley_probability_ <= 0.1) ? __builtin_expect(!!(expr), 0) : !!(expr))); \ + })) +# define JSON_HEDLEY_PREDICT_FALSE(expr, probability) \ + (__extension__ ({ \ + double hedley_probability_ = (probability); \ + ((hedley_probability_ >= 0.9) ? __builtin_expect(!!(expr), 0) : ((hedley_probability_ <= 0.1) ? __builtin_expect(!!(expr), 1) : !!(expr))); \ + })) +# define JSON_HEDLEY_LIKELY(expr) __builtin_expect(!!(expr), 1) +# define JSON_HEDLEY_UNLIKELY(expr) __builtin_expect(!!(expr), 0) +#else +# define JSON_HEDLEY_PREDICT(expr, expected, probability) (JSON_HEDLEY_STATIC_CAST(void, expected), (expr)) +# define JSON_HEDLEY_PREDICT_TRUE(expr, probability) (!!(expr)) +# define JSON_HEDLEY_PREDICT_FALSE(expr, probability) (!!(expr)) +# define JSON_HEDLEY_LIKELY(expr) (!!(expr)) +# define JSON_HEDLEY_UNLIKELY(expr) (!!(expr)) +#endif +#if !defined(JSON_HEDLEY_UNPREDICTABLE) + #define JSON_HEDLEY_UNPREDICTABLE(expr) JSON_HEDLEY_PREDICT(expr, 1, 0.5) +#endif + +#if defined(JSON_HEDLEY_MALLOC) + #undef JSON_HEDLEY_MALLOC +#endif +#if \ + JSON_HEDLEY_HAS_ATTRIBUTE(malloc) || \ + JSON_HEDLEY_GCC_VERSION_CHECK(3,1,0) || \ + JSON_HEDLEY_INTEL_VERSION_CHECK(13,0,0) || \ + JSON_HEDLEY_SUNPRO_VERSION_CHECK(5,11,0) || \ + JSON_HEDLEY_ARM_VERSION_CHECK(4,1,0) || \ + JSON_HEDLEY_IBM_VERSION_CHECK(12,1,0) || \ + JSON_HEDLEY_TI_VERSION_CHECK(15,12,0) || \ + (JSON_HEDLEY_TI_ARMCL_VERSION_CHECK(4,8,0) && defined(__TI_GNU_ATTRIBUTE_SUPPORT__)) || \ + JSON_HEDLEY_TI_ARMCL_VERSION_CHECK(5,2,0) || \ + (JSON_HEDLEY_TI_CL2000_VERSION_CHECK(6,0,0) && defined(__TI_GNU_ATTRIBUTE_SUPPORT__)) || \ + JSON_HEDLEY_TI_CL2000_VERSION_CHECK(6,4,0) || \ + (JSON_HEDLEY_TI_CL430_VERSION_CHECK(4,0,0) && defined(__TI_GNU_ATTRIBUTE_SUPPORT__)) || \ + JSON_HEDLEY_TI_CL430_VERSION_CHECK(4,3,0) || \ + (JSON_HEDLEY_TI_CL6X_VERSION_CHECK(7,2,0) && defined(__TI_GNU_ATTRIBUTE_SUPPORT__)) || \ + JSON_HEDLEY_TI_CL6X_VERSION_CHECK(7,5,0) || \ + JSON_HEDLEY_TI_CL7X_VERSION_CHECK(1,2,0) || \ + JSON_HEDLEY_TI_CLPRU_VERSION_CHECK(2,1,0) || \ + JSON_HEDLEY_MCST_LCC_VERSION_CHECK(1,25,10) + #define JSON_HEDLEY_MALLOC __attribute__((__malloc__)) +#elif JSON_HEDLEY_SUNPRO_VERSION_CHECK(5,10,0) + #define JSON_HEDLEY_MALLOC _Pragma("returns_new_memory") +#elif \ + JSON_HEDLEY_MSVC_VERSION_CHECK(14,0,0) || \ + JSON_HEDLEY_INTEL_CL_VERSION_CHECK(2021,1,0) + #define JSON_HEDLEY_MALLOC __declspec(restrict) +#else + #define JSON_HEDLEY_MALLOC +#endif + +#if defined(JSON_HEDLEY_PURE) + #undef JSON_HEDLEY_PURE +#endif +#if \ + JSON_HEDLEY_HAS_ATTRIBUTE(pure) || \ + JSON_HEDLEY_GCC_VERSION_CHECK(2,96,0) || \ + JSON_HEDLEY_INTEL_VERSION_CHECK(13,0,0) || \ + JSON_HEDLEY_SUNPRO_VERSION_CHECK(5,11,0) || \ + JSON_HEDLEY_ARM_VERSION_CHECK(4,1,0) || \ + JSON_HEDLEY_IBM_VERSION_CHECK(10,1,0) || \ + JSON_HEDLEY_TI_VERSION_CHECK(15,12,0) || \ + (JSON_HEDLEY_TI_ARMCL_VERSION_CHECK(4,8,0) && defined(__TI_GNU_ATTRIBUTE_SUPPORT__)) || \ + JSON_HEDLEY_TI_ARMCL_VERSION_CHECK(5,2,0) || \ + (JSON_HEDLEY_TI_CL2000_VERSION_CHECK(6,0,0) && defined(__TI_GNU_ATTRIBUTE_SUPPORT__)) || \ + JSON_HEDLEY_TI_CL2000_VERSION_CHECK(6,4,0) || \ + (JSON_HEDLEY_TI_CL430_VERSION_CHECK(4,0,0) && defined(__TI_GNU_ATTRIBUTE_SUPPORT__)) || \ + JSON_HEDLEY_TI_CL430_VERSION_CHECK(4,3,0) || \ + (JSON_HEDLEY_TI_CL6X_VERSION_CHECK(7,2,0) && defined(__TI_GNU_ATTRIBUTE_SUPPORT__)) || \ + JSON_HEDLEY_TI_CL6X_VERSION_CHECK(7,5,0) || \ + JSON_HEDLEY_TI_CL7X_VERSION_CHECK(1,2,0) || \ + JSON_HEDLEY_TI_CLPRU_VERSION_CHECK(2,1,0) || \ + JSON_HEDLEY_PGI_VERSION_CHECK(17,10,0) || \ + JSON_HEDLEY_MCST_LCC_VERSION_CHECK(1,25,10) +# define JSON_HEDLEY_PURE __attribute__((__pure__)) +#elif JSON_HEDLEY_SUNPRO_VERSION_CHECK(5,10,0) +# define JSON_HEDLEY_PURE _Pragma("does_not_write_global_data") +#elif defined(__cplusplus) && \ + ( \ + JSON_HEDLEY_TI_CL430_VERSION_CHECK(2,0,1) || \ + JSON_HEDLEY_TI_CL6X_VERSION_CHECK(4,0,0) || \ + JSON_HEDLEY_TI_CL7X_VERSION_CHECK(1,2,0) \ + ) +# define JSON_HEDLEY_PURE _Pragma("FUNC_IS_PURE;") +#else +# define JSON_HEDLEY_PURE +#endif + +#if defined(JSON_HEDLEY_CONST) + #undef JSON_HEDLEY_CONST +#endif +#if \ + JSON_HEDLEY_HAS_ATTRIBUTE(const) || \ + JSON_HEDLEY_GCC_VERSION_CHECK(2,5,0) || \ + JSON_HEDLEY_INTEL_VERSION_CHECK(13,0,0) || \ + JSON_HEDLEY_SUNPRO_VERSION_CHECK(5,11,0) || \ + JSON_HEDLEY_ARM_VERSION_CHECK(4,1,0) || \ + JSON_HEDLEY_IBM_VERSION_CHECK(10,1,0) || \ + JSON_HEDLEY_TI_VERSION_CHECK(15,12,0) || \ + (JSON_HEDLEY_TI_ARMCL_VERSION_CHECK(4,8,0) && defined(__TI_GNU_ATTRIBUTE_SUPPORT__)) || \ + JSON_HEDLEY_TI_ARMCL_VERSION_CHECK(5,2,0) || \ + (JSON_HEDLEY_TI_CL2000_VERSION_CHECK(6,0,0) && defined(__TI_GNU_ATTRIBUTE_SUPPORT__)) || \ + JSON_HEDLEY_TI_CL2000_VERSION_CHECK(6,4,0) || \ + (JSON_HEDLEY_TI_CL430_VERSION_CHECK(4,0,0) && defined(__TI_GNU_ATTRIBUTE_SUPPORT__)) || \ + JSON_HEDLEY_TI_CL430_VERSION_CHECK(4,3,0) || \ + (JSON_HEDLEY_TI_CL6X_VERSION_CHECK(7,2,0) && defined(__TI_GNU_ATTRIBUTE_SUPPORT__)) || \ + JSON_HEDLEY_TI_CL6X_VERSION_CHECK(7,5,0) || \ + JSON_HEDLEY_TI_CL7X_VERSION_CHECK(1,2,0) || \ + JSON_HEDLEY_TI_CLPRU_VERSION_CHECK(2,1,0) || \ + JSON_HEDLEY_PGI_VERSION_CHECK(17,10,0) || \ + JSON_HEDLEY_MCST_LCC_VERSION_CHECK(1,25,10) + #define JSON_HEDLEY_CONST __attribute__((__const__)) +#elif \ + JSON_HEDLEY_SUNPRO_VERSION_CHECK(5,10,0) + #define JSON_HEDLEY_CONST _Pragma("no_side_effect") +#else + #define JSON_HEDLEY_CONST JSON_HEDLEY_PURE +#endif + +#if defined(JSON_HEDLEY_RESTRICT) + #undef JSON_HEDLEY_RESTRICT +#endif +#if defined(__STDC_VERSION__) && (__STDC_VERSION__ >= 199901L) && !defined(__cplusplus) + #define JSON_HEDLEY_RESTRICT restrict +#elif \ + JSON_HEDLEY_GCC_VERSION_CHECK(3,1,0) || \ + JSON_HEDLEY_MSVC_VERSION_CHECK(14,0,0) || \ + JSON_HEDLEY_INTEL_VERSION_CHECK(13,0,0) || \ + JSON_HEDLEY_INTEL_CL_VERSION_CHECK(2021,1,0) || \ + JSON_HEDLEY_ARM_VERSION_CHECK(4,1,0) || \ + JSON_HEDLEY_IBM_VERSION_CHECK(10,1,0) || \ + JSON_HEDLEY_PGI_VERSION_CHECK(17,10,0) || \ + JSON_HEDLEY_TI_CL430_VERSION_CHECK(4,3,0) || \ + JSON_HEDLEY_TI_CL2000_VERSION_CHECK(6,2,4) || \ + JSON_HEDLEY_TI_CL6X_VERSION_CHECK(8,1,0) || \ + JSON_HEDLEY_TI_CL7X_VERSION_CHECK(1,2,0) || \ + (JSON_HEDLEY_SUNPRO_VERSION_CHECK(5,14,0) && defined(__cplusplus)) || \ + JSON_HEDLEY_IAR_VERSION_CHECK(8,0,0) || \ + defined(__clang__) || \ + JSON_HEDLEY_MCST_LCC_VERSION_CHECK(1,25,10) + #define JSON_HEDLEY_RESTRICT __restrict +#elif JSON_HEDLEY_SUNPRO_VERSION_CHECK(5,3,0) && !defined(__cplusplus) + #define JSON_HEDLEY_RESTRICT _Restrict +#else + #define JSON_HEDLEY_RESTRICT +#endif + +#if defined(JSON_HEDLEY_INLINE) + #undef JSON_HEDLEY_INLINE +#endif +#if \ + (defined(__STDC_VERSION__) && (__STDC_VERSION__ >= 199901L)) || \ + (defined(__cplusplus) && (__cplusplus >= 199711L)) + #define JSON_HEDLEY_INLINE inline +#elif \ + defined(JSON_HEDLEY_GCC_VERSION) || \ + JSON_HEDLEY_ARM_VERSION_CHECK(6,2,0) + #define JSON_HEDLEY_INLINE __inline__ +#elif \ + JSON_HEDLEY_MSVC_VERSION_CHECK(12,0,0) || \ + JSON_HEDLEY_INTEL_CL_VERSION_CHECK(2021,1,0) || \ + JSON_HEDLEY_ARM_VERSION_CHECK(4,1,0) || \ + JSON_HEDLEY_TI_ARMCL_VERSION_CHECK(5,1,0) || \ + JSON_HEDLEY_TI_CL430_VERSION_CHECK(3,1,0) || \ + JSON_HEDLEY_TI_CL2000_VERSION_CHECK(6,2,0) || \ + JSON_HEDLEY_TI_CL6X_VERSION_CHECK(8,0,0) || \ + JSON_HEDLEY_TI_CL7X_VERSION_CHECK(1,2,0) || \ + JSON_HEDLEY_TI_CLPRU_VERSION_CHECK(2,1,0) || \ + JSON_HEDLEY_MCST_LCC_VERSION_CHECK(1,25,10) + #define JSON_HEDLEY_INLINE __inline +#else + #define JSON_HEDLEY_INLINE +#endif + +#if defined(JSON_HEDLEY_ALWAYS_INLINE) + #undef JSON_HEDLEY_ALWAYS_INLINE +#endif +#if \ + JSON_HEDLEY_HAS_ATTRIBUTE(always_inline) || \ + JSON_HEDLEY_GCC_VERSION_CHECK(4,0,0) || \ + JSON_HEDLEY_INTEL_VERSION_CHECK(13,0,0) || \ + JSON_HEDLEY_SUNPRO_VERSION_CHECK(5,11,0) || \ + JSON_HEDLEY_ARM_VERSION_CHECK(4,1,0) || \ + JSON_HEDLEY_IBM_VERSION_CHECK(10,1,0) || \ + JSON_HEDLEY_TI_VERSION_CHECK(15,12,0) || \ + (JSON_HEDLEY_TI_ARMCL_VERSION_CHECK(4,8,0) && defined(__TI_GNU_ATTRIBUTE_SUPPORT__)) || \ + JSON_HEDLEY_TI_ARMCL_VERSION_CHECK(5,2,0) || \ + (JSON_HEDLEY_TI_CL2000_VERSION_CHECK(6,0,0) && defined(__TI_GNU_ATTRIBUTE_SUPPORT__)) || \ + JSON_HEDLEY_TI_CL2000_VERSION_CHECK(6,4,0) || \ + (JSON_HEDLEY_TI_CL430_VERSION_CHECK(4,0,0) && defined(__TI_GNU_ATTRIBUTE_SUPPORT__)) || \ + JSON_HEDLEY_TI_CL430_VERSION_CHECK(4,3,0) || \ + (JSON_HEDLEY_TI_CL6X_VERSION_CHECK(7,2,0) && defined(__TI_GNU_ATTRIBUTE_SUPPORT__)) || \ + JSON_HEDLEY_TI_CL6X_VERSION_CHECK(7,5,0) || \ + JSON_HEDLEY_TI_CL7X_VERSION_CHECK(1,2,0) || \ + JSON_HEDLEY_TI_CLPRU_VERSION_CHECK(2,1,0) || \ + JSON_HEDLEY_MCST_LCC_VERSION_CHECK(1,25,10) || \ + JSON_HEDLEY_IAR_VERSION_CHECK(8,10,0) +# define JSON_HEDLEY_ALWAYS_INLINE __attribute__((__always_inline__)) JSON_HEDLEY_INLINE +#elif \ + JSON_HEDLEY_MSVC_VERSION_CHECK(12,0,0) || \ + JSON_HEDLEY_INTEL_CL_VERSION_CHECK(2021,1,0) +# define JSON_HEDLEY_ALWAYS_INLINE __forceinline +#elif defined(__cplusplus) && \ + ( \ + JSON_HEDLEY_TI_ARMCL_VERSION_CHECK(5,2,0) || \ + JSON_HEDLEY_TI_CL430_VERSION_CHECK(4,3,0) || \ + JSON_HEDLEY_TI_CL2000_VERSION_CHECK(6,4,0) || \ + JSON_HEDLEY_TI_CL6X_VERSION_CHECK(6,1,0) || \ + JSON_HEDLEY_TI_CL7X_VERSION_CHECK(1,2,0) || \ + JSON_HEDLEY_TI_CLPRU_VERSION_CHECK(2,1,0) \ + ) +# define JSON_HEDLEY_ALWAYS_INLINE _Pragma("FUNC_ALWAYS_INLINE;") +#elif JSON_HEDLEY_IAR_VERSION_CHECK(8,0,0) +# define JSON_HEDLEY_ALWAYS_INLINE _Pragma("inline=forced") +#else +# define JSON_HEDLEY_ALWAYS_INLINE JSON_HEDLEY_INLINE +#endif + +#if defined(JSON_HEDLEY_NEVER_INLINE) + #undef JSON_HEDLEY_NEVER_INLINE +#endif +#if \ + JSON_HEDLEY_HAS_ATTRIBUTE(noinline) || \ + JSON_HEDLEY_GCC_VERSION_CHECK(4,0,0) || \ + JSON_HEDLEY_INTEL_VERSION_CHECK(13,0,0) || \ + JSON_HEDLEY_SUNPRO_VERSION_CHECK(5,11,0) || \ + JSON_HEDLEY_ARM_VERSION_CHECK(4,1,0) || \ + JSON_HEDLEY_IBM_VERSION_CHECK(10,1,0) || \ + JSON_HEDLEY_TI_VERSION_CHECK(15,12,0) || \ + (JSON_HEDLEY_TI_ARMCL_VERSION_CHECK(4,8,0) && defined(__TI_GNU_ATTRIBUTE_SUPPORT__)) || \ + JSON_HEDLEY_TI_ARMCL_VERSION_CHECK(5,2,0) || \ + (JSON_HEDLEY_TI_CL2000_VERSION_CHECK(6,0,0) && defined(__TI_GNU_ATTRIBUTE_SUPPORT__)) || \ + JSON_HEDLEY_TI_CL2000_VERSION_CHECK(6,4,0) || \ + (JSON_HEDLEY_TI_CL430_VERSION_CHECK(4,0,0) && defined(__TI_GNU_ATTRIBUTE_SUPPORT__)) || \ + JSON_HEDLEY_TI_CL430_VERSION_CHECK(4,3,0) || \ + (JSON_HEDLEY_TI_CL6X_VERSION_CHECK(7,2,0) && defined(__TI_GNU_ATTRIBUTE_SUPPORT__)) || \ + JSON_HEDLEY_TI_CL6X_VERSION_CHECK(7,5,0) || \ + JSON_HEDLEY_TI_CL7X_VERSION_CHECK(1,2,0) || \ + JSON_HEDLEY_TI_CLPRU_VERSION_CHECK(2,1,0) || \ + JSON_HEDLEY_MCST_LCC_VERSION_CHECK(1,25,10) || \ + JSON_HEDLEY_IAR_VERSION_CHECK(8,10,0) + #define JSON_HEDLEY_NEVER_INLINE __attribute__((__noinline__)) +#elif \ + JSON_HEDLEY_MSVC_VERSION_CHECK(13,10,0) || \ + JSON_HEDLEY_INTEL_CL_VERSION_CHECK(2021,1,0) + #define JSON_HEDLEY_NEVER_INLINE __declspec(noinline) +#elif JSON_HEDLEY_PGI_VERSION_CHECK(10,2,0) + #define JSON_HEDLEY_NEVER_INLINE _Pragma("noinline") +#elif JSON_HEDLEY_TI_CL6X_VERSION_CHECK(6,0,0) && defined(__cplusplus) + #define JSON_HEDLEY_NEVER_INLINE _Pragma("FUNC_CANNOT_INLINE;") +#elif JSON_HEDLEY_IAR_VERSION_CHECK(8,0,0) + #define JSON_HEDLEY_NEVER_INLINE _Pragma("inline=never") +#elif JSON_HEDLEY_COMPCERT_VERSION_CHECK(3,2,0) + #define JSON_HEDLEY_NEVER_INLINE __attribute((noinline)) +#elif JSON_HEDLEY_PELLES_VERSION_CHECK(9,0,0) + #define JSON_HEDLEY_NEVER_INLINE __declspec(noinline) +#else + #define JSON_HEDLEY_NEVER_INLINE +#endif + +#if defined(JSON_HEDLEY_PRIVATE) + #undef JSON_HEDLEY_PRIVATE +#endif +#if defined(JSON_HEDLEY_PUBLIC) + #undef JSON_HEDLEY_PUBLIC +#endif +#if defined(JSON_HEDLEY_IMPORT) + #undef JSON_HEDLEY_IMPORT +#endif +#if defined(_WIN32) || defined(__CYGWIN__) +# define JSON_HEDLEY_PRIVATE +# define JSON_HEDLEY_PUBLIC __declspec(dllexport) +# define JSON_HEDLEY_IMPORT __declspec(dllimport) +#else +# if \ + JSON_HEDLEY_HAS_ATTRIBUTE(visibility) || \ + JSON_HEDLEY_GCC_VERSION_CHECK(3,3,0) || \ + JSON_HEDLEY_SUNPRO_VERSION_CHECK(5,11,0) || \ + JSON_HEDLEY_INTEL_VERSION_CHECK(13,0,0) || \ + JSON_HEDLEY_ARM_VERSION_CHECK(4,1,0) || \ + JSON_HEDLEY_IBM_VERSION_CHECK(13,1,0) || \ + ( \ + defined(__TI_EABI__) && \ + ( \ + (JSON_HEDLEY_TI_CL6X_VERSION_CHECK(7,2,0) && defined(__TI_GNU_ATTRIBUTE_SUPPORT__)) || \ + JSON_HEDLEY_TI_CL6X_VERSION_CHECK(7,5,0) \ + ) \ + ) || \ + JSON_HEDLEY_MCST_LCC_VERSION_CHECK(1,25,10) +# define JSON_HEDLEY_PRIVATE __attribute__((__visibility__("hidden"))) +# define JSON_HEDLEY_PUBLIC __attribute__((__visibility__("default"))) +# else +# define JSON_HEDLEY_PRIVATE +# define JSON_HEDLEY_PUBLIC +# endif +# define JSON_HEDLEY_IMPORT extern +#endif + +#if defined(JSON_HEDLEY_NO_THROW) + #undef JSON_HEDLEY_NO_THROW +#endif +#if \ + JSON_HEDLEY_HAS_ATTRIBUTE(nothrow) || \ + JSON_HEDLEY_GCC_VERSION_CHECK(3,3,0) || \ + JSON_HEDLEY_INTEL_VERSION_CHECK(13,0,0) || \ + JSON_HEDLEY_MCST_LCC_VERSION_CHECK(1,25,10) + #define JSON_HEDLEY_NO_THROW __attribute__((__nothrow__)) +#elif \ + JSON_HEDLEY_MSVC_VERSION_CHECK(13,1,0) || \ + JSON_HEDLEY_INTEL_CL_VERSION_CHECK(2021,1,0) || \ + JSON_HEDLEY_ARM_VERSION_CHECK(4,1,0) + #define JSON_HEDLEY_NO_THROW __declspec(nothrow) +#else + #define JSON_HEDLEY_NO_THROW +#endif + +#if defined(JSON_HEDLEY_FALL_THROUGH) + #undef JSON_HEDLEY_FALL_THROUGH +#endif +#if \ + JSON_HEDLEY_HAS_ATTRIBUTE(fallthrough) || \ + JSON_HEDLEY_GCC_VERSION_CHECK(7,0,0) || \ + JSON_HEDLEY_MCST_LCC_VERSION_CHECK(1,25,10) + #define JSON_HEDLEY_FALL_THROUGH __attribute__((__fallthrough__)) +#elif JSON_HEDLEY_HAS_CPP_ATTRIBUTE_NS(clang,fallthrough) + #define JSON_HEDLEY_FALL_THROUGH JSON_HEDLEY_DIAGNOSTIC_DISABLE_CPP98_COMPAT_WRAP_([[clang::fallthrough]]) +#elif JSON_HEDLEY_HAS_CPP_ATTRIBUTE(fallthrough) + #define JSON_HEDLEY_FALL_THROUGH JSON_HEDLEY_DIAGNOSTIC_DISABLE_CPP98_COMPAT_WRAP_([[fallthrough]]) +#elif defined(__fallthrough) /* SAL */ + #define JSON_HEDLEY_FALL_THROUGH __fallthrough +#else + #define JSON_HEDLEY_FALL_THROUGH +#endif + +#if defined(JSON_HEDLEY_RETURNS_NON_NULL) + #undef JSON_HEDLEY_RETURNS_NON_NULL +#endif +#if \ + JSON_HEDLEY_HAS_ATTRIBUTE(returns_nonnull) || \ + JSON_HEDLEY_GCC_VERSION_CHECK(4,9,0) || \ + JSON_HEDLEY_MCST_LCC_VERSION_CHECK(1,25,10) + #define JSON_HEDLEY_RETURNS_NON_NULL __attribute__((__returns_nonnull__)) +#elif defined(_Ret_notnull_) /* SAL */ + #define JSON_HEDLEY_RETURNS_NON_NULL _Ret_notnull_ +#else + #define JSON_HEDLEY_RETURNS_NON_NULL +#endif + +#if defined(JSON_HEDLEY_ARRAY_PARAM) + #undef JSON_HEDLEY_ARRAY_PARAM +#endif +#if \ + defined(__STDC_VERSION__) && (__STDC_VERSION__ >= 199901L) && \ + !defined(__STDC_NO_VLA__) && \ + !defined(__cplusplus) && \ + !defined(JSON_HEDLEY_PGI_VERSION) && \ + !defined(JSON_HEDLEY_TINYC_VERSION) + #define JSON_HEDLEY_ARRAY_PARAM(name) (name) +#else + #define JSON_HEDLEY_ARRAY_PARAM(name) +#endif + +#if defined(JSON_HEDLEY_IS_CONSTANT) + #undef JSON_HEDLEY_IS_CONSTANT +#endif +#if defined(JSON_HEDLEY_REQUIRE_CONSTEXPR) + #undef JSON_HEDLEY_REQUIRE_CONSTEXPR +#endif +/* JSON_HEDLEY_IS_CONSTEXPR_ is for + HEDLEY INTERNAL USE ONLY. API subject to change without notice. */ +#if defined(JSON_HEDLEY_IS_CONSTEXPR_) + #undef JSON_HEDLEY_IS_CONSTEXPR_ +#endif +#if \ + JSON_HEDLEY_HAS_BUILTIN(__builtin_constant_p) || \ + JSON_HEDLEY_GCC_VERSION_CHECK(3,4,0) || \ + JSON_HEDLEY_INTEL_VERSION_CHECK(13,0,0) || \ + JSON_HEDLEY_TINYC_VERSION_CHECK(0,9,19) || \ + JSON_HEDLEY_ARM_VERSION_CHECK(4,1,0) || \ + JSON_HEDLEY_IBM_VERSION_CHECK(13,1,0) || \ + JSON_HEDLEY_TI_CL6X_VERSION_CHECK(6,1,0) || \ + (JSON_HEDLEY_SUNPRO_VERSION_CHECK(5,10,0) && !defined(__cplusplus)) || \ + JSON_HEDLEY_CRAY_VERSION_CHECK(8,1,0) || \ + JSON_HEDLEY_MCST_LCC_VERSION_CHECK(1,25,10) + #define JSON_HEDLEY_IS_CONSTANT(expr) __builtin_constant_p(expr) +#endif +#if !defined(__cplusplus) +# if \ + JSON_HEDLEY_HAS_BUILTIN(__builtin_types_compatible_p) || \ + JSON_HEDLEY_GCC_VERSION_CHECK(3,4,0) || \ + JSON_HEDLEY_INTEL_VERSION_CHECK(13,0,0) || \ + JSON_HEDLEY_IBM_VERSION_CHECK(13,1,0) || \ + JSON_HEDLEY_CRAY_VERSION_CHECK(8,1,0) || \ + JSON_HEDLEY_ARM_VERSION_CHECK(5,4,0) || \ + JSON_HEDLEY_TINYC_VERSION_CHECK(0,9,24) +#if defined(__INTPTR_TYPE__) + #define JSON_HEDLEY_IS_CONSTEXPR_(expr) __builtin_types_compatible_p(__typeof__((1 ? (void*) ((__INTPTR_TYPE__) ((expr) * 0)) : (int*) 0)), int*) +#else + #include + #define JSON_HEDLEY_IS_CONSTEXPR_(expr) __builtin_types_compatible_p(__typeof__((1 ? (void*) ((intptr_t) ((expr) * 0)) : (int*) 0)), int*) +#endif +# elif \ + ( \ + defined(__STDC_VERSION__) && (__STDC_VERSION__ >= 201112L) && \ + !defined(JSON_HEDLEY_SUNPRO_VERSION) && \ + !defined(JSON_HEDLEY_PGI_VERSION) && \ + !defined(JSON_HEDLEY_IAR_VERSION)) || \ + (JSON_HEDLEY_HAS_EXTENSION(c_generic_selections) && !defined(JSON_HEDLEY_IAR_VERSION)) || \ + JSON_HEDLEY_GCC_VERSION_CHECK(4,9,0) || \ + JSON_HEDLEY_INTEL_VERSION_CHECK(17,0,0) || \ + JSON_HEDLEY_IBM_VERSION_CHECK(12,1,0) || \ + JSON_HEDLEY_ARM_VERSION_CHECK(5,3,0) +#if defined(__INTPTR_TYPE__) + #define JSON_HEDLEY_IS_CONSTEXPR_(expr) _Generic((1 ? (void*) ((__INTPTR_TYPE__) ((expr) * 0)) : (int*) 0), int*: 1, void*: 0) +#else + #include + #define JSON_HEDLEY_IS_CONSTEXPR_(expr) _Generic((1 ? (void*) ((intptr_t) * 0) : (int*) 0), int*: 1, void*: 0) +#endif +# elif \ + defined(JSON_HEDLEY_GCC_VERSION) || \ + defined(JSON_HEDLEY_INTEL_VERSION) || \ + defined(JSON_HEDLEY_TINYC_VERSION) || \ + defined(JSON_HEDLEY_TI_ARMCL_VERSION) || \ + JSON_HEDLEY_TI_CL430_VERSION_CHECK(18,12,0) || \ + defined(JSON_HEDLEY_TI_CL2000_VERSION) || \ + defined(JSON_HEDLEY_TI_CL6X_VERSION) || \ + defined(JSON_HEDLEY_TI_CL7X_VERSION) || \ + defined(JSON_HEDLEY_TI_CLPRU_VERSION) || \ + defined(__clang__) +# define JSON_HEDLEY_IS_CONSTEXPR_(expr) ( \ + sizeof(void) != \ + sizeof(*( \ + 1 ? \ + ((void*) ((expr) * 0L) ) : \ +((struct { char v[sizeof(void) * 2]; } *) 1) \ + ) \ + ) \ + ) +# endif +#endif +#if defined(JSON_HEDLEY_IS_CONSTEXPR_) + #if !defined(JSON_HEDLEY_IS_CONSTANT) + #define JSON_HEDLEY_IS_CONSTANT(expr) JSON_HEDLEY_IS_CONSTEXPR_(expr) + #endif + #define JSON_HEDLEY_REQUIRE_CONSTEXPR(expr) (JSON_HEDLEY_IS_CONSTEXPR_(expr) ? (expr) : (-1)) +#else + #if !defined(JSON_HEDLEY_IS_CONSTANT) + #define JSON_HEDLEY_IS_CONSTANT(expr) (0) + #endif + #define JSON_HEDLEY_REQUIRE_CONSTEXPR(expr) (expr) +#endif + +#if defined(JSON_HEDLEY_BEGIN_C_DECLS) + #undef JSON_HEDLEY_BEGIN_C_DECLS +#endif +#if defined(JSON_HEDLEY_END_C_DECLS) + #undef JSON_HEDLEY_END_C_DECLS +#endif +#if defined(JSON_HEDLEY_C_DECL) + #undef JSON_HEDLEY_C_DECL +#endif +#if defined(__cplusplus) + #define JSON_HEDLEY_BEGIN_C_DECLS extern "C" { + #define JSON_HEDLEY_END_C_DECLS } + #define JSON_HEDLEY_C_DECL extern "C" +#else + #define JSON_HEDLEY_BEGIN_C_DECLS + #define JSON_HEDLEY_END_C_DECLS + #define JSON_HEDLEY_C_DECL +#endif + +#if defined(JSON_HEDLEY_STATIC_ASSERT) + #undef JSON_HEDLEY_STATIC_ASSERT +#endif +#if \ + !defined(__cplusplus) && ( \ + (defined(__STDC_VERSION__) && (__STDC_VERSION__ >= 201112L)) || \ + (JSON_HEDLEY_HAS_FEATURE(c_static_assert) && !defined(JSON_HEDLEY_INTEL_CL_VERSION)) || \ + JSON_HEDLEY_GCC_VERSION_CHECK(6,0,0) || \ + JSON_HEDLEY_INTEL_VERSION_CHECK(13,0,0) || \ + defined(_Static_assert) \ + ) +# define JSON_HEDLEY_STATIC_ASSERT(expr, message) _Static_assert(expr, message) +#elif \ + (defined(__cplusplus) && (__cplusplus >= 201103L)) || \ + JSON_HEDLEY_MSVC_VERSION_CHECK(16,0,0) || \ + JSON_HEDLEY_INTEL_CL_VERSION_CHECK(2021,1,0) +# define JSON_HEDLEY_STATIC_ASSERT(expr, message) JSON_HEDLEY_DIAGNOSTIC_DISABLE_CPP98_COMPAT_WRAP_(static_assert(expr, message)) +#else +# define JSON_HEDLEY_STATIC_ASSERT(expr, message) +#endif + +#if defined(JSON_HEDLEY_NULL) + #undef JSON_HEDLEY_NULL +#endif +#if defined(__cplusplus) + #if __cplusplus >= 201103L + #define JSON_HEDLEY_NULL JSON_HEDLEY_DIAGNOSTIC_DISABLE_CPP98_COMPAT_WRAP_(nullptr) + #elif defined(NULL) + #define JSON_HEDLEY_NULL NULL + #else + #define JSON_HEDLEY_NULL JSON_HEDLEY_STATIC_CAST(void*, 0) + #endif +#elif defined(NULL) + #define JSON_HEDLEY_NULL NULL +#else + #define JSON_HEDLEY_NULL ((void*) 0) +#endif + +#if defined(JSON_HEDLEY_MESSAGE) + #undef JSON_HEDLEY_MESSAGE +#endif +#if JSON_HEDLEY_HAS_WARNING("-Wunknown-pragmas") +# define JSON_HEDLEY_MESSAGE(msg) \ + JSON_HEDLEY_DIAGNOSTIC_PUSH \ + JSON_HEDLEY_DIAGNOSTIC_DISABLE_UNKNOWN_PRAGMAS \ + JSON_HEDLEY_PRAGMA(message msg) \ + JSON_HEDLEY_DIAGNOSTIC_POP +#elif \ + JSON_HEDLEY_GCC_VERSION_CHECK(4,4,0) || \ + JSON_HEDLEY_INTEL_VERSION_CHECK(13,0,0) +# define JSON_HEDLEY_MESSAGE(msg) JSON_HEDLEY_PRAGMA(message msg) +#elif JSON_HEDLEY_CRAY_VERSION_CHECK(5,0,0) +# define JSON_HEDLEY_MESSAGE(msg) JSON_HEDLEY_PRAGMA(_CRI message msg) +#elif JSON_HEDLEY_IAR_VERSION_CHECK(8,0,0) +# define JSON_HEDLEY_MESSAGE(msg) JSON_HEDLEY_PRAGMA(message(msg)) +#elif JSON_HEDLEY_PELLES_VERSION_CHECK(2,0,0) +# define JSON_HEDLEY_MESSAGE(msg) JSON_HEDLEY_PRAGMA(message(msg)) +#else +# define JSON_HEDLEY_MESSAGE(msg) +#endif + +#if defined(JSON_HEDLEY_WARNING) + #undef JSON_HEDLEY_WARNING +#endif +#if JSON_HEDLEY_HAS_WARNING("-Wunknown-pragmas") +# define JSON_HEDLEY_WARNING(msg) \ + JSON_HEDLEY_DIAGNOSTIC_PUSH \ + JSON_HEDLEY_DIAGNOSTIC_DISABLE_UNKNOWN_PRAGMAS \ + JSON_HEDLEY_PRAGMA(clang warning msg) \ + JSON_HEDLEY_DIAGNOSTIC_POP +#elif \ + JSON_HEDLEY_GCC_VERSION_CHECK(4,8,0) || \ + JSON_HEDLEY_PGI_VERSION_CHECK(18,4,0) || \ + JSON_HEDLEY_INTEL_VERSION_CHECK(13,0,0) +# define JSON_HEDLEY_WARNING(msg) JSON_HEDLEY_PRAGMA(GCC warning msg) +#elif \ + JSON_HEDLEY_MSVC_VERSION_CHECK(15,0,0) || \ + JSON_HEDLEY_INTEL_CL_VERSION_CHECK(2021,1,0) +# define JSON_HEDLEY_WARNING(msg) JSON_HEDLEY_PRAGMA(message(msg)) +#else +# define JSON_HEDLEY_WARNING(msg) JSON_HEDLEY_MESSAGE(msg) +#endif + +#if defined(JSON_HEDLEY_REQUIRE) + #undef JSON_HEDLEY_REQUIRE +#endif +#if defined(JSON_HEDLEY_REQUIRE_MSG) + #undef JSON_HEDLEY_REQUIRE_MSG +#endif +#if JSON_HEDLEY_HAS_ATTRIBUTE(diagnose_if) +# if JSON_HEDLEY_HAS_WARNING("-Wgcc-compat") +# define JSON_HEDLEY_REQUIRE(expr) \ + JSON_HEDLEY_DIAGNOSTIC_PUSH \ + _Pragma("clang diagnostic ignored \"-Wgcc-compat\"") \ + __attribute__((diagnose_if(!(expr), #expr, "error"))) \ + JSON_HEDLEY_DIAGNOSTIC_POP +# define JSON_HEDLEY_REQUIRE_MSG(expr,msg) \ + JSON_HEDLEY_DIAGNOSTIC_PUSH \ + _Pragma("clang diagnostic ignored \"-Wgcc-compat\"") \ + __attribute__((diagnose_if(!(expr), msg, "error"))) \ + JSON_HEDLEY_DIAGNOSTIC_POP +# else +# define JSON_HEDLEY_REQUIRE(expr) __attribute__((diagnose_if(!(expr), #expr, "error"))) +# define JSON_HEDLEY_REQUIRE_MSG(expr,msg) __attribute__((diagnose_if(!(expr), msg, "error"))) +# endif +#else +# define JSON_HEDLEY_REQUIRE(expr) +# define JSON_HEDLEY_REQUIRE_MSG(expr,msg) +#endif + +#if defined(JSON_HEDLEY_FLAGS) + #undef JSON_HEDLEY_FLAGS +#endif +#if JSON_HEDLEY_HAS_ATTRIBUTE(flag_enum) && (!defined(__cplusplus) || JSON_HEDLEY_HAS_WARNING("-Wbitfield-enum-conversion")) + #define JSON_HEDLEY_FLAGS __attribute__((__flag_enum__)) +#else + #define JSON_HEDLEY_FLAGS +#endif + +#if defined(JSON_HEDLEY_FLAGS_CAST) + #undef JSON_HEDLEY_FLAGS_CAST +#endif +#if JSON_HEDLEY_INTEL_VERSION_CHECK(19,0,0) +# define JSON_HEDLEY_FLAGS_CAST(T, expr) (__extension__ ({ \ + JSON_HEDLEY_DIAGNOSTIC_PUSH \ + _Pragma("warning(disable:188)") \ + ((T) (expr)); \ + JSON_HEDLEY_DIAGNOSTIC_POP \ + })) +#else +# define JSON_HEDLEY_FLAGS_CAST(T, expr) JSON_HEDLEY_STATIC_CAST(T, expr) +#endif + +#if defined(JSON_HEDLEY_EMPTY_BASES) + #undef JSON_HEDLEY_EMPTY_BASES +#endif +#if \ + (JSON_HEDLEY_MSVC_VERSION_CHECK(19,0,23918) && !JSON_HEDLEY_MSVC_VERSION_CHECK(20,0,0)) || \ + JSON_HEDLEY_INTEL_CL_VERSION_CHECK(2021,1,0) + #define JSON_HEDLEY_EMPTY_BASES __declspec(empty_bases) +#else + #define JSON_HEDLEY_EMPTY_BASES +#endif + +/* Remaining macros are deprecated. */ + +#if defined(JSON_HEDLEY_GCC_NOT_CLANG_VERSION_CHECK) + #undef JSON_HEDLEY_GCC_NOT_CLANG_VERSION_CHECK +#endif +#if defined(__clang__) + #define JSON_HEDLEY_GCC_NOT_CLANG_VERSION_CHECK(major,minor,patch) (0) +#else + #define JSON_HEDLEY_GCC_NOT_CLANG_VERSION_CHECK(major,minor,patch) JSON_HEDLEY_GCC_VERSION_CHECK(major,minor,patch) +#endif + +#if defined(JSON_HEDLEY_CLANG_HAS_ATTRIBUTE) + #undef JSON_HEDLEY_CLANG_HAS_ATTRIBUTE +#endif +#define JSON_HEDLEY_CLANG_HAS_ATTRIBUTE(attribute) JSON_HEDLEY_HAS_ATTRIBUTE(attribute) + +#if defined(JSON_HEDLEY_CLANG_HAS_CPP_ATTRIBUTE) + #undef JSON_HEDLEY_CLANG_HAS_CPP_ATTRIBUTE +#endif +#define JSON_HEDLEY_CLANG_HAS_CPP_ATTRIBUTE(attribute) JSON_HEDLEY_HAS_CPP_ATTRIBUTE(attribute) + +#if defined(JSON_HEDLEY_CLANG_HAS_BUILTIN) + #undef JSON_HEDLEY_CLANG_HAS_BUILTIN +#endif +#define JSON_HEDLEY_CLANG_HAS_BUILTIN(builtin) JSON_HEDLEY_HAS_BUILTIN(builtin) + +#if defined(JSON_HEDLEY_CLANG_HAS_FEATURE) + #undef JSON_HEDLEY_CLANG_HAS_FEATURE +#endif +#define JSON_HEDLEY_CLANG_HAS_FEATURE(feature) JSON_HEDLEY_HAS_FEATURE(feature) + +#if defined(JSON_HEDLEY_CLANG_HAS_EXTENSION) + #undef JSON_HEDLEY_CLANG_HAS_EXTENSION +#endif +#define JSON_HEDLEY_CLANG_HAS_EXTENSION(extension) JSON_HEDLEY_HAS_EXTENSION(extension) + +#if defined(JSON_HEDLEY_CLANG_HAS_DECLSPEC_DECLSPEC_ATTRIBUTE) + #undef JSON_HEDLEY_CLANG_HAS_DECLSPEC_DECLSPEC_ATTRIBUTE +#endif +#define JSON_HEDLEY_CLANG_HAS_DECLSPEC_ATTRIBUTE(attribute) JSON_HEDLEY_HAS_DECLSPEC_ATTRIBUTE(attribute) + +#if defined(JSON_HEDLEY_CLANG_HAS_WARNING) + #undef JSON_HEDLEY_CLANG_HAS_WARNING +#endif +#define JSON_HEDLEY_CLANG_HAS_WARNING(warning) JSON_HEDLEY_HAS_WARNING(warning) + +#endif /* !defined(JSON_HEDLEY_VERSION) || (JSON_HEDLEY_VERSION < X) */ + + +// This file contains all internal macro definitions (except those affecting ABI) +// You MUST include macro_unscope.hpp at the end of json.hpp to undef all of them + +// #include + + +// exclude unsupported compilers +#if !defined(JSON_SKIP_UNSUPPORTED_COMPILER_CHECK) + #if defined(__clang__) + #if (__clang_major__ * 10000 + __clang_minor__ * 100 + __clang_patchlevel__) < 30400 + #error "unsupported Clang version - see https://github.com/nlohmann/json#supported-compilers" + #endif + #elif defined(__GNUC__) && !(defined(__ICC) || defined(__INTEL_COMPILER)) + #if (__GNUC__ * 10000 + __GNUC_MINOR__ * 100 + __GNUC_PATCHLEVEL__) < 40800 + #error "unsupported GCC version - see https://github.com/nlohmann/json#supported-compilers" + #endif + #endif +#endif + +// C++ language standard detection +// if the user manually specified the used c++ version this is skipped +#if !defined(JSON_HAS_CPP_20) && !defined(JSON_HAS_CPP_17) && !defined(JSON_HAS_CPP_14) && !defined(JSON_HAS_CPP_11) + #if (defined(__cplusplus) && __cplusplus >= 202002L) || (defined(_MSVC_LANG) && _MSVC_LANG >= 202002L) + #define JSON_HAS_CPP_20 + #define JSON_HAS_CPP_17 + #define JSON_HAS_CPP_14 + #elif (defined(__cplusplus) && __cplusplus >= 201703L) || (defined(_HAS_CXX17) && _HAS_CXX17 == 1) // fix for issue #464 + #define JSON_HAS_CPP_17 + #define JSON_HAS_CPP_14 + #elif (defined(__cplusplus) && __cplusplus >= 201402L) || (defined(_HAS_CXX14) && _HAS_CXX14 == 1) + #define JSON_HAS_CPP_14 + #endif + // the cpp 11 flag is always specified because it is the minimal required version + #define JSON_HAS_CPP_11 +#endif + +#ifdef __has_include + #if __has_include() + #include + #endif +#endif + +#if !defined(JSON_HAS_FILESYSTEM) && !defined(JSON_HAS_EXPERIMENTAL_FILESYSTEM) + #ifdef JSON_HAS_CPP_17 + #if defined(__cpp_lib_filesystem) + #define JSON_HAS_FILESYSTEM 1 + #elif defined(__cpp_lib_experimental_filesystem) + #define JSON_HAS_EXPERIMENTAL_FILESYSTEM 1 + #elif !defined(__has_include) + #define JSON_HAS_EXPERIMENTAL_FILESYSTEM 1 + #elif __has_include() + #define JSON_HAS_FILESYSTEM 1 + #elif __has_include() + #define JSON_HAS_EXPERIMENTAL_FILESYSTEM 1 + #endif + + // std::filesystem does not work on MinGW GCC 8: https://sourceforge.net/p/mingw-w64/bugs/737/ + #if defined(__MINGW32__) && defined(__GNUC__) && __GNUC__ == 8 + #undef JSON_HAS_FILESYSTEM + #undef JSON_HAS_EXPERIMENTAL_FILESYSTEM + #endif + + // no filesystem support before GCC 8: https://en.cppreference.com/w/cpp/compiler_support + #if defined(__GNUC__) && !defined(__clang__) && __GNUC__ < 8 + #undef JSON_HAS_FILESYSTEM + #undef JSON_HAS_EXPERIMENTAL_FILESYSTEM + #endif + + // no filesystem support before Clang 7: https://en.cppreference.com/w/cpp/compiler_support + #if defined(__clang_major__) && __clang_major__ < 7 + #undef JSON_HAS_FILESYSTEM + #undef JSON_HAS_EXPERIMENTAL_FILESYSTEM + #endif + + // no filesystem support before MSVC 19.14: https://en.cppreference.com/w/cpp/compiler_support + #if defined(_MSC_VER) && _MSC_VER < 1914 + #undef JSON_HAS_FILESYSTEM + #undef JSON_HAS_EXPERIMENTAL_FILESYSTEM + #endif + + // no filesystem support before iOS 13 + #if defined(__IPHONE_OS_VERSION_MIN_REQUIRED) && __IPHONE_OS_VERSION_MIN_REQUIRED < 130000 + #undef JSON_HAS_FILESYSTEM + #undef JSON_HAS_EXPERIMENTAL_FILESYSTEM + #endif + + // no filesystem support before macOS Catalina + #if defined(__MAC_OS_X_VERSION_MIN_REQUIRED) && __MAC_OS_X_VERSION_MIN_REQUIRED < 101500 + #undef JSON_HAS_FILESYSTEM + #undef JSON_HAS_EXPERIMENTAL_FILESYSTEM + #endif + #endif +#endif + +#ifndef JSON_HAS_EXPERIMENTAL_FILESYSTEM + #define JSON_HAS_EXPERIMENTAL_FILESYSTEM 0 +#endif + +#ifndef JSON_HAS_FILESYSTEM + #define JSON_HAS_FILESYSTEM 0 +#endif + +#ifndef JSON_HAS_THREE_WAY_COMPARISON + #if defined(__cpp_impl_three_way_comparison) && __cpp_impl_three_way_comparison >= 201907L \ + && defined(__cpp_lib_three_way_comparison) && __cpp_lib_three_way_comparison >= 201907L + #define JSON_HAS_THREE_WAY_COMPARISON 1 + #else + #define JSON_HAS_THREE_WAY_COMPARISON 0 + #endif +#endif + +#ifndef JSON_HAS_RANGES + // ranges header shipping in GCC 11.1.0 (released 2021-04-27) has syntax error + #if defined(__GLIBCXX__) && __GLIBCXX__ == 20210427 + #define JSON_HAS_RANGES 0 + #elif defined(__cpp_lib_ranges) + #define JSON_HAS_RANGES 1 + #else + #define JSON_HAS_RANGES 0 + #endif +#endif + +#ifdef JSON_HAS_CPP_17 + #define JSON_INLINE_VARIABLE inline +#else + #define JSON_INLINE_VARIABLE +#endif + +#if JSON_HEDLEY_HAS_ATTRIBUTE(no_unique_address) + #define JSON_NO_UNIQUE_ADDRESS [[no_unique_address]] +#else + #define JSON_NO_UNIQUE_ADDRESS +#endif + +// disable documentation warnings on clang +#if defined(__clang__) + #pragma clang diagnostic push + #pragma clang diagnostic ignored "-Wdocumentation" + #pragma clang diagnostic ignored "-Wdocumentation-unknown-command" +#endif + +// allow disabling exceptions +#if (defined(__cpp_exceptions) || defined(__EXCEPTIONS) || defined(_CPPUNWIND)) && !defined(JSON_NOEXCEPTION) + #define JSON_THROW(exception) throw exception + #define JSON_TRY try + #define JSON_CATCH(exception) catch(exception) + #define JSON_INTERNAL_CATCH(exception) catch(exception) +#else + #include + #define JSON_THROW(exception) std::abort() + #define JSON_TRY if(true) + #define JSON_CATCH(exception) if(false) + #define JSON_INTERNAL_CATCH(exception) if(false) +#endif + +// override exception macros +#if defined(JSON_THROW_USER) + #undef JSON_THROW + #define JSON_THROW JSON_THROW_USER +#endif +#if defined(JSON_TRY_USER) + #undef JSON_TRY + #define JSON_TRY JSON_TRY_USER +#endif +#if defined(JSON_CATCH_USER) + #undef JSON_CATCH + #define JSON_CATCH JSON_CATCH_USER + #undef JSON_INTERNAL_CATCH + #define JSON_INTERNAL_CATCH JSON_CATCH_USER +#endif +#if defined(JSON_INTERNAL_CATCH_USER) + #undef JSON_INTERNAL_CATCH + #define JSON_INTERNAL_CATCH JSON_INTERNAL_CATCH_USER +#endif + +// allow overriding assert +#if !defined(JSON_ASSERT) + #include // assert + #define JSON_ASSERT(x) assert(x) +#endif + +// allow to access some private functions (needed by the test suite) +#if defined(JSON_TESTS_PRIVATE) + #define JSON_PRIVATE_UNLESS_TESTED public +#else + #define JSON_PRIVATE_UNLESS_TESTED private +#endif + +/*! +@brief macro to briefly define a mapping between an enum and JSON +@def NLOHMANN_JSON_SERIALIZE_ENUM +@since version 3.4.0 +*/ +#define NLOHMANN_JSON_SERIALIZE_ENUM(ENUM_TYPE, ...) \ + template \ + inline void to_json(BasicJsonType& j, const ENUM_TYPE& e) \ + { \ + static_assert(std::is_enum::value, #ENUM_TYPE " must be an enum!"); \ + static const std::pair m[] = __VA_ARGS__; \ + auto it = std::find_if(std::begin(m), std::end(m), \ + [e](const std::pair& ej_pair) -> bool \ + { \ + return ej_pair.first == e; \ + }); \ + j = ((it != std::end(m)) ? it : std::begin(m))->second; \ + } \ + template \ + inline void from_json(const BasicJsonType& j, ENUM_TYPE& e) \ + { \ + static_assert(std::is_enum::value, #ENUM_TYPE " must be an enum!"); \ + static const std::pair m[] = __VA_ARGS__; \ + auto it = std::find_if(std::begin(m), std::end(m), \ + [&j](const std::pair& ej_pair) -> bool \ + { \ + return ej_pair.second == j; \ + }); \ + e = ((it != std::end(m)) ? it : std::begin(m))->first; \ + } + +// Ugly macros to avoid uglier copy-paste when specializing basic_json. They +// may be removed in the future once the class is split. + +#define NLOHMANN_BASIC_JSON_TPL_DECLARATION \ + template class ObjectType, \ + template class ArrayType, \ + class StringType, class BooleanType, class NumberIntegerType, \ + class NumberUnsignedType, class NumberFloatType, \ + template class AllocatorType, \ + template class JSONSerializer, \ + class BinaryType> + +#define NLOHMANN_BASIC_JSON_TPL \ + basic_json + +// Macros to simplify conversion from/to types + +#define NLOHMANN_JSON_EXPAND( x ) x +#define NLOHMANN_JSON_GET_MACRO(_1, _2, _3, _4, _5, _6, _7, _8, _9, _10, _11, _12, _13, _14, _15, _16, _17, _18, _19, _20, _21, _22, _23, _24, _25, _26, _27, _28, _29, _30, _31, _32, _33, _34, _35, _36, _37, _38, _39, _40, _41, _42, _43, _44, _45, _46, _47, _48, _49, _50, _51, _52, _53, _54, _55, _56, _57, _58, _59, _60, _61, _62, _63, _64, NAME,...) NAME +#define NLOHMANN_JSON_PASTE(...) NLOHMANN_JSON_EXPAND(NLOHMANN_JSON_GET_MACRO(__VA_ARGS__, \ + NLOHMANN_JSON_PASTE64, \ + NLOHMANN_JSON_PASTE63, \ + NLOHMANN_JSON_PASTE62, \ + NLOHMANN_JSON_PASTE61, \ + NLOHMANN_JSON_PASTE60, \ + NLOHMANN_JSON_PASTE59, \ + NLOHMANN_JSON_PASTE58, \ + NLOHMANN_JSON_PASTE57, \ + NLOHMANN_JSON_PASTE56, \ + NLOHMANN_JSON_PASTE55, \ + NLOHMANN_JSON_PASTE54, \ + NLOHMANN_JSON_PASTE53, \ + NLOHMANN_JSON_PASTE52, \ + NLOHMANN_JSON_PASTE51, \ + NLOHMANN_JSON_PASTE50, \ + NLOHMANN_JSON_PASTE49, \ + NLOHMANN_JSON_PASTE48, \ + NLOHMANN_JSON_PASTE47, \ + NLOHMANN_JSON_PASTE46, \ + NLOHMANN_JSON_PASTE45, \ + NLOHMANN_JSON_PASTE44, \ + NLOHMANN_JSON_PASTE43, \ + NLOHMANN_JSON_PASTE42, \ + NLOHMANN_JSON_PASTE41, \ + NLOHMANN_JSON_PASTE40, \ + NLOHMANN_JSON_PASTE39, \ + NLOHMANN_JSON_PASTE38, \ + NLOHMANN_JSON_PASTE37, \ + NLOHMANN_JSON_PASTE36, \ + NLOHMANN_JSON_PASTE35, \ + NLOHMANN_JSON_PASTE34, \ + NLOHMANN_JSON_PASTE33, \ + NLOHMANN_JSON_PASTE32, \ + NLOHMANN_JSON_PASTE31, \ + NLOHMANN_JSON_PASTE30, \ + NLOHMANN_JSON_PASTE29, \ + NLOHMANN_JSON_PASTE28, \ + NLOHMANN_JSON_PASTE27, \ + NLOHMANN_JSON_PASTE26, \ + NLOHMANN_JSON_PASTE25, \ + NLOHMANN_JSON_PASTE24, \ + NLOHMANN_JSON_PASTE23, \ + NLOHMANN_JSON_PASTE22, \ + NLOHMANN_JSON_PASTE21, \ + NLOHMANN_JSON_PASTE20, \ + NLOHMANN_JSON_PASTE19, \ + NLOHMANN_JSON_PASTE18, \ + NLOHMANN_JSON_PASTE17, \ + NLOHMANN_JSON_PASTE16, \ + NLOHMANN_JSON_PASTE15, \ + NLOHMANN_JSON_PASTE14, \ + NLOHMANN_JSON_PASTE13, \ + NLOHMANN_JSON_PASTE12, \ + NLOHMANN_JSON_PASTE11, \ + NLOHMANN_JSON_PASTE10, \ + NLOHMANN_JSON_PASTE9, \ + NLOHMANN_JSON_PASTE8, \ + NLOHMANN_JSON_PASTE7, \ + NLOHMANN_JSON_PASTE6, \ + NLOHMANN_JSON_PASTE5, \ + NLOHMANN_JSON_PASTE4, \ + NLOHMANN_JSON_PASTE3, \ + NLOHMANN_JSON_PASTE2, \ + NLOHMANN_JSON_PASTE1)(__VA_ARGS__)) +#define NLOHMANN_JSON_PASTE2(func, v1) func(v1) +#define NLOHMANN_JSON_PASTE3(func, v1, v2) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE2(func, v2) +#define NLOHMANN_JSON_PASTE4(func, v1, v2, v3) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE3(func, v2, v3) +#define NLOHMANN_JSON_PASTE5(func, v1, v2, v3, v4) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE4(func, v2, v3, v4) +#define NLOHMANN_JSON_PASTE6(func, v1, v2, v3, v4, v5) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE5(func, v2, v3, v4, v5) +#define NLOHMANN_JSON_PASTE7(func, v1, v2, v3, v4, v5, v6) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE6(func, v2, v3, v4, v5, v6) +#define NLOHMANN_JSON_PASTE8(func, v1, v2, v3, v4, v5, v6, v7) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE7(func, v2, v3, v4, v5, v6, v7) +#define NLOHMANN_JSON_PASTE9(func, v1, v2, v3, v4, v5, v6, v7, v8) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE8(func, v2, v3, v4, v5, v6, v7, v8) +#define NLOHMANN_JSON_PASTE10(func, v1, v2, v3, v4, v5, v6, v7, v8, v9) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE9(func, v2, v3, v4, v5, v6, v7, v8, v9) +#define NLOHMANN_JSON_PASTE11(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE10(func, v2, v3, v4, v5, v6, v7, v8, v9, v10) +#define NLOHMANN_JSON_PASTE12(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE11(func, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11) +#define NLOHMANN_JSON_PASTE13(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE12(func, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12) +#define NLOHMANN_JSON_PASTE14(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE13(func, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13) +#define NLOHMANN_JSON_PASTE15(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE14(func, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14) +#define NLOHMANN_JSON_PASTE16(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE15(func, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15) +#define NLOHMANN_JSON_PASTE17(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE16(func, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16) +#define NLOHMANN_JSON_PASTE18(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE17(func, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17) +#define NLOHMANN_JSON_PASTE19(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE18(func, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18) +#define NLOHMANN_JSON_PASTE20(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE19(func, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19) +#define NLOHMANN_JSON_PASTE21(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE20(func, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20) +#define NLOHMANN_JSON_PASTE22(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE21(func, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21) +#define NLOHMANN_JSON_PASTE23(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE22(func, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22) +#define NLOHMANN_JSON_PASTE24(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE23(func, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23) +#define NLOHMANN_JSON_PASTE25(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE24(func, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24) +#define NLOHMANN_JSON_PASTE26(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE25(func, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25) +#define NLOHMANN_JSON_PASTE27(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE26(func, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26) +#define NLOHMANN_JSON_PASTE28(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE27(func, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27) +#define NLOHMANN_JSON_PASTE29(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE28(func, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28) +#define NLOHMANN_JSON_PASTE30(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE29(func, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29) +#define NLOHMANN_JSON_PASTE31(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE30(func, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30) +#define NLOHMANN_JSON_PASTE32(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE31(func, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31) +#define NLOHMANN_JSON_PASTE33(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE32(func, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32) +#define NLOHMANN_JSON_PASTE34(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE33(func, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33) +#define NLOHMANN_JSON_PASTE35(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE34(func, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34) +#define NLOHMANN_JSON_PASTE36(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE35(func, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35) +#define NLOHMANN_JSON_PASTE37(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE36(func, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36) +#define NLOHMANN_JSON_PASTE38(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE37(func, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37) +#define NLOHMANN_JSON_PASTE39(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE38(func, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38) +#define NLOHMANN_JSON_PASTE40(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE39(func, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39) +#define NLOHMANN_JSON_PASTE41(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE40(func, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40) +#define NLOHMANN_JSON_PASTE42(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40, v41) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE41(func, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40, v41) +#define NLOHMANN_JSON_PASTE43(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40, v41, v42) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE42(func, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40, v41, v42) +#define NLOHMANN_JSON_PASTE44(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40, v41, v42, v43) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE43(func, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40, v41, v42, v43) +#define NLOHMANN_JSON_PASTE45(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40, v41, v42, v43, v44) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE44(func, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40, v41, v42, v43, v44) +#define NLOHMANN_JSON_PASTE46(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40, v41, v42, v43, v44, v45) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE45(func, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40, v41, v42, v43, v44, v45) +#define NLOHMANN_JSON_PASTE47(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40, v41, v42, v43, v44, v45, v46) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE46(func, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40, v41, v42, v43, v44, v45, v46) +#define NLOHMANN_JSON_PASTE48(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40, v41, v42, v43, v44, v45, v46, v47) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE47(func, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40, v41, v42, v43, v44, v45, v46, v47) +#define NLOHMANN_JSON_PASTE49(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40, v41, v42, v43, v44, v45, v46, v47, v48) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE48(func, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40, v41, v42, v43, v44, v45, v46, v47, v48) +#define NLOHMANN_JSON_PASTE50(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40, v41, v42, v43, v44, v45, v46, v47, v48, v49) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE49(func, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40, v41, v42, v43, v44, v45, v46, v47, v48, v49) +#define NLOHMANN_JSON_PASTE51(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40, v41, v42, v43, v44, v45, v46, v47, v48, v49, v50) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE50(func, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40, v41, v42, v43, v44, v45, v46, v47, v48, v49, v50) +#define NLOHMANN_JSON_PASTE52(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40, v41, v42, v43, v44, v45, v46, v47, v48, v49, v50, v51) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE51(func, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40, v41, v42, v43, v44, v45, v46, v47, v48, v49, v50, v51) +#define NLOHMANN_JSON_PASTE53(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40, v41, v42, v43, v44, v45, v46, v47, v48, v49, v50, v51, v52) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE52(func, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40, v41, v42, v43, v44, v45, v46, v47, v48, v49, v50, v51, v52) +#define NLOHMANN_JSON_PASTE54(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40, v41, v42, v43, v44, v45, v46, v47, v48, v49, v50, v51, v52, v53) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE53(func, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40, v41, v42, v43, v44, v45, v46, v47, v48, v49, v50, v51, v52, v53) +#define NLOHMANN_JSON_PASTE55(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40, v41, v42, v43, v44, v45, v46, v47, v48, v49, v50, v51, v52, v53, v54) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE54(func, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40, v41, v42, v43, v44, v45, v46, v47, v48, v49, v50, v51, v52, v53, v54) +#define NLOHMANN_JSON_PASTE56(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40, v41, v42, v43, v44, v45, v46, v47, v48, v49, v50, v51, v52, v53, v54, v55) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE55(func, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40, v41, v42, v43, v44, v45, v46, v47, v48, v49, v50, v51, v52, v53, v54, v55) +#define NLOHMANN_JSON_PASTE57(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40, v41, v42, v43, v44, v45, v46, v47, v48, v49, v50, v51, v52, v53, v54, v55, v56) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE56(func, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40, v41, v42, v43, v44, v45, v46, v47, v48, v49, v50, v51, v52, v53, v54, v55, v56) +#define NLOHMANN_JSON_PASTE58(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40, v41, v42, v43, v44, v45, v46, v47, v48, v49, v50, v51, v52, v53, v54, v55, v56, v57) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE57(func, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40, v41, v42, v43, v44, v45, v46, v47, v48, v49, v50, v51, v52, v53, v54, v55, v56, v57) +#define NLOHMANN_JSON_PASTE59(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40, v41, v42, v43, v44, v45, v46, v47, v48, v49, v50, v51, v52, v53, v54, v55, v56, v57, v58) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE58(func, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40, v41, v42, v43, v44, v45, v46, v47, v48, v49, v50, v51, v52, v53, v54, v55, v56, v57, v58) +#define NLOHMANN_JSON_PASTE60(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40, v41, v42, v43, v44, v45, v46, v47, v48, v49, v50, v51, v52, v53, v54, v55, v56, v57, v58, v59) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE59(func, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40, v41, v42, v43, v44, v45, v46, v47, v48, v49, v50, v51, v52, v53, v54, v55, v56, v57, v58, v59) +#define NLOHMANN_JSON_PASTE61(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40, v41, v42, v43, v44, v45, v46, v47, v48, v49, v50, v51, v52, v53, v54, v55, v56, v57, v58, v59, v60) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE60(func, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40, v41, v42, v43, v44, v45, v46, v47, v48, v49, v50, v51, v52, v53, v54, v55, v56, v57, v58, v59, v60) +#define NLOHMANN_JSON_PASTE62(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40, v41, v42, v43, v44, v45, v46, v47, v48, v49, v50, v51, v52, v53, v54, v55, v56, v57, v58, v59, v60, v61) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE61(func, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40, v41, v42, v43, v44, v45, v46, v47, v48, v49, v50, v51, v52, v53, v54, v55, v56, v57, v58, v59, v60, v61) +#define NLOHMANN_JSON_PASTE63(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40, v41, v42, v43, v44, v45, v46, v47, v48, v49, v50, v51, v52, v53, v54, v55, v56, v57, v58, v59, v60, v61, v62) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE62(func, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40, v41, v42, v43, v44, v45, v46, v47, v48, v49, v50, v51, v52, v53, v54, v55, v56, v57, v58, v59, v60, v61, v62) +#define NLOHMANN_JSON_PASTE64(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40, v41, v42, v43, v44, v45, v46, v47, v48, v49, v50, v51, v52, v53, v54, v55, v56, v57, v58, v59, v60, v61, v62, v63) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE63(func, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40, v41, v42, v43, v44, v45, v46, v47, v48, v49, v50, v51, v52, v53, v54, v55, v56, v57, v58, v59, v60, v61, v62, v63) + +#define NLOHMANN_JSON_TO(v1) nlohmann_json_j[#v1] = nlohmann_json_t.v1; +#define NLOHMANN_JSON_FROM(v1) nlohmann_json_j.at(#v1).get_to(nlohmann_json_t.v1); +#define NLOHMANN_JSON_FROM_WITH_DEFAULT(v1) nlohmann_json_t.v1 = nlohmann_json_j.value(#v1, nlohmann_json_default_obj.v1); + +/*! +@brief macro +@def NLOHMANN_DEFINE_TYPE_INTRUSIVE +@since version 3.9.0 +*/ +#define NLOHMANN_DEFINE_TYPE_INTRUSIVE(Type, ...) \ + friend void to_json(nlohmann::json& nlohmann_json_j, const Type& nlohmann_json_t) { NLOHMANN_JSON_EXPAND(NLOHMANN_JSON_PASTE(NLOHMANN_JSON_TO, __VA_ARGS__)) } \ + friend void from_json(const nlohmann::json& nlohmann_json_j, Type& nlohmann_json_t) { NLOHMANN_JSON_EXPAND(NLOHMANN_JSON_PASTE(NLOHMANN_JSON_FROM, __VA_ARGS__)) } + +#define NLOHMANN_DEFINE_TYPE_INTRUSIVE_WITH_DEFAULT(Type, ...) \ + friend void to_json(nlohmann::json& nlohmann_json_j, const Type& nlohmann_json_t) { NLOHMANN_JSON_EXPAND(NLOHMANN_JSON_PASTE(NLOHMANN_JSON_TO, __VA_ARGS__)) } \ + friend void from_json(const nlohmann::json& nlohmann_json_j, Type& nlohmann_json_t) { Type nlohmann_json_default_obj; NLOHMANN_JSON_EXPAND(NLOHMANN_JSON_PASTE(NLOHMANN_JSON_FROM_WITH_DEFAULT, __VA_ARGS__)) } + +/*! +@brief macro +@def NLOHMANN_DEFINE_TYPE_NON_INTRUSIVE +@since version 3.9.0 +*/ +#define NLOHMANN_DEFINE_TYPE_NON_INTRUSIVE(Type, ...) \ + inline void to_json(nlohmann::json& nlohmann_json_j, const Type& nlohmann_json_t) { NLOHMANN_JSON_EXPAND(NLOHMANN_JSON_PASTE(NLOHMANN_JSON_TO, __VA_ARGS__)) } \ + inline void from_json(const nlohmann::json& nlohmann_json_j, Type& nlohmann_json_t) { NLOHMANN_JSON_EXPAND(NLOHMANN_JSON_PASTE(NLOHMANN_JSON_FROM, __VA_ARGS__)) } + +#define NLOHMANN_DEFINE_TYPE_NON_INTRUSIVE_WITH_DEFAULT(Type, ...) \ + inline void to_json(nlohmann::json& nlohmann_json_j, const Type& nlohmann_json_t) { NLOHMANN_JSON_EXPAND(NLOHMANN_JSON_PASTE(NLOHMANN_JSON_TO, __VA_ARGS__)) } \ + inline void from_json(const nlohmann::json& nlohmann_json_j, Type& nlohmann_json_t) { Type nlohmann_json_default_obj; NLOHMANN_JSON_EXPAND(NLOHMANN_JSON_PASTE(NLOHMANN_JSON_FROM_WITH_DEFAULT, __VA_ARGS__)) } + + +// inspired from https://stackoverflow.com/a/26745591 +// allows to call any std function as if (e.g. with begin): +// using std::begin; begin(x); +// +// it allows using the detected idiom to retrieve the return type +// of such an expression +#define NLOHMANN_CAN_CALL_STD_FUNC_IMPL(std_name) \ + namespace detail { \ + using std::std_name; \ + \ + template \ + using result_of_##std_name = decltype(std_name(std::declval()...)); \ + } \ + \ + namespace detail2 { \ + struct std_name##_tag \ + { \ + }; \ + \ + template \ + std_name##_tag std_name(T&&...); \ + \ + template \ + using result_of_##std_name = decltype(std_name(std::declval()...)); \ + \ + template \ + struct would_call_std_##std_name \ + { \ + static constexpr auto const value = ::nlohmann::detail:: \ + is_detected_exact::value; \ + }; \ + } /* namespace detail2 */ \ + \ + template \ + struct would_call_std_##std_name : detail2::would_call_std_##std_name \ + { \ + } + +#ifndef JSON_USE_IMPLICIT_CONVERSIONS + #define JSON_USE_IMPLICIT_CONVERSIONS 1 +#endif + +#if JSON_USE_IMPLICIT_CONVERSIONS + #define JSON_EXPLICIT +#else + #define JSON_EXPLICIT explicit +#endif + +#ifndef JSON_DISABLE_ENUM_SERIALIZATION + #define JSON_DISABLE_ENUM_SERIALIZATION 0 +#endif + +#ifndef JSON_USE_GLOBAL_UDLS + #define JSON_USE_GLOBAL_UDLS 1 +#endif + +#if JSON_HAS_THREE_WAY_COMPARISON + #include // partial_ordering +#endif + +NLOHMANN_JSON_NAMESPACE_BEGIN +namespace detail +{ + +/////////////////////////// +// JSON type enumeration // +/////////////////////////// + +/*! +@brief the JSON type enumeration + +This enumeration collects the different JSON types. It is internally used to +distinguish the stored values, and the functions @ref basic_json::is_null(), +@ref basic_json::is_object(), @ref basic_json::is_array(), +@ref basic_json::is_string(), @ref basic_json::is_boolean(), +@ref basic_json::is_number() (with @ref basic_json::is_number_integer(), +@ref basic_json::is_number_unsigned(), and @ref basic_json::is_number_float()), +@ref basic_json::is_discarded(), @ref basic_json::is_primitive(), and +@ref basic_json::is_structured() rely on it. + +@note There are three enumeration entries (number_integer, number_unsigned, and +number_float), because the library distinguishes these three types for numbers: +@ref basic_json::number_unsigned_t is used for unsigned integers, +@ref basic_json::number_integer_t is used for signed integers, and +@ref basic_json::number_float_t is used for floating-point numbers or to +approximate integers which do not fit in the limits of their respective type. + +@sa see @ref basic_json::basic_json(const value_t value_type) -- create a JSON +value with the default value for a given type + +@since version 1.0.0 +*/ +enum class value_t : std::uint8_t +{ + null, ///< null value + object, ///< object (unordered set of name/value pairs) + array, ///< array (ordered collection of values) + string, ///< string value + boolean, ///< boolean value + number_integer, ///< number value (signed integer) + number_unsigned, ///< number value (unsigned integer) + number_float, ///< number value (floating-point) + binary, ///< binary array (ordered collection of bytes) + discarded ///< discarded by the parser callback function +}; + +/*! +@brief comparison operator for JSON types + +Returns an ordering that is similar to Python: +- order: null < boolean < number < object < array < string < binary +- furthermore, each type is not smaller than itself +- discarded values are not comparable +- binary is represented as a b"" string in python and directly comparable to a + string; however, making a binary array directly comparable with a string would + be surprising behavior in a JSON file. + +@since version 1.0.0 +*/ +#if JSON_HAS_THREE_WAY_COMPARISON + inline std::partial_ordering operator<=>(const value_t lhs, const value_t rhs) noexcept // *NOPAD* +#else + inline bool operator<(const value_t lhs, const value_t rhs) noexcept +#endif +{ + static constexpr std::array order = {{ + 0 /* null */, 3 /* object */, 4 /* array */, 5 /* string */, + 1 /* boolean */, 2 /* integer */, 2 /* unsigned */, 2 /* float */, + 6 /* binary */ + } + }; + + const auto l_index = static_cast(lhs); + const auto r_index = static_cast(rhs); +#if JSON_HAS_THREE_WAY_COMPARISON + if (l_index < order.size() && r_index < order.size()) + { + return order[l_index] <=> order[r_index]; // *NOPAD* + } + return std::partial_ordering::unordered; +#else + return l_index < order.size() && r_index < order.size() && order[l_index] < order[r_index]; +#endif +} + +// GCC selects the built-in operator< over an operator rewritten from +// a user-defined spaceship operator +// Clang, MSVC, and ICC select the rewritten candidate +// (see GCC bug https://gcc.gnu.org/bugzilla/show_bug.cgi?id=105200) +#if JSON_HAS_THREE_WAY_COMPARISON && defined(__GNUC__) +inline bool operator<(const value_t lhs, const value_t rhs) noexcept +{ + return std::is_lt(lhs <=> rhs); // *NOPAD* +} +#endif + +} // namespace detail +NLOHMANN_JSON_NAMESPACE_END + +// #include +// __ _____ _____ _____ +// __| | __| | | | JSON for Modern C++ +// | | |__ | | | | | | version 3.11.2 +// |_____|_____|_____|_|___| https://github.com/nlohmann/json +// +// SPDX-FileCopyrightText: 2013-2022 Niels Lohmann +// SPDX-License-Identifier: MIT + + + +// #include + + +NLOHMANN_JSON_NAMESPACE_BEGIN +namespace detail +{ + +/*! +@brief replace all occurrences of a substring by another string + +@param[in,out] s the string to manipulate; changed so that all + occurrences of @a f are replaced with @a t +@param[in] f the substring to replace with @a t +@param[in] t the string to replace @a f + +@pre The search string @a f must not be empty. **This precondition is +enforced with an assertion.** + +@since version 2.0.0 +*/ +template +inline void replace_substring(StringType& s, const StringType& f, + const StringType& t) +{ + JSON_ASSERT(!f.empty()); + for (auto pos = s.find(f); // find first occurrence of f + pos != StringType::npos; // make sure f was found + s.replace(pos, f.size(), t), // replace with t, and + pos = s.find(f, pos + t.size())) // find next occurrence of f + {} +} + +/*! + * @brief string escaping as described in RFC 6901 (Sect. 4) + * @param[in] s string to escape + * @return escaped string + * + * Note the order of escaping "~" to "~0" and "/" to "~1" is important. + */ +template +inline StringType escape(StringType s) +{ + replace_substring(s, StringType{"~"}, StringType{"~0"}); + replace_substring(s, StringType{"/"}, StringType{"~1"}); + return s; +} + +/*! + * @brief string unescaping as described in RFC 6901 (Sect. 4) + * @param[in] s string to unescape + * @return unescaped string + * + * Note the order of escaping "~1" to "/" and "~0" to "~" is important. + */ +template +static void unescape(StringType& s) +{ + replace_substring(s, StringType{"~1"}, StringType{"/"}); + replace_substring(s, StringType{"~0"}, StringType{"~"}); +} + +} // namespace detail +NLOHMANN_JSON_NAMESPACE_END + +// #include +// __ _____ _____ _____ +// __| | __| | | | JSON for Modern C++ +// | | |__ | | | | | | version 3.11.2 +// |_____|_____|_____|_|___| https://github.com/nlohmann/json +// +// SPDX-FileCopyrightText: 2013-2022 Niels Lohmann +// SPDX-License-Identifier: MIT + + + +#include // size_t + +// #include + + +NLOHMANN_JSON_NAMESPACE_BEGIN +namespace detail +{ + +/// struct to capture the start position of the current token +struct position_t +{ + /// the total number of characters read + std::size_t chars_read_total = 0; + /// the number of characters read in the current line + std::size_t chars_read_current_line = 0; + /// the number of lines read + std::size_t lines_read = 0; + + /// conversion to size_t to preserve SAX interface + constexpr operator size_t() const + { + return chars_read_total; + } +}; + +} // namespace detail +NLOHMANN_JSON_NAMESPACE_END + +// #include + +// #include +// __ _____ _____ _____ +// __| | __| | | | JSON for Modern C++ +// | | |__ | | | | | | version 3.11.2 +// |_____|_____|_____|_|___| https://github.com/nlohmann/json +// +// SPDX-FileCopyrightText: 2013-2022 Niels Lohmann +// SPDX-FileCopyrightText: 2018 The Abseil Authors +// SPDX-License-Identifier: MIT + + + +#include // array +#include // size_t +#include // conditional, enable_if, false_type, integral_constant, is_constructible, is_integral, is_same, remove_cv, remove_reference, true_type +#include // index_sequence, make_index_sequence, index_sequence_for + +// #include + + +NLOHMANN_JSON_NAMESPACE_BEGIN +namespace detail +{ + +template +using uncvref_t = typename std::remove_cv::type>::type; + +#ifdef JSON_HAS_CPP_14 + +// the following utilities are natively available in C++14 +using std::enable_if_t; +using std::index_sequence; +using std::make_index_sequence; +using std::index_sequence_for; + +#else + +// alias templates to reduce boilerplate +template +using enable_if_t = typename std::enable_if::type; + +// The following code is taken from https://github.com/abseil/abseil-cpp/blob/10cb35e459f5ecca5b2ff107635da0bfa41011b4/absl/utility/utility.h +// which is part of Google Abseil (https://github.com/abseil/abseil-cpp), licensed under the Apache License 2.0. + +//// START OF CODE FROM GOOGLE ABSEIL + +// integer_sequence +// +// Class template representing a compile-time integer sequence. An instantiation +// of `integer_sequence` has a sequence of integers encoded in its +// type through its template arguments (which is a common need when +// working with C++11 variadic templates). `absl::integer_sequence` is designed +// to be a drop-in replacement for C++14's `std::integer_sequence`. +// +// Example: +// +// template< class T, T... Ints > +// void user_function(integer_sequence); +// +// int main() +// { +// // user_function's `T` will be deduced to `int` and `Ints...` +// // will be deduced to `0, 1, 2, 3, 4`. +// user_function(make_integer_sequence()); +// } +template +struct integer_sequence +{ + using value_type = T; + static constexpr std::size_t size() noexcept + { + return sizeof...(Ints); + } +}; + +// index_sequence +// +// A helper template for an `integer_sequence` of `size_t`, +// `absl::index_sequence` is designed to be a drop-in replacement for C++14's +// `std::index_sequence`. +template +using index_sequence = integer_sequence; + +namespace utility_internal +{ + +template +struct Extend; + +// Note that SeqSize == sizeof...(Ints). It's passed explicitly for efficiency. +template +struct Extend, SeqSize, 0> +{ + using type = integer_sequence < T, Ints..., (Ints + SeqSize)... >; +}; + +template +struct Extend, SeqSize, 1> +{ + using type = integer_sequence < T, Ints..., (Ints + SeqSize)..., 2 * SeqSize >; +}; + +// Recursion helper for 'make_integer_sequence'. +// 'Gen::type' is an alias for 'integer_sequence'. +template +struct Gen +{ + using type = + typename Extend < typename Gen < T, N / 2 >::type, N / 2, N % 2 >::type; +}; + +template +struct Gen +{ + using type = integer_sequence; +}; + +} // namespace utility_internal + +// Compile-time sequences of integers + +// make_integer_sequence +// +// This template alias is equivalent to +// `integer_sequence`, and is designed to be a drop-in +// replacement for C++14's `std::make_integer_sequence`. +template +using make_integer_sequence = typename utility_internal::Gen::type; + +// make_index_sequence +// +// This template alias is equivalent to `index_sequence<0, 1, ..., N-1>`, +// and is designed to be a drop-in replacement for C++14's +// `std::make_index_sequence`. +template +using make_index_sequence = make_integer_sequence; + +// index_sequence_for +// +// Converts a typename pack into an index sequence of the same length, and +// is designed to be a drop-in replacement for C++14's +// `std::index_sequence_for()` +template +using index_sequence_for = make_index_sequence; + +//// END OF CODE FROM GOOGLE ABSEIL + +#endif + +// dispatch utility (taken from ranges-v3) +template struct priority_tag : priority_tag < N - 1 > {}; +template<> struct priority_tag<0> {}; + +// taken from ranges-v3 +template +struct static_const +{ + static JSON_INLINE_VARIABLE constexpr T value{}; +}; + +#ifndef JSON_HAS_CPP_17 + template + constexpr T static_const::value; +#endif + +template +inline constexpr std::array make_array(Args&& ... args) +{ + return std::array {{static_cast(std::forward(args))...}}; +} + +} // namespace detail +NLOHMANN_JSON_NAMESPACE_END + +// #include +// __ _____ _____ _____ +// __| | __| | | | JSON for Modern C++ +// | | |__ | | | | | | version 3.11.2 +// |_____|_____|_____|_|___| https://github.com/nlohmann/json +// +// SPDX-FileCopyrightText: 2013-2022 Niels Lohmann +// SPDX-License-Identifier: MIT + + + +#include // numeric_limits +#include // false_type, is_constructible, is_integral, is_same, true_type +#include // declval +#include // tuple + +// #include +// __ _____ _____ _____ +// __| | __| | | | JSON for Modern C++ +// | | |__ | | | | | | version 3.11.2 +// |_____|_____|_____|_|___| https://github.com/nlohmann/json +// +// SPDX-FileCopyrightText: 2013-2022 Niels Lohmann +// SPDX-License-Identifier: MIT + + + +#include // random_access_iterator_tag + +// #include + +// #include + +// #include + + +NLOHMANN_JSON_NAMESPACE_BEGIN +namespace detail +{ + +template +struct iterator_types {}; + +template +struct iterator_types < + It, + void_t> +{ + using difference_type = typename It::difference_type; + using value_type = typename It::value_type; + using pointer = typename It::pointer; + using reference = typename It::reference; + using iterator_category = typename It::iterator_category; +}; + +// This is required as some compilers implement std::iterator_traits in a way that +// doesn't work with SFINAE. See https://github.com/nlohmann/json/issues/1341. +template +struct iterator_traits +{ +}; + +template +struct iterator_traits < T, enable_if_t < !std::is_pointer::value >> + : iterator_types +{ +}; + +template +struct iterator_traits::value>> +{ + using iterator_category = std::random_access_iterator_tag; + using value_type = T; + using difference_type = ptrdiff_t; + using pointer = T*; + using reference = T&; +}; + +} // namespace detail +NLOHMANN_JSON_NAMESPACE_END + +// #include + +// #include +// __ _____ _____ _____ +// __| | __| | | | JSON for Modern C++ +// | | |__ | | | | | | version 3.11.2 +// |_____|_____|_____|_|___| https://github.com/nlohmann/json +// +// SPDX-FileCopyrightText: 2013-2022 Niels Lohmann +// SPDX-License-Identifier: MIT + + + +// #include + + +NLOHMANN_JSON_NAMESPACE_BEGIN + +NLOHMANN_CAN_CALL_STD_FUNC_IMPL(begin); + +NLOHMANN_JSON_NAMESPACE_END + +// #include +// __ _____ _____ _____ +// __| | __| | | | JSON for Modern C++ +// | | |__ | | | | | | version 3.11.2 +// |_____|_____|_____|_|___| https://github.com/nlohmann/json +// +// SPDX-FileCopyrightText: 2013-2022 Niels Lohmann +// SPDX-License-Identifier: MIT + + + +// #include + + +NLOHMANN_JSON_NAMESPACE_BEGIN + +NLOHMANN_CAN_CALL_STD_FUNC_IMPL(end); + +NLOHMANN_JSON_NAMESPACE_END + +// #include + +// #include + +// #include +// __ _____ _____ _____ +// __| | __| | | | JSON for Modern C++ +// | | |__ | | | | | | version 3.11.2 +// |_____|_____|_____|_|___| https://github.com/nlohmann/json +// +// SPDX-FileCopyrightText: 2013-2022 Niels Lohmann +// SPDX-License-Identifier: MIT + +#ifndef INCLUDE_NLOHMANN_JSON_FWD_HPP_ + #define INCLUDE_NLOHMANN_JSON_FWD_HPP_ + + #include // int64_t, uint64_t + #include // map + #include // allocator + #include // string + #include // vector + + // #include + + + /*! + @brief namespace for Niels Lohmann + @see https://github.com/nlohmann + @since version 1.0.0 + */ + NLOHMANN_JSON_NAMESPACE_BEGIN + + /*! + @brief default JSONSerializer template argument + + This serializer ignores the template arguments and uses ADL + ([argument-dependent lookup](https://en.cppreference.com/w/cpp/language/adl)) + for serialization. + */ + template + struct adl_serializer; + + /// a class to store JSON values + /// @sa https://json.nlohmann.me/api/basic_json/ + template class ObjectType = + std::map, + template class ArrayType = std::vector, + class StringType = std::string, class BooleanType = bool, + class NumberIntegerType = std::int64_t, + class NumberUnsignedType = std::uint64_t, + class NumberFloatType = double, + template class AllocatorType = std::allocator, + template class JSONSerializer = + adl_serializer, + class BinaryType = std::vector> + class basic_json; + + /// @brief JSON Pointer defines a string syntax for identifying a specific value within a JSON document + /// @sa https://json.nlohmann.me/api/json_pointer/ + template + class json_pointer; + + /*! + @brief default specialization + @sa https://json.nlohmann.me/api/json/ + */ + using json = basic_json<>; + + /// @brief a minimal map-like container that preserves insertion order + /// @sa https://json.nlohmann.me/api/ordered_map/ + template + struct ordered_map; + + /// @brief specialization that maintains the insertion order of object keys + /// @sa https://json.nlohmann.me/api/ordered_json/ + using ordered_json = basic_json; + + NLOHMANN_JSON_NAMESPACE_END + +#endif // INCLUDE_NLOHMANN_JSON_FWD_HPP_ + + +NLOHMANN_JSON_NAMESPACE_BEGIN +/*! +@brief detail namespace with internal helper functions + +This namespace collects functions that should not be exposed, +implementations of some @ref basic_json methods, and meta-programming helpers. + +@since version 2.1.0 +*/ +namespace detail +{ + +///////////// +// helpers // +///////////// + +// Note to maintainers: +// +// Every trait in this file expects a non CV-qualified type. +// The only exceptions are in the 'aliases for detected' section +// (i.e. those of the form: decltype(T::member_function(std::declval()))) +// +// In this case, T has to be properly CV-qualified to constraint the function arguments +// (e.g. to_json(BasicJsonType&, const T&)) + +template struct is_basic_json : std::false_type {}; + +NLOHMANN_BASIC_JSON_TPL_DECLARATION +struct is_basic_json : std::true_type {}; + +// used by exceptions create() member functions +// true_type for pointer to possibly cv-qualified basic_json or std::nullptr_t +// false_type otherwise +template +struct is_basic_json_context : + std::integral_constant < bool, + is_basic_json::type>::type>::value + || std::is_same::value > +{}; + +////////////////////// +// json_ref helpers // +////////////////////// + +template +class json_ref; + +template +struct is_json_ref : std::false_type {}; + +template +struct is_json_ref> : std::true_type {}; + +////////////////////////// +// aliases for detected // +////////////////////////// + +template +using mapped_type_t = typename T::mapped_type; + +template +using key_type_t = typename T::key_type; + +template +using value_type_t = typename T::value_type; + +template +using difference_type_t = typename T::difference_type; + +template +using pointer_t = typename T::pointer; + +template +using reference_t = typename T::reference; + +template +using iterator_category_t = typename T::iterator_category; + +template +using to_json_function = decltype(T::to_json(std::declval()...)); + +template +using from_json_function = decltype(T::from_json(std::declval()...)); + +template +using get_template_function = decltype(std::declval().template get()); + +// trait checking if JSONSerializer::from_json(json const&, udt&) exists +template +struct has_from_json : std::false_type {}; + +// trait checking if j.get is valid +// use this trait instead of std::is_constructible or std::is_convertible, +// both rely on, or make use of implicit conversions, and thus fail when T +// has several constructors/operator= (see https://github.com/nlohmann/json/issues/958) +template +struct is_getable +{ + static constexpr bool value = is_detected::value; +}; + +template +struct has_from_json < BasicJsonType, T, enable_if_t < !is_basic_json::value >> +{ + using serializer = typename BasicJsonType::template json_serializer; + + static constexpr bool value = + is_detected_exact::value; +}; + +// This trait checks if JSONSerializer::from_json(json const&) exists +// this overload is used for non-default-constructible user-defined-types +template +struct has_non_default_from_json : std::false_type {}; + +template +struct has_non_default_from_json < BasicJsonType, T, enable_if_t < !is_basic_json::value >> +{ + using serializer = typename BasicJsonType::template json_serializer; + + static constexpr bool value = + is_detected_exact::value; +}; + +// This trait checks if BasicJsonType::json_serializer::to_json exists +// Do not evaluate the trait when T is a basic_json type, to avoid template instantiation infinite recursion. +template +struct has_to_json : std::false_type {}; + +template +struct has_to_json < BasicJsonType, T, enable_if_t < !is_basic_json::value >> +{ + using serializer = typename BasicJsonType::template json_serializer; + + static constexpr bool value = + is_detected_exact::value; +}; + +template +using detect_key_compare = typename T::key_compare; + +template +struct has_key_compare : std::integral_constant::value> {}; + +// obtains the actual object key comparator +template +struct actual_object_comparator +{ + using object_t = typename BasicJsonType::object_t; + using object_comparator_t = typename BasicJsonType::default_object_comparator_t; + using type = typename std::conditional < has_key_compare::value, + typename object_t::key_compare, object_comparator_t>::type; +}; + +template +using actual_object_comparator_t = typename actual_object_comparator::type; + +/////////////////// +// is_ functions // +/////////////////// + +// https://en.cppreference.com/w/cpp/types/conjunction +template struct conjunction : std::true_type { }; +template struct conjunction : B { }; +template +struct conjunction +: std::conditional(B::value), conjunction, B>::type {}; + +// https://en.cppreference.com/w/cpp/types/negation +template struct negation : std::integral_constant < bool, !B::value > { }; + +// Reimplementation of is_constructible and is_default_constructible, due to them being broken for +// std::pair and std::tuple until LWG 2367 fix (see https://cplusplus.github.io/LWG/lwg-defects.html#2367). +// This causes compile errors in e.g. clang 3.5 or gcc 4.9. +template +struct is_default_constructible : std::is_default_constructible {}; + +template +struct is_default_constructible> + : conjunction, is_default_constructible> {}; + +template +struct is_default_constructible> + : conjunction, is_default_constructible> {}; + +template +struct is_default_constructible> + : conjunction...> {}; + +template +struct is_default_constructible> + : conjunction...> {}; + + +template +struct is_constructible : std::is_constructible {}; + +template +struct is_constructible> : is_default_constructible> {}; + +template +struct is_constructible> : is_default_constructible> {}; + +template +struct is_constructible> : is_default_constructible> {}; + +template +struct is_constructible> : is_default_constructible> {}; + + +template +struct is_iterator_traits : std::false_type {}; + +template +struct is_iterator_traits> +{ + private: + using traits = iterator_traits; + + public: + static constexpr auto value = + is_detected::value && + is_detected::value && + is_detected::value && + is_detected::value && + is_detected::value; +}; + +template +struct is_range +{ + private: + using t_ref = typename std::add_lvalue_reference::type; + + using iterator = detected_t; + using sentinel = detected_t; + + // to be 100% correct, it should use https://en.cppreference.com/w/cpp/iterator/input_or_output_iterator + // and https://en.cppreference.com/w/cpp/iterator/sentinel_for + // but reimplementing these would be too much work, as a lot of other concepts are used underneath + static constexpr auto is_iterator_begin = + is_iterator_traits>::value; + + public: + static constexpr bool value = !std::is_same::value && !std::is_same::value && is_iterator_begin; +}; + +template +using iterator_t = enable_if_t::value, result_of_begin())>>; + +template +using range_value_t = value_type_t>>; + +// The following implementation of is_complete_type is taken from +// https://blogs.msdn.microsoft.com/vcblog/2015/12/02/partial-support-for-expression-sfinae-in-vs-2015-update-1/ +// and is written by Xiang Fan who agreed to using it in this library. + +template +struct is_complete_type : std::false_type {}; + +template +struct is_complete_type : std::true_type {}; + +template +struct is_compatible_object_type_impl : std::false_type {}; + +template +struct is_compatible_object_type_impl < + BasicJsonType, CompatibleObjectType, + enable_if_t < is_detected::value&& + is_detected::value >> +{ + using object_t = typename BasicJsonType::object_t; + + // macOS's is_constructible does not play well with nonesuch... + static constexpr bool value = + is_constructible::value && + is_constructible::value; +}; + +template +struct is_compatible_object_type + : is_compatible_object_type_impl {}; + +template +struct is_constructible_object_type_impl : std::false_type {}; + +template +struct is_constructible_object_type_impl < + BasicJsonType, ConstructibleObjectType, + enable_if_t < is_detected::value&& + is_detected::value >> +{ + using object_t = typename BasicJsonType::object_t; + + static constexpr bool value = + (is_default_constructible::value && + (std::is_move_assignable::value || + std::is_copy_assignable::value) && + (is_constructible::value && + std::is_same < + typename object_t::mapped_type, + typename ConstructibleObjectType::mapped_type >::value)) || + (has_from_json::value || + has_non_default_from_json < + BasicJsonType, + typename ConstructibleObjectType::mapped_type >::value); +}; + +template +struct is_constructible_object_type + : is_constructible_object_type_impl {}; + +template +struct is_compatible_string_type +{ + static constexpr auto value = + is_constructible::value; +}; + +template +struct is_constructible_string_type +{ + // launder type through decltype() to fix compilation failure on ICPC +#ifdef __INTEL_COMPILER + using laundered_type = decltype(std::declval()); +#else + using laundered_type = ConstructibleStringType; +#endif + + static constexpr auto value = + conjunction < + is_constructible, + is_detected_exact>::value; +}; + +template +struct is_compatible_array_type_impl : std::false_type {}; + +template +struct is_compatible_array_type_impl < + BasicJsonType, CompatibleArrayType, + enable_if_t < + is_detected::value&& + is_iterator_traits>>::value&& +// special case for types like std::filesystem::path whose iterator's value_type are themselves +// c.f. https://github.com/nlohmann/json/pull/3073 + !std::is_same>::value >> +{ + static constexpr bool value = + is_constructible>::value; +}; + +template +struct is_compatible_array_type + : is_compatible_array_type_impl {}; + +template +struct is_constructible_array_type_impl : std::false_type {}; + +template +struct is_constructible_array_type_impl < + BasicJsonType, ConstructibleArrayType, + enable_if_t::value >> + : std::true_type {}; + +template +struct is_constructible_array_type_impl < + BasicJsonType, ConstructibleArrayType, + enable_if_t < !std::is_same::value&& + !is_compatible_string_type::value&& + is_default_constructible::value&& +(std::is_move_assignable::value || + std::is_copy_assignable::value)&& +is_detected::value&& +is_iterator_traits>>::value&& +is_detected::value&& +// special case for types like std::filesystem::path whose iterator's value_type are themselves +// c.f. https://github.com/nlohmann/json/pull/3073 +!std::is_same>::value&& + is_complete_type < + detected_t>::value >> +{ + using value_type = range_value_t; + + static constexpr bool value = + std::is_same::value || + has_from_json::value || + has_non_default_from_json < + BasicJsonType, + value_type >::value; +}; + +template +struct is_constructible_array_type + : is_constructible_array_type_impl {}; + +template +struct is_compatible_integer_type_impl : std::false_type {}; + +template +struct is_compatible_integer_type_impl < + RealIntegerType, CompatibleNumberIntegerType, + enable_if_t < std::is_integral::value&& + std::is_integral::value&& + !std::is_same::value >> +{ + // is there an assert somewhere on overflows? + using RealLimits = std::numeric_limits; + using CompatibleLimits = std::numeric_limits; + + static constexpr auto value = + is_constructible::value && + CompatibleLimits::is_integer && + RealLimits::is_signed == CompatibleLimits::is_signed; +}; + +template +struct is_compatible_integer_type + : is_compatible_integer_type_impl {}; + +template +struct is_compatible_type_impl: std::false_type {}; + +template +struct is_compatible_type_impl < + BasicJsonType, CompatibleType, + enable_if_t::value >> +{ + static constexpr bool value = + has_to_json::value; +}; + +template +struct is_compatible_type + : is_compatible_type_impl {}; + +template +struct is_constructible_tuple : std::false_type {}; + +template +struct is_constructible_tuple> : conjunction...> {}; + +template +struct is_json_iterator_of : std::false_type {}; + +template +struct is_json_iterator_of : std::true_type {}; + +template +struct is_json_iterator_of : std::true_type +{}; + +// checks if a given type T is a template specialization of Primary +template