├── .gitignore ├── premake5.lua ├── readme.md ├── license.txt ├── azure-pipelines.yml └── source ├── main.cpp └── hackedconvar.h /.gitignore: -------------------------------------------------------------------------------- 1 | /projects/ 2 | -------------------------------------------------------------------------------- /premake5.lua: -------------------------------------------------------------------------------- 1 | PROJECT_GENERATOR_VERSION = 2 2 | 3 | newoption({ 4 | trigger = "gmcommon", 5 | description = "Sets the path to the garrysmod_common (https://github.com/danielga/garrysmod_common) directory", 6 | value = "path to garrysmod_common directory" 7 | }) 8 | 9 | local gmcommon = assert(_OPTIONS.gmcommon or os.getenv("GARRYSMOD_COMMON"), 10 | "you didn't provide a path to your garrysmod_common (https://github.com/danielga/garrysmod_common) directory") 11 | include(gmcommon) 12 | 13 | CreateWorkspace({name = "concommandx"}) 14 | CreateProject({serverside = true}) 15 | IncludeLuaShared() 16 | IncludeSDKCommon() 17 | IncludeSDKTier0() 18 | IncludeSDKTier1() 19 | 20 | CreateProject({serverside = false}) 21 | IncludeLuaShared() 22 | IncludeSDKCommon() 23 | IncludeSDKTier0() 24 | IncludeSDKTier1() 25 | -------------------------------------------------------------------------------- /readme.md: -------------------------------------------------------------------------------- 1 | # gm\_concommandx 2 | 3 | A module for Garry's Mod that provides interfaces to interact with concommands from VALVe's engine. 4 | 5 | ## Compiling 6 | 7 | The only supported compilation platform for this project on Windows is **Visual Studio 2017** on **release** mode. However, it's possible it'll work with *Visual Studio 2015*, *Visual Studio 2019* and *Visual Studio 2022* because of the unified runtime. 8 | 9 | On Linux, everything should work fine as is, on **release** mode. 10 | 11 | For macOS, any **Xcode (using the GCC compiler)** version *MIGHT* work as long as the **Mac OSX 10.7 SDK** is used, on **release** mode. 12 | 13 | These restrictions are not random; they exist because of ABI compatibility reasons. 14 | 15 | If stuff starts erroring or fails to work, be sure to check the correct line endings (`\n` and such) are present in the files for each OS. 16 | 17 | ## Requirements 18 | 19 | This project requires [garrysmod\_common][1], a framework to facilitate the creation of compilations files (Visual Studio, make, XCode, etc). Simply set the environment variable `GARRYSMOD_COMMON` or the premake option `--gmcommon=path` to the path of your local copy of [garrysmod\_common][1]. 20 | 21 | We also use [SourceSDK2013][2]. The links to [SourceSDK2013][2] point to my own fork of VALVe's repo and for good reason: Garry's Mod has lots of backwards incompatible changes to interfaces and it's much smaller, being perfect for automated build systems like Azure Pipelines. 22 | 23 | [1]: https://github.com/danielga/garrysmod_common 24 | [2]: https://github.com/danielga/sourcesdk-minimal 25 | -------------------------------------------------------------------------------- /license.txt: -------------------------------------------------------------------------------- 1 | gm_concommandx 2 | A module for Garry's Mod that provides interfaces to interact with 3 | concommands from VALVe's engine. 4 | ----------------------------------------------------------------------- 5 | Copyright (c) 2015-2022, Daniel Almeida 6 | All rights reserved. 7 | 8 | Redistribution and use in source and binary forms, with or without 9 | modification, are permitted provided that the following conditions 10 | are met: 11 | 12 | 1. Redistributions of source code must retain the above copyright 13 | notice, this list of conditions and the following disclaimer. 14 | 15 | 2. Redistributions in binary form must reproduce the above copyright 16 | notice, this list of conditions and the following disclaimer in the 17 | documentation and/or other materials provided with the distribution. 18 | 19 | 3. Neither the name of the copyright holder nor the names of its 20 | contributors may be used to endorse or promote products derived from 21 | this software without specific prior written permission. 22 | 23 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 24 | "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 25 | LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 26 | A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 27 | HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 28 | SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 29 | LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 30 | DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 31 | THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 32 | (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 33 | OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 34 | -------------------------------------------------------------------------------- /azure-pipelines.yml: -------------------------------------------------------------------------------- 1 | variables: 2 | MODULE_NAME: concommandx 3 | DEPENDENCIES: $(System.DefaultWorkingDirectory)/dependencies 4 | GARRYSMOD_COMMON: $(System.DefaultWorkingDirectory)/dependencies/garrysmod_common 5 | GARRYSMOD_COMMON_BRANCH: master 6 | GARRYSMOD_COMMON_REPOSITORY: https://github.com/danielga/garrysmod_common.git 7 | PROJECT_GENERATOR_VERSION: 2 8 | REPOSITORY_DIR: $(System.DefaultWorkingDirectory) 9 | trigger: 10 | batch: true 11 | branches: 12 | include: 13 | - '*' 14 | tags: 15 | include: 16 | - '*' 17 | paths: 18 | include: 19 | - azure-pipelines.yml 20 | - premake5.lua 21 | - source 22 | jobs: 23 | - job: windows 24 | displayName: Windows 25 | pool: 26 | name: Azure Pipelines 27 | vmImage: windows-2019 28 | timeoutInMinutes: 10 29 | variables: 30 | BOOTSTRAP_URL: https://raw.githubusercontent.com/danielga/garrysmod_common/master/build/bootstrap.ps1 31 | BUILD_SCRIPT: $(System.DefaultWorkingDirectory)/dependencies/garrysmod_common/build/build.ps1 32 | COMPILER_PLATFORM: vs2019 33 | PROJECT_OS: windows 34 | PREMAKE5: $(System.DefaultWorkingDirectory)/dependencies/windows/premake-core/premake5.exe 35 | PREMAKE5_URL: https://github.com/danielga/garrysmod_common/releases/download/premake-build%2F5.0.0-beta1/premake-5.0.0-beta1-windows.zip 36 | steps: 37 | - checkout: self 38 | clean: true 39 | fetchDepth: 1 40 | submodules: recursive 41 | - powershell: 'Invoke-Expression ((New-Object System.Net.WebClient).DownloadString("$env:BOOTSTRAP_URL"))' 42 | displayName: Bootstrap 43 | - powershell: '& "$env:BUILD_SCRIPT"' 44 | displayName: Build 45 | - task: CopyFiles@2 46 | displayName: 'Copy files to $(Build.ArtifactStagingDirectory)' 47 | inputs: 48 | SourceFolder: '$(System.DefaultWorkingDirectory)/projects/windows/vs2019' 49 | Contents: '*/Release/*.dll' 50 | TargetFolder: '$(Build.ArtifactStagingDirectory)' 51 | CleanTargetFolder: true 52 | flattenFolders: true 53 | preserveTimestamp: true 54 | - task: PublishBuildArtifacts@1 55 | displayName: 'Publish build artifacts' 56 | inputs: 57 | ArtifactName: windows 58 | - job: linux 59 | displayName: Linux 60 | pool: 61 | name: Azure Pipelines 62 | vmImage: ubuntu-latest 63 | container: 64 | image: registry.gitlab.steamos.cloud/steamrt/scout/sdk:latest 65 | options: -v /home 66 | timeoutInMinutes: 10 67 | variables: 68 | BOOTSTRAP_URL: https://raw.githubusercontent.com/danielga/garrysmod_common/master/build/bootstrap.sh 69 | BUILD_SCRIPT: $(System.DefaultWorkingDirectory)/dependencies/garrysmod_common/build/build.sh 70 | COMPILER_PLATFORM: gmake 71 | PREMAKE5: $(System.DefaultWorkingDirectory)/dependencies/linux/premake-core/premake5 72 | PROJECT_OS: linux 73 | PREMAKE5_URL: https://github.com/danielga/garrysmod_common/releases/download/premake-build%2F5.0.0-beta1/premake-5.0.0-beta1-linux.tar.gz 74 | CC: gcc-9 75 | CXX: g++-9 76 | AR: gcc-ar-9 77 | NM: gcc-nm-9 78 | RANLIB: gcc-ranlib-9 79 | steps: 80 | - checkout: self 81 | clean: true 82 | fetchDepth: 1 83 | submodules: recursive 84 | - bash: 'curl -s -L "$BOOTSTRAP_URL" | bash' 85 | displayName: Bootstrap 86 | - bash: '$BUILD_SCRIPT' 87 | displayName: Build 88 | - task: CopyFiles@2 89 | displayName: 'Copy files to $(Build.ArtifactStagingDirectory)' 90 | inputs: 91 | SourceFolder: '$(System.DefaultWorkingDirectory)/projects/linux/gmake' 92 | Contents: '*/Release/*.dll' 93 | TargetFolder: '$(Build.ArtifactStagingDirectory)' 94 | CleanTargetFolder: true 95 | flattenFolders: true 96 | preserveTimestamp: true 97 | - task: PublishBuildArtifacts@1 98 | displayName: 'Publish build artifacts' 99 | inputs: 100 | ArtifactName: linux 101 | - job: macosx 102 | displayName: macOS 103 | pool: 104 | name: Azure Pipelines 105 | vmImage: macOS-10.15 106 | timeoutInMinutes: 10 107 | variables: 108 | BOOTSTRAP_URL: https://raw.githubusercontent.com/danielga/garrysmod_common/master/build/bootstrap.sh 109 | BUILD_SCRIPT: $(System.DefaultWorkingDirectory)/dependencies/garrysmod_common/build/build.sh 110 | COMPILER_PLATFORM: gmake 111 | PREMAKE5: $(System.DefaultWorkingDirectory)/dependencies/macosx/premake-core/premake5 112 | PROJECT_OS: macosx 113 | PREMAKE5_URL: https://github.com/danielga/garrysmod_common/releases/download/premake-build%2F5.0.0-beta1/premake-5.0.0-beta1-macosx.tar.gz 114 | MACOSX_SDK_URL: https://github.com/phracker/MacOSX-SDKs/releases/download/10.15/MacOSX10.7.sdk.tar.xz 115 | MACOSX_SDK_DIRECTORY: $(System.DefaultWorkingDirectory)/dependencies/macosx/MacOSX10.7.sdk 116 | SDKROOT: $(System.DefaultWorkingDirectory)/dependencies/macosx/MacOSX10.7.sdk 117 | AR: ar 118 | steps: 119 | - checkout: self 120 | clean: true 121 | fetchDepth: 1 122 | submodules: recursive 123 | - bash: 'curl -s -L "$BOOTSTRAP_URL" | bash' 124 | displayName: Bootstrap 125 | - bash: | 126 | sudo xcode-select -s "/Applications/Xcode_11.4.1.app/Contents/Developer" 127 | $BUILD_SCRIPT 128 | displayName: Build 129 | - task: CopyFiles@2 130 | displayName: 'Copy files to $(Build.ArtifactStagingDirectory)' 131 | inputs: 132 | SourceFolder: '$(System.DefaultWorkingDirectory)/projects/macosx/gmake' 133 | Contents: '*/Release/*.dll' 134 | TargetFolder: '$(Build.ArtifactStagingDirectory)' 135 | CleanTargetFolder: true 136 | flattenFolders: true 137 | preserveTimestamp: true 138 | - task: PublishBuildArtifacts@1 139 | displayName: 'Publish build artifacts' 140 | inputs: 141 | ArtifactName: macosx 142 | - job: publish 143 | displayName: Publish to GitHub Releases 144 | pool: 145 | name: Azure Pipelines 146 | vmImage: ubuntu-latest 147 | timeoutInMinutes: 5 148 | dependsOn: 149 | - windows 150 | - linux 151 | - macosx 152 | condition: and(succeeded(), startsWith(variables['Build.SourceBranch'], 'refs/tags/')) 153 | steps: 154 | - task: DownloadBuildArtifacts@0 155 | displayName: 'Download build artifacts' 156 | inputs: 157 | downloadType: specific 158 | parallelizationLimit: 12 159 | - task: GitHubRelease@1 160 | displayName: 'Publish GitHub release $(build.sourceBranchName)' 161 | inputs: 162 | gitHubConnection: 'GitHub danielga' 163 | releaseNotesSource: inline 164 | assets: '$(System.ArtifactsDirectory)/**' 165 | addChangeLog: false 166 | -------------------------------------------------------------------------------- /source/main.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | 7 | #if defined CONCOMMANDX_SERVER 8 | 9 | #include 10 | 11 | #elif defined CONCOMMANDX_CLIENT 12 | 13 | #include 14 | 15 | #endif 16 | 17 | namespace global 18 | { 19 | 20 | static SourceSDK::FactoryLoader icvar_loader( "vstdlib", true, IS_SERVERSIDE, "bin/" ); 21 | static SourceSDK::FactoryLoader engine_loader( "engine", false, IS_SERVERSIDE, "bin/" ); 22 | 23 | #if defined CONCOMMANDX_SERVER 24 | 25 | static const char *ivengine_name = "VEngineServer021"; 26 | 27 | typedef IVEngineServer IVEngine; 28 | 29 | #elif defined CONCOMMANDX_CLIENT 30 | 31 | static const char *ivengine_name = "VEngineClient015"; 32 | 33 | typedef IVEngineClient IVEngine; 34 | 35 | #endif 36 | 37 | static ICvar *icvar = nullptr; 38 | static IVEngine *ivengine = nullptr; 39 | 40 | static void Initialize( GarrysMod::Lua::ILuaBase *LUA ) 41 | { 42 | icvar = icvar_loader.GetInterface( CVAR_INTERFACE_VERSION ); 43 | if( icvar == nullptr ) 44 | LUA->ThrowError( "ICVar not initialized. Critical error." ); 45 | 46 | ivengine = engine_loader.GetInterface( ivengine_name ); 47 | if( ivengine == nullptr ) 48 | LUA->ThrowError( "IVEngineServer/Client not initialized. Critical error." ); 49 | } 50 | 51 | } 52 | 53 | namespace concommand 54 | { 55 | 56 | struct Container 57 | { 58 | ConCommand *cmd; 59 | const char *name_original; 60 | char name[64]; 61 | const char *help_original; 62 | char help[256]; 63 | }; 64 | 65 | static const char *metaname = "concommand"; 66 | static int32_t metatype = -1; 67 | static const char *invalid_error = "invalid concommand"; 68 | static const char *table_name = "concommands_objects"; 69 | 70 | inline void CheckType( GarrysMod::Lua::ILuaBase *LUA, int32_t index ) 71 | { 72 | if( !LUA->IsType( index, metatype ) ) 73 | LUA->TypeError( index, metaname ); 74 | } 75 | 76 | inline Container *GetUserdata( GarrysMod::Lua::ILuaBase *LUA, int32_t index ) 77 | { 78 | return LUA->GetUserType( index, metatype ); 79 | } 80 | 81 | static ConCommand *Get( GarrysMod::Lua::ILuaBase *LUA, int32_t index ) 82 | { 83 | CheckType( LUA, index ); 84 | ConCommand *command = LUA->GetUserType( index, metatype )->cmd; 85 | if( command == nullptr ) 86 | LUA->ArgError( index, invalid_error ); 87 | 88 | return command; 89 | } 90 | 91 | inline void Push( GarrysMod::Lua::ILuaBase *LUA, ConCommand *command ) 92 | { 93 | if( command == nullptr ) 94 | { 95 | LUA->PushNil( ); 96 | return; 97 | } 98 | 99 | LUA->GetField( GarrysMod::Lua::INDEX_REGISTRY, table_name ); 100 | LUA->PushUserdata( command ); 101 | LUA->GetTable( -2 ); 102 | if( LUA->IsType( -1, metatype ) ) 103 | { 104 | LUA->Remove( -2 ); 105 | return; 106 | } 107 | 108 | LUA->Pop( 1 ); 109 | 110 | Container *udata = LUA->NewUserType( metatype ); 111 | udata->cmd = command; 112 | udata->name_original = command->m_pszName; 113 | udata->help_original = command->m_pszHelpString; 114 | 115 | LUA->PushMetaTable( metatype ); 116 | LUA->SetMetaTable( -2 ); 117 | 118 | LUA->CreateTable( ); 119 | LUA->SetFEnv( -2 ); 120 | 121 | LUA->PushUserdata( command ); 122 | LUA->Push( -2 ); 123 | LUA->SetTable( -4 ); 124 | LUA->Remove( -2 ); 125 | } 126 | 127 | inline ConCommand *Destroy( GarrysMod::Lua::ILuaBase *LUA, int32_t index ) 128 | { 129 | Container *udata = GetUserdata( LUA, 1 ); 130 | ConCommand *command = udata->cmd; 131 | if( command == nullptr ) 132 | return nullptr; 133 | 134 | LUA->GetField( GarrysMod::Lua::INDEX_REGISTRY, table_name ); 135 | LUA->PushUserdata( command ); 136 | LUA->PushNil( ); 137 | LUA->SetTable( -3 ); 138 | LUA->Pop( 1 ); 139 | 140 | command->m_pszName = udata->name_original; 141 | command->m_pszHelpString = udata->help_original; 142 | udata->cmd = nullptr; 143 | 144 | return command; 145 | } 146 | 147 | LUA_FUNCTION_STATIC( gc ) 148 | { 149 | if( !LUA->IsType( 1, metatype ) ) 150 | return 0; 151 | 152 | Destroy( LUA, 1 ); 153 | return 0; 154 | } 155 | 156 | LUA_FUNCTION_STATIC( eq ) 157 | { 158 | LUA->PushBool( Get( LUA, 1 ) == Get( LUA, 2 ) ); 159 | return 1; 160 | } 161 | 162 | LUA_FUNCTION_STATIC( tostring ) 163 | { 164 | LUA->PushFormattedString( "%s: %p", metaname, Get( LUA, 1 ) ); 165 | return 1; 166 | } 167 | 168 | LUA_FUNCTION_STATIC( index ) 169 | { 170 | LUA->GetMetaTable( 1 ); 171 | LUA->Push( 2 ); 172 | LUA->RawGet( -2 ); 173 | if( !LUA->IsType( -1, GarrysMod::Lua::Type::NIL ) ) 174 | return 1; 175 | 176 | LUA->Pop( 2 ); 177 | 178 | LUA->GetFEnv( 1 ); 179 | LUA->Push( 2 ); 180 | LUA->RawGet( -2 ); 181 | return 1; 182 | } 183 | 184 | LUA_FUNCTION_STATIC( newindex ) 185 | { 186 | LUA->GetFEnv( 1 ); 187 | LUA->Push( 2 ); 188 | LUA->Push( 3 ); 189 | LUA->RawSet( -3 ); 190 | return 0; 191 | } 192 | 193 | LUA_FUNCTION_STATIC( GetName ) 194 | { 195 | LUA->PushString( Get( LUA, 1 )->GetName( ) ); 196 | return 1; 197 | } 198 | 199 | LUA_FUNCTION_STATIC( SetName ) 200 | { 201 | Container *udata = GetUserdata( LUA, 1 ); 202 | ConCommand *command = udata->cmd; 203 | if( command == nullptr ) 204 | LUA->ThrowError( invalid_error ); 205 | 206 | V_strncpy( udata->name, LUA->CheckString( 2 ), sizeof( udata->name ) ); 207 | command->m_pszName = udata->name; 208 | 209 | return 0; 210 | } 211 | 212 | LUA_FUNCTION_STATIC( SetFlags ) 213 | { 214 | Get( LUA, 1 )->m_nFlags = static_cast( LUA->CheckNumber( 2 ) ); 215 | return 0; 216 | } 217 | 218 | LUA_FUNCTION_STATIC( GetFlags ) 219 | { 220 | LUA->PushNumber( Get( LUA, 1 )->m_nFlags ); 221 | return 1; 222 | } 223 | 224 | LUA_FUNCTION_STATIC( HasFlag ) 225 | { 226 | LUA->Push( Get( LUA, 1 )->IsFlagSet( static_cast( LUA->CheckNumber( 2 ) ) ) ); 227 | return 1; 228 | } 229 | 230 | LUA_FUNCTION_STATIC( SetHelpText ) 231 | { 232 | Container *udata = GetUserdata( LUA, 1 ); 233 | ConCommand *command = udata->cmd; 234 | if( command == nullptr ) 235 | LUA->ThrowError( invalid_error ); 236 | 237 | V_strncpy( udata->help, LUA->CheckString( 2 ), sizeof( udata->help ) ); 238 | command->m_pszHelpString = udata->help; 239 | 240 | return 0; 241 | } 242 | 243 | LUA_FUNCTION_STATIC( GetHelpText ) 244 | { 245 | LUA->PushString( Get( LUA, 1 )->GetHelpText( ) ); 246 | return 1; 247 | } 248 | 249 | LUA_FUNCTION_STATIC( Remove ) 250 | { 251 | CheckType( LUA, 1 ); 252 | global::icvar->UnregisterConCommand( Destroy( LUA, 1 ) ); 253 | return 0; 254 | } 255 | 256 | static void Initialize( GarrysMod::Lua::ILuaBase *LUA ) 257 | { 258 | LUA->CreateTable( ); 259 | LUA->SetField( GarrysMod::Lua::INDEX_REGISTRY, table_name ); 260 | 261 | metatype = LUA->CreateMetaTable( metaname ); 262 | 263 | LUA->PushCFunction( gc ); 264 | LUA->SetField( -2, "__gc" ); 265 | 266 | LUA->PushCFunction( tostring ); 267 | LUA->SetField( -2, "__tostring" ); 268 | 269 | LUA->PushCFunction( eq ); 270 | LUA->SetField( -2, "__eq" ); 271 | 272 | LUA->PushCFunction( index ); 273 | LUA->SetField( -2, "__index" ); 274 | 275 | LUA->PushCFunction( newindex ); 276 | LUA->SetField( -2, "__newindex" ); 277 | 278 | LUA->PushCFunction( GetName ); 279 | LUA->SetField( -2, "GetName" ); 280 | 281 | LUA->PushCFunction( SetName ); 282 | LUA->SetField( -2, "SetName" ); 283 | 284 | LUA->PushCFunction( SetFlags ); 285 | LUA->SetField( -2, "SetFlags" ); 286 | 287 | LUA->PushCFunction( GetFlags ); 288 | LUA->SetField( -2, "GetFlags" ); 289 | 290 | LUA->PushCFunction( HasFlag ); 291 | LUA->SetField( -2, "HasFlag" ); 292 | 293 | LUA->PushCFunction( SetHelpText ); 294 | LUA->SetField( -2, "SetHelpText" ); 295 | 296 | LUA->PushCFunction( GetHelpText ); 297 | LUA->SetField( -2, "GetHelpText" ); 298 | 299 | LUA->PushCFunction( Remove ); 300 | LUA->SetField( -2, "Remove" ); 301 | 302 | LUA->Pop( 1 ); 303 | } 304 | 305 | static void Deinitialize( GarrysMod::Lua::ILuaBase *LUA ) 306 | { 307 | LUA->PushNil( ); 308 | LUA->SetField( GarrysMod::Lua::INDEX_REGISTRY, metaname ); 309 | 310 | LUA->PushNil( ); 311 | LUA->SetField( GarrysMod::Lua::INDEX_REGISTRY, table_name ); 312 | } 313 | 314 | } 315 | 316 | namespace concommands 317 | { 318 | 319 | LUA_FUNCTION_STATIC( Exists ) 320 | { 321 | LUA->CheckType( 1, GarrysMod::Lua::Type::STRING ); 322 | 323 | ConCommand *command = global::icvar->FindCommand( LUA->GetString( 1 ) ); 324 | if( command == nullptr ) 325 | LUA->PushBool( false ); 326 | else 327 | LUA->PushBool( command->IsCommand( ) ); 328 | 329 | return 1; 330 | } 331 | 332 | LUA_FUNCTION_STATIC( GetAll ) 333 | { 334 | LUA->CreateTable( ); 335 | 336 | size_t i = 0; 337 | ICvar::Iterator iter( global::icvar ); 338 | for( iter.SetFirst( ); iter.IsValid( ); iter.Next( ) ) 339 | { 340 | ConCommand *cmd = static_cast( iter.Get( ) ); 341 | if( cmd->IsCommand( ) ) 342 | { 343 | concommand::Push( LUA, cmd ); 344 | LUA->PushNumber( ++i ); 345 | LUA->SetTable( -3 ); 346 | } 347 | } 348 | 349 | return 1; 350 | } 351 | 352 | LUA_FUNCTION_STATIC( Get ) 353 | { 354 | concommand::Push( LUA, global::icvar->FindCommand( LUA->CheckString( 1 ) ) ); 355 | return 1; 356 | } 357 | 358 | #if defined CONCOMMANDX_SERVER 359 | 360 | LUA_FUNCTION_STATIC( Execute ) 361 | { 362 | global::ivengine->ServerCommand( LUA->CheckString( 1 ) ); 363 | return 0; 364 | } 365 | 366 | #elif defined CONCOMMANDX_CLIENT 367 | 368 | LUA_FUNCTION_STATIC( Execute ) 369 | { 370 | if( LUA->IsType( 2, GarrysMod::Lua::Type::BOOL ) && LUA->GetBool( 2 ) ) 371 | global::ivengine->ClientCmd_Unrestricted( LUA->CheckString( 1 ) ); 372 | else 373 | global::ivengine->ClientCmd( LUA->CheckString( 1 ) ); 374 | 375 | return 0; 376 | } 377 | 378 | LUA_FUNCTION_STATIC( ExecuteOnServer ) 379 | { 380 | global::ivengine->ServerCmd( LUA->CheckString( 1 ) ); 381 | return 0; 382 | } 383 | 384 | #endif 385 | 386 | static void Initialize( GarrysMod::Lua::ILuaBase *LUA ) 387 | { 388 | LUA->GetField( GarrysMod::Lua::INDEX_GLOBAL, "concommand" ); 389 | 390 | LUA->PushCFunction( Exists ); 391 | LUA->SetField( -2, "Exists" ); 392 | 393 | LUA->PushCFunction( GetAll ); 394 | LUA->SetField( -2, "GetAll" ); 395 | 396 | LUA->PushCFunction( Get ); 397 | LUA->SetField( -2, "Get" ); 398 | 399 | LUA->PushCFunction( Execute ); 400 | LUA->SetField( -2, "Execute" ); 401 | 402 | #if defined CONCOMMANDX_CLIENT 403 | 404 | LUA->PushCFunction( ExecuteOnServer ); 405 | LUA->SetField( -2, "ExecuteOnServer" ); 406 | 407 | #endif 408 | 409 | LUA->Pop( 1 ); 410 | } 411 | 412 | static void Deinitialize( GarrysMod::Lua::ILuaBase *LUA ) 413 | { 414 | LUA->GetField( GarrysMod::Lua::INDEX_GLOBAL, "concommand" ); 415 | 416 | LUA->PushNil( ); 417 | LUA->SetField( -2, "Exists" ); 418 | 419 | LUA->PushNil( ); 420 | LUA->SetField( -2, "GetAll" ); 421 | 422 | LUA->PushNil( ); 423 | LUA->SetField( -2, "Get" ); 424 | 425 | LUA->PushNil( ); 426 | LUA->SetField( -2, "Execute" ); 427 | 428 | #if defined CONCOMMANDX_CLIENT 429 | 430 | LUA->PushNil( ); 431 | LUA->SetField( -2, "ExecuteOnServer" ); 432 | 433 | #endif 434 | 435 | LUA->Pop( 1 ); 436 | } 437 | 438 | } 439 | 440 | #if defined CONCOMMANDX_SERVER 441 | 442 | namespace Player 443 | { 444 | 445 | static const char *invalid_error = "Player object is not valid"; 446 | 447 | inline int32_t GetEntityIndex( GarrysMod::Lua::ILuaBase *LUA, int32_t i ) 448 | { 449 | LUA->Push( i ); 450 | LUA->GetField( -1, "EntIndex" ); 451 | LUA->Push( -2 ); 452 | LUA->Call( 1, 1 ); 453 | 454 | return static_cast( LUA->GetNumber( -1 ) ); 455 | } 456 | 457 | LUA_FUNCTION_STATIC( Command ) 458 | { 459 | LUA->CheckType( 1, GarrysMod::Lua::Type::ENTITY ); 460 | LUA->CheckType( 2, GarrysMod::Lua::Type::STRING ); 461 | 462 | edict_t *edict = global::ivengine->PEntityOfEntIndex( GetEntityIndex( LUA, 1 ) ); 463 | if( edict == nullptr ) 464 | LUA->ThrowError( invalid_error ); 465 | 466 | global::ivengine->ClientCommand( edict, "%s", LUA->GetString( 2 ) ); 467 | return 0; 468 | } 469 | 470 | static void Initialize( GarrysMod::Lua::ILuaBase *LUA ) 471 | { 472 | LUA->GetField( GarrysMod::Lua::INDEX_REGISTRY, "Player" ); 473 | 474 | LUA->PushCFunction( Command ); 475 | LUA->SetField( -2, "Command" ); 476 | 477 | LUA->Pop( 1 ); 478 | } 479 | 480 | static void Deinitialize( GarrysMod::Lua::ILuaBase *LUA ) 481 | { 482 | LUA->GetField( GarrysMod::Lua::INDEX_REGISTRY, "Player" ); 483 | 484 | LUA->PushNil( ); 485 | LUA->SetField( -2, "Command" ); 486 | 487 | LUA->Pop( 1 ); 488 | } 489 | 490 | } 491 | 492 | #endif 493 | 494 | GMOD_MODULE_OPEN( ) 495 | { 496 | global::Initialize( LUA ); 497 | concommands::Initialize( LUA ); 498 | concommand::Initialize( LUA ); 499 | 500 | #if defined CONCOMMANDX_SERVER 501 | 502 | Player::Initialize( LUA ); 503 | 504 | #endif 505 | 506 | return 0; 507 | } 508 | 509 | GMOD_MODULE_CLOSE( ) 510 | { 511 | 512 | #if defined CONCOMMANDX_SERVER 513 | 514 | Player::Deinitialize( LUA ); 515 | 516 | #endif 517 | 518 | concommands::Deinitialize( LUA ); 519 | concommand::Deinitialize( LUA ); 520 | return 0; 521 | } 522 | -------------------------------------------------------------------------------- /source/hackedconvar.h: -------------------------------------------------------------------------------- 1 | //========= Copyright Valve Corporation, All rights reserved. ============// 2 | // 3 | // Purpose: 4 | // 5 | // $Workfile: $ 6 | // $Date: $ 7 | // 8 | //----------------------------------------------------------------------------- 9 | // $NoKeywords: $ 10 | //===========================================================================// 11 | 12 | #ifndef CONVAR_H 13 | #define CONVAR_H 14 | 15 | #if _WIN32 16 | #pragma once 17 | #endif 18 | 19 | #include "tier0/dbg.h" 20 | #include "tier1/iconvar.h" 21 | #include "tier1/utlvector.h" 22 | #include "tier1/utlstring.h" 23 | #include "icvar.h" 24 | 25 | #ifdef _WIN32 26 | #define FORCEINLINE_CVAR FORCEINLINE 27 | #elif POSIX 28 | #define FORCEINLINE_CVAR inline 29 | #else 30 | #error "implement me" 31 | #endif 32 | 33 | 34 | //----------------------------------------------------------------------------- 35 | // Forward declarations 36 | //----------------------------------------------------------------------------- 37 | class ConVar; 38 | class CCommand; 39 | class ConCommand; 40 | class ConCommandBase; 41 | struct characterset_t; 42 | 43 | 44 | 45 | //----------------------------------------------------------------------------- 46 | // Any executable that wants to use ConVars need to implement one of 47 | // these to hook up access to console variables. 48 | //----------------------------------------------------------------------------- 49 | class IConCommandBaseAccessor 50 | { 51 | public: 52 | // Flags is a combination of FCVAR flags in cvar.h. 53 | // hOut is filled in with a handle to the variable. 54 | virtual bool RegisterConCommandBase( ConCommandBase *pVar ) = 0; 55 | }; 56 | 57 | 58 | //----------------------------------------------------------------------------- 59 | // Helper method for console development 60 | //----------------------------------------------------------------------------- 61 | #if defined( _X360 ) && !defined( _RETAIL ) 62 | void ConVar_PublishToVXConsole(); 63 | #endif 64 | 65 | 66 | //----------------------------------------------------------------------------- 67 | // Called when a ConCommand needs to execute 68 | //----------------------------------------------------------------------------- 69 | typedef void ( *FnCommandCallbackV1_t )( void ); 70 | typedef void ( *FnCommandCallback_t )( const CCommand &command ); 71 | 72 | #define COMMAND_COMPLETION_MAXITEMS 64 73 | #define COMMAND_COMPLETION_ITEM_LENGTH 64 74 | 75 | //----------------------------------------------------------------------------- 76 | // Returns 0 to COMMAND_COMPLETION_MAXITEMS worth of completion strings 77 | //----------------------------------------------------------------------------- 78 | typedef int ( *FnCommandCompletionCallback )( const char *partial, char commands[ COMMAND_COMPLETION_MAXITEMS ][ COMMAND_COMPLETION_ITEM_LENGTH ] ); 79 | 80 | 81 | //----------------------------------------------------------------------------- 82 | // Interface version 83 | //----------------------------------------------------------------------------- 84 | class ICommandCallback 85 | { 86 | public: 87 | virtual void CommandCallback( const CCommand &command ) = 0; 88 | }; 89 | 90 | class ICommandCompletionCallback 91 | { 92 | public: 93 | virtual int CommandCompletionCallback( const char *pPartial, CUtlVector< CUtlString > &commands ) = 0; 94 | }; 95 | 96 | //----------------------------------------------------------------------------- 97 | // Purpose: The base console invoked command/cvar interface 98 | //----------------------------------------------------------------------------- 99 | class ConCommandBase 100 | { 101 | friend class CCvar; 102 | friend class ConVar; 103 | friend class ConCommand; 104 | friend void ConVar_Register( int nCVarFlag, IConCommandBaseAccessor *pAccessor ); 105 | friend void ConVar_PublishToVXConsole(); 106 | 107 | // FIXME: Remove when ConVar changes are done 108 | friend class CDefaultCvar; 109 | 110 | public: 111 | ConCommandBase( void ); 112 | ConCommandBase( const char *pName, const char *pHelpString = 0, 113 | int flags = 0 ); 114 | 115 | virtual ~ConCommandBase( void ); 116 | 117 | virtual bool IsCommand( void ) const; 118 | 119 | // Check flag 120 | virtual bool IsFlagSet( int flag ) const; 121 | // Set flag 122 | virtual void AddFlags( int flags ); 123 | 124 | // Return name of cvar 125 | virtual const char *GetName( void ) const; 126 | 127 | // Return help text for cvar 128 | virtual const char *GetHelpText( void ) const; 129 | 130 | // Deal with next pointer 131 | const ConCommandBase *GetNext( void ) const; 132 | ConCommandBase *GetNext( void ); 133 | 134 | virtual bool IsRegistered( void ) const; 135 | 136 | // Returns the DLL identifier 137 | virtual CVarDLLIdentifier_t GetDLLIdentifier() const; 138 | 139 | protected: 140 | virtual void Create( const char *pName, const char *pHelpString = 0, 141 | int flags = 0 ); 142 | 143 | // Used internally by OneTimeInit to initialize/shutdown 144 | virtual void Init(); 145 | void Shutdown(); 146 | 147 | // Internal copy routine ( uses new operator from correct module ) 148 | char *CopyString( const char *from ); 149 | 150 | public: 151 | // Next ConVar in chain 152 | // Prior to register, it points to the next convar in the DLL. 153 | // Once registered, though, m_pNext is reset to point to the next 154 | // convar in the global list 155 | ConCommandBase *m_pNext; 156 | 157 | // Has the cvar been added to the global list? 158 | bool m_bRegistered; 159 | 160 | // Static data 161 | const char *m_pszName; 162 | const char *m_pszHelpString; 163 | 164 | // ConVar flags 165 | int m_nFlags; 166 | 167 | protected: 168 | // ConVars add themselves to this list for the executable. 169 | // Then ConVar_Register runs through all the console variables 170 | // and registers them into a global list stored in vstdlib.dll 171 | static ConCommandBase *s_pConCommandBases; 172 | 173 | // ConVars in this executable use this 'global' to access values. 174 | static IConCommandBaseAccessor *s_pAccessor; 175 | }; 176 | 177 | 178 | //----------------------------------------------------------------------------- 179 | // Command tokenizer 180 | //----------------------------------------------------------------------------- 181 | class CCommand 182 | { 183 | public: 184 | CCommand(); 185 | CCommand( int nArgC, const char **ppArgV ); 186 | bool Tokenize( const char *pCommand, characterset_t *pBreakSet = NULL ); 187 | void Reset(); 188 | 189 | int ArgC() const; 190 | const char **ArgV() const; 191 | const char *ArgS() const; // All args that occur after the 0th arg, in string form 192 | const char *GetCommandString() const; // The entire command in string form, including the 0th arg 193 | const char *operator[]( int nIndex ) const; // Gets at arguments 194 | const char *Arg( int nIndex ) const; // Gets at arguments 195 | 196 | // Helper functions to parse arguments to commands. 197 | const char* FindArg( const char *pName ) const; 198 | int FindArgInt( const char *pName, int nDefaultVal ) const; 199 | 200 | static int MaxCommandLength(); 201 | static characterset_t* DefaultBreakSet(); 202 | 203 | private: 204 | enum 205 | { 206 | COMMAND_MAX_ARGC = 64, 207 | COMMAND_MAX_LENGTH = 512, 208 | }; 209 | 210 | int m_nArgc; 211 | int m_nArgv0Size; 212 | char m_pArgSBuffer[ COMMAND_MAX_LENGTH ]; 213 | char m_pArgvBuffer[ COMMAND_MAX_LENGTH ]; 214 | const char* m_ppArgv[ COMMAND_MAX_ARGC ]; 215 | }; 216 | 217 | inline int CCommand::MaxCommandLength() 218 | { 219 | return COMMAND_MAX_LENGTH - 1; 220 | } 221 | 222 | inline int CCommand::ArgC() const 223 | { 224 | return m_nArgc; 225 | } 226 | 227 | inline const char **CCommand::ArgV() const 228 | { 229 | return m_nArgc ? (const char**)m_ppArgv : NULL; 230 | } 231 | 232 | inline const char *CCommand::ArgS() const 233 | { 234 | return m_nArgv0Size ? &m_pArgSBuffer[m_nArgv0Size] : ""; 235 | } 236 | 237 | inline const char *CCommand::GetCommandString() const 238 | { 239 | return m_nArgc ? m_pArgSBuffer : ""; 240 | } 241 | 242 | inline const char *CCommand::Arg( int nIndex ) const 243 | { 244 | // FIXME: Many command handlers appear to not be particularly careful 245 | // about checking for valid argc range. For now, we're going to 246 | // do the extra check and return an empty string if it's out of range 247 | if ( nIndex < 0 || nIndex >= m_nArgc ) 248 | return ""; 249 | return m_ppArgv[nIndex]; 250 | } 251 | 252 | inline const char *CCommand::operator[]( int nIndex ) const 253 | { 254 | return Arg( nIndex ); 255 | } 256 | 257 | 258 | //----------------------------------------------------------------------------- 259 | // Purpose: The console invoked command 260 | //----------------------------------------------------------------------------- 261 | class ConCommand : public ConCommandBase 262 | { 263 | friend class CCvar; 264 | 265 | public: 266 | typedef ConCommandBase BaseClass; 267 | 268 | ConCommand( const char *pName, FnCommandCallbackV1_t callback, 269 | const char *pHelpString = 0, int flags = 0, FnCommandCompletionCallback completionFunc = 0 ); 270 | ConCommand( const char *pName, FnCommandCallback_t callback, 271 | const char *pHelpString = 0, int flags = 0, FnCommandCompletionCallback completionFunc = 0 ); 272 | ConCommand( const char *pName, ICommandCallback *pCallback, 273 | const char *pHelpString = 0, int flags = 0, ICommandCompletionCallback *pCommandCompletionCallback = 0 ); 274 | 275 | virtual ~ConCommand( void ); 276 | 277 | virtual bool IsCommand( void ) const; 278 | 279 | virtual int AutoCompleteSuggest( const char *partial, CUtlVector< CUtlString > &commands ); 280 | 281 | virtual bool CanAutoComplete( void ); 282 | 283 | // Invoke the function 284 | virtual void Dispatch( const CCommand &command ); 285 | 286 | private: 287 | // NOTE: To maintain backward compat, we have to be very careful: 288 | // All public virtual methods must appear in the same order always 289 | // since engine code will be calling into this code, which *does not match* 290 | // in the mod code; it's using slightly different, but compatible versions 291 | // of this class. Also: Be very careful about adding new fields to this class. 292 | // Those fields will not exist in the version of this class that is instanced 293 | // in mod code. 294 | 295 | // Call this function when executing the command 296 | union 297 | { 298 | FnCommandCallbackV1_t m_fnCommandCallbackV1; 299 | FnCommandCallback_t m_fnCommandCallback; 300 | ICommandCallback *m_pCommandCallback; 301 | }; 302 | 303 | union 304 | { 305 | FnCommandCompletionCallback m_fnCompletionCallback; 306 | ICommandCompletionCallback *m_pCommandCompletionCallback; 307 | }; 308 | 309 | bool m_bHasCompletionCallback : 1; 310 | bool m_bUsingNewCommandCallback : 1; 311 | bool m_bUsingCommandCallbackInterface : 1; 312 | }; 313 | 314 | 315 | //----------------------------------------------------------------------------- 316 | // Purpose: A console variable 317 | //----------------------------------------------------------------------------- 318 | class ConVar : public ConCommandBase, public IConVar 319 | { 320 | friend class CCvar; 321 | friend class ConVarRef; 322 | 323 | public: 324 | typedef ConCommandBase BaseClass; 325 | 326 | ConVar( const char *pName, const char *pDefaultValue, int flags = 0); 327 | 328 | ConVar( const char *pName, const char *pDefaultValue, int flags, 329 | const char *pHelpString ); 330 | ConVar( const char *pName, const char *pDefaultValue, int flags, 331 | const char *pHelpString, bool bMin, float fMin, bool bMax, float fMax ); 332 | ConVar( const char *pName, const char *pDefaultValue, int flags, 333 | const char *pHelpString, FnChangeCallback_t callback ); 334 | ConVar( const char *pName, const char *pDefaultValue, int flags, 335 | const char *pHelpString, bool bMin, float fMin, bool bMax, float fMax, 336 | FnChangeCallback_t callback ); 337 | 338 | virtual ~ConVar( void ); 339 | 340 | virtual bool IsFlagSet( int flag ) const; 341 | virtual const char* GetHelpText( void ) const; 342 | virtual bool IsRegistered( void ) const; 343 | virtual const char *GetName( void ) const; 344 | virtual void AddFlags( int flags ); 345 | virtual bool IsCommand( void ) const; 346 | 347 | // Install a change callback (there shouldn't already be one....) 348 | void InstallChangeCallback( FnChangeCallback_t callback ); 349 | 350 | // Retrieve value 351 | FORCEINLINE_CVAR float GetFloat( void ) const; 352 | FORCEINLINE_CVAR int GetInt( void ) const; 353 | FORCEINLINE_CVAR bool GetBool() const { return !!GetInt(); } 354 | FORCEINLINE_CVAR char const *GetString( void ) const; 355 | 356 | // Any function that allocates/frees memory needs to be virtual or else you'll have crashes 357 | // from alloc/free across dll/exe boundaries. 358 | 359 | // These just call into the IConCommandBaseAccessor to check flags and set the var (which ends up calling InternalSetValue). 360 | virtual void SetValue( const char *value ); 361 | virtual void SetValue( float value ); 362 | virtual void SetValue( int value ); 363 | 364 | // Reset to default value 365 | void Revert( void ); 366 | 367 | // True if it has a min/max setting 368 | bool GetMin( float& minVal ) const; 369 | bool GetMax( float& maxVal ) const; 370 | const char *GetDefault( void ) const; 371 | void SetDefault( const char *pszDefault ); 372 | 373 | private: 374 | // Called by CCvar when the value of a var is changing. 375 | virtual void InternalSetValue(const char *value); 376 | // For CVARs marked FCVAR_NEVER_AS_STRING 377 | virtual void InternalSetFloatValue( float fNewValue ); 378 | virtual void InternalSetIntValue( int nValue ); 379 | 380 | virtual bool ClampValue( float& value ); 381 | virtual void ChangeStringValue( const char *tempVal, float flOldValue ); 382 | 383 | virtual void Create( const char *pName, const char *pDefaultValue, int flags = 0, 384 | const char *pHelpString = 0, bool bMin = false, float fMin = 0.0, 385 | bool bMax = false, float fMax = false, FnChangeCallback_t callback = 0 ); 386 | 387 | // Used internally by OneTimeInit to initialize. 388 | virtual void Init(); 389 | int GetFlags() { return m_pParent->m_nFlags; } 390 | public: 391 | 392 | // This either points to "this" or it points to the original declaration of a ConVar. 393 | // This allows ConVars to exist in separate modules, and they all use the first one to be declared. 394 | // m_pParent->m_pParent must equal m_pParent (ie: m_pParent must be the root, or original, ConVar). 395 | ConVar *m_pParent; 396 | 397 | // Static data 398 | const char *m_pszDefaultValue; 399 | 400 | // Value 401 | // Dynamically allocated 402 | char *m_pszString; 403 | int m_StringLength; 404 | 405 | // Values 406 | float m_fValue; 407 | int m_nValue; 408 | 409 | // Min/Max values 410 | bool m_bHasMin; 411 | float m_fMinVal; 412 | bool m_bHasMax; 413 | float m_fMaxVal; 414 | 415 | // Call this function when ConVar changes 416 | FnChangeCallback_t m_fnChangeCallback; 417 | }; 418 | 419 | 420 | //----------------------------------------------------------------------------- 421 | // Purpose: Return ConVar value as a float 422 | // Output : float 423 | //----------------------------------------------------------------------------- 424 | FORCEINLINE_CVAR float ConVar::GetFloat( void ) const 425 | { 426 | return m_pParent->m_fValue; 427 | } 428 | 429 | //----------------------------------------------------------------------------- 430 | // Purpose: Return ConVar value as an int 431 | // Output : int 432 | //----------------------------------------------------------------------------- 433 | FORCEINLINE_CVAR int ConVar::GetInt( void ) const 434 | { 435 | return m_pParent->m_nValue; 436 | } 437 | 438 | 439 | //----------------------------------------------------------------------------- 440 | // Purpose: Return ConVar value as a string, return "" for bogus string pointer, etc. 441 | // Output : const char * 442 | //----------------------------------------------------------------------------- 443 | FORCEINLINE_CVAR const char *ConVar::GetString( void ) const 444 | { 445 | if ( m_nFlags & FCVAR_NEVER_AS_STRING ) 446 | return "FCVAR_NEVER_AS_STRING"; 447 | 448 | return ( m_pParent->m_pszString ) ? m_pParent->m_pszString : ""; 449 | } 450 | 451 | 452 | //----------------------------------------------------------------------------- 453 | // Used to read/write convars that already exist (replaces the FindVar method) 454 | //----------------------------------------------------------------------------- 455 | class ConVarRef 456 | { 457 | public: 458 | ConVarRef( const char *pName ); 459 | ConVarRef( const char *pName, bool bIgnoreMissing ); 460 | ConVarRef( IConVar *pConVar ); 461 | 462 | void Init( const char *pName, bool bIgnoreMissing ); 463 | bool IsValid() const; 464 | bool IsFlagSet( int nFlags ) const; 465 | IConVar *GetLinkedConVar(); 466 | 467 | // Get/Set value 468 | float GetFloat( void ) const; 469 | int GetInt( void ) const; 470 | bool GetBool() const { return !!GetInt(); } 471 | const char *GetString( void ) const; 472 | 473 | void SetValue( const char *pValue ); 474 | void SetValue( float flValue ); 475 | void SetValue( int nValue ); 476 | void SetValue( bool bValue ); 477 | 478 | const char *GetName() const; 479 | 480 | const char *GetDefault() const; 481 | 482 | private: 483 | // High-speed method to read convar data 484 | IConVar *m_pConVar; 485 | ConVar *m_pConVarState; 486 | }; 487 | 488 | 489 | //----------------------------------------------------------------------------- 490 | // Did we find an existing convar of that name? 491 | //----------------------------------------------------------------------------- 492 | FORCEINLINE_CVAR bool ConVarRef::IsFlagSet( int nFlags ) const 493 | { 494 | return ( m_pConVar->IsFlagSet( nFlags ) != 0 ); 495 | } 496 | 497 | FORCEINLINE_CVAR IConVar *ConVarRef::GetLinkedConVar() 498 | { 499 | return m_pConVar; 500 | } 501 | 502 | FORCEINLINE_CVAR const char *ConVarRef::GetName() const 503 | { 504 | return m_pConVar->GetName(); 505 | } 506 | 507 | 508 | //----------------------------------------------------------------------------- 509 | // Purpose: Return ConVar value as a float 510 | //----------------------------------------------------------------------------- 511 | FORCEINLINE_CVAR float ConVarRef::GetFloat( void ) const 512 | { 513 | return m_pConVarState->m_fValue; 514 | } 515 | 516 | //----------------------------------------------------------------------------- 517 | // Purpose: Return ConVar value as an int 518 | //----------------------------------------------------------------------------- 519 | FORCEINLINE_CVAR int ConVarRef::GetInt( void ) const 520 | { 521 | return m_pConVarState->m_nValue; 522 | } 523 | 524 | //----------------------------------------------------------------------------- 525 | // Purpose: Return ConVar value as a string, return "" for bogus string pointer, etc. 526 | //----------------------------------------------------------------------------- 527 | FORCEINLINE_CVAR const char *ConVarRef::GetString( void ) const 528 | { 529 | Assert( !IsFlagSet( FCVAR_NEVER_AS_STRING ) ); 530 | return m_pConVarState->m_pszString; 531 | } 532 | 533 | 534 | FORCEINLINE_CVAR void ConVarRef::SetValue( const char *pValue ) 535 | { 536 | m_pConVar->SetValue( pValue ); 537 | } 538 | 539 | FORCEINLINE_CVAR void ConVarRef::SetValue( float flValue ) 540 | { 541 | m_pConVar->SetValue( flValue ); 542 | } 543 | 544 | FORCEINLINE_CVAR void ConVarRef::SetValue( int nValue ) 545 | { 546 | m_pConVar->SetValue( nValue ); 547 | } 548 | 549 | FORCEINLINE_CVAR void ConVarRef::SetValue( bool bValue ) 550 | { 551 | m_pConVar->SetValue( bValue ? 1 : 0 ); 552 | } 553 | 554 | FORCEINLINE_CVAR const char *ConVarRef::GetDefault() const 555 | { 556 | return m_pConVarState->m_pszDefaultValue; 557 | } 558 | 559 | 560 | //----------------------------------------------------------------------------- 561 | // Called by the framework to register ConCommands with the ICVar 562 | //----------------------------------------------------------------------------- 563 | void ConVar_Register( int nCVarFlag = 0, IConCommandBaseAccessor *pAccessor = NULL ); 564 | void ConVar_Unregister( ); 565 | 566 | 567 | //----------------------------------------------------------------------------- 568 | // Utility methods 569 | //----------------------------------------------------------------------------- 570 | void ConVar_PrintFlags( const ConCommandBase *var ); 571 | void ConVar_PrintDescription( const ConCommandBase *pVar ); 572 | 573 | 574 | //----------------------------------------------------------------------------- 575 | // Purpose: Utility class to quickly allow ConCommands to call member methods 576 | //----------------------------------------------------------------------------- 577 | #pragma warning (disable : 4355 ) 578 | 579 | template< class T > 580 | class CConCommandMemberAccessor : public ConCommand, public ICommandCallback, public ICommandCompletionCallback 581 | { 582 | typedef ConCommand BaseClass; 583 | typedef void ( T::*FnMemberCommandCallback_t )( const CCommand &command ); 584 | typedef int ( T::*FnMemberCommandCompletionCallback_t )( const char *pPartial, CUtlVector< CUtlString > &commands ); 585 | 586 | public: 587 | CConCommandMemberAccessor( T* pOwner, const char *pName, FnMemberCommandCallback_t callback, const char *pHelpString = 0, 588 | int flags = 0, FnMemberCommandCompletionCallback_t completionFunc = 0 ) : 589 | BaseClass( pName, this, pHelpString, flags, ( completionFunc != 0 ) ? this : NULL ) 590 | { 591 | m_pOwner = pOwner; 592 | m_Func = callback; 593 | m_CompletionFunc = completionFunc; 594 | } 595 | 596 | ~CConCommandMemberAccessor() 597 | { 598 | Shutdown(); 599 | } 600 | 601 | void SetOwner( T* pOwner ) 602 | { 603 | m_pOwner = pOwner; 604 | } 605 | 606 | virtual void CommandCallback( const CCommand &command ) 607 | { 608 | Assert( m_pOwner && m_Func ); 609 | (m_pOwner->*m_Func)( command ); 610 | } 611 | 612 | virtual int CommandCompletionCallback( const char *pPartial, CUtlVector< CUtlString > &commands ) 613 | { 614 | Assert( m_pOwner && m_CompletionFunc ); 615 | return (m_pOwner->*m_CompletionFunc)( pPartial, commands ); 616 | } 617 | 618 | private: 619 | T* m_pOwner; 620 | FnMemberCommandCallback_t m_Func; 621 | FnMemberCommandCompletionCallback_t m_CompletionFunc; 622 | }; 623 | 624 | #pragma warning ( default : 4355 ) 625 | 626 | 627 | //----------------------------------------------------------------------------- 628 | // Purpose: Utility macros to quicky generate a simple console command 629 | //----------------------------------------------------------------------------- 630 | #define CON_COMMAND( name, description ) \ 631 | static void name( const CCommand &args ); \ 632 | static ConCommand name##_command( #name, name, description ); \ 633 | static void name( const CCommand &args ) 634 | 635 | #define CON_COMMAND_F( name, description, flags ) \ 636 | static void name( const CCommand &args ); \ 637 | static ConCommand name##_command( #name, name, description, flags ); \ 638 | static void name( const CCommand &args ) 639 | 640 | #define CON_COMMAND_F_COMPLETION( name, description, flags, completion ) \ 641 | static void name( const CCommand &args ); \ 642 | static ConCommand name##_command( #name, name, description, flags, completion ); \ 643 | static void name( const CCommand &args ) 644 | 645 | #define CON_COMMAND_EXTERN( name, _funcname, description ) \ 646 | void _funcname( const CCommand &args ); \ 647 | static ConCommand name##_command( #name, _funcname, description ); \ 648 | void _funcname( const CCommand &args ) 649 | 650 | #define CON_COMMAND_EXTERN_F( name, _funcname, description, flags ) \ 651 | void _funcname( const CCommand &args ); \ 652 | static ConCommand name##_command( #name, _funcname, description, flags ); \ 653 | void _funcname( const CCommand &args ) 654 | 655 | #define CON_COMMAND_MEMBER_F( _thisclass, name, _funcname, description, flags ) \ 656 | void _funcname( const CCommand &args ); \ 657 | friend class CCommandMemberInitializer_##_funcname; \ 658 | class CCommandMemberInitializer_##_funcname \ 659 | { \ 660 | public: \ 661 | CCommandMemberInitializer_##_funcname() : m_ConCommandAccessor( NULL, name, &_thisclass::_funcname, description, flags ) \ 662 | { \ 663 | m_ConCommandAccessor.SetOwner( GET_OUTER( _thisclass, m_##_funcname##_register ) ); \ 664 | } \ 665 | private: \ 666 | CConCommandMemberAccessor< _thisclass > m_ConCommandAccessor; \ 667 | }; \ 668 | \ 669 | CCommandMemberInitializer_##_funcname m_##_funcname##_register; \ 670 | 671 | 672 | #endif // CONVAR_H 673 | --------------------------------------------------------------------------------