├── src ├── cluainterface.h └── main.cpp ├── lua └── menu_plugins │ └── modules │ └── roc.lua ├── include ├── GarrysMod │ └── Lua │ │ ├── UserData.h │ │ ├── Interface.h │ │ ├── Types.h │ │ └── LuaBase.h ├── util.h └── vtable.h ├── README.md ├── premake5.lua └── .gitignore /src/cluainterface.h: -------------------------------------------------------------------------------- 1 | class CLuaInterface 2 | { 3 | private: 4 | template 5 | inline t get(unsigned short which) 6 | { 7 | return t((*(char ***)(this))[which]); 8 | } 9 | }; -------------------------------------------------------------------------------- /lua/menu_plugins/modules/roc.lua: -------------------------------------------------------------------------------- 1 | require("roc") 2 | 3 | concommand.Add("lua_run_client", function(ply, cmd, args, txt) 4 | RunOnClient(txt) 5 | end) 6 | 7 | hook.Add("RunOnClient", "idk", function(path, torun) 8 | return file.Read("overrides/"..path, "DATA") or torun 9 | end) -------------------------------------------------------------------------------- /include/GarrysMod/Lua/UserData.h: -------------------------------------------------------------------------------- 1 | 2 | #ifndef GARRYSMOD_LUA_USERDATA_H 3 | #define GARRYSMOD_LUA_USERDATA_H 4 | 5 | namespace GarrysMod 6 | { 7 | namespace Lua 8 | { 9 | struct UserData 10 | { 11 | void* data; 12 | unsigned char type; 13 | }; 14 | } 15 | } 16 | 17 | #endif 18 | 19 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | gm_roc 2 | ====== 3 | 4 | Brings the cool little function RunOnClient back into the menu state! 5 | 6 | You should install [menu plugins](https://github.com/glua/gmod-menu-plugins) to get this to load properly (you can probs do it yourself though) 7 | 8 | Then copy the lua folder to your gmod/gmod directory. 9 | 10 | ## Building the project files 11 | Get the latest premake5.exe and add it to your PATH. Then run build.bat 12 | -------------------------------------------------------------------------------- /premake5.lua: -------------------------------------------------------------------------------- 1 | solution "gm_roc2" 2 | language "C++" 3 | location "./proj" 4 | 5 | architecture "x86" 6 | 7 | configurations "Release" 8 | 9 | configuration "Release" 10 | defines {"NDEBUG"} 11 | optimize "On" 12 | 13 | project "gmsv_roc2_win32" 14 | flags "StaticRuntime" 15 | kind "SharedLib" 16 | 17 | targetdir "C:/Program Files (x86)/Steam/steamapps/common/GarrysMod/garrysmod/lua/bin" 18 | 19 | buildoptions {"/Os", "/MP", "/arch:SSE2"} 20 | 21 | includedirs { 22 | "include", 23 | "src" 24 | } 25 | 26 | files { 27 | "src/**.cpp", 28 | "src/**.hpp", 29 | "src/**.h", 30 | } 31 | 32 | defines { 33 | "GMMODULE", 34 | "WIN32", 35 | "_WINDOWS", 36 | "_USRDLL" 37 | } 38 | -------------------------------------------------------------------------------- /include/GarrysMod/Lua/Interface.h: -------------------------------------------------------------------------------- 1 | 2 | #ifndef GARRYSMOD_LUA_INTERFACE_H 3 | #define GARRYSMOD_LUA_INTERFACE_H 4 | 5 | #include "Types.h" 6 | #include "LuaBase.h" 7 | #include "UserData.h" 8 | 9 | 10 | #ifdef GMMODULE 11 | 12 | struct lua_State 13 | { 14 | unsigned char _ignore_this_common_lua_header_[69]; 15 | GarrysMod::Lua::ILuaBase* luabase; 16 | }; 17 | 18 | #ifdef _WIN32 19 | #define DLL_EXPORT extern "C" __declspec( dllexport ) 20 | #else 21 | #define DLL_EXPORT extern "C" __attribute__((visibility("default"))) 22 | #endif 23 | 24 | #define GMOD_MODULE_OPEN() DLL_EXPORT int gmod13_open( lua_State* state ) 25 | #define GMOD_MODULE_CLOSE() DLL_EXPORT int gmod13_close( lua_State* state ) 26 | 27 | #define LUA state->luabase 28 | 29 | #endif 30 | 31 | #endif 32 | 33 | -------------------------------------------------------------------------------- /include/util.h: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | namespace util { 4 | 5 | typedef void *(__cdecl *CreateInterfaceFn)(const char *name, int *found); 6 | 7 | template 8 | t GetInterface(const char *module, const char *name) 9 | { 10 | HMODULE hmodule = GetModuleHandleA(module); 11 | CreateInterfaceFn create = (CreateInterfaceFn)GetProcAddress(hmodule, "CreateInterface"); 12 | 13 | void *ret = 0; 14 | 15 | char temp_name[256]; // up this if it causes problems 16 | for (unsigned short i = 0; i < 1000; i++) 17 | { 18 | sprintf_s(temp_name, 256, "%s%03i", name, i); 19 | ret = create(temp_name, 0); 20 | if (ret) break; 21 | } 22 | 23 | return t(ret); 24 | } 25 | 26 | 27 | template 28 | t GetInterfaceSingle(const char *module, const char *name) 29 | { 30 | auto fn = CreateInterfaceFn(GetProcAddress(GetModuleHandleA(module), "CreateInterface")); 31 | return fn(name, 0); 32 | } 33 | 34 | inline char *getvfunc(void *obj, unsigned short which) 35 | { 36 | return (*(char ***)obj)[which]; 37 | } 38 | } -------------------------------------------------------------------------------- /include/vtable.h: -------------------------------------------------------------------------------- 1 | #ifndef VTABLE_H 2 | #define VTABLE_H 3 | 4 | #define ushort_max (unsigned short(-1)) 5 | 6 | typedef char *vtindex; // sizeof(pointer) with ability to add numbers and shit 7 | #ifndef offset 8 | #define offset(x,y) ((char *)(x) - (char *)(y)) 9 | #endif 10 | 11 | class VTable 12 | { 13 | public: 14 | VTable(void *object) 15 | { 16 | original_vt = *(vtindex **)object; 17 | vtindex *last_index = original_vt; 18 | while (*last_index++); 19 | 20 | unsigned int size = offset(last_index, original_vt) / sizeof(*last_index); 21 | 22 | new_vt = new vtindex[size]; 23 | while (--last_index >= original_vt) 24 | new_vt[offset(last_index, original_vt) / sizeof(*last_index)] = *last_index; 25 | 26 | *(vtindex **)object = new_vt; 27 | 28 | hooked = (void **)object; 29 | } 30 | ~VTable() 31 | { 32 | *hooked = original_vt; 33 | delete[] new_vt; 34 | } 35 | 36 | void hook(unsigned short index, void *func) 37 | { 38 | get(index) = (vtindex)func; 39 | } 40 | void unhook(unsigned short index) 41 | { 42 | get(index) = getold(index); 43 | } 44 | 45 | 46 | vtindex &getold(unsigned short index) { return original_vt[index]; } 47 | 48 | private: 49 | vtindex &get (unsigned short index) { return new_vt[index]; } 50 | 51 | 52 | public: 53 | vtindex *original_vt; 54 | vtindex *new_vt; 55 | void **hooked; 56 | 57 | }; 58 | 59 | #undef offset 60 | 61 | #endif // VTABLE_H -------------------------------------------------------------------------------- /include/GarrysMod/Lua/Types.h: -------------------------------------------------------------------------------- 1 | 2 | #ifndef GARRYSMOD_LUA_TYPES_H 3 | #define GARRYSMOD_LUA_TYPES_H 4 | 5 | #ifdef ENTITY 6 | #undef ENTITY 7 | #endif 8 | 9 | #ifdef VECTOR 10 | #undef VECTOR 11 | #endif 12 | 13 | namespace GarrysMod 14 | { 15 | namespace Lua 16 | { 17 | namespace Type 18 | { 19 | enum 20 | { 21 | 22 | INVALID = -1, 23 | NIL, 24 | BOOL, 25 | LIGHTUSERDATA, 26 | NUMBER, 27 | STRING, 28 | TABLE, 29 | FUNCTION, 30 | USERDATA, 31 | THREAD, 32 | 33 | // UserData 34 | ENTITY, 35 | VECTOR, 36 | ANGLE, 37 | PHYSOBJ, 38 | SAVE, 39 | RESTORE, 40 | DAMAGEINFO, 41 | EFFECTDATA, 42 | MOVEDATA, 43 | RECIPIENTFILTER, 44 | USERCMD, 45 | SCRIPTEDVEHICLE, 46 | 47 | // Client Only 48 | MATERIAL, 49 | PANEL, 50 | PARTICLE, 51 | PARTICLEEMITTER, 52 | TEXTURE, 53 | USERMSG, 54 | 55 | CONVAR, 56 | IMESH, 57 | MATRIX, 58 | SOUND, 59 | PIXELVISHANDLE, 60 | DLIGHT, 61 | VIDEO, 62 | FILE, 63 | 64 | COUNT 65 | }; 66 | 67 | static const char* Name[] = 68 | { 69 | "nil", 70 | "bool", 71 | "lightuserdata", 72 | "number", 73 | "string", 74 | "table", 75 | "function", 76 | "userdata", 77 | "thread", 78 | "entity", 79 | "vector", 80 | "angle", 81 | "physobj", 82 | "save", 83 | "restore", 84 | "damageinfo", 85 | "effectdata", 86 | "movedata", 87 | "recipientfilter", 88 | "usercmd", 89 | "vehicle", 90 | "material", 91 | "panel", 92 | "particle", 93 | "particleemitter", 94 | "texture", 95 | "usermsg", 96 | "convar", 97 | "mesh", 98 | "matrix", 99 | "sound", 100 | "pixelvishandle", 101 | "dlight", 102 | "video", 103 | "file", 104 | 105 | 0 106 | }; 107 | } 108 | } 109 | } 110 | 111 | #endif 112 | 113 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | ## Ignore Visual Studio temporary files, build results, and 2 | ## files generated by popular Visual Studio add-ons. 3 | 4 | # User-specific files 5 | *.suo 6 | *.user 7 | *.sln.docstates 8 | 9 | windows-vs2013/ 10 | windows/ 11 | premake5.exe 12 | premake.bat 13 | 14 | proj/ 15 | 16 | # Build results 17 | [Dd]ebug/ 18 | [Dd]ebugPublic/ 19 | [Rr]elease/ 20 | x64/ 21 | build/ 22 | bld/ 23 | bin/ 24 | [Oo]bj/ 25 | 26 | # MSTest test Results 27 | [Tt]est[Rr]esult*/ 28 | [Bb]uild[Ll]og.* 29 | 30 | #NUNIT 31 | *.VisualState.xml 32 | TestResult.xml 33 | 34 | # Build Results of an ATL Project 35 | [Dd]ebugPS/ 36 | [Rr]eleasePS/ 37 | dlldata.c 38 | 39 | *_i.c 40 | *_p.c 41 | *_i.h 42 | *.ilk 43 | *.meta 44 | *.obj 45 | *.pch 46 | *.pdb 47 | *.pgc 48 | *.pgd 49 | *.rsp 50 | *.sbr 51 | *.tlb 52 | *.tli 53 | *.tlh 54 | *.tmp 55 | *.tmp_proj 56 | *.log 57 | *.vspscc 58 | *.vssscc 59 | .builds 60 | *.pidb 61 | *.svclog 62 | *.scc 63 | 64 | # Chutzpah Test files 65 | _Chutzpah* 66 | 67 | # Visual C++ cache files 68 | ipch/ 69 | *.aps 70 | *.ncb 71 | *.opensdf 72 | *.sdf 73 | *.cachefile 74 | 75 | # Visual Studio profiler 76 | *.psess 77 | *.vsp 78 | *.vspx 79 | 80 | # TFS 2012 Local Workspace 81 | $tf/ 82 | 83 | # Guidance Automation Toolkit 84 | *.gpState 85 | 86 | # ReSharper is a .NET coding add-in 87 | _ReSharper*/ 88 | *.[Rr]e[Ss]harper 89 | *.DotSettings.user 90 | 91 | # JustCode is a .NET coding addin-in 92 | .JustCode 93 | 94 | # TeamCity is a build add-in 95 | _TeamCity* 96 | 97 | # DotCover is a Code Coverage Tool 98 | *.dotCover 99 | 100 | # NCrunch 101 | *.ncrunch* 102 | _NCrunch_* 103 | .*crunch*.local.xml 104 | 105 | # MightyMoose 106 | *.mm.* 107 | AutoTest.Net/ 108 | 109 | # Web workbench (sass) 110 | .sass-cache/ 111 | 112 | # Installshield output folder 113 | [Ee]xpress/ 114 | 115 | # DocProject is a documentation generator add-in 116 | DocProject/buildhelp/ 117 | DocProject/Help/*.HxT 118 | DocProject/Help/*.HxC 119 | DocProject/Help/*.hhc 120 | DocProject/Help/*.hhk 121 | DocProject/Help/*.hhp 122 | DocProject/Help/Html2 123 | DocProject/Help/html 124 | 125 | # Click-Once directory 126 | publish/ 127 | 128 | # Publish Web Output 129 | *.[Pp]ublish.xml 130 | *.azurePubxml 131 | 132 | # NuGet Packages Directory 133 | packages/ 134 | ## TODO: If the tool you use requires repositories.config uncomment the next line 135 | #!packages/repositories.config 136 | 137 | # Enable "build/" folder in the NuGet Packages folder since NuGet packages use it for MSBuild targets 138 | # This line needs to be after the ignore of the build folder (and the packages folder if the line above has been uncommented) 139 | !packages/build/ 140 | 141 | # Windows Azure Build Output 142 | csx/ 143 | *.build.csdef 144 | 145 | # Windows Store app package directory 146 | AppPackages/ 147 | 148 | # Others 149 | sql/ 150 | *.Cache 151 | ClientBin/ 152 | [Ss]tyle[Cc]op.* 153 | ~$* 154 | *~ 155 | *.dbmdl 156 | *.dbproj.schemaview 157 | *.pfx 158 | *.publishsettings 159 | node_modules/ 160 | 161 | # RIA/Silverlight projects 162 | Generated_Code/ 163 | 164 | # Backup & report files from converting an old project file to a newer 165 | # Visual Studio version. Backup files are not needed, because we have git ;-) 166 | _UpgradeReport_Files/ 167 | Backup*/ 168 | UpgradeLog*.XML 169 | UpgradeLog*.htm 170 | 171 | # SQL Server files 172 | *.mdf 173 | *.ldf 174 | 175 | # Business Intelligence projects 176 | *.rdl.data 177 | *.bim.layout 178 | *.bim_*.settings 179 | 180 | # Microsoft Fakes 181 | FakesAssemblies/ 182 | *.exp 183 | -------------------------------------------------------------------------------- /include/GarrysMod/Lua/LuaBase.h: -------------------------------------------------------------------------------- 1 | 2 | #ifndef GARRYSMOD_LUA_LUABASE_H 3 | #define GARRYSMOD_LUA_LUABASE_H 4 | 5 | #include 6 | 7 | struct lua_State; 8 | 9 | namespace GarrysMod 10 | { 11 | namespace Lua 12 | { 13 | typedef int (*CFunc) (lua_State *L); 14 | 15 | // 16 | // Access to raw Lua function calls 17 | // 18 | class ILuaBase 19 | { 20 | public: 21 | 22 | virtual int Top( void ) = 0; 23 | virtual void Push( int iStackPos ) = 0; 24 | virtual void Pop( int iAmt = 1 ) = 0; 25 | virtual void GetTable( int iStackPos ) = 0; 26 | virtual void GetField( int iStackPos, const char* strName ) = 0; 27 | virtual void SetField( int iStackPos, const char* strName ) = 0; 28 | virtual void CreateTable() = 0; 29 | virtual void SetTable( int i ) = 0; 30 | virtual void SetMetaTable( int i ) = 0; 31 | virtual bool GetMetaTable( int i ) = 0; 32 | virtual void Call( int iArgs, int iResults ) = 0; 33 | virtual int PCall( int iArgs, int iResults, int iErrorFunc ) = 0; 34 | virtual int Equal( int iA, int iB ) = 0; 35 | virtual int RawEqual( int iA, int iB ) = 0; 36 | virtual void Insert( int iStackPos ) = 0; 37 | virtual void Remove( int iStackPos ) = 0; 38 | virtual int Next( int iStackPos ) = 0; 39 | virtual void* NewUserdata( unsigned int iSize ) = 0; 40 | virtual void ThrowError( const char* strError ) = 0; 41 | virtual void CheckType( int iStackPos, int iType ) = 0; 42 | virtual void ArgError( int iArgNum, const char* strMessage ) = 0; 43 | virtual void RawGet( int iStackPos ) = 0; 44 | virtual void RawSet( int iStackPos ) = 0; 45 | 46 | virtual const char* GetString( int iStackPos = -1, unsigned int* iOutLen = NULL ) = 0; 47 | virtual double GetNumber( int iStackPos = -1 ) = 0; 48 | virtual bool GetBool( int iStackPos = -1 ) = 0; 49 | virtual CFunc GetCFunction( int iStackPos = -1 ) = 0; 50 | virtual void* GetUserdata( int iStackPos = -1 ) = 0; 51 | 52 | virtual void PushNil() = 0; 53 | virtual void PushString( const char* val, unsigned int iLen = 0 ) = 0; 54 | virtual void PushNumber( double val ) = 0; 55 | virtual void PushBool( bool val ) = 0; 56 | virtual void PushCFunction( CFunc val ) = 0; 57 | virtual void PushCClosure( CFunc val, int iVars ) = 0; 58 | virtual void PushUserdata( void* ) = 0; 59 | 60 | // 61 | // If you create a reference - don't forget to free it! 62 | // 63 | virtual int ReferenceCreate() = 0; 64 | virtual void ReferenceFree( int i ) = 0; 65 | virtual void ReferencePush( int i ) = 0; 66 | 67 | // 68 | // Push a special value onto the top of the stack ( see below ) 69 | // 70 | virtual void PushSpecial( int iType ) = 0; 71 | 72 | // 73 | // For type enums see Types.h 74 | // 75 | virtual bool IsType( int iStackPos, int iType ) = 0; 76 | virtual int GetType( int iStackPos ) = 0; 77 | virtual const char* GetTypeName( int iType ) = 0; 78 | 79 | // 80 | // Creates a new meta table of string and type and leaves it on the stack. 81 | // Will return the old meta table of this name if it already exists. 82 | // 83 | virtual void CreateMetaTableType( const char* strName, int iType ) = 0; 84 | 85 | // 86 | // Like Get* but throws errors and returns if they're not of the expected type 87 | // 88 | virtual const char* CheckString( int iStackPos = -1 ) = 0; 89 | virtual double CheckNumber( int iStackPos = -1 ) = 0; 90 | 91 | }; 92 | 93 | enum 94 | { 95 | SPECIAL_GLOB, // Global table 96 | SPECIAL_ENV, // Environment table 97 | SPECIAL_REG, // Registry table 98 | }; 99 | } 100 | } 101 | 102 | #endif 103 | 104 | -------------------------------------------------------------------------------- /src/main.cpp: -------------------------------------------------------------------------------- 1 | #include "GarrysMod/Lua/Interface.h" 2 | #include "vtable.h" 3 | #include "util.h" 4 | #include "windows.h" 5 | 6 | #define CREATELUAINTERFACE 4 7 | #define CLOSELUAINTERFACE 5 8 | #define RUNSTRINGEX 111 9 | 10 | typedef unsigned char uchar; 11 | 12 | VTable* sharedHooker; 13 | VTable* clientHooker; 14 | 15 | using namespace GarrysMod; 16 | 17 | Lua::ILuaBase *MENU; 18 | void *clientState; 19 | 20 | typedef void *(__thiscall *hRunStringExFn)(void*, char const*, char const*, char const*, bool, bool, bool, bool); 21 | void * __fastcall hRunStringEx(void *_this, void*, char const* filename, char const* path, char const* torun, bool run, bool showerrors, bool idk, bool idk2) 22 | { 23 | MENU->PushSpecial(Lua::SPECIAL_GLOB); 24 | MENU->GetField(-1, "hook"); 25 | MENU->GetField(-1, "Call"); 26 | MENU->PushString("RunOnClient"); 27 | MENU->PushNil(); 28 | MENU->PushString(filename); 29 | MENU->PushString(torun); 30 | MENU->Call(4, 1); 31 | if (!MENU->IsType(-1, Lua::Type::NIL)) 32 | torun = MENU->CheckString(); 33 | MENU->Pop(3); 34 | 35 | return hRunStringExFn(clientHooker->getold(RUNSTRINGEX))(_this, filename, path, torun, run, showerrors, idk, idk2); 36 | } 37 | 38 | typedef void *(__thiscall *hCreateLuaInterfaceFn)(void *, uchar, bool); 39 | void * __fastcall hCreateLuaInterface(void *_this, void *, uchar stateType, bool renew) 40 | { 41 | void *state = hCreateLuaInterfaceFn(sharedHooker->getold(CREATELUAINTERFACE))(_this, stateType, renew); 42 | 43 | MENU->PushSpecial(Lua::SPECIAL_GLOB); 44 | MENU->GetField(-1, "hook"); 45 | MENU->GetField(-1, "Call"); 46 | MENU->PushString("ClientStateCreated"); 47 | MENU->PushNil(); 48 | MENU->Call(2, 0); 49 | MENU->Pop(2); 50 | 51 | if (stateType != 0) 52 | return state; 53 | 54 | clientState = state; 55 | 56 | clientHooker = new VTable(clientState); 57 | clientHooker->hook(RUNSTRINGEX, hRunStringEx); 58 | 59 | return clientState; 60 | } 61 | 62 | typedef void *(__thiscall *hCloseLuaInterfaceFn)(void*, void*); 63 | void * __fastcall hCloseLuaInterface(void *_this, void *ukwn, void *luaInterface) 64 | { 65 | if (luaInterface == clientState) 66 | clientState = NULL; 67 | 68 | return hCloseLuaInterfaceFn(sharedHooker->getold(CLOSELUAINTERFACE))(_this, luaInterface); 69 | } 70 | 71 | class CLuaInterface 72 | { 73 | private: 74 | template 75 | inline t get(unsigned short which) 76 | { 77 | return t((*(char ***)(this))[which]); 78 | } 79 | 80 | public: 81 | void RunStringEx(char const* filename, char const* path, char const* torun, bool run = true, bool showerrors = true, bool idk = true, bool idk2 = true) 82 | { 83 | return get(RUNSTRINGEX)(this, filename, path, torun, run, showerrors, idk, idk2); //free cookies for people that know how to detect stuff 84 | } 85 | 86 | }; 87 | 88 | int RunOnClient(lua_State* state) 89 | { 90 | if (!clientState) 91 | LUA->ThrowError("Not in game"); 92 | 93 | reinterpret_cast(clientState)->RunStringEx(LUA->CheckString(-3), LUA->CheckString(-2), LUA->CheckString()); 94 | 95 | return 0; 96 | } 97 | 98 | GMOD_MODULE_OPEN() 99 | { 100 | MENU = LUA; 101 | 102 | auto luaShared = util::GetInterfaceSingle("lua_shared.dll", "LUASHARED003"); 103 | 104 | if (!luaShared) 105 | MessageBoxA(NULL, "gay", "gay", NULL); 106 | 107 | sharedHooker = new VTable(luaShared); 108 | 109 | sharedHooker->hook(CREATELUAINTERFACE, hCreateLuaInterface); 110 | sharedHooker->hook(CLOSELUAINTERFACE, hCloseLuaInterface); 111 | 112 | LUA->PushSpecial(Lua::SPECIAL_GLOB); 113 | LUA->PushString("RunOnClient"); 114 | LUA->PushCFunction(RunOnClient); 115 | LUA->SetTable(-3); 116 | LUA->Pop(); 117 | 118 | return 0; 119 | } --------------------------------------------------------------------------------