├── .github └── workflows │ └── build.yml ├── .gitignore ├── AMBuildScript ├── AMBuilder ├── PackageScript ├── README.md ├── configs ├── core.cfg └── signatures.ini ├── configure.py ├── funchook ├── LICENSE ├── README.md ├── include │ └── funchook.h └── lib │ ├── distorm.lib │ ├── funchook.lib │ ├── libdistorm.a │ └── libfunchook.a ├── hl2sdk-manifests ├── SdkHelpers.ambuild └── manifests │ └── cs2.json ├── include ├── cookies.h └── menus.h ├── menu_buttons ├── info.txt ├── site │ ├── a-p.svg │ ├── a.svg │ ├── d-p.svg │ ├── d.svg │ ├── e-p.svg │ ├── e.svg │ ├── empty.svg │ ├── empty_half.svg │ ├── f.svg │ ├── s-p.svg │ ├── s.svg │ ├── w-p.svg │ └── w.svg └── workshop │ ├── a-p.svg │ ├── a.svg │ ├── d-p.svg │ ├── d.svg │ ├── e-p.svg │ ├── e.svg │ ├── empty.svg │ ├── empty_half.svg │ ├── f.svg │ ├── install.txt │ ├── s-p.svg │ ├── s.svg │ ├── w-p.svg │ └── w.svg ├── translations └── menus.phrases.txt ├── utils.cpp └── utils.h /.github/workflows/build.yml: -------------------------------------------------------------------------------- 1 | name: Build AMBuild Plugin 2 | 3 | on: 4 | push: 5 | branches: 6 | - main 7 | pull_request: 8 | branches: 9 | - main 10 | release: 11 | types: 12 | - created 13 | 14 | jobs: 15 | build: 16 | if: "!contains(github.event.head_commit.message, '[skip ci]')" 17 | permissions: 18 | contents: write 19 | runs-on: ubuntu-latest 20 | container: 21 | image: ghcr.io/pisex/ubuntu20:latest 22 | 23 | env: 24 | HL2SDK_ROOT: "${{ github.workspace }}/external" 25 | MMS_PATH: "${{ github.workspace }}/external/metamod-source" 26 | MANIFEST_PATH: "${{ github.workspace }}/external/metamod-source/hl2sdk-manifests" 27 | 28 | steps: 29 | - name: Generate build number 30 | if: ${{ github.event_name == 'push' && github.ref == 'refs/heads/main' }} 31 | id: buildnumber 32 | uses: onyxmueller/build-tag-number@v1 33 | with: 34 | token: ${{secrets.github_token}} 35 | 36 | - name: Checkout code 37 | uses: actions/checkout@v3 38 | 39 | - name: Set up dependencies 40 | run: | 41 | export DEBIAN_FRONTEND=noninteractive 42 | apt-get update -qy 43 | apt-get install -y git clang-10 clang++-10 binutils python3 python3-pip zip 44 | 45 | python3 -m pip install --upgrade pip importlib-metadata 46 | python3 -m pip install setuptools==45.2.0 47 | 48 | git clone https://github.com/alliedmodders/ambuild.git ambuild 49 | cd ambuild 50 | pip3 install . 51 | cd .. 52 | 53 | mkdir -p external 54 | cd external 55 | git clone --recursive --branch master --single-branch \ 56 | https://github.com/alliedmodders/metamod-source.git 57 | git clone --recursive --branch cs2 --single-branch \ 58 | https://github.com/alliedmodders/hl2sdk.git hl2sdk-cs2 59 | 60 | cd ../.. 61 | 62 | git clone https://github.com/pisex/SchemaEntity.git 63 | 64 | - name: Configure and build plugin 65 | run: | 66 | mkdir build 67 | cd build 68 | python3 ../configure.py -s cs2 --targets x86_64 --enable-optimize --hl2sdk-manifests=./hl2sdk-manifests --mms_path=$MMS_PATH --hl2sdk-root=$HL2SDK_ROOT 69 | ambuild 70 | 71 | - name: Package addon into ZIP 72 | run: | 73 | cd build/package/addons 74 | zip -r "${{ github.event.repository.name }}.zip" . 75 | mv "${{ github.event.repository.name }}.zip" "${GITHUB_WORKSPACE}/" 76 | 77 | - name: Create GitHub Release 78 | uses: softprops/action-gh-release@v1 79 | with: 80 | tag_name: ${{ github.event.head_commit.message }} 81 | files: ${{ github.workspace }}/${{ github.event.repository.name }}.zip -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | build/ -------------------------------------------------------------------------------- /AMBuildScript: -------------------------------------------------------------------------------- 1 | # vim: set sts=2 ts=8 sw=2 tw=99 et ft=python: 2 | import os, sys 3 | 4 | def ResolveEnvPath(env, folder): 5 | if env in os.environ: 6 | path = os.environ[env] 7 | if os.path.isdir(path): 8 | return path 9 | else: 10 | head = os.getcwd() 11 | oldhead = None 12 | while head != None and head != oldhead: 13 | path = os.path.join(head, folder) 14 | if os.path.isdir(path): 15 | return path 16 | oldhead = head 17 | head, tail = os.path.split(head) 18 | return None 19 | 20 | def ResolveMMSRoot(): 21 | prenormalized_path = None 22 | if builder.options.mms_path: 23 | prenormalized_path = builder.options.mms_path 24 | else: 25 | prenormalized_path = ResolveEnvPath('MMSOURCE112', 'mmsource-1.12') 26 | if not prenormalized_path: 27 | prenormalized_path = ResolveEnvPath('MMSOURCE111', 'mmsource-1.11') 28 | if not prenormalized_path: 29 | prenormalized_path = ResolveEnvPath('MMSOURCE110', 'mmsource-1.10') 30 | if not prenormalized_path: 31 | prenormalized_path = ResolveEnvPath('MMSOURCE_DEV', 'metamod-source') 32 | if not prenormalized_path: 33 | prenormalized_path = ResolveEnvPath('MMSOURCE_DEV', 'mmsource-central') 34 | if not prenormalized_path or not os.path.isdir(prenormalized_path): 35 | raise Exception('Could not find a source copy of Metamod:Source') 36 | 37 | return os.path.abspath(os.path.normpath(prenormalized_path)) 38 | 39 | mms_root = ResolveMMSRoot() 40 | 41 | if not builder.options.hl2sdk_manifests: 42 | raise Exception('Could not find a source copy of HL2SDK manifests') 43 | hl2sdk_manifests = builder.options.hl2sdk_manifests 44 | 45 | SdkHelpers = builder.Eval(os.path.join(hl2sdk_manifests, 'SdkHelpers.ambuild'), { 46 | 'Project': 'metamod' 47 | }) 48 | 49 | class MMSPluginConfig(object): 50 | def __init__(self): 51 | self.sdk_manifests = [] 52 | self.sdks = {} 53 | self.sdk_targets = [] 54 | self.binaries = [] 55 | self.mms_root = mms_root 56 | self.all_targets = [] 57 | self.target_archs = set() 58 | 59 | if builder.options.plugin_name is not None: 60 | self.plugin_name = builder.options.plugin_name 61 | else: 62 | self.plugin_name = 'utils' 63 | 64 | if builder.options.plugin_alias is not None: 65 | self.plugin_alias = builder.options.plugin_alias 66 | else: 67 | self.plugin_alias = 'utils' 68 | 69 | if builder.options.targets: 70 | target_archs = builder.options.targets.split(',') 71 | else: 72 | target_archs = ['x86', 'x86_64'] 73 | 74 | for arch in target_archs: 75 | try: 76 | cxx = builder.DetectCxx(target_arch = arch) 77 | self.target_archs.add(cxx.target.arch) 78 | except Exception as e: 79 | # Error if archs were manually overridden. 80 | if builder.options.targets: 81 | raise 82 | print('Skipping target {}: {}'.format(arch, e)) 83 | continue 84 | self.all_targets.append(cxx) 85 | 86 | if not self.all_targets: 87 | raise Exception('No suitable C/C++ compiler was found.') 88 | 89 | def findSdkPath(self, sdk_name): 90 | dir_name = 'hl2sdk-{}'.format(sdk_name) 91 | if builder.options.hl2sdk_root: 92 | sdk_path = os.path.join(builder.options.hl2sdk_root, dir_name) 93 | if os.path.exists(sdk_path): 94 | return sdk_path 95 | return ResolveEnvPath('HL2SDK{}'.format(sdk_name.upper()), dir_name) 96 | 97 | def detectSDKs(self): 98 | sdk_list = [s for s in builder.options.sdks.split(',') if s] 99 | SdkHelpers.find_sdk_path = self.findSdkPath 100 | SdkHelpers.findSdks(builder, self.all_targets, sdk_list) 101 | 102 | self.sdks = SdkHelpers.sdks 103 | self.sdk_manifests = SdkHelpers.sdk_manifests 104 | self.sdk_targets = SdkHelpers.sdk_targets 105 | 106 | if len(self.sdks) > 1: 107 | raise Exception('Only one sdk at a time is supported, for multi-sdk approach use loader based solution.') 108 | 109 | def configure(self): 110 | for cxx in self.all_targets: 111 | if cxx.target.arch not in ['x86', 'x86_64']: 112 | raise Exception('Unknown target architecture: {0}'.format(arch)) 113 | 114 | self.configure_cxx(cxx) 115 | 116 | def configure_cxx(self, cxx): 117 | if cxx.behavior == 'gcc': 118 | cxx.defines += [ 119 | 'stricmp=strcasecmp', 120 | '_stricmp=strcasecmp', 121 | '_snprintf=snprintf', 122 | '_vsnprintf=vsnprintf', 123 | 'HAVE_STDINT_H', 124 | 'GNUC', 125 | ] 126 | cxx.cflags += [ 127 | '-pipe', 128 | '-fno-strict-aliasing', 129 | '-Wall', 130 | '-Werror', 131 | '-Wno-uninitialized', 132 | '-Wno-unused', 133 | '-Wno-switch', 134 | '-msse', 135 | '-fPIC', 136 | '-frtti', 137 | '-Wno-sign-compare', 138 | '-Wno-error=sign-compare', 139 | '-Wno-attributes' 140 | ] 141 | 142 | cxx.cxxflags += ['-std=c++17'] 143 | if (cxx.version >= 'gcc-4.0') or cxx.family == 'clang': 144 | cxx.cflags += ['-fvisibility=hidden'] 145 | cxx.cxxflags += ['-fvisibility-inlines-hidden'] 146 | cxx.cxxflags += [ 147 | '-fno-threadsafe-statics', 148 | '-Wno-non-virtual-dtor', 149 | '-Wno-overloaded-virtual', 150 | '-Wno-register', 151 | ] 152 | if (cxx.version >= 'gcc-4.7' or cxx.family == 'clang'): 153 | cxx.cxxflags += ['-Wno-delete-non-virtual-dtor'] 154 | if cxx.family == 'gcc': 155 | cxx.cflags += ['-mfpmath=sse'] 156 | if cxx.family == 'clang': 157 | cxx.cxxflags += ['-Wno-implicit-exception-spec-mismatch'] 158 | if cxx.version >= 'clang-3.9': 159 | cxx.cxxflags += ['-Wno-expansion-to-defined'] 160 | if cxx.version >= 'clang-3.6': 161 | cxx.cxxflags += ['-Wno-inconsistent-missing-override'] 162 | if cxx.version >= 'clang-3.4': 163 | cxx.cxxflags += ['-Wno-deprecated-register'] 164 | else: 165 | cxx.cxxflags += ['-Wno-deprecated'] 166 | 167 | # Work around SDK warnings. 168 | if cxx.version >= 'clang-10.0': 169 | cxx.cflags += [ 170 | '-Wno-implicit-int-float-conversion', 171 | '-Wno-tautological-overlap-compare', 172 | ] 173 | 174 | elif cxx.like('msvc'): 175 | if builder.options.debug == '1': 176 | cxx.cflags += ['/MTd'] 177 | cxx.linkflags += ['/NODEFAULTLIB:libcmt'] 178 | else: 179 | cxx.cflags += ['/MT'] 180 | cxx.defines += [ 181 | '_CRT_SECURE_NO_DEPRECATE', 182 | '_CRT_SECURE_NO_WARNINGS', 183 | '_CRT_NONSTDC_NO_DEPRECATE', 184 | ] 185 | cxx.cflags += [ 186 | '/W3', 187 | '/Zi', 188 | '/EHsc', 189 | '/std:c++17', 190 | ] 191 | cxx.cxxflags += ['/TP'] 192 | 193 | cxx.linkflags += [ 194 | '/SUBSYSTEM:WINDOWS', 195 | 'kernel32.lib', 196 | 'user32.lib', 197 | 'gdi32.lib', 198 | 'winspool.lib', 199 | 'comdlg32.lib', 200 | 'advapi32.lib', 201 | 'shell32.lib', 202 | 'ole32.lib', 203 | 'oleaut32.lib', 204 | 'uuid.lib', 205 | 'odbc32.lib', 206 | 'odbccp32.lib', 207 | ] 208 | 209 | # Optimization 210 | if builder.options.opt == '1': 211 | cxx.defines += ['NDEBUG'] 212 | if cxx.behavior == 'gcc': 213 | cxx.cflags += ['-O3'] 214 | elif cxx.behavior == 'msvc': 215 | cxx.cflags += ['/Ox', '/Zo'] 216 | cxx.linkflags += ['/OPT:ICF', '/OPT:REF'] 217 | 218 | # Debugging 219 | if builder.options.debug == '1': 220 | cxx.defines += ['DEBUG', '_DEBUG'] 221 | if cxx.behavior == 'gcc': 222 | cxx.cflags += ['-g3'] 223 | elif cxx.behavior == 'msvc': 224 | cxx.cflags += ['/Od', '/RTC1'] 225 | 226 | # Don't omit the frame pointer. 227 | # This needs to be after our optimization flags which could otherwise disable it. 228 | if cxx.behavior == 'gcc': 229 | cxx.cflags += ['-fno-omit-frame-pointer'] 230 | elif cxx.behavior == 'msvc': 231 | cxx.cflags += ['/Oy-'] 232 | 233 | # Platform-specifics 234 | if cxx.target.platform == 'linux': 235 | cxx.defines += ['LINUX', '_LINUX', 'POSIX', '_FILE_OFFSET_BITS=64'] 236 | if cxx.family == 'gcc': 237 | cxx.linkflags += ['-static-libgcc'] 238 | elif cxx.family == 'clang': 239 | cxx.linkflags += ['-lgcc_eh'] 240 | cxx.linkflags += ['-static-libstdc++'] 241 | elif cxx.target.platform == 'windows': 242 | cxx.defines += ['WIN32', '_WINDOWS'] 243 | 244 | def Library(self, cxx, name): 245 | binary = cxx.Library(name) 246 | return binary 247 | 248 | def HL2Library(self, context, compiler, name, sdk): 249 | binary = self.Library(compiler, name) 250 | mms_core_path = os.path.join(self.mms_root, 'core') 251 | cxx = binary.compiler 252 | 253 | cxx.cxxincludes += [ 254 | os.path.join(context.currentSourcePath), 255 | os.path.join(mms_core_path), 256 | os.path.join(mms_core_path, 'sourcehook'), 257 | ] 258 | 259 | defines = [] 260 | for other_sdk in self.sdk_manifests: 261 | cxx.defines += ['SE_{}={}'.format(other_sdk['define'], other_sdk['code'])] 262 | 263 | cxx.defines += ['META_IS_SOURCE2'] 264 | binary.sources += [ 265 | os.path.join(sdk['path'], 'public', 'tier0', 'memoverride.cpp'), 266 | os.path.join(sdk['path'], 'tier1', 'generichash.cpp'), 267 | os.path.join(sdk['path'], 'entity2', 'entitysystem.cpp'), 268 | os.path.join(sdk['path'], 'entity2', 'entityidentity.cpp'), 269 | os.path.join(sdk['path'], 'entity2', 'entitykeyvalues.cpp'), 270 | os.path.join(sdk['path'], 'tier1', 'convar.cpp'), 271 | os.path.join(sdk['path'], 'tier1', 'keyvalues3.cpp'), 272 | ] 273 | 274 | SdkHelpers.configureCxx(context, binary, sdk) 275 | 276 | return binary 277 | 278 | MMSPlugin = MMSPluginConfig() 279 | MMSPlugin.detectSDKs() 280 | MMSPlugin.configure() 281 | 282 | BuildScripts = [ 283 | 'AMBuilder', 284 | 'PackageScript' 285 | ] 286 | 287 | builder.Build(BuildScripts, { 'MMSPlugin': MMSPlugin }) 288 | -------------------------------------------------------------------------------- /AMBuilder: -------------------------------------------------------------------------------- 1 | # vim: set sts=2 ts=8 sw=2 tw=99 et ft=python: 2 | import os 3 | 4 | # Here only one sdk should be available to generate only one executable in the end, 5 | # as multi-sdk loading isn't supported out of the box by metamod, and would require specifying the full path in the vdf 6 | # which in the end would ruin the multi-platform (unix, win etc) loading by metamod as it won't be able to append platform specific extension 7 | # so just fall back to the single binary. 8 | # Multi-sdk solutions should be manually loaded with a custom plugin loader (examples being sourcemod, stripper:source) 9 | for sdk_target in MMSPlugin.sdk_targets: 10 | sdk = sdk_target.sdk 11 | cxx = sdk_target.cxx 12 | 13 | cxx.cxxflags += ['-Wno-invalid-offsetof'] 14 | binary = MMSPlugin.HL2Library(builder, cxx, MMSPlugin.plugin_name, sdk) 15 | 16 | binary.compiler.cxxincludes += [ 17 | os.path.join(builder.currentSourcePath, 'funchook', 'include'), 18 | os.path.join(builder.sourcePath, 'include'), 19 | os.path.join(builder.sourcePath, '..', 'SchemaEntity'), 20 | ] 21 | 22 | if binary.compiler.target.platform == 'linux': 23 | binary.compiler.postlink += [ 24 | os.path.join(builder.sourcePath, 'funchook', 'lib', 'libfunchook.a'), 25 | os.path.join(builder.sourcePath, 'funchook', 'lib', 'libdistorm.a'), 26 | ] 27 | elif binary.compiler.target.platform == 'windows': 28 | binary.compiler.postlink += [ 29 | os.path.join('psapi.lib'), 30 | os.path.join(builder.sourcePath, 'funchook', 'lib', 'funchook.lib'), 31 | os.path.join(builder.sourcePath, 'funchook', 'lib', 'distorm.lib'), 32 | ] 33 | 34 | binary.custom = [builder.tools.Protoc(protoc = sdk_target.protoc, sources = [ 35 | os.path.join(sdk['path'], 'game', 'shared', 'usermessages.proto'), 36 | os.path.join(sdk['path'], 'common', 'network_connection.proto'), 37 | os.path.join(sdk['path'], 'common', 'networkbasetypes.proto'), 38 | os.path.join(sdk['path'], 'common', 'engine_gcmessages.proto'), 39 | os.path.join(sdk['path'], 'game', 'shared', 'usercmd.proto'), 40 | os.path.join(sdk['path'], 'game', 'shared', 'gameevents.proto'), 41 | ])] 42 | 43 | binary.sources += [ 44 | 'utils.cpp', 45 | os.path.join('..', 'SchemaEntity', 'schemasystem.cpp'), 46 | os.path.join('..', 'SchemaEntity', 'module.cpp'), 47 | os.path.join('..', 'SchemaEntity', 'ctimer.cpp'), 48 | ] 49 | 50 | if cxx.target.arch == 'x86': 51 | binary.sources += ['sourcehook/sourcehook_hookmangen.cpp'] 52 | nodes = builder.Add(binary) 53 | MMSPlugin.binaries += [nodes] -------------------------------------------------------------------------------- /PackageScript: -------------------------------------------------------------------------------- 1 | # vim: set ts=2 sw=2 tw=99 noet ft=python: 2 | import os 3 | 4 | builder.SetBuildFolder('package') 5 | 6 | metamod_folder = builder.AddFolder(os.path.join('addons', 'metamod')) 7 | bin_folder_path = os.path.join('addons', MMSPlugin.plugin_name) 8 | bin_folder = builder.AddFolder(bin_folder_path) 9 | 10 | for cxx in MMSPlugin.all_targets: 11 | if cxx.target.arch == 'x86_64': 12 | bin64_folder_path = os.path.join('addons', MMSPlugin.plugin_name) 13 | bin64_folder = builder.AddFolder(bin64_folder_path) 14 | 15 | pdb_list = [] 16 | for task in MMSPlugin.binaries: 17 | # This hardly assumes there's only 1 targetted platform and would be overwritten 18 | # with whatever comes last if multiple are used! 19 | with open(os.path.join(builder.buildPath, MMSPlugin.plugin_name + '.vdf'), 'w') as fp: 20 | fp.write('"Metamod Plugin"\n') 21 | fp.write('{\n') 22 | fp.write(f'\t"alias"\t"{MMSPlugin.plugin_alias}"\n') 23 | if task.target.arch == 'x86_64': 24 | fp.write(f'\t"file"\t"{os.path.join(bin64_folder_path, MMSPlugin.plugin_name)}"\n') 25 | else: 26 | fp.write(f'\t"file"\t"{os.path.join(bin_folder_path, MMSPlugin.plugin_name)}"\n') 27 | fp.write('}\n') 28 | 29 | if task.target.arch == 'x86_64': 30 | builder.AddCopy(task.binary, bin64_folder) 31 | else: 32 | builder.AddCopy(task.binary, bin_folder) 33 | 34 | if task.debug: 35 | pdb_list.append(task.debug) 36 | 37 | builder.AddCopy(os.path.join(builder.buildPath, MMSPlugin.plugin_name + '.vdf'), metamod_folder) 38 | 39 | configs_folder = builder.AddFolder(os.path.join('addons', 'translations')) 40 | builder.AddCopy(os.path.join(builder.sourcePath, 'translations', 'menus.phrases.txt'), configs_folder) 41 | configs_folder = builder.AddFolder(os.path.join('addons', 'configs')) 42 | builder.AddCopy(os.path.join(builder.sourcePath, 'configs', 'core.cfg'), configs_folder) 43 | builder.AddCopy(os.path.join(builder.sourcePath, 'configs', 'signatures.ini'), configs_folder) 44 | configs_folder = builder.AddFolder(os.path.join('addons', 'logs')) -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | The language setting is - addons/configs/core.cfg 2 | 3 | Signatures - addons/configs/signatures.ini 4 | -------------------------------------------------------------------------------- /configs/core.cfg: -------------------------------------------------------------------------------- 1 | "Core" 2 | { 3 | "ServerLang" "ru" 4 | "MenuType" "0" //Default menu type || Тип меню по умолчанию 5 | //0 - Chat 6 | //1 - HTML Center 7 | //2 - HTML Center with WASD 8 | "MenuFlashFix" "0" //Fix for flash in the menu(possibly unstable) || Фикс мигания в меню(возможно нестабильно) 9 | //0 - Disable 10 | //1 - Enable 11 | "MenuChangeCommand" "!menu" //Команда для открытия меню редактирования типа меню || Command to open the menu for editing the menu type 12 | "AccessUserChangeType" "1" //Давать ли пользователю возможность менять тип меню(MenuChangeCommand) || Can the user change the menu type(MenuChangeCommand) 13 | //0 - Disable 14 | //1 - Enable 15 | "MenuAddon" "0" //Откуда будут браться визуальный кнопки для меню || Where the visual buttons for the menu will be taken from 16 | // Только для MenuType == 2 || Only for MenuType == 2 17 | // 0 - Site URL 18 | // 1 - Addon 19 | "StopingUser" "0" //Блокировать ли игроку передвижение при открытом меню || Block player movement when the menu is open 20 | // Только для MenuType == 2 || Only for MenuType == 2 21 | // 0 - Disable 22 | // 1 - Enable 23 | "MenuURL" "pisex.online/module/buttons"// Только для MenuType == 2 || Only for MenuType == 2 24 | "MenuTime" "120" //Menu auto-close time 25 | 26 | "TimeoutInputMenu" "200" // Только для MenuType == 2 || Only for MenuType == 2 27 | // Задержка перед следующим нажатием клавиши меню в миллисекундах || Delay before the next key press in the menu in milliseconds 28 | 29 | "delay_auth_fail_kick" "30" //After how many seconds to kick an unauthorized player, 0 - no kicking 30 | 31 | "commands_eater" "!,/" // С каким префиксом команды не будут отображаться в чате (если она существует) через запятую || 32 | // With what prefix the commands will not be displayed in the chat (if it exists) separated by commas 33 | } -------------------------------------------------------------------------------- /configs/signatures.ini: -------------------------------------------------------------------------------- 1 | "Gamedata" 2 | { 3 | // Search: "Script_StopSoundOn" or "Stop named sound on Entity" or "StopSoundOn" 4 | // Function: return sub_1005700(result, a1); 5 | "StopSoundEvent" "55 48 89 E5 41 54 49 89 F4 48 83 EC 08 E8 ? ? ? ? 4D 85 E4" 6 | 7 | // Search: "CBaseEntity::EmitSound" 8 | // We need the shortest function, at the time of the search the function consists of 10 lines 9 | "EmitSoundFilter" "55 48 89 E5 41 56 49 89 D6 41 55 41 89 F5 41 54 48 8D 35" 10 | 11 | "IsHearingClient" "55 48 89 E5 41 55 41 54 53 48 89 FB 48 83 EC 08 3B 77 58" 12 | 13 | // Search: "CCSPlayerPawnBase::SwitchTeam( %d ) - invalid team index.\n" 14 | // We need the shortest function, at the time of the search the function consists of 11 lines 15 | "SwitchTeam" "55 48 89 E5 41 55 49 89 FD 89 F7" 16 | 17 | // Search: "Display player message to team" 18 | "UTIL_Say" "55 48 89 E5 41 56 41 55 49 89 F5 41 54 49 89 FC 53 48 83 EC 10 48 8D 05" 19 | 20 | "GetGameEventManager" "55 31 C9 BA ? ? ? ? 48 89 E5 41 56 49 89 FE 41 55 49 89 F5 41 54 48 8D 35 ? ? ? ? 53" 21 | 22 | // Search: "models/weapons/w_bullet.vmdl" 23 | // We need the longest function, at the time of the search the function consists of 77 lines 24 | "CBaseModelEntity_SetModel" "55 48 89 F2 48 89 E5 41 54 49 89 FC 48 8D 7D E0 48 83 EC 18 48 8D 05 ? ? ? ? 48 8B 30 48 8B 06" 25 | 26 | // Search: "OnRescueZoneTouch" 27 | // function: sub_1320870(v6, (__int64)"OnRescueZoneTouch", 0LL, 0LL, (__int64)&v17, 0) 28 | "UTIL_AcceptInput" "55 48 89 E5 41 57 49 89 FF 41 56 48 8D 7D C0" 29 | 30 | "UTIL_DispatchSpawn" "48 85 FF 74 ? 55 48 89 E5 41 56" 31 | 32 | // Search: "info_hostage_rescue_zone_hint" 33 | // function: sub_D91D60("info_hostage_rescue_zone_hint", 0xFFFFFFFFLL); 34 | "UTIL_CreateEntity" "48 8D 05 ? ? ? ? 55 48 89 FA 41 89 F0 48 89 E5 48 83 EC 08" 35 | 36 | // Search: "Scorch" 37 | // 38 | // sub_E19E00(v37, "Scorch") 39 | // sub_C05C50(a1) 40 | // return sub_D92060(a1) 41 | // 42 | // function: sub_D92060(a1) 43 | "UTIL_Remove" "48 89 FE 48 85 FF" 44 | 45 | // Search: "CSource2GameClients::StartHLTVServer: game event %s not found.\n" 46 | // function: sub_D94D80(a2) 47 | "GetLegacyGameEventListener" "48 8B 05 ? ? ? ? 48 85 C0 74 ? 85 FF" 48 | 49 | // Search: "CBaseEntity::TakeDamageOld: damagetype %d with info.GetDamageForce() == vec3_origin\n" 50 | // function: __int64 __fastcall sub_860720(__int64 a1) 51 | // How to search: find a line, go to the first line, find that function and go over the function with jmp 52 | "OnTakeDamagePre" "48 8B 47 10 F6 40 31 02 75 ? E9 ? ? ? ?" 53 | 54 | // Search: "weapons/models/c4/weapon_c4.vmdl" 55 | // function: sub_8577C0(a1, 0LL, 0LL); 56 | // 57 | // sub_D01CA0(); 58 | // sub_8577C0(a1, 0LL, 0LL); 59 | // sub_EA25D0(a1 + 2280, 0LL); 60 | // sub_856740(a1, 0x2000000LL); 61 | // sub_E9D470(a1 + 2280, 1LL); 62 | // sub_D09AF0(a1, (__int64)"weapons/models/c4/weapon_c4.vmdl"); 63 | // 64 | "SetMoveType" "55 48 89 E5 41 57 41 56 41 55 41 89 D5 41 54 49 89 FC 53 48 83 EC" 65 | 66 | "OnTakeDamage_Alive" "230" 67 | "CommitSuicide" "380" 68 | "CollisionRulesChanged" "178" 69 | "Teleport" "156" 70 | "ChangeTeam" "99" 71 | "Respawn" "259" 72 | "DropWeapon" "23" 73 | } -------------------------------------------------------------------------------- /configure.py: -------------------------------------------------------------------------------- 1 | # vim: set sts=2 ts=8 sw=2 tw=99 et: 2 | import sys 3 | try: 4 | from ambuild2 import run, util 5 | except: 6 | try: 7 | import ambuild 8 | sys.stderr.write('It looks like you have AMBuild 1 installed, but this project uses AMBuild 2.\n') 9 | sys.stderr.write('Upgrade to the latest version of AMBuild to continue.\n') 10 | except: 11 | sys.stderr.write('AMBuild must be installed to build this project.\n') 12 | sys.stderr.write('http://www.alliedmods.net/ambuild\n') 13 | sys.exit(1) 14 | 15 | # Hack to show a decent upgrade message, which wasn't done until 2.2. 16 | ambuild_version = getattr(run, 'CURRENT_API', '2.1') 17 | if ambuild_version.startswith('2.1'): 18 | sys.stderr.write("AMBuild 2.2 or higher is required; please update\n") 19 | sys.exit(1) 20 | 21 | parser = run.BuildParser(sourcePath=sys.path[0], api='2.2') 22 | parser.options.add_argument('-n', '--plugin-name', type=str, dest='plugin_name', default=None, 23 | help='Plugin name') 24 | parser.options.add_argument('-a', '--plugin-alias', type=str, dest='plugin_alias', default=None, 25 | help='Plugin alias') 26 | parser.options.add_argument('--hl2sdk-root', type=str, dest='hl2sdk_root', default=None, 27 | help='Root search folder for HL2SDKs') 28 | parser.options.add_argument('--hl2sdk-manifests', type=str, dest='hl2sdk_manifests', default=None, 29 | help='HL2SDK manifests source tree folder') 30 | parser.options.add_argument('--mms_path', type=str, dest='mms_path', default=None, 31 | help='Metamod:Source source tree folder') 32 | parser.options.add_argument('--enable-debug', action='store_const', const='1', dest='debug', 33 | help='Enable debugging symbols') 34 | parser.options.add_argument('--enable-optimize', action='store_const', const='1', dest='opt', 35 | help='Enable optimization') 36 | parser.options.add_argument('-s', '--sdks', default='all', dest='sdks', 37 | help='Build against specified SDKs; valid args are "all", "present", or ' 38 | 'comma-delimited list of engine names (default: "all")') 39 | parser.options.add_argument('--targets', type=str, dest='targets', default=None, 40 | help="Override the target architecture (use commas to separate multiple targets).") 41 | parser.Configure() 42 | -------------------------------------------------------------------------------- /funchook/LICENSE: -------------------------------------------------------------------------------- 1 | Funchook is distributed under the terms of the GNU General Public 2 | License version 2 or later with the following clarification and 3 | special exception. 4 | 5 | Linking this library statically or dynamically with other modules is 6 | making a combined work based on this library. Thus, the terms and 7 | conditions of the GNU General Public License cover the whole 8 | combination. 9 | 10 | As a special exception, the copyright holders of this library give you 11 | permission to link this library with independent modules to produce an 12 | executable, regardless of the license terms of these independent 13 | modules, and to copy and distribute the resulting executable under 14 | terms of your choice, provided that you also meet, for each linked 15 | independent module, the terms and conditions of the license of that 16 | module. An independent module is a module which is not derived from or 17 | based on this library. If you modify this library, you must extend this 18 | exception to your version of the library. 19 | 20 | ===================================================================== 21 | 22 | GNU GENERAL PUBLIC LICENSE 23 | Version 2, June 1991 24 | 25 | Copyright (C) 1989, 1991 Free Software Foundation, Inc., 26 | 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA 27 | Everyone is permitted to copy and distribute verbatim copies 28 | of this license document, but changing it is not allowed. 29 | 30 | Preamble 31 | 32 | The licenses for most software are designed to take away your 33 | freedom to share and change it. By contrast, the GNU General Public 34 | License is intended to guarantee your freedom to share and change free 35 | software--to make sure the software is free for all its users. This 36 | General Public License applies to most of the Free Software 37 | Foundation's software and to any other program whose authors commit to 38 | using it. (Some other Free Software Foundation software is covered by 39 | the GNU Lesser General Public License instead.) You can apply it to 40 | your programs, too. 41 | 42 | When we speak of free software, we are referring to freedom, not 43 | price. Our General Public Licenses are designed to make sure that you 44 | have the freedom to distribute copies of free software (and charge for 45 | this service if you wish), that you receive source code or can get it 46 | if you want it, that you can change the software or use pieces of it 47 | in new free programs; and that you know you can do these things. 48 | 49 | To protect your rights, we need to make restrictions that forbid 50 | anyone to deny you these rights or to ask you to surrender the rights. 51 | These restrictions translate to certain responsibilities for you if you 52 | distribute copies of the software, or if you modify it. 53 | 54 | For example, if you distribute copies of such a program, whether 55 | gratis or for a fee, you must give the recipients all the rights that 56 | you have. You must make sure that they, too, receive or can get the 57 | source code. And you must show them these terms so they know their 58 | rights. 59 | 60 | We protect your rights with two steps: (1) copyright the software, and 61 | (2) offer you this license which gives you legal permission to copy, 62 | distribute and/or modify the software. 63 | 64 | Also, for each author's protection and ours, we want to make certain 65 | that everyone understands that there is no warranty for this free 66 | software. If the software is modified by someone else and passed on, we 67 | want its recipients to know that what they have is not the original, so 68 | that any problems introduced by others will not reflect on the original 69 | authors' reputations. 70 | 71 | Finally, any free program is threatened constantly by software 72 | patents. We wish to avoid the danger that redistributors of a free 73 | program will individually obtain patent licenses, in effect making the 74 | program proprietary. To prevent this, we have made it clear that any 75 | patent must be licensed for everyone's free use or not licensed at all. 76 | 77 | The precise terms and conditions for copying, distribution and 78 | modification follow. 79 | 80 | GNU GENERAL PUBLIC LICENSE 81 | TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION 82 | 83 | 0. This License applies to any program or other work which contains 84 | a notice placed by the copyright holder saying it may be distributed 85 | under the terms of this General Public License. The "Program", below, 86 | refers to any such program or work, and a "work based on the Program" 87 | means either the Program or any derivative work under copyright law: 88 | that is to say, a work containing the Program or a portion of it, 89 | either verbatim or with modifications and/or translated into another 90 | language. (Hereinafter, translation is included without limitation in 91 | the term "modification".) Each licensee is addressed as "you". 92 | 93 | Activities other than copying, distribution and modification are not 94 | covered by this License; they are outside its scope. The act of 95 | running the Program is not restricted, and the output from the Program 96 | is covered only if its contents constitute a work based on the 97 | Program (independent of having been made by running the Program). 98 | Whether that is true depends on what the Program does. 99 | 100 | 1. You may copy and distribute verbatim copies of the Program's 101 | source code as you receive it, in any medium, provided that you 102 | conspicuously and appropriately publish on each copy an appropriate 103 | copyright notice and disclaimer of warranty; keep intact all the 104 | notices that refer to this License and to the absence of any warranty; 105 | and give any other recipients of the Program a copy of this License 106 | along with the Program. 107 | 108 | You may charge a fee for the physical act of transferring a copy, and 109 | you may at your option offer warranty protection in exchange for a fee. 110 | 111 | 2. You may modify your copy or copies of the Program or any portion 112 | of it, thus forming a work based on the Program, and copy and 113 | distribute such modifications or work under the terms of Section 1 114 | above, provided that you also meet all of these conditions: 115 | 116 | a) You must cause the modified files to carry prominent notices 117 | stating that you changed the files and the date of any change. 118 | 119 | b) You must cause any work that you distribute or publish, that in 120 | whole or in part contains or is derived from the Program or any 121 | part thereof, to be licensed as a whole at no charge to all third 122 | parties under the terms of this License. 123 | 124 | c) If the modified program normally reads commands interactively 125 | when run, you must cause it, when started running for such 126 | interactive use in the most ordinary way, to print or display an 127 | announcement including an appropriate copyright notice and a 128 | notice that there is no warranty (or else, saying that you provide 129 | a warranty) and that users may redistribute the program under 130 | these conditions, and telling the user how to view a copy of this 131 | License. (Exception: if the Program itself is interactive but 132 | does not normally print such an announcement, your work based on 133 | the Program is not required to print an announcement.) 134 | 135 | These requirements apply to the modified work as a whole. If 136 | identifiable sections of that work are not derived from the Program, 137 | and can be reasonably considered independent and separate works in 138 | themselves, then this License, and its terms, do not apply to those 139 | sections when you distribute them as separate works. But when you 140 | distribute the same sections as part of a whole which is a work based 141 | on the Program, the distribution of the whole must be on the terms of 142 | this License, whose permissions for other licensees extend to the 143 | entire whole, and thus to each and every part regardless of who wrote it. 144 | 145 | Thus, it is not the intent of this section to claim rights or contest 146 | your rights to work written entirely by you; rather, the intent is to 147 | exercise the right to control the distribution of derivative or 148 | collective works based on the Program. 149 | 150 | In addition, mere aggregation of another work not based on the Program 151 | with the Program (or with a work based on the Program) on a volume of 152 | a storage or distribution medium does not bring the other work under 153 | the scope of this License. 154 | 155 | 3. You may copy and distribute the Program (or a work based on it, 156 | under Section 2) in object code or executable form under the terms of 157 | Sections 1 and 2 above provided that you also do one of the following: 158 | 159 | a) Accompany it with the complete corresponding machine-readable 160 | source code, which must be distributed under the terms of Sections 161 | 1 and 2 above on a medium customarily used for software interchange; or, 162 | 163 | b) Accompany it with a written offer, valid for at least three 164 | years, to give any third party, for a charge no more than your 165 | cost of physically performing source distribution, a complete 166 | machine-readable copy of the corresponding source code, to be 167 | distributed under the terms of Sections 1 and 2 above on a medium 168 | customarily used for software interchange; or, 169 | 170 | c) Accompany it with the information you received as to the offer 171 | to distribute corresponding source code. (This alternative is 172 | allowed only for noncommercial distribution and only if you 173 | received the program in object code or executable form with such 174 | an offer, in accord with Subsection b above.) 175 | 176 | The source code for a work means the preferred form of the work for 177 | making modifications to it. For an executable work, complete source 178 | code means all the source code for all modules it contains, plus any 179 | associated interface definition files, plus the scripts used to 180 | control compilation and installation of the executable. However, as a 181 | special exception, the source code distributed need not include 182 | anything that is normally distributed (in either source or binary 183 | form) with the major components (compiler, kernel, and so on) of the 184 | operating system on which the executable runs, unless that component 185 | itself accompanies the executable. 186 | 187 | If distribution of executable or object code is made by offering 188 | access to copy from a designated place, then offering equivalent 189 | access to copy the source code from the same place counts as 190 | distribution of the source code, even though third parties are not 191 | compelled to copy the source along with the object code. 192 | 193 | 4. You may not copy, modify, sublicense, or distribute the Program 194 | except as expressly provided under this License. Any attempt 195 | otherwise to copy, modify, sublicense or distribute the Program is 196 | void, and will automatically terminate your rights under this License. 197 | However, parties who have received copies, or rights, from you under 198 | this License will not have their licenses terminated so long as such 199 | parties remain in full compliance. 200 | 201 | 5. You are not required to accept this License, since you have not 202 | signed it. However, nothing else grants you permission to modify or 203 | distribute the Program or its derivative works. These actions are 204 | prohibited by law if you do not accept this License. Therefore, by 205 | modifying or distributing the Program (or any work based on the 206 | Program), you indicate your acceptance of this License to do so, and 207 | all its terms and conditions for copying, distributing or modifying 208 | the Program or works based on it. 209 | 210 | 6. Each time you redistribute the Program (or any work based on the 211 | Program), the recipient automatically receives a license from the 212 | original licensor to copy, distribute or modify the Program subject to 213 | these terms and conditions. You may not impose any further 214 | restrictions on the recipients' exercise of the rights granted herein. 215 | You are not responsible for enforcing compliance by third parties to 216 | this License. 217 | 218 | 7. If, as a consequence of a court judgment or allegation of patent 219 | infringement or for any other reason (not limited to patent issues), 220 | conditions are imposed on you (whether by court order, agreement or 221 | otherwise) that contradict the conditions of this License, they do not 222 | excuse you from the conditions of this License. If you cannot 223 | distribute so as to satisfy simultaneously your obligations under this 224 | License and any other pertinent obligations, then as a consequence you 225 | may not distribute the Program at all. For example, if a patent 226 | license would not permit royalty-free redistribution of the Program by 227 | all those who receive copies directly or indirectly through you, then 228 | the only way you could satisfy both it and this License would be to 229 | refrain entirely from distribution of the Program. 230 | 231 | If any portion of this section is held invalid or unenforceable under 232 | any particular circumstance, the balance of the section is intended to 233 | apply and the section as a whole is intended to apply in other 234 | circumstances. 235 | 236 | It is not the purpose of this section to induce you to infringe any 237 | patents or other property right claims or to contest validity of any 238 | such claims; this section has the sole purpose of protecting the 239 | integrity of the free software distribution system, which is 240 | implemented by public license practices. Many people have made 241 | generous contributions to the wide range of software distributed 242 | through that system in reliance on consistent application of that 243 | system; it is up to the author/donor to decide if he or she is willing 244 | to distribute software through any other system and a licensee cannot 245 | impose that choice. 246 | 247 | This section is intended to make thoroughly clear what is believed to 248 | be a consequence of the rest of this License. 249 | 250 | 8. If the distribution and/or use of the Program is restricted in 251 | certain countries either by patents or by copyrighted interfaces, the 252 | original copyright holder who places the Program under this License 253 | may add an explicit geographical distribution limitation excluding 254 | those countries, so that distribution is permitted only in or among 255 | countries not thus excluded. In such case, this License incorporates 256 | the limitation as if written in the body of this License. 257 | 258 | 9. The Free Software Foundation may publish revised and/or new versions 259 | of the General Public License from time to time. Such new versions will 260 | be similar in spirit to the present version, but may differ in detail to 261 | address new problems or concerns. 262 | 263 | Each version is given a distinguishing version number. If the Program 264 | specifies a version number of this License which applies to it and "any 265 | later version", you have the option of following the terms and conditions 266 | either of that version or of any later version published by the Free 267 | Software Foundation. If the Program does not specify a version number of 268 | this License, you may choose any version ever published by the Free Software 269 | Foundation. 270 | 271 | 10. If you wish to incorporate parts of the Program into other free 272 | programs whose distribution conditions are different, write to the author 273 | to ask for permission. For software which is copyrighted by the Free 274 | Software Foundation, write to the Free Software Foundation; we sometimes 275 | make exceptions for this. Our decision will be guided by the two goals 276 | of preserving the free status of all derivatives of our free software and 277 | of promoting the sharing and reuse of software generally. 278 | 279 | NO WARRANTY 280 | 281 | 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY 282 | FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN 283 | OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES 284 | PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED 285 | OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF 286 | MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS 287 | TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE 288 | PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, 289 | REPAIR OR CORRECTION. 290 | 291 | 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING 292 | WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR 293 | REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, 294 | INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING 295 | OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED 296 | TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY 297 | YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER 298 | PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE 299 | POSSIBILITY OF SUCH DAMAGES. 300 | 301 | END OF TERMS AND CONDITIONS 302 | 303 | How to Apply These Terms to Your New Programs 304 | 305 | If you develop a new program, and you want it to be of the greatest 306 | possible use to the public, the best way to achieve this is to make it 307 | free software which everyone can redistribute and change under these terms. 308 | 309 | To do so, attach the following notices to the program. It is safest 310 | to attach them to the start of each source file to most effectively 311 | convey the exclusion of warranty; and each file should have at least 312 | the "copyright" line and a pointer to where the full notice is found. 313 | 314 | 315 | Copyright (C) 316 | 317 | This program is free software; you can redistribute it and/or modify 318 | it under the terms of the GNU General Public License as published by 319 | the Free Software Foundation; either version 2 of the License, or 320 | (at your option) any later version. 321 | 322 | This program is distributed in the hope that it will be useful, 323 | but WITHOUT ANY WARRANTY; without even the implied warranty of 324 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 325 | GNU General Public License for more details. 326 | 327 | You should have received a copy of the GNU General Public License along 328 | with this program; if not, write to the Free Software Foundation, Inc., 329 | 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. 330 | 331 | Also add information on how to contact you by electronic and paper mail. 332 | 333 | If the program is interactive, make it output a short notice like this 334 | when it starts in an interactive mode: 335 | 336 | Gnomovision version 69, Copyright (C) year name of author 337 | Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'. 338 | This is free software, and you are welcome to redistribute it 339 | under certain conditions; type `show c' for details. 340 | 341 | The hypothetical commands `show w' and `show c' should show the appropriate 342 | parts of the General Public License. Of course, the commands you use may 343 | be called something other than `show w' and `show c'; they could even be 344 | mouse-clicks or menu items--whatever suits your program. 345 | 346 | You should also get your employer (if you work as a programmer) or your 347 | school, if any, to sign a "copyright disclaimer" for the program, if 348 | necessary. Here is a sample; alter the names: 349 | 350 | Yoyodyne, Inc., hereby disclaims all copyright interest in the program 351 | `Gnomovision' (which makes passes at compilers) written by James Hacker. 352 | 353 | , 1 April 1989 354 | Ty Coon, President of Vice 355 | 356 | This General Public License does not permit incorporating your program into 357 | proprietary programs. If your program is a subroutine library, you may 358 | consider it more useful to permit linking proprietary applications with the 359 | library. If this is what you want to do, use the GNU Lesser General 360 | Public License instead of this License. 361 | -------------------------------------------------------------------------------- /funchook/README.md: -------------------------------------------------------------------------------- 1 | Funchook - an API hook library 2 | ============================== 3 | 4 | [![tests](https://github.com/kubo/funchook/actions/workflows/run-tests.yml/badge.svg?branch=master)](https://github.com/kubo/funchook/actions/workflows/run-tests.yml) 5 | 6 | This library depends on one of the following disassemblers. 7 | 8 | On x86_64 and x86 9 | * [diStorm3][] (default) 10 | * [zydis][] (when `-DFUNCHOOK_DISASM=zydis` is passed to the `cmake` command) 11 | * [capstone][] (when `-DFUNCHOOK_DISASM=capstone` is passed to the `cmake` command) 12 | 13 | On arm64 14 | * [capstone][] 15 | 16 | TODO 17 | ---- 18 | 19 | * write documents. 20 | 21 | News 22 | ---- 23 | 24 | ### 2.0.0 (20XX-XX-XX) 25 | 26 | * Add `funchook_prepare_with_params()` to support prehook. 27 | * Add `funchook_get_arg()` to get arguments in prehook. 28 | 29 | ### 1.1.1 (2022-10-02) 30 | 31 | * More permissive check for page allocation mmap ([#25][]) 32 | * Flush instruction cache for arm64. It does nothing for intel CPU. 33 | * Disassember engine 34 | * Upgrade capstone to 4.0.2 35 | * Upgrade distorm to 3.5.2 36 | * CMake 37 | * Allow user to specify FUNCHOOK_CPU explicitly ([#19][]) 38 | * Avoid polluting global include and link dirs ([#20][]) 39 | * Use target based compile options for gcc's -Wall ([#21][]) 40 | * Use ExternalProject_add to download captone only ([#30][]) 41 | * Add option FUNCHOOK_INSTALL ([#31][]) 42 | * Use "FUNCHOOK_CPU MATCHES " ([#32][]) 43 | * Documentation 44 | * added example usage from python ([#22][]) 45 | * Fix tests on Android ([#29][]) 46 | 47 | ### 1.1.0 (2020-03-22) 48 | 49 | * Arm64 Linux support. [capstone][] is used as the disassembler library on arm64. 50 | * Options to use [zydis][] and [capstone][] as a disassembler library on x86_64 and x86. 51 | * `extern "C"` was added in funchook.h for C++. ([#15][]) 52 | * Libc-compatible functions were removed to simplify code. 53 | 54 | ### 1.0.0 (2020-01-19) 55 | 56 | * [diStorm3][] is used as the disassembler library. 57 | * Libc-compatible functions were implemented on Linux in order not to hook function calls issued by funchook itself. 58 | 59 | Supported Platforms 60 | ------------------- 61 | 62 | * Linux x86_64 63 | * Linux x86 64 | * Linux arm64 (since 1.1.0) 65 | * macOS x86_64 (Functions in executables cannot be hooked when Xcode version >= 11.0. (*1)) 66 | * Windows x64 (except C-runtime functions under [Wine][]) 67 | * Windows 32-bit 68 | 69 | *1 [`mprotect`] fails with EACCES. 70 | 71 | Unsupported Platforms 72 | --------------------- 73 | 74 | * macOS arm64 (*1) 75 | 76 | *1 I received a mail that [`mprotect`] failed with `EINVAL`. Apple seems to prevent executable memory regions from being writable. 77 | 78 | Compilation and installation 79 | ----------- 80 | 81 | ### Unix 82 | 83 | ```shell 84 | $ git clone --recursive https://github.com/kubo/funchook.git 85 | $ mkdir build 86 | $ cd build 87 | $ cmake -DCMAKE_BUILD_TYPE=Release -DCMAKE_INSTALL_PREFIX=/path/to/install/directory ../funchook 88 | $ make 89 | $ make install 90 | ``` 91 | 92 | * Available [`CMAKE_BUILD_TYPE`][] values are empty(default), `Debug`, `Release`, `RelWithDebInfo`(release build with debug information) and `MinSizeRel`. 93 | * When [`CMAKE_INSTALL_PREFIX`][] isn't set, funchook is installed at `/usr/local`. 94 | 95 | installed files: 96 | * `${CMAKE_INSTALL_PREFIX}/include/funchook.h` (header file) 97 | * `${CMAKE_INSTALL_PREFIX}/lib/libfunchook.so` (symbolic link to `libfunchook.so.1`) 98 | * `${CMAKE_INSTALL_PREFIX}/lib/libfunchook.so.1` ([soname][]; symbolic link to `libfunchook.so.1.1.0`) 99 | * `${CMAKE_INSTALL_PREFIX}/lib/libfunchook.so.1.1.0` (shared library) 100 | * `${CMAKE_INSTALL_PREFIX}/lib/libfunchook.a` (static library) 101 | 102 | ### Windows 103 | 104 | Here is an example to compile funchook with Visual Studio 2017 Win64. 105 | Change the argument of `-G` to use other compilers. 106 | 107 | ```shell 108 | $ git clone --recursive https://github.com/kubo/funchook.git 109 | $ mkdir build 110 | $ cd build 111 | $ cmake -G "Visual Studio 15 2017 Win64" -DCMAKE_INSTALL_PREFIX=c:\path\to\install\directory ..\funchook 112 | $ cmake --build . --config Release --target INSTALL 113 | ``` 114 | 115 | * Available `-G` arguments (generators) are listed in the output of `cmake --help`. 116 | * Available `--config` arguments are `Debug`(default), `Release`, `RelWithDebInfo` and `MinSizeRel`. 117 | * When [`CMAKE_INSTALL_PREFIX`][] isn't set, funchook is installed at `c:\Program Files\funchook`. 118 | 119 | installed files: 120 | * `${CMAKE_INSTALL_PREFIX}\include\funchook.h` (header file) 121 | * `${CMAKE_INSTALL_PREFIX}\bin\funchook.dll` (shared library) 122 | * `${CMAKE_INSTALL_PREFIX}\bin\funchook.pdb` (debug file for `funchook.dll` when `--config` is `Debug` or `RelWithDebInfo`) 123 | * `${CMAKE_INSTALL_PREFIX}\lib\funchook.lib` (static library) 124 | * `${CMAKE_INSTALL_PREFIX}\lib\funchook_dll.lib` (import library for `funchook.dll`) 125 | 126 | Example 127 | ------- 128 | 129 | ```c 130 | static ssize_t (*send_func)(int sockfd, const void *buf, size_t len, int flags); 131 | static ssize_t (*recv_func)(int sockfd, void *buf, size_t len, int flags); 132 | 133 | static ssize_t send_hook(int sockfd, const void *buf, size_t len, int flags); 134 | { 135 | ssize_t rv; 136 | 137 | ... do your task: logging, etc. ... 138 | rv = send_func(sockfd, buf, len, flags); /* call the original send(). */ 139 | ... do your task: logging, checking the return value, etc. ... 140 | return rv; 141 | } 142 | 143 | static ssize_t recv_hook(int sockfd, void *buf, size_t len, int flags); 144 | { 145 | ssize_t rv; 146 | 147 | ... do your task: logging, etc. ... 148 | rv = recv_func(sockfd, buf, len, flags); /* call the original recv(). */ 149 | ... do your task: logging, checking received data, etc. ... 150 | return rv; 151 | } 152 | 153 | int install_hooks() 154 | { 155 | funchook_t *funchook = funchook_create(); 156 | int rv; 157 | 158 | /* Prepare hooking. 159 | * The return value is used to call the original send function 160 | * in send_hook. 161 | */ 162 | send_func = send; 163 | rv = funchook_prepare(funchook, (void**)&send_func, send_hook); 164 | if (rv != 0) { 165 | /* error */ 166 | ... 167 | } 168 | 169 | /* ditto */ 170 | recv_func = recv; 171 | rv = funchook_prepare(funchook, (void**)&recv_func, recv_hook); 172 | if (rv != 0) { 173 | /* error */ 174 | ... 175 | } 176 | 177 | /* Install hooks. 178 | * The first 5-byte code of send() and recv() are changed respectively. 179 | */ 180 | rv = funchook_install(funchook, 0); 181 | if (rv != 0) { 182 | /* error */ 183 | ... 184 | } 185 | } 186 | 187 | ``` 188 | 189 | Example - Using Python ctypes 190 | ----------------------------- 191 | ```python 192 | # should work on python 2.7/3 windows/linux 193 | 194 | # load funchook 195 | import ctypes 196 | fh_lib = ctypes.cdll.LoadLibrary('/path/to/funchook/dll/or/so') 197 | 198 | # define signatures 199 | funchook_create = fh_lib.funchook_create 200 | funchook_create.restype = ctypes.c_void_p 201 | funchook_create.argtypes = [] 202 | 203 | funchook_prepare = fh_lib.funchook_prepare 204 | funchook_prepare.restype = ctypes.c_ssize_t 205 | funchook_prepare.argtypes = [ctypes.c_void_p, ctypes.c_void_p, ctypes.c_void_p] 206 | 207 | funchook_install = fh_lib.funchook_install 208 | funchook_install.restype = ctypes.c_ssize_t 209 | funchook_install.argtypes = [ctypes.c_void_p, ctypes.c_int] 210 | 211 | PySys_WriteStdout = ctypes.pythonapi.PySys_WriteStdout 212 | PySys_WriteStdout.restype = None 213 | PySys_WriteStdout.argtypes=[ctypes.c_char_p] 214 | 215 | # must keep those references alive, or stuff will be GC'd and weird errors will occur 216 | global orig_write, hook, orig_write_ptr 217 | 218 | # create hook (this function will replace the original function) 219 | hook_type = ctypes.PYFUNCTYPE(None, ctypes.c_char_p) 220 | orig_write = None 221 | def hook_impl(msg): 222 | print('about to write: ' + str(msg)) # do what we want 223 | orig_write(msg) # call the original function 224 | 225 | hook = hook_type(hook_impl) 226 | 227 | fh = funchook_create() 228 | # create a pointer object with the function address 229 | orig_write_ptr = ctypes.c_void_p(ctypes.c_void_p.from_address(ctypes.addressof(PySys_WriteStdout)).value) 230 | # orig_write_ptr.value will get a ptr to the original PySys_WriteStdout and PySys_WriteStdout will now point to the hook 231 | ret = funchook_prepare(fh, ctypes.addressof(orig_write_ptr), hook) 232 | assert not ret, 'ret is ' + str(ret) 233 | ret = funchook_install(fh, 0) 234 | assert not ret, 'ret is ' + str(ret) 235 | orig_write = hook_type.from_address(ctypes.addressof(orig_write_ptr)) 236 | PySys_WriteStdout(b'hi there\n') 237 | ``` 238 | 239 | License 240 | ------- 241 | 242 | GPLv2 or later with a [GPL linking exception][]. 243 | 244 | You can use funchook in any software. Though funchook is licensed under 245 | the GPL, it doesn't affect outside of funchook due to the linking exception. 246 | You have no need to open your souce code under the GPL except funchook itself. 247 | 248 | If you modify funchook itself and release it, the modifed part must be 249 | open under the GPL with or without the linking exception because funchook 250 | itself is under the GPL. 251 | 252 | [diStorm3][] and [capstone][] are released under the 3-clause BSD license. 253 | [zydis][] is released under the MIT license. They are compatible with the GPL. 254 | 255 | [GPL linking exception]: https://en.wikipedia.org/wiki/GPL_linking_exception 256 | [diStorm3]: https://github.com/gdabah/distorm/ 257 | [zydis]: https://github.com/zyantific/zydis 258 | [capstone]: https://github.com/aquynh/capstone 259 | [Wine]: https://www.winehq.org/ 260 | [`CMAKE_BUILD_TYPE`]: https://cmake.org/cmake/help/latest/variable/CMAKE_BUILD_TYPE.html 261 | [`CMAKE_INSTALL_PREFIX`]: https://cmake.org/cmake/help/latest/variable/CMAKE_INSTALL_PREFIX.html 262 | [soname]: https://en.wikipedia.org/wiki/Soname 263 | [#15]: https://github.com/kubo/funchook/issues/15 264 | [#19]: https://github.com/kubo/funchook/pull/19 265 | [#20]: https://github.com/kubo/funchook/pull/20 266 | [#21]: https://github.com/kubo/funchook/pull/21 267 | [#22]: https://github.com/kubo/funchook/pull/22 268 | [#25]: https://github.com/kubo/funchook/pull/25 269 | [#29]: https://github.com/kubo/funchook/pull/29 270 | [#30]: https://github.com/kubo/funchook/pull/30 271 | [#31]: https://github.com/kubo/funchook/pull/31 272 | [#32]: https://github.com/kubo/funchook/pull/32 273 | [`mprotect`]: https://developer.apple.com/library/archive/documentation/System/Conceptual/ManPages_iPhoneOS/man2/mprotect.2.html 274 | -------------------------------------------------------------------------------- /funchook/include/funchook.h: -------------------------------------------------------------------------------- 1 | /* 2 | * This file is part of Funchook. 3 | * https://github.com/kubo/funchook 4 | * 5 | * Funchook is free software: you can redistribute it and/or modify it 6 | * under the terms of the GNU General Public License as published by the 7 | * Free Software Foundation, either version 2 of the License, or (at your 8 | * option) any later version. 9 | * 10 | * As a special exception, the copyright holders of this library give you 11 | * permission to link this library with independent modules to produce an 12 | * executable, regardless of the license terms of these independent 13 | * modules, and to copy and distribute the resulting executable under 14 | * terms of your choice, provided that you also meet, for each linked 15 | * independent module, the terms and conditions of the license of that 16 | * module. An independent module is a module which is not derived from or 17 | * based on this library. If you modify this library, you may extend this 18 | * exception to your version of the library, but you are not obliged to 19 | * do so. If you do not wish to do so, delete this exception statement 20 | * from your version. 21 | * 22 | * Funchook is distributed in the hope that it will be useful, but WITHOUT 23 | * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 24 | * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 25 | * for more details. 26 | * 27 | * You should have received a copy of the GNU General Public License 28 | * along with Funchook. If not, see . 29 | */ 30 | #ifndef FUNCHOOK_H 31 | #define FUNCHOOK_H 1 32 | 33 | #ifdef __cplusplus 34 | extern "C" { 35 | #endif 36 | 37 | /* 38 | * Only functions with FUNCHOOK_EXPORT are visible from outside of funchook.dll 39 | * or libfunchook.so. Others are invisible. 40 | */ 41 | #ifdef FUNCHOOK_EXPORTS 42 | #if defined(_WIN32) 43 | #define FUNCHOOK_EXPORT __declspec(dllexport) 44 | #elif defined(__GNUC__) 45 | #define FUNCHOOK_EXPORT __attribute__((visibility("default"))) 46 | #endif 47 | #endif /* FUNCHOOK_EXPORTS */ 48 | #ifndef FUNCHOOK_EXPORT 49 | #define FUNCHOOK_EXPORT 50 | #endif 51 | 52 | typedef struct funchook funchook_t; 53 | 54 | #define FUNCHOOK_ERROR_INTERNAL_ERROR -1 55 | #define FUNCHOOK_ERROR_SUCCESS 0 56 | #define FUNCHOOK_ERROR_OUT_OF_MEMORY 1 57 | #define FUNCHOOK_ERROR_ALREADY_INSTALLED 2 58 | #define FUNCHOOK_ERROR_DISASSEMBLY 3 59 | #define FUNCHOOK_ERROR_IP_RELATIVE_OFFSET 4 60 | #define FUNCHOOK_ERROR_CANNOT_FIX_IP_RELATIVE 5 61 | #define FUNCHOOK_ERROR_FOUND_BACK_JUMP 6 62 | #define FUNCHOOK_ERROR_TOO_SHORT_INSTRUCTIONS 7 63 | #define FUNCHOOK_ERROR_MEMORY_ALLOCATION 8 /* memory allocation error */ 64 | #define FUNCHOOK_ERROR_MEMORY_FUNCTION 9 /* other memory function errors */ 65 | #define FUNCHOOK_ERROR_NOT_INSTALLED 10 66 | #define FUNCHOOK_ERROR_NO_AVAILABLE_REGISTERS 11 67 | #define FUNCHOOK_ERROR_NO_SPACE_NEAR_TARGET_ADDR 12 68 | 69 | #define FUNCHOOK_FLAG_THISCALL (1u << 0) 70 | #define FUNCHOOK_FLAG_FASTCALL (1u << 1) 71 | 72 | typedef struct funchook_arg_handle funchook_arg_handle_t; 73 | 74 | typedef struct funchook_info { 75 | void *original_target_func; 76 | void *target_func; 77 | void *trampoline_func; 78 | void *hook_func; 79 | void *user_data; 80 | funchook_arg_handle_t *arg_handle; 81 | } funchook_info_t; 82 | 83 | typedef void (*funchook_hook_t)(funchook_info_t *fi); 84 | 85 | typedef struct { 86 | void *hook_func; 87 | funchook_hook_t prehook; 88 | void *user_data; 89 | unsigned int flags; 90 | } funchook_params_t; 91 | 92 | /** 93 | * Create a funchook handle 94 | * 95 | * @return allocated funchook handle. NULL when out-of-memory. 96 | */ 97 | FUNCHOOK_EXPORT funchook_t *funchook_create(void); 98 | 99 | /** 100 | * Prepare hooking 101 | * 102 | * @param funchook a funchook handle created by funchook_create() 103 | * @param target_func function pointer to be intercepted. The pointer to trampoline function is set on success. 104 | * @param hook_func function pointer which is called istead of target_func 105 | * @return error code. one of FUNCHOOK_ERROR_*. 106 | */ 107 | FUNCHOOK_EXPORT int funchook_prepare(funchook_t *funchook, void **target_func, void *hook_func); 108 | 109 | FUNCHOOK_EXPORT int funchook_prepare_with_params(funchook_t *funchook, 110 | void **target_func, const funchook_params_t *params); 111 | 112 | /** 113 | * Install hooks prepared by funchook_prepare(). 114 | * 115 | * @param funchook a funchook handle created by funchook_create() 116 | * @param flags reserved. Set zero. 117 | * @return error code. one of FUNCHOOK_ERROR_*. 118 | */ 119 | FUNCHOOK_EXPORT int funchook_install(funchook_t *funchook, int flags); 120 | 121 | /** 122 | * Uninstall hooks installed by funchook_install(). 123 | * 124 | * @param funchook a funchook handle created by funchook_create() 125 | * @param flags reserved. Set zero. 126 | * @return error code. one of FUNCHOOK_ERROR_*. 127 | */ 128 | FUNCHOOK_EXPORT int funchook_uninstall(funchook_t *funchook, int flags); 129 | 130 | /** 131 | * Destroy a funchook handle 132 | * 133 | * @param funchook a funchook handle created by funchook_create() 134 | * @return error code. one of FUNCHOOK_ERROR_*. 135 | */ 136 | FUNCHOOK_EXPORT int funchook_destroy(funchook_t *funchook); 137 | 138 | /** 139 | * Get error message 140 | * 141 | * @param funchook a funchook handle created by funchook_create() 142 | * @return pointer to buffer containing error message 143 | */ 144 | FUNCHOOK_EXPORT const char *funchook_error_message(const funchook_t *funchook); 145 | 146 | /** 147 | * Set log file name to debug funchook itself. 148 | * 149 | * @param name log file name 150 | * @return error code. one of FUNCHOOK_ERROR_*. 151 | */ 152 | FUNCHOOK_EXPORT int funchook_set_debug_file(const char *name); 153 | 154 | /* This function is under developemnt. It will be used by C++ template functions later. */ 155 | FUNCHOOK_EXPORT void *funchook_arg_get_int_reg_addr(const funchook_arg_handle_t *arg_handle, int pos); 156 | 157 | /* This function is under developemnt. It will be used by C++ template functions later. */ 158 | FUNCHOOK_EXPORT void *funchook_arg_get_flt_reg_addr(const funchook_arg_handle_t *arg_handle, int pos); 159 | 160 | /* This function is under developemnt. It will be used by C++ template functions later. */ 161 | FUNCHOOK_EXPORT void *funchook_arg_get_stack_addr(const funchook_arg_handle_t *arg_handle, int pos); 162 | 163 | #ifdef __cplusplus 164 | } // extern "C" 165 | #endif 166 | 167 | #endif 168 | -------------------------------------------------------------------------------- /funchook/lib/distorm.lib: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Pisex/cs2-menus/dab962ef364df8d317d02bc82e54166a5010d7fe/funchook/lib/distorm.lib -------------------------------------------------------------------------------- /funchook/lib/funchook.lib: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Pisex/cs2-menus/dab962ef364df8d317d02bc82e54166a5010d7fe/funchook/lib/funchook.lib -------------------------------------------------------------------------------- /funchook/lib/libdistorm.a: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Pisex/cs2-menus/dab962ef364df8d317d02bc82e54166a5010d7fe/funchook/lib/libdistorm.a -------------------------------------------------------------------------------- /funchook/lib/libfunchook.a: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Pisex/cs2-menus/dab962ef364df8d317d02bc82e54166a5010d7fe/funchook/lib/libfunchook.a -------------------------------------------------------------------------------- /hl2sdk-manifests/SdkHelpers.ambuild: -------------------------------------------------------------------------------- 1 | # vim: set sts=2 ts=8 sw=2 tw=99 et ft=python: 2 | import json 3 | import os 4 | 5 | class SdkTarget(object): 6 | def __init__(self, sdk, cxx, protoc): 7 | self.sdk = sdk 8 | self.cxx = cxx 9 | self.protoc = protoc 10 | 11 | class SdkHelpers(object): 12 | def __init__(self): 13 | self.sdks = {} 14 | self.sdk_manifests = [] 15 | self.sdk_filter = None 16 | self.find_sdk_path = None 17 | self.sdk_targets = [] 18 | 19 | # find_sdk_path must be set to use. 20 | def findSdks(self, builder, cxx_list, sdk_list): 21 | not_found = [] 22 | sdk_remaining = set(sdk_list) 23 | for sdk_name, sdk in SdkHelpers.getSdks(builder): 24 | self.sdk_manifests.append(sdk) 25 | # Skip SDKs that weren't specified or are not supported. 26 | if not self.shouldFindSdk(sdk, sdk_list): 27 | continue 28 | # Skip SDKs that won't build on any targets. 29 | if not SdkHelpers.sdkHasBuildTargets(sdk, cxx_list): 30 | continue 31 | 32 | sdk_path = self.find_sdk_path(sdk_name) 33 | if sdk_path is None: 34 | if SdkHelpers.shouldRequireSdk(sdk_name, sdk_list): 35 | raise Exception('Could not find a valid path for {0}'.format(sdk_name)) 36 | not_found.append(sdk_name) 37 | continue 38 | 39 | sdk_remaining.discard(sdk_name) 40 | 41 | sdk['path'] = sdk_path 42 | self.sdks[sdk_name] = sdk 43 | 44 | for cxx in cxx_list: 45 | if SdkHelpers.shouldBuildSdk(sdk, cxx): 46 | protoc = None 47 | rel_protoc_path = sdk[cxx.target.platform].get('protoc_path', None) 48 | if rel_protoc_path: 49 | protoc_path = os.path.join(sdk['path'], rel_protoc_path) 50 | protoc = builder.DetectProtoc(path = protoc_path) 51 | for path in sdk['include_paths']: 52 | protoc.includes += [os.path.join(sdk['path'], path)] 53 | self.sdk_targets += [SdkTarget(sdk, cxx, protoc)] 54 | 55 | if 'present' in sdk_list: 56 | for sdk in not_found: 57 | print('Warning: hl2sdk-{} was not found, and will not be included in build.'.format(sdk)) 58 | elif len(sdk_remaining) and 'all' not in sdk_list: 59 | for sdk in sdk_remaining: 60 | print('Error: hl2sdk-{} was not found.'.format(sdk)) 61 | raise Exception('Missing hl2sdks: {}'.format(','.join(sdk_remaining))) 62 | 63 | if not len(self.sdk_targets) and len(sdk_list): 64 | raise Exception('No buildable SDKs were found, nothing to build.') 65 | 66 | @staticmethod 67 | def shouldRequireSdk(sdk_name, sdk_list): 68 | if 'all' in sdk_list: 69 | return sdk_name != 'mock' 70 | if sdk_name in sdk_list: 71 | return True 72 | return 'present' in sdk_list 73 | 74 | def shouldFindSdk(self, sdk, sdk_list): 75 | # Remove SDKs that the project doesn't support. 76 | if self.sdk_filter and not self.sdk_filter(sdk): 77 | return False 78 | if 'all' in sdk_list or 'present' in sdk_list: 79 | return True 80 | return sdk['name'] in sdk_list 81 | 82 | @staticmethod 83 | def sdkHasBuildTargets(sdk, cxx_list): 84 | for cxx in cxx_list: 85 | if SdkHelpers.shouldBuildSdk(sdk, cxx): 86 | return True 87 | return False 88 | 89 | @staticmethod 90 | def shouldBuildSdk(sdk, cxx): 91 | if cxx.target.platform in sdk['platforms']: 92 | if cxx.target.arch in sdk['platforms'][cxx.target.platform]: 93 | return True 94 | return False 95 | 96 | @staticmethod 97 | def addLists(sdk, list_name, cxx): 98 | result = SdkHelpers.getLists(sdk, list_name, cxx) 99 | cxx_list = getattr(cxx, list_name) 100 | cxx_list.extend(result) 101 | 102 | @staticmethod 103 | def getLists(sdk, list_name, cxx): 104 | result = SdkHelpers.getListsImpl(sdk, list_name, cxx) 105 | if Project in sdk: 106 | result += SdkHelpers.getListsImpl(sdk[Project], list_name, cxx) 107 | return result 108 | 109 | @staticmethod 110 | def getListsImpl(info, list_name, cxx): 111 | result = [] 112 | if cxx.target.platform in info: 113 | platform_info = info[cxx.target.platform] 114 | result += platform_info.get(list_name, []) 115 | if cxx.target.arch in platform_info: 116 | arch_info = platform_info[cxx.target.arch] 117 | result += arch_info.get(list_name, []) 118 | return result 119 | 120 | @staticmethod 121 | def getSdks(builder): 122 | sdk_manifest_dir = os.path.join(builder.sourcePath, 'hl2sdk-manifests', 123 | 'manifests') 124 | 125 | out = [] 126 | for sdk_manifest in os.listdir(sdk_manifest_dir): 127 | sdk_name, _ = os.path.splitext(sdk_manifest) 128 | sdk_manifest_path = os.path.join(sdk_manifest_dir, sdk_manifest) 129 | with open(sdk_manifest_path, 'rt') as fp: 130 | sdk = json.load(fp) 131 | builder.AddConfigureFile(sdk_manifest_path) 132 | out.append((sdk_name, sdk)) 133 | return out 134 | 135 | @staticmethod 136 | def configureCxx(context, binary, sdk): 137 | cxx = binary.compiler 138 | 139 | # Includes/defines. 140 | cxx.defines += ['SOURCE_ENGINE={}'.format(sdk['code'])] 141 | 142 | if sdk['name'] in ['sdk2013', 'bms', 'pvkii'] and cxx.like('gcc'): 143 | # The 2013 SDK already has these in public/tier0/basetypes.h 144 | rm_defines = [ 145 | 'stricmp=strcasecmp', '_stricmp=strcasecmp', 146 | '_snprintf=snprintf', '_vsnprintf=vsnprintf,' 147 | ] 148 | for rm_define in rm_defines: 149 | if rm_define in cxx.defines: 150 | cxx.defines.remove(rm_define) 151 | 152 | if cxx.family == 'msvc': 153 | cxx.defines += ['COMPILER_MSVC'] 154 | if cxx.target.arch == 'x86': 155 | cxx.defines += ['COMPILER_MSVC32'] 156 | elif cxx.target.arch == 'x86_64': 157 | cxx.defines += ['COMPILER_MSVC64'] 158 | 159 | if cxx.version >= 1900: 160 | cxx.linkflags += ['legacy_stdio_definitions.lib'] 161 | else: 162 | cxx.defines += ['COMPILER_GCC'] 163 | 164 | if cxx.target.arch == 'x86_64': 165 | cxx.defines += ['X64BITS', 'PLATFORM_64BITS'] 166 | 167 | SdkHelpers.addLists(sdk, 'defines', cxx) 168 | SdkHelpers.addLists(sdk, 'linkflags', cxx) 169 | 170 | for path in sdk['include_paths']: 171 | cxx.cxxincludes += [os.path.join(sdk['path'], path)] 172 | 173 | # Link steps. 174 | for lib in SdkHelpers.getLists(sdk, 'libs', cxx): 175 | cxx.linkflags += [os.path.join(sdk['path'], lib)] 176 | for lib in SdkHelpers.getLists(sdk, 'postlink_libs', cxx): 177 | cxx.postlink += [os.path.join(sdk['path'], lib)] 178 | 179 | if cxx.target.platform == 'linux': 180 | cxx.linkflags[0:0] = ['-lm'] 181 | elif cxx.target.platform == 'mac': 182 | cxx.linkflags.append('-liconv') 183 | 184 | dynamic_libs = SdkHelpers.getLists(sdk, 'dynamic_libs', cxx) 185 | for library in dynamic_libs: 186 | file_name = os.path.split(library)[1] 187 | source_path = os.path.join(sdk['path'], library) 188 | output_path = os.path.join(binary.localFolder, file_name) 189 | 190 | context.AddFolder(binary.localFolder) 191 | output = context.AddSymlink(source_path, output_path) 192 | 193 | cxx.weaklinkdeps += [output] 194 | cxx.linkflags[0:0] = [file_name] 195 | 196 | if cxx.target.platform == 'linux': 197 | if sdk[cxx.target.platform]['uses_system_cxxlib']: 198 | cxx.linkflags.remove('-static-libstdc++') 199 | cxx.linkflags += ['-lstdc++'] 200 | elif cxx.target.platform == 'mac': 201 | if sdk[cxx.target.platform]['cxxlib'] == 'stdc++': 202 | # Switch libc++ to libstdc++ for protobuf linkage. 203 | cxx.cxxflags.remove('-stdlib=libc++') 204 | cxx.linkflags.remove('-stdlib=libc++') 205 | cxx.linkflags.remove('-lc++') 206 | 207 | cxx.cxxflags += ['-stdlib=libstdc++'] 208 | cxx.linkflags += ['-stdlib=libstdc++'] 209 | cxx.linkflags += ['-lstdc++'] 210 | 211 | 212 | rvalue = SdkHelpers() 213 | -------------------------------------------------------------------------------- /hl2sdk-manifests/manifests/cs2.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "cs2", 3 | "env_var": "HL2SDKCS2", 4 | "extension": "2.cs2", 5 | "code": 25, 6 | "define": "CS2", 7 | "platforms": { 8 | "windows": [ 9 | "x86_64" 10 | ], 11 | "linux": [ 12 | "x86_64" 13 | ] 14 | }, 15 | "source2": true, 16 | "include_paths": [ 17 | "thirdparty/protobuf-3.21.8/src", 18 | "public", 19 | "public/engine", 20 | "public/mathlib", 21 | "public/vstdlib", 22 | "public/tier0", 23 | "public/tier1", 24 | "public/entity2", 25 | "public/game/server", 26 | "game/shared", 27 | "game/server", 28 | "common" 29 | ], 30 | "linux": { 31 | "x86_64": { 32 | "postlink_libs": [ 33 | "lib/linux64/mathlib.a", 34 | "lib/linux64/tier1.a", 35 | "lib/linux64/interfaces.a", 36 | "lib/linux64/release/libprotobuf.a" 37 | ], 38 | "dynamic_libs": [ 39 | "lib/linux64/libtier0.so" 40 | ] 41 | }, 42 | "defines": [ 43 | "_GLIBCXX_USE_CXX11_ABI=0" 44 | ], 45 | "uses_system_cxxlib": false, 46 | "protoc_path": "devtools/bin/linux/protoc" 47 | }, 48 | "windows": { 49 | "x86_64": { 50 | "libs": [ 51 | "lib/public/win64/2015/libprotobuf.lib", 52 | "lib/public/win64/mathlib.lib", 53 | "lib/public/win64/tier0.lib", 54 | "lib/public/win64/tier1.lib", 55 | "lib/public/win64/interfaces.lib" 56 | ] 57 | }, 58 | "protoc_path": "devtools/bin/protoc.exe" 59 | } 60 | } -------------------------------------------------------------------------------- /include/cookies.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #define COOKIES_INTERFACE "ICookiesApi" 4 | 5 | typedef std::function ClientCookieLoadedCallback; 6 | 7 | class ICookiesApi 8 | { 9 | public: 10 | virtual void SetCookie(int iSlot, const char* sCookieName, const char* sData) = 0; 11 | virtual const char* GetCookie(int iSlot, const char* sCookieName) = 0; 12 | virtual void HookClientCookieLoaded(SourceMM::PluginId id, ClientCookieLoadedCallback callback) = 0; 13 | }; -------------------------------------------------------------------------------- /include/menus.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | #include 5 | 6 | class CBaseEntity; 7 | class CBaseModelEntity; 8 | class CEntityInstance; 9 | class CEntityKeyValues; 10 | class CSteamID; 11 | class CGameEntitySystem; 12 | class CEntitySystem; 13 | class CGlobalVars; 14 | class IGameEvent; 15 | class IGameEventManager2; 16 | struct CTakeDamageInfoContainer; 17 | class CTakeDamageInfo; 18 | class IGameEventListener2; 19 | 20 | ///////////////////////////////////////////////////////////////// 21 | /////////////////////// PLAYERS ////////////////////////// 22 | ///////////////////////////////////////////////////////////////// 23 | 24 | typedef std::function OnClientAuthorizedCallback; 25 | 26 | #define PLAYERS_INTERFACE "IPlayersApi" 27 | class IPlayersApi 28 | { 29 | public: 30 | virtual bool IsFakeClient(int iSlot) = 0; 31 | virtual bool IsAuthenticated(int iSlot) = 0; 32 | virtual bool IsConnected(int iSlot) = 0; 33 | virtual bool IsInGame(int iSlot) = 0; 34 | virtual const char* GetIpAddress(int iSlot) = 0; 35 | virtual uint64 GetSteamID64(int iSlot) = 0; 36 | virtual const CSteamID* GetSteamID(int iSlot) = 0; 37 | 38 | virtual void HookOnClientAuthorized(SourceMM::PluginId id, OnClientAuthorizedCallback callback) = 0; 39 | 40 | virtual void CommitSuicide(int iSlot, bool bExplode, bool bForce) = 0; 41 | virtual void ChangeTeam(int iSlot, int iNewTeam) = 0; 42 | virtual void Teleport(int iSlot, const Vector *position, const QAngle *angles, const Vector *velocity) = 0; 43 | virtual void Respawn(int iSlot) = 0; 44 | virtual void DropWeapon(int iSlot, CBaseEntity* pWeapon, Vector* pVecTarget = nullptr, Vector* pVelocity = nullptr) = 0; 45 | virtual void SwitchTeam(int iSlot, int iNewTeam) = 0; 46 | virtual const char* GetPlayerName(int iSlot) = 0; 47 | virtual void SetPlayerName(int iSlot, const char* szName) = 0; 48 | virtual void SetMoveType(int iSlot, MoveType_t moveType) = 0; 49 | virtual void EmitSound(std::vector vPlayers, CEntityIndex ent, std::string sound_name, int pitch, float volume) = 0; 50 | virtual void EmitSound(int iSlot, CEntityIndex ent, std::string sound_name, int pitch, float volume) = 0; 51 | virtual void StopSoundEvent(int iSlot, const char* sound_name) = 0; 52 | virtual IGameEventListener2* GetLegacyGameEventListener(int iSlot) = 0; 53 | virtual int FindPlayer(uint64 iSteamID64) = 0; 54 | virtual int FindPlayer(const CSteamID* steamID) = 0; 55 | virtual int FindPlayer(const char* szName) = 0; 56 | }; 57 | 58 | ///////////////////////////////////////////////////////////////// 59 | /////////////////////// UTILS ////////////////////////// 60 | ///////////////////////////////////////////////////////////////// 61 | 62 | class CCSGameRules; 63 | class CTimer; 64 | 65 | #define Utils_INTERFACE "IUtilsApi" 66 | 67 | typedef std::function CommandCallback; 68 | typedef std::function CommandCallbackPre; 69 | typedef std::function CommandCallbackPost; 70 | typedef std::function EventCallback; 71 | typedef std::function StartupCallback; 72 | typedef std::function OnTakeDamageCallback; 73 | typedef std::function OnTakeDamagePreCallback; 74 | typedef std::function OnHearingClientCallback; 75 | 76 | class IUtilsApi 77 | { 78 | public: 79 | virtual void PrintToChat(int iSlot, const char* msg, ...) = 0; 80 | virtual void PrintToChatAll(const char* msg, ...) = 0; 81 | virtual void NextFrame(std::function fn) = 0; 82 | virtual CCSGameRules* GetCCSGameRules() = 0; 83 | virtual CGameEntitySystem* GetCGameEntitySystem() = 0; 84 | virtual CEntitySystem* GetCEntitySystem() = 0; 85 | virtual CGlobalVars* GetCGlobalVars() = 0; 86 | virtual IGameEventManager2* GetGameEventManager() = 0; 87 | 88 | virtual const char* GetLanguage() = 0; 89 | 90 | virtual void StartupServer(SourceMM::PluginId id, StartupCallback fn) = 0; 91 | virtual void OnGetGameRules(SourceMM::PluginId id, StartupCallback fn) = 0; 92 | 93 | virtual void RegCommand(SourceMM::PluginId id, const std::vector &console, const std::vector &chat, const CommandCallback &callback) = 0; 94 | virtual void AddChatListenerPre(SourceMM::PluginId id, CommandCallbackPre callback) = 0; 95 | virtual void AddChatListenerPost(SourceMM::PluginId id, CommandCallbackPost callback) = 0; 96 | virtual void HookEvent(SourceMM::PluginId id, const char* sName, EventCallback callback) = 0; 97 | 98 | virtual void SetStateChanged(CBaseEntity* entity, const char* sClassName, const char* sFieldName, int extraOffset = 0) = 0; 99 | 100 | virtual void ClearAllHooks(SourceMM::PluginId id) = 0; 101 | 102 | virtual void LoadTranslations(const char* szFile) = 0; 103 | virtual void PrintToConsole(int iSlot, const char* msg, ...) = 0; 104 | virtual void PrintToConsoleAll(const char* msg, ...) = 0; 105 | virtual void PrintToCenter(int iSlot, const char* msg, ...) = 0; 106 | virtual void PrintToCenterAll(const char* msg, ...) = 0; 107 | virtual void PrintToCenterHtml(int iSlot, int iDuration, const char* msg, ...) = 0; 108 | virtual void PrintToCenterHtmlAll(int iDuration, const char* msg, ...) = 0; 109 | 110 | virtual void LogToFile(const char* szFile, const char* szText, ...) = 0; 111 | virtual void ErrorLog(const char* msg, ...) = 0; 112 | virtual void PrintToAlert(int iSlot, const char *msg, ...) = 0; 113 | virtual void PrintToAlertAll(const char *msg, ...) = 0; 114 | virtual void SetEntityModel(CBaseModelEntity* pEntity, const char* szModel) = 0; 115 | virtual void DispatchSpawn(CEntityInstance* pEntity, CEntityKeyValues*) = 0; 116 | virtual CBaseEntity* CreateEntityByName(const char *pClassName, CEntityIndex iForceEdictIndex) = 0; 117 | virtual void RemoveEntity(CEntityInstance* pEntity) = 0; 118 | virtual void AcceptEntityInput(CEntityInstance* pEntity, const char* szInputName, variant_t value = variant_t(""), CEntityInstance *pActivator = nullptr, CEntityInstance *pCaller = nullptr) = 0; 119 | virtual CTimer* CreateTimer(float flInterval, std::function func) = 0; 120 | virtual void RemoveTimer(CTimer* timer) = 0; 121 | virtual void HookOnTakeDamage(SourceMM::PluginId id, OnTakeDamageCallback callback) = 0; 122 | virtual void HookOnTakeDamagePre(SourceMM::PluginId id, OnTakeDamagePreCallback callback) = 0; 123 | virtual void CollisionRulesChanged(CBaseEntity* pEnt) = 0; 124 | virtual void TeleportEntity(CBaseEntity* pEnt, const Vector *position, const QAngle *angles, const Vector *velocity) = 0; 125 | virtual void HookIsHearingClient(SourceMM::PluginId id, OnHearingClientCallback callback) = 0; 126 | virtual const char* GetVersion() = 0; 127 | }; 128 | 129 | ///////////////////////////////////////////////////////////////// 130 | /////////////////////// MENUS ////////////////////////// 131 | ///////////////////////////////////////////////////////////////// 132 | 133 | #define Menus_INTERFACE "IMenusApi" 134 | 135 | #define ITEM_HIDE 0 136 | #define ITEM_DEFAULT 1 137 | #define ITEM_DISABLED 2 138 | 139 | typedef std::function MenuCallbackFunc; 140 | 141 | struct Items 142 | { 143 | int iType; 144 | std::string sBack; 145 | std::string sText; 146 | }; 147 | 148 | struct Menu 149 | { 150 | std::string szTitle; 151 | std::vector hItems; 152 | bool bBack = false; 153 | bool bExit = false; 154 | MenuCallbackFunc hFunc = nullptr; 155 | 156 | void clear() { 157 | szTitle.clear(); 158 | hItems.clear(); 159 | bBack = false; 160 | bExit = false; 161 | hFunc = nullptr; 162 | } 163 | }; 164 | 165 | struct MenuPlayer 166 | { 167 | bool bEnabled; 168 | int iList; 169 | Menu hMenu; 170 | int iEnd; 171 | 172 | void clear() { 173 | bEnabled = false; 174 | iList = 0; 175 | hMenu.clear(); 176 | iEnd = 0; 177 | } 178 | }; 179 | 180 | class IMenusApi 181 | { 182 | public: 183 | virtual void AddItemMenu(Menu& hMenu, const char* sBack, const char* sText, int iType = 1) = 0; 184 | virtual void DisplayPlayerMenu(Menu& hMenu, int iSlot, bool bClose = true) = 0; 185 | virtual void SetExitMenu(Menu& hMenu, bool bExit) = 0; 186 | virtual void SetBackMenu(Menu& hMenu, bool bBack) = 0; 187 | virtual void SetTitleMenu(Menu& hMenu, const char* szTitle) = 0; 188 | virtual void SetCallback(Menu& hMenu, MenuCallbackFunc func) = 0; 189 | virtual void ClosePlayerMenu(int iSlot) = 0; 190 | virtual std::string escapeString(const std::string& input) = 0; 191 | virtual bool IsMenuOpen(int iSlot) = 0; 192 | virtual void DisplayPlayerMenu(Menu& hMenu, int iSlot, bool bClose = true, bool bReset = true) = 0; 193 | }; 194 | 195 | ///////////////////////////////////////////////////////////////// 196 | ///////////////////////////////////////////////////////////////// 197 | ///////////////////////////////////////////////////////////////// -------------------------------------------------------------------------------- /menu_buttons/info.txt: -------------------------------------------------------------------------------- 1 | RU: 2 | При использовании site - визуальное отображение будет зависеть только от скорости интернета клиента 3 | При использовании workshop - визуально идеальный вариант независящий от интернета пользователя 4 | EN: 5 | When using site - visual display will depend only on the client's internet speed 6 | When using workshop - the visual ideal is independent of the user's internet speed -------------------------------------------------------------------------------- /menu_buttons/site/a-p.svg: -------------------------------------------------------------------------------- 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 | -------------------------------------------------------------------------------- /menu_buttons/site/a.svg: -------------------------------------------------------------------------------- 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 | -------------------------------------------------------------------------------- /menu_buttons/site/d-p.svg: -------------------------------------------------------------------------------- 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 | -------------------------------------------------------------------------------- /menu_buttons/site/d.svg: -------------------------------------------------------------------------------- 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 | -------------------------------------------------------------------------------- /menu_buttons/site/e-p.svg: -------------------------------------------------------------------------------- 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 | -------------------------------------------------------------------------------- /menu_buttons/site/e.svg: -------------------------------------------------------------------------------- 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 | -------------------------------------------------------------------------------- /menu_buttons/site/empty.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | -------------------------------------------------------------------------------- /menu_buttons/site/empty_half.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | -------------------------------------------------------------------------------- /menu_buttons/site/f.svg: -------------------------------------------------------------------------------- 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 | -------------------------------------------------------------------------------- /menu_buttons/site/s-p.svg: -------------------------------------------------------------------------------- 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 | -------------------------------------------------------------------------------- /menu_buttons/site/s.svg: -------------------------------------------------------------------------------- 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 | -------------------------------------------------------------------------------- /menu_buttons/site/w-p.svg: -------------------------------------------------------------------------------- 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 | -------------------------------------------------------------------------------- /menu_buttons/site/w.svg: -------------------------------------------------------------------------------- 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 | -------------------------------------------------------------------------------- /menu_buttons/workshop/a-p.svg: -------------------------------------------------------------------------------- 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 | -------------------------------------------------------------------------------- /menu_buttons/workshop/a.svg: -------------------------------------------------------------------------------- 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 | -------------------------------------------------------------------------------- /menu_buttons/workshop/d-p.svg: -------------------------------------------------------------------------------- 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 | -------------------------------------------------------------------------------- /menu_buttons/workshop/d.svg: -------------------------------------------------------------------------------- 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 | -------------------------------------------------------------------------------- /menu_buttons/workshop/e-p.svg: -------------------------------------------------------------------------------- 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 | -------------------------------------------------------------------------------- /menu_buttons/workshop/e.svg: -------------------------------------------------------------------------------- 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 | -------------------------------------------------------------------------------- /menu_buttons/workshop/empty.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | -------------------------------------------------------------------------------- /menu_buttons/workshop/empty_half.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | -------------------------------------------------------------------------------- /menu_buttons/workshop/f.svg: -------------------------------------------------------------------------------- 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 | -------------------------------------------------------------------------------- /menu_buttons/workshop/install.txt: -------------------------------------------------------------------------------- 1 | RU: 2 | Добавить в свой аддон по пути resource/menus/ 3 | Поменять тип в конфиге MenuAddon на 1 4 | EN: 5 | Add to your addon at the path resource/menus/ 6 | Change the type in the MenuAddon config to 1 -------------------------------------------------------------------------------- /menu_buttons/workshop/s-p.svg: -------------------------------------------------------------------------------- 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 | -------------------------------------------------------------------------------- /menu_buttons/workshop/s.svg: -------------------------------------------------------------------------------- 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 | -------------------------------------------------------------------------------- /menu_buttons/workshop/w-p.svg: -------------------------------------------------------------------------------- 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 | -------------------------------------------------------------------------------- /menu_buttons/workshop/w.svg: -------------------------------------------------------------------------------- 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 | -------------------------------------------------------------------------------- /translations/menus.phrases.txt: -------------------------------------------------------------------------------- 1 | "Phrases" 2 | { 3 | "Back" 4 | { 5 | "ru" " {GRAY}[!7]{DEFAULT} ← Назад" 6 | "en" " {GRAY}[!7]{DEFAULT} ← Back" 7 | } 8 | "Next" 9 | { 10 | "ru" " {GRAY}[!8]{DEFAULT} → Вперёд" 11 | "en" " {GRAY}[!8]{DEFAULT} → Next" 12 | } 13 | "Exit" 14 | { 15 | "ru" " {LIGHTRED}[!9]{DEFAULT} Выход" 16 | "en" " {LIGHTRED}[!9]{DEFAULT} Exit" 17 | } 18 | "HtmlTitle" 19 | { 20 | "ru" "%s
" 21 | "en" "%s
" 22 | } 23 | "HtmlNumber" 24 | { 25 | "ru" "[!%i] %s
" 26 | "en" "[!%i] %s
" 27 | } 28 | "HtmlNumberBlock" 29 | { 30 | "ru" "[!%i] %s
" 31 | "en" "[!%i] %s
" 32 | } 33 | "HtmlBack" 34 | { 35 | "ru" "[!7] Назад " 36 | "en" "[!7] Back " 37 | } 38 | "HtmlNext" 39 | { 40 | "ru" "[!8] Вперёд " 41 | "en" "[!8] Next " 42 | } 43 | "HtmlExit" 44 | { 45 | "ru" "[!9] Выход
" 46 | "en" "[!9] Exit
" 47 | } 48 | 49 | "HtmlButton" 50 | { 51 | "ru" "%s" 52 | "en" "%s" 53 | } 54 | "HtmlButtonBlock" 55 | { 56 | "ru" "%s" 57 | "en" "%s" 58 | } 59 | "HtmlButtonBR" 60 | { 61 | "ru" "
" 62 | "en" "
" 63 | } 64 | "HtmlEButtons_Web" 65 | { 66 | "ru" "" 67 | "en" "" 68 | } 69 | "HtmlE_PButtons_Web" 70 | { 71 | "ru" "" 72 | "en" "" 73 | } 74 | "HtmlWButtons_Web" 75 | { 76 | "ru" " " 77 | "en" " " 78 | } 79 | "HtmlW_PButtons_Web" 80 | { 81 | "ru" " " 82 | "en" " " 83 | } 84 | "HtmlSButtons_Web" 85 | { 86 | "ru" " " 87 | "en" " " 88 | } 89 | "HtmlS_PButtons_Web" 90 | { 91 | "ru" " " 92 | "en" " " 93 | } 94 | "HtmlAButtons_Web" 95 | { 96 | "ru" " " 97 | "en" " " 98 | } 99 | "HtmlA_PButtons_Web" 100 | { 101 | "ru" " " 102 | "en" " " 103 | } 104 | "HtmlDButtons_Web" 105 | { 106 | "ru" " " 107 | "en" " " 108 | } 109 | "HtmlD_PButtons_Web" 110 | { 111 | "ru" " " 112 | "en" " " 113 | } 114 | "HtmlFButtons_Web" 115 | { 116 | "ru" " " 117 | "en" " " 118 | } 119 | "HtmlSpaceButtons_Web" 120 | { 121 | "ru" " " 122 | "en" " " 123 | } 124 | "HtmlSpaceShortButtons_Web" 125 | { 126 | "ru" " " 127 | "en" " " 128 | } 129 | 130 | "HtmlEButtons" 131 | { 132 | "ru" "" 133 | "en" "" 134 | } 135 | "HtmlE_PButtons" 136 | { 137 | "ru" "" 138 | "en" "" 139 | } 140 | "HtmlWButtons" 141 | { 142 | "ru" " " 143 | "en" " " 144 | } 145 | "HtmlW_PButtons" 146 | { 147 | "ru" " " 148 | "en" " " 149 | } 150 | "HtmlSButtons" 151 | { 152 | "ru" " " 153 | "en" " " 154 | } 155 | "HtmlS_PButtons" 156 | { 157 | "ru" " " 158 | "en" " " 159 | } 160 | "HtmlAButtons" 161 | { 162 | "ru" " " 163 | "en" " " 164 | } 165 | "HtmlA_PButtons" 166 | { 167 | "ru" " " 168 | "en" " " 169 | } 170 | "HtmlDButtons" 171 | { 172 | "ru" " " 173 | "en" " " 174 | } 175 | "HtmlD_PButtons" 176 | { 177 | "ru" " " 178 | "en" " " 179 | } 180 | "HtmlFButtons" 181 | { 182 | "ru" " " 183 | "en" " " 184 | } 185 | "HtmlSpaceButtons" 186 | { 187 | "ru" " " 188 | "en" " " 189 | } 190 | "HtmlSpaceShortButtons" 191 | { 192 | "ru" " " 193 | "en" " " 194 | } 195 | 196 | "AuthTicketInvalid" 197 | { 198 | "ru" " {LIGHTRED}Ваша аутентификация в Steam не удалась из-за недействительного или использованного билета. Возможно, вам придется перезапустить клиент Steam, чтобы исправить ситуацию." 199 | "en" " {LIGHTRED}Your Steam authentication failed due to an invalid or used ticket. You may have to restart your Steam client in order to fix this." 200 | } 201 | 202 | "AuthFailed" 203 | { 204 | "ru" " {LIGHTRED}ПРЕДУПРЕЖДЕНИЕ: Вы будете кикнуты через %i секунд из-за неудачной аутентификации в Steam." 205 | "en" " {LIGHTRED}WARNING: You will be kicked in %i seconds due to failed Steam authentication." 206 | } 207 | 208 | "MenuMenusTitle" 209 | { 210 | "ru" "Выберите тип меню" 211 | "en" "Choose menu type" 212 | } 213 | 214 | "MenuMenusItem0" 215 | { 216 | "ru" "Чат меню" 217 | "en" "Chat menu" 218 | } 219 | "MenuMenusItem1" 220 | { 221 | "ru" "Чат + Центр меню" 222 | "en" "Chat + Center menu" 223 | } 224 | "MenuMenusItem2" 225 | { 226 | "ru" "WASD меню" 227 | "en" "WASD menu" 228 | } 229 | } -------------------------------------------------------------------------------- /utils.h: -------------------------------------------------------------------------------- 1 | #ifndef _INCLUDE_METAMOD_SOURCE_STUB_PLUGIN_H_ 2 | #define _INCLUDE_METAMOD_SOURCE_STUB_PLUGIN_H_ 3 | 4 | #include 5 | #include 6 | #include "utlvector.h" 7 | #include "ehandle.h" 8 | #include 9 | #include 10 | #include 11 | #include "irecipientfilter.h" 12 | #include "igameevents.h" 13 | #include "entitysystem.h" 14 | #include "vector.h" 15 | #include 16 | #include 17 | #include "utils.hpp" 18 | #include 19 | #include 20 | #include "CCSPlayerController.h" 21 | #include "igameeventsystem.h" 22 | #include 23 | #include 24 | #include 25 | #include "usermessages.pb.h" 26 | #include "CGameRules.h" 27 | #include "module.h" 28 | #include "ctimer.h" 29 | #include "funchook.h" 30 | #include "include/menus.h" 31 | #include "include/cookies.h" 32 | #include 33 | #include 34 | #include 35 | #include 36 | #include 37 | 38 | std::map> ConsoleCommands; 39 | std::map> ChatCommands; 40 | 41 | class CRecipientFilter : public IRecipientFilter 42 | { 43 | public: 44 | CRecipientFilter(NetChannelBufType_t nBufType = BUF_RELIABLE, bool bInitMessage = false) : m_nBufType(nBufType), m_bInitMessage(bInitMessage) {} 45 | 46 | ~CRecipientFilter() override {} 47 | 48 | NetChannelBufType_t GetNetworkBufType(void) const override 49 | { 50 | return m_nBufType; 51 | } 52 | 53 | bool IsInitMessage(void) const override 54 | { 55 | return m_bInitMessage; 56 | } 57 | 58 | int GetRecipientCount(void) const override 59 | { 60 | return m_Recipients.Count(); 61 | } 62 | 63 | CPlayerSlot GetRecipientIndex(int slot) const override 64 | { 65 | if (slot < 0 || slot >= GetRecipientCount()) 66 | { 67 | return CPlayerSlot(-1); 68 | } 69 | 70 | return m_Recipients[slot]; 71 | } 72 | 73 | void AddRecipient(CPlayerSlot slot) 74 | { 75 | // Don't add if it already exists 76 | if (m_Recipients.Find(slot) != m_Recipients.InvalidIndex()) 77 | { 78 | return; 79 | } 80 | 81 | m_Recipients.AddToTail(slot); 82 | } 83 | 84 | void AddAllPlayers() 85 | { 86 | m_Recipients.RemoveAll(); 87 | 88 | for (int i = 0; i < 64; i++) 89 | { 90 | CCSPlayerController* pPlayer = CCSPlayerController::FromSlot(i); 91 | if (!pPlayer) continue; 92 | 93 | AddRecipient(i); 94 | } 95 | } 96 | 97 | private: 98 | // Can't copy this unless we explicitly do it! 99 | CRecipientFilter(CRecipientFilter const &source) 100 | { 101 | Assert(0); 102 | } 103 | 104 | NetChannelBufType_t m_nBufType; 105 | bool m_bInitMessage; 106 | CUtlVectorFixed m_Recipients; 107 | }; 108 | 109 | class CSingleRecipientFilter : public IRecipientFilter 110 | { 111 | public: 112 | CSingleRecipientFilter(int iRecipient, NetChannelBufType_t nBufType = BUF_RELIABLE, bool bInitMessage = false) 113 | : m_nBufType(nBufType), m_bInitMessage(bInitMessage), m_iRecipient(iRecipient) 114 | { 115 | } 116 | 117 | ~CSingleRecipientFilter() override {} 118 | 119 | NetChannelBufType_t GetNetworkBufType(void) const override 120 | { 121 | return m_nBufType; 122 | } 123 | 124 | bool IsInitMessage(void) const override 125 | { 126 | return m_bInitMessage; 127 | } 128 | 129 | int GetRecipientCount(void) const override 130 | { 131 | return 1; 132 | } 133 | 134 | CPlayerSlot GetRecipientIndex(int slot) const override 135 | { 136 | return CPlayerSlot(m_iRecipient); 137 | } 138 | 139 | private: 140 | NetChannelBufType_t m_nBufType; 141 | bool m_bInitMessage; 142 | int m_iRecipient; 143 | }; 144 | 145 | class Menus final : public ISmmPlugin, public IMetamodListener 146 | { 147 | public: 148 | bool Load(PluginId id, ISmmAPI* ismm, char* error, size_t maxlen, bool late); 149 | bool Unload(char* error, size_t maxlen); 150 | void AllPluginsLoaded(); 151 | void* OnMetamodQuery(const char* iface, int* ret); 152 | bool FireEvent(IGameEvent* pEvent, bool bDontBroadcast); 153 | STEAM_GAMESERVER_CALLBACK_MANUAL(Menus, OnValidateAuthTicket, ValidateAuthTicketResponse_t, m_CallbackValidateAuthTicketResponse); 154 | private: 155 | const char* GetAuthor(); 156 | const char* GetName(); 157 | const char* GetDescription(); 158 | const char* GetURL(); 159 | const char* GetLicense(); 160 | const char* GetVersion(); 161 | const char* GetDate(); 162 | const char* GetLogTag(); 163 | 164 | private: // Hooks 165 | void ClientCommand(CPlayerSlot slot, const CCommand &args); 166 | void GameFrame(bool simulating, bool bFirstTick, bool bLastTick); 167 | void StartupServer(const GameSessionConfiguration_t& config, ISource2WorldSession*, const char*); 168 | void OnDispatchConCommand(ConCommandRef cmd, const CCommandContext& ctx, const CCommand& args); 169 | void OnClientDisconnect( CPlayerSlot slot, ENetworkDisconnectionReason reason, const char *pszName, uint64 xuid, const char *pszNetworkID ); 170 | void OnGameServerSteamAPIActivated(); 171 | void OnValidateAuthTicketHook(ValidateAuthTicketResponse_t *pResponse); 172 | void Hook_OnClientConnected( CPlayerSlot slot, const char *pszName, uint64 xuid, const char *pszNetworkID, const char *pszAddress, bool bFakePlayer ); 173 | bool Hook_ClientConnect( CPlayerSlot slot, const char *pszName, uint64 xuid, const char *pszNetworkID, bool unk1, CBufferString *pRejectReason ); 174 | void Hook_ClientPutInServer( CPlayerSlot slot, char const *pszName, int type, uint64 xuid ); 175 | bool Hook_OnTakeDamage_Alive(CTakeDamageInfoContainer *pInfoContainer); 176 | }; 177 | 178 | class MenusApi : public IMenusApi { 179 | void AddItemMenu(Menu& hMenu, const char* sBack, const char* sText, int iType); 180 | void DisplayPlayerMenu(Menu& hMenu, int iSlot, bool bClose); 181 | void SetExitMenu(Menu& hMenu, bool bExit); 182 | void SetBackMenu(Menu& hMenu, bool bBack); 183 | void SetTitleMenu(Menu& hMenu, const char* szTitle); 184 | void ClosePlayerMenu(int iSlot); 185 | void SetCallback(Menu& hMenu, MenuCallbackFunc func) override { 186 | hMenu.hFunc = func; 187 | } 188 | std::string escapeString(const std::string& input); 189 | bool IsMenuOpen(int iSlot); 190 | void DisplayPlayerMenu(Menu& hMenu, int iSlot, bool bClose, bool bReset); 191 | }; 192 | 193 | class UtilsApi : public IUtilsApi 194 | { 195 | public: 196 | void PrintToChat(int iSlot, const char* msg, ...); 197 | void PrintToChatAll(const char* msg, ...); 198 | void NextFrame(std::function fn); 199 | CCSGameRules* GetCCSGameRules(); 200 | CGameEntitySystem* GetCGameEntitySystem(); 201 | CEntitySystem* GetCEntitySystem(); 202 | CGlobalVars* GetCGlobalVars(); 203 | IGameEventManager2* GetGameEventManager(); 204 | const char* GetLanguage(); 205 | void LoadTranslations(const char* szFile); 206 | void PrintToConsole(int iSlot, const char* msg, ...); 207 | void PrintToConsoleAll(const char* msg, ...); 208 | void PrintToCenter(int iSlot, const char* msg, ...); 209 | void PrintToCenterAll(const char* msg, ...); 210 | void PrintToCenterHtml(int iSlot, int iDuration, const char* msg, ...); 211 | void PrintToCenterHtmlAll(int iDuration, const char* msg, ...); 212 | void LogToFile(const char* szFile, const char* szText, ...); 213 | void ErrorLog(const char* msg, ...); 214 | CTimer* CreateTimer(float flInterval, std::function func); 215 | void RemoveTimer(CTimer* pTimer); 216 | 217 | void StartupServer(SourceMM::PluginId id, StartupCallback fn) override { 218 | StartupHook[id].push_back(fn); 219 | } 220 | 221 | void OnGetGameRules(SourceMM::PluginId id, StartupCallback fn) override { 222 | GetGameRules[id].push_back(fn); 223 | } 224 | 225 | void SetStateChanged(CBaseEntity* entity, const char* sClassName, const char* sFieldName, int extraOffset); 226 | 227 | void AddChatListenerPre(SourceMM::PluginId id, CommandCallbackPre callback) override { 228 | ChatHookPre[id].push_back(callback); 229 | } 230 | 231 | void AddChatListenerPost(SourceMM::PluginId id, CommandCallbackPost callback) override { 232 | ChatHookPost[id].push_back(callback); 233 | } 234 | 235 | void HookEvent(SourceMM::PluginId id, const char* sName, EventCallback callback) override { 236 | HookEvents[id][std::string(sName)] = callback; 237 | } 238 | 239 | void SendHookEventCallback(const char* szName, IGameEvent* pEvent, bool bDontBroadcast) { 240 | for(auto& item : HookEvents) 241 | { 242 | if (item.second[std::string(szName)]) { 243 | item.second[std::string(szName)](szName, pEvent, bDontBroadcast); 244 | } 245 | } 246 | } 247 | 248 | void SendHookStartup() { 249 | for(auto& item : StartupHook) 250 | { 251 | for (auto& callback : item.second) { 252 | if (callback) { 253 | callback(); 254 | } 255 | } 256 | } 257 | } 258 | 259 | void SendHookGameRules() { 260 | for(auto& item : GetGameRules) 261 | { 262 | for (auto& callback : item.second) { 263 | if (callback) { 264 | callback(); 265 | } 266 | } 267 | } 268 | } 269 | 270 | bool SendChatListenerPreCallback(int iSlot, const char* szContent, bool bTeam) { 271 | bool bFound = true; 272 | for(auto& item : ChatHookPre) 273 | { 274 | for (auto& callback : item.second) { 275 | if (callback && !callback(iSlot, szContent, bTeam)) { 276 | bFound = false; 277 | } 278 | } 279 | } 280 | return bFound; 281 | } 282 | 283 | bool SendChatListenerPostCallback(int iSlot, const char* szContent, bool bMute, bool bTeam) { 284 | bool bFound = bMute; 285 | for(auto& item : ChatHookPost) 286 | { 287 | for (auto& callback : item.second) { 288 | if (callback && !callback(iSlot, szContent, bMute, bTeam)) { 289 | bFound = false; 290 | } 291 | } 292 | } 293 | return bFound; 294 | } 295 | static bool FindAndSendCommandCallback(const char* szCommand, int iSlot, const char* szContent, bool bConsole) { 296 | bool bFound = false; 297 | if(bConsole) 298 | { 299 | for(auto& item : ConsoleCommands) 300 | { 301 | if(item.second[std::string(szCommand)] && item.second[std::string(szCommand)](iSlot, szContent)) 302 | { 303 | bFound = true; 304 | } 305 | } 306 | } 307 | else 308 | { 309 | for(auto& item : ChatCommands) 310 | { 311 | if(item.second[std::string(szCommand)] && item.second[std::string(szCommand)](iSlot, szContent)) 312 | { 313 | bFound = true; 314 | } 315 | } 316 | } 317 | return bFound; 318 | } 319 | 320 | static void CommandHandler(const CCommandContext& context, const CCommand& args) { 321 | FindAndSendCommandCallback(args.Arg(0), context.GetPlayerSlot().Get(), args.ArgS(), true); 322 | } 323 | 324 | void RegCommand(SourceMM::PluginId id, const std::vector &console, const std::vector &chat, const CommandCallback &callback) override { 325 | for (const auto &element : console) { 326 | ConsoleCommands[id][element] = callback; 327 | if (element.find("mm_") == std::string::npos) { 328 | continue; 329 | } 330 | new ConCommand( 331 | element.c_str(), 332 | CommandHandler, 333 | "", 334 | FCVAR_LINKED_CONCOMMAND | FCVAR_SERVER_CAN_EXECUTE | FCVAR_CLIENT_CAN_EXECUTE 335 | ); 336 | } 337 | 338 | for (const auto &element : chat) { 339 | ChatCommands[id][element] = callback; 340 | } 341 | } 342 | 343 | bool FindCommand(const char* szCommand) { 344 | bool bFound = false; 345 | for(auto& item : ConsoleCommands) 346 | { 347 | if(item.second[std::string(szCommand)]) 348 | { 349 | bFound = true; 350 | } 351 | } 352 | for(auto& item : ChatCommands) 353 | { 354 | if(item.second[std::string(szCommand)]) 355 | { 356 | bFound = true; 357 | } 358 | } 359 | return bFound; 360 | } 361 | 362 | 363 | void PrintToAlert(int iSlot, const char *msg, ...); 364 | void PrintToAlertAll(const char *msg, ...); 365 | 366 | void SetEntityModel(CBaseModelEntity*, const char* szModel); 367 | void DispatchSpawn(CEntityInstance* pEntity, CEntityKeyValues* pKeyValues); 368 | CBaseEntity* CreateEntityByName(const char *pClassName, CEntityIndex iForceEdictIndex); 369 | void RemoveEntity(CEntityInstance* pEntity); 370 | void AcceptEntityInput(CEntityInstance* pEntity, const char* szInputName, variant_t value, CEntityInstance *pActivator, CEntityInstance *pCaller); 371 | void CollisionRulesChanged(CBaseEntity* pEnt); 372 | void TeleportEntity(CBaseEntity* pEnt, const Vector *position, const QAngle *angles, const Vector *velocity); 373 | 374 | void ClearAllHooks(SourceMM::PluginId id) override { 375 | ConsoleCommands[id].clear(); 376 | ChatCommands[id].clear(); 377 | HookEvents[id].clear(); 378 | ChatHookPre[id].clear(); 379 | ChatHookPost[id].clear(); 380 | StartupHook[id].clear(); 381 | GetGameRules[id].clear(); 382 | OnTakeDamageHookPre[id].clear(); 383 | OnTakeDamageHook[id].clear(); 384 | } 385 | 386 | void NextFrame() { 387 | while (!m_nextFrame.empty()) 388 | { 389 | m_nextFrame.front()(); 390 | m_nextFrame.pop_front(); 391 | } 392 | } 393 | 394 | void HookOnTakeDamage(SourceMM::PluginId id, OnTakeDamageCallback callback) override { 395 | OnTakeDamageHook[id].push_back(callback); 396 | } 397 | 398 | void HookOnTakeDamagePre(SourceMM::PluginId id, OnTakeDamagePreCallback callback) override { 399 | OnTakeDamageHookPre[id].push_back(callback); 400 | } 401 | 402 | void HookIsHearingClient(SourceMM::PluginId id, OnHearingClientCallback callback) override { 403 | OnHearingClientHook[id].push_back(callback); 404 | } 405 | 406 | bool SendHookOnTakeDamage(int iSlot, CTakeDamageInfoContainer* &pInfoContainer) { 407 | bool bFound = true; 408 | for(auto& item : OnTakeDamageHook) 409 | { 410 | for (auto& callback : item.second) { 411 | if (callback && !callback(iSlot, pInfoContainer)) { 412 | bFound = false; 413 | } 414 | } 415 | } 416 | return bFound; 417 | } 418 | bool SendHookOnTakeDamagePre(int iSlot, CTakeDamageInfo &pInfo) { 419 | bool bFound = true; 420 | for(auto& item : OnTakeDamageHookPre) 421 | { 422 | for (auto& callback : item.second) { 423 | if (callback && !callback(iSlot, pInfo)) { 424 | bFound = false; 425 | } 426 | } 427 | } 428 | return bFound; 429 | } 430 | bool SendHookOnHearingClient(int iSlot) { 431 | bool bFound = true; 432 | for(auto& item : OnHearingClientHook) 433 | { 434 | for (auto& callback : item.second) { 435 | if (callback && !callback(iSlot)) { 436 | bFound = false; 437 | } 438 | } 439 | } 440 | return bFound; 441 | } 442 | 443 | const char* GetVersion(); 444 | private: 445 | std::map> ChatHookPre; 446 | std::map> ChatHookPost; 447 | 448 | std::map> StartupHook; 449 | std::map> GetGameRules; 450 | 451 | std::map> HookEvents; 452 | 453 | std::map> OnTakeDamageHook; 454 | std::map> OnTakeDamageHookPre; 455 | 456 | std::map> OnHearingClientHook; 457 | 458 | std::deque> m_nextFrame; 459 | }; 460 | 461 | class Player 462 | { 463 | public: 464 | Player(int iSlot, bool bFakeClient = false) : m_iSlot(iSlot), m_bFakeClient(bFakeClient) { 465 | m_bAuthenticated = false; 466 | m_bConnected = false; 467 | m_bInGame = false; 468 | m_SteamID = nullptr; 469 | } 470 | bool IsFakeClient() { return m_bFakeClient; } 471 | bool IsAuthenticated() { return m_bAuthenticated; } 472 | bool IsConnected() { return m_bConnected; } 473 | bool IsInGame() { return m_bInGame; } 474 | 475 | const char* GetIpAddress() { return m_strIp.c_str(); } 476 | 477 | uint64 GetUnauthenticatedSteamId64() { return m_UnauthenticatedSteamID->ConvertToUint64(); } 478 | const CSteamID* GetUnauthenticatedSteamId() { return m_UnauthenticatedSteamID; } 479 | 480 | uint64 GetSteamId64() { return m_SteamID?m_SteamID->ConvertToUint64():0; } 481 | const CSteamID* GetSteamId() { return m_SteamID; } 482 | 483 | void SetAuthenticated(bool bAuthenticated) { m_bAuthenticated = bAuthenticated; } 484 | void SetInGame(bool bInGame) { m_bInGame = bInGame; } 485 | void SetConnected() { m_bConnected = true; } 486 | 487 | void SetUnauthenticatedSteamId(const CSteamID* steamID) { m_UnauthenticatedSteamID = steamID; } 488 | 489 | void SetSteamId(const CSteamID* steamID) { m_SteamID = steamID; } 490 | 491 | void SetIpAddress(std::string strIp) { m_strIp = strIp; } 492 | private: 493 | int m_iSlot; 494 | bool m_bFakeClient = false; 495 | bool m_bAuthenticated = false; 496 | bool m_bConnected = false; 497 | bool m_bInGame = false; 498 | std::string m_strIp; 499 | const CSteamID* m_UnauthenticatedSteamID; 500 | const CSteamID* m_SteamID; 501 | }; 502 | 503 | Player* m_Players[64]; 504 | 505 | class PlayersApi : public IPlayersApi 506 | { 507 | public: 508 | bool IsFakeClient(int iSlot) { 509 | if (iSlot < 0 || iSlot >= 64) { 510 | return true; 511 | } 512 | if(m_Players[iSlot] == nullptr) 513 | return true; 514 | else 515 | return m_Players[iSlot]->IsFakeClient(); 516 | } 517 | bool IsAuthenticated(int iSlot) { 518 | if (iSlot < 0 || iSlot >= 64) { 519 | return false; 520 | } 521 | if(m_Players[iSlot] == nullptr) 522 | return false; 523 | else 524 | return m_Players[iSlot]->IsAuthenticated(); 525 | } 526 | bool IsConnected(int iSlot) { 527 | if (iSlot < 0 || iSlot >= 64) { 528 | return false; 529 | } 530 | if(m_Players[iSlot] == nullptr) 531 | return false; 532 | else 533 | return m_Players[iSlot]->IsConnected(); 534 | } 535 | bool IsInGame(int iSlot) { 536 | if (iSlot < 0 || iSlot >= 64) { 537 | return false; 538 | } 539 | if(m_Players[iSlot] == nullptr) 540 | return false; 541 | else 542 | return m_Players[iSlot]->IsInGame(); 543 | } 544 | const char* GetIpAddress(int iSlot) { 545 | if (iSlot < 0 || iSlot >= 64) { 546 | return ""; 547 | } 548 | if(m_Players[iSlot] == nullptr) 549 | return ""; 550 | else 551 | return m_Players[iSlot]->GetIpAddress(); 552 | } 553 | uint64 GetSteamID64(int iSlot) { 554 | if (iSlot < 0 || iSlot >= 64) { 555 | return 0; 556 | } 557 | if(m_Players[iSlot] == nullptr) 558 | return 0; 559 | else 560 | return m_Players[iSlot]->GetSteamId64(); 561 | } 562 | const CSteamID* GetSteamID(int iSlot) { 563 | if (iSlot < 0 || iSlot >= 64) { 564 | return nullptr; 565 | } 566 | if(m_Players[iSlot] == nullptr) 567 | return nullptr; 568 | else 569 | return m_Players[iSlot]->GetSteamId(); 570 | } 571 | 572 | void HookOnClientAuthorized(SourceMM::PluginId id, OnClientAuthorizedCallback callback) override { 573 | m_OnClientAuthorized[id].push_back(callback); 574 | } 575 | 576 | void SendClientAuthCallback(int iSlot, uint64 steamID) { 577 | for(auto& item : m_OnClientAuthorized) 578 | { 579 | for (auto& callback : item.second) { 580 | if (callback) { 581 | callback(iSlot, steamID); 582 | } 583 | } 584 | } 585 | } 586 | 587 | void CommitSuicide(int iSlot, bool bExplode, bool bForce); 588 | void ChangeTeam(int iSlot, int iNewTeam); 589 | void Teleport(int iSlot, const Vector *position, const QAngle *angles, const Vector *velocity); 590 | void Respawn(int iSlot); 591 | void DropWeapon(int iSlot, CBaseEntity* pWeapon, Vector* pVecTarget, Vector* pVelocity); 592 | void SwitchTeam(int iSlot, int iNewTeam); 593 | const char* GetPlayerName(int iSlot); 594 | void SetPlayerName(int iSlot, const char* szName); 595 | void SetMoveType(int iSlot, MoveType_t moveType); 596 | void EmitSound(std::vector vPlayers, CEntityIndex ent, std::string sound_name, int pitch, float volume); 597 | void EmitSound(int iSlot, CEntityIndex ent, std::string sound_name, int pitch, float volume); 598 | void StopSoundEvent(int iSlot, const char* sound_name); 599 | IGameEventListener2* GetLegacyGameEventListener(int iSlot); 600 | int FindPlayer(uint64 iSteamID64); 601 | int FindPlayer(const CSteamID* steamID); 602 | int FindPlayer(const char* szName); 603 | private: 604 | std::map> m_OnClientAuthorized; 605 | }; 606 | 607 | enum MsgDest : int32_t 608 | { 609 | HUD_PRINTNOTIFY = 1, 610 | HUD_PRINTCONSOLE = 2, 611 | HUD_PRINTTALK = 3, 612 | HUD_PRINTCENTER = 4, 613 | HUD_PRINTTALK2 = 5, // Not sure what the difference between this and HUD_PRINTTALK is... 614 | HUD_PRINTALERT = 6 615 | }; 616 | 617 | const std::string colors_text[] = { 618 | "{DEFAULT}", 619 | "{WHITE}", 620 | "{RED}", 621 | "{LIGHTPURPLE}", 622 | "{GREEN}", 623 | "{LIME}", 624 | "{LIGHTGREEN}", 625 | "{DARKRED}", 626 | "{GRAY}", 627 | "{LIGHTOLIVE}", 628 | "{OLIVE}", 629 | "{LIGHTBLUE}", 630 | "{BLUE}", 631 | "{PURPLE}", 632 | "{LIGHTRED}", 633 | "{GRAYBLUE}", 634 | "\\n" 635 | }; 636 | 637 | const std::string colors_hex[] = { 638 | "\x01", 639 | "\x01", 640 | "\x02", 641 | "\x03", 642 | "\x04", 643 | "\x05", 644 | "\x06", 645 | "\x07", 646 | "\x08", 647 | "\x09", 648 | "\x10", 649 | "\x0B", 650 | "\x0C", 651 | "\x0E", 652 | "\x0F", 653 | "\x0A", 654 | "\xe2\x80\xa9" 655 | }; 656 | 657 | #endif //_INCLUDE_METAMOD_SOURCE_STUB_PLUGIN_H_ 658 | --------------------------------------------------------------------------------