diff --git a/INCLUDES/GARRYSMOD/LUA/Interface.h b/INCLUDES/GARRYSMOD/LUA/Interface.h new file mode 100644 index 0000000..7152362 --- /dev/null +++ b/INCLUDES/GARRYSMOD/LUA/Interface.h @@ -0,0 +1,75 @@ +#ifndef GARRYSMOD_LUA_INTERFACE_H +#define GARRYSMOD_LUA_INTERFACE_H + +#include "LuaBase.h" + +struct lua_State +{ +#if defined( _WIN32 ) && !defined( _M_X64 ) + // Win32 + unsigned char _ignore_this_common_lua_header_[48 + 22]; +#elif defined( _WIN32 ) && defined( _M_X64 ) + // Win64 + unsigned char _ignore_this_common_lua_header_[92 + 22]; +#elif defined( __linux__ ) && !defined( __x86_64__ ) + // Linux32 + unsigned char _ignore_this_common_lua_header_[48 + 22]; +#elif defined( __linux__ ) && defined( __x86_64__ ) + // Linux64 + unsigned char _ignore_this_common_lua_header_[92 + 22]; +#elif defined ( __APPLE__ ) && !defined( __x86_64__ ) + // macOS32 + unsigned char _ignore_this_common_lua_header_[48 + 22]; +#elif defined ( __APPLE__ ) && defined( __x86_64__ ) + // macOS64 + unsigned char _ignore_this_common_lua_header_[92 + 22]; +#else + #error agh +#endif + + GarrysMod::Lua::ILuaBase* luabase; +}; + +#ifndef GMOD + #ifdef _WIN32 + #define DLL_EXPORT extern "C" __declspec( dllexport ) + #else + #define DLL_EXPORT extern "C" __attribute__((visibility("default"))) + #endif + + #ifdef GMOD_ALLOW_DEPRECATED + // Stop using this and use LUA_FUNCTION! + #define LUA ( state->luabase ) + + #define GMOD_MODULE_OPEN() DLL_EXPORT int gmod13_open( lua_State* state ) + #define GMOD_MODULE_CLOSE() DLL_EXPORT int gmod13_close( lua_State* state ) + #else + #define GMOD_MODULE_OPEN() \ + int gmod13_open__Imp( GarrysMod::Lua::ILuaBase* LUA ); \ + DLL_EXPORT int gmod13_open( lua_State* L ) \ + { \ + return gmod13_open__Imp( L->luabase ); \ + } \ + int gmod13_open__Imp( GarrysMod::Lua::ILuaBase* LUA ) + + #define GMOD_MODULE_CLOSE() \ + int gmod13_close__Imp( GarrysMod::Lua::ILuaBase* LUA ); \ + DLL_EXPORT int gmod13_close( lua_State* L ) \ + { \ + return gmod13_close__Imp( L->luabase ); \ + } \ + int gmod13_close__Imp( GarrysMod::Lua::ILuaBase* LUA ) + + #define LUA_FUNCTION( FUNC ) \ + int FUNC##__Imp( GarrysMod::Lua::ILuaBase* LUA ); \ + int FUNC( lua_State* L ) \ + { \ + GarrysMod::Lua::ILuaBase* LUA = L->luabase; \ + LUA->SetState(L); \ + return FUNC##__Imp( LUA ); \ + } \ + int FUNC##__Imp( GarrysMod::Lua::ILuaBase* LUA ) + #endif +#endif + +#endif diff --git a/INCLUDES/GARRYSMOD/LUA/LuaBase.h b/INCLUDES/GARRYSMOD/LUA/LuaBase.h new file mode 100644 index 0000000..0ceab47 --- /dev/null +++ b/INCLUDES/GARRYSMOD/LUA/LuaBase.h @@ -0,0 +1,313 @@ +#ifndef GARRYSMOD_LUA_LUABASE_H +#define GARRYSMOD_LUA_LUABASE_H + +#include +#include + +#include "Types.h" +#include "UserData.h" +#include "SourceCompat.h" + +struct lua_State; + +namespace GarrysMod +{ + namespace Lua + { + typedef int ( *CFunc )( lua_State* L ); + + // + // Use this to communicate between C and Lua + // + class ILuaBase + { + public: + // You shouldn't need to use this struct + // Instead, use the UserType functions + struct UserData + { + void* data; + unsigned char type; // Change me to a uint32 one day + }; + + protected: + template + struct UserData_Value : UserData + { + T value; + }; + + public: + // Returns the amount of values on the stack + virtual int Top( void ) = 0; + + // Pushes a copy of the value at iStackPos to the top of the stack + virtual void Push( int iStackPos ) = 0; + + // Pops iAmt values from the top of the stack + virtual void Pop( int iAmt = 1 ) = 0; + + // Pushes table[key] on to the stack + // table = value at iStackPos + // key = value at top of the stack + // Pops the key from the stack + virtual void GetTable( int iStackPos ) = 0; + + // Pushes table[key] on to the stack + // table = value at iStackPos + // key = strName + virtual void GetField( int iStackPos, const char* strName ) = 0; + + // Sets table[key] to the value at the top of the stack + // table = value at iStackPos + // key = strName + // Pops the value from the stack + virtual void SetField( int iStackPos, const char* strName ) = 0; + + // Creates a new table and pushes it to the top of the stack + virtual void CreateTable() = 0; + + // Sets table[key] to the value at the top of the stack + // table = value at iStackPos + // key = value 2nd to the top of the stack + // Pops the key and the value from the stack + virtual void SetTable( int iStackPos ) = 0; + + // Sets the metatable for the value at iStackPos to the value at the top of the stack + // Pops the value off of the top of the stack + virtual void SetMetaTable( int iStackPos ) = 0; + + // Pushes the metatable of the value at iStackPos on to the top of the stack + // Upon failure, returns false and does not push anything + virtual bool GetMetaTable( int i ) = 0; + + // Calls a function + // To use it: Push the function on to the stack followed by each argument + // Pops the function and arguments from the stack, leaves iResults values on the stack + // If this function errors, any local C values will not have their destructors called! + virtual void Call( int iArgs, int iResults ) = 0; + + // Similar to Call + // See: lua_pcall( lua_State*, int, int, int ) + virtual int PCall( int iArgs, int iResults, int iErrorFunc ) = 0; + + // Returns true if the values at iA and iB are equal + virtual int Equal( int iA, int iB ) = 0; + + // Returns true if the value at iA and iB are equal + // Does not invoke metamethods + virtual int RawEqual( int iA, int iB ) = 0; + + // Moves the value at the top of the stack in to iStackPos + // Any elements above iStackPos are shifted upwards + virtual void Insert( int iStackPos ) = 0; + + // Removes the value at iStackPos from the stack + // Any elements above iStackPos are shifted downwards + virtual void Remove( int iStackPos ) = 0; + + // Allows you to iterate tables similar to pairs(...) + // See: lua_next( lua_State*, int ); + virtual int Next( int iStackPos ) = 0; + +#ifndef GMOD_ALLOW_DEPRECATED + protected: +#endif + // Deprecated: Use the UserType functions instead of this + virtual void* NewUserdata( unsigned int iSize ) = 0; + + public: + // Throws an error and ceases execution of the function + // If this function is called, any local C values will not have their destructors called! + virtual void ThrowError( const char* strError ) = 0; + + // Checks that the type of the value at iStackPos is iType + // Throws and error and ceases execution of the function otherwise + // If this function errors, any local C values will not have their destructors called! + virtual void CheckType( int iStackPos, int iType ) = 0; + + // Throws a pretty error message about the given argument + // If this function is called, any local C values will not have their destructors called! + virtual void ArgError( int iArgNum, const char* strMessage ) = 0; + + // Pushes table[key] on to the stack + // table = value at iStackPos + // key = value at top of the stack + // Does not invoke metamethods + virtual void RawGet( int iStackPos ) = 0; + + // Sets table[key] to the value at the top of the stack + // table = value at iStackPos + // key = value 2nd to the top of the stack + // Pops the key and the value from the stack + // Does not invoke metamethods + virtual void RawSet( int iStackPos ) = 0; + + // Returns the string at iStackPos. iOutLen is set to the length of the string if it is not NULL + // If the value at iStackPos is a number, it will be converted in to a string + // Returns NULL upon failure + virtual const char* GetString( int iStackPos = -1, unsigned int* iOutLen = NULL ) = 0; + + // Returns the number at iStackPos + // Returns 0 upon failure + virtual double GetNumber( int iStackPos = -1 ) = 0; + + // Returns the boolean at iStackPos + // Returns false upon failure + virtual bool GetBool( int iStackPos = -1 ) = 0; + + // Returns the C-Function at iStackPos + // returns NULL upon failure + virtual CFunc GetCFunction( int iStackPos = -1 ) = 0; + +#ifndef GMOD_ALLOW_DEPRECATED + protected: +#endif + // Deprecated: You should probably be using the UserType functions instead of this + virtual void* GetUserdata( int iStackPos = -1 ) = 0; + + public: + // Pushes a nil value on to the stack + virtual void PushNil() = 0; + + // Pushes the given string on to the stack + // If iLen is 0, strlen will be used to determine the string's length + virtual void PushString( const char* val, unsigned int iLen = 0 ) = 0; + + // Pushes the given double on to the stack + virtual void PushNumber( double val ) = 0; + + // Pushes the given bobolean on to the stack + virtual void PushBool( bool val ) = 0; + + // Pushes the given C-Function on to the stack + virtual void PushCFunction( CFunc val ) = 0; + + // Pushes the given C-Function on to the stack with upvalues + // See: GetUpvalueIndex() + virtual void PushCClosure( CFunc val, int iVars ) = 0; + + +#ifndef GMOD_ALLOW_DEPRECATED + protected: +#endif + // Deprecated: Don't use light userdata in GMod + virtual void PushUserdata( void* ) = 0; + + public: + // Allows for values to be stored by reference for later use + // Make sure you call ReferenceFree when you are done with a reference + virtual int ReferenceCreate() = 0; + virtual void ReferenceFree( int i ) = 0; + virtual void ReferencePush( int i ) = 0; + + // Push a special value onto the top of the stack (see SPECIAL_* enums) + virtual void PushSpecial( int iType ) = 0; + + // Returns true if the value at iStackPos is of type iType + // See: Types.h + virtual bool IsType( int iStackPos, int iType ) = 0; + + // Returns the type of the value at iStackPos + // See: Types.h + virtual int GetType( int iStackPos ) = 0; + + // Returns the name associated with the given type ID + // See: Types.h + // Note: GetTypeName does not work with user-created types + virtual const char* GetTypeName( int iType ) = 0; + +#ifndef GMOD_ALLOW_DEPRECATED + protected: +#endif + // Deprecated: Use CreateMetaTable + virtual void CreateMetaTableType( const char* strName, int iType ) = 0; + + public: + // Like Get* but throws errors and returns if they're not of the expected type + // If these functions error, any local C values will not have their destructors called! + virtual const char* CheckString( int iStackPos = -1 ) = 0; + virtual double CheckNumber( int iStackPos = -1 ) = 0; + + // Returns the length of the object at iStackPos + // Works for: strings, tables, userdata + virtual int ObjLen( int iStackPos = -1 ) = 0; + + // Returns the angle at iStackPos + virtual const QAngle& GetAngle( int iStackPos = -1 ) = 0; + + // Returns the vector at iStackPos + virtual const Vector& GetVector( int iStackPos = -1 ) = 0; + + // Pushes the given angle to the top of the stack + virtual void PushAngle( const QAngle& val ) = 0; + + // Pushes the given vector to the top of the stack + virtual void PushVector( const Vector& val ) = 0; + + // Sets the lua_State to be used by the ILuaBase implementation + // You don't need to use this if you use the LUA_FUNCTION macro + virtual void SetState( lua_State* L ) = 0; + + // Pushes the metatable associated with the given type name + // Returns the type ID to use for this type + // If the type doesn't currently exist, it will be created + virtual int CreateMetaTable( const char* strName ) = 0; + + // Pushes the metatable associated with the given type + virtual bool PushMetaTable( int iType ) = 0; + + // Creates a new UserData of type iType that references the given data + virtual void PushUserType( void* data, int iType ) = 0; + + // Sets the data pointer of the UserType at iStackPos + // You can use this to invalidate a UserType by passing NULL + virtual void SetUserType( int iStackPos, void* data ) = 0; + + // Returns the data of the UserType at iStackPos if it is of the given type + template + T* GetUserType( int iStackPos, int iType ) + { + auto* ud = static_cast( GetUserdata( iStackPos ) ); + + if ( ud == nullptr || ud->data == nullptr || ud->type != iType ) + return nullptr; + + return static_cast( ud->data ); + } + + // Creates a new UserData with your own data embedded within it + template + void PushUserType_Value( const T& val, int iType ) + { + using UserData_T = UserData_Value; + + // The UserData allocated by CLuaInterface is only guaranteed to have a data alignment of 8 + static_assert( std::alignment_of::value <= 8, + "PushUserType_Value given type with unsupported alignment requirement" ); + + // Don't give this function objects that can't be trivially destructed + // You could ignore this limitation if you implement object destruction in `__gc` + static_assert( std::is_trivially_destructible::value, + "PushUserType_Value given type that is not trivially destructible" ); + + auto* ud = static_cast( NewUserdata( sizeof( UserData_T ) ) ); + ud->data = new( &ud->value ) T ( val ); + ud->type = iType; + + // Set the metatable + if ( PushMetaTable( iType ) ) SetMetaTable( -2 ); + } + }; + + // For use with ILuaBase::PushSpecial + enum + { + SPECIAL_GLOB, // Global table + SPECIAL_ENV, // Environment table + SPECIAL_REG, // Registry table + }; + } +} + +#endif diff --git a/INCLUDES/GARRYSMOD/LUA/SourceCompat.h b/INCLUDES/GARRYSMOD/LUA/SourceCompat.h new file mode 100644 index 0000000..13ebeec --- /dev/null +++ b/INCLUDES/GARRYSMOD/LUA/SourceCompat.h @@ -0,0 +1,35 @@ +#ifndef GARRYSMOD_LUA_SOURCECOMPAT_H +#define GARRYSMOD_LUA_SOURCECOMPAT_H + +#ifdef GMOD_USE_SOURCESDK +#include "mathlib/vector.h" +#else + struct Vector + { + Vector() + : x( 0.f ) + , y( 0.f ) + , z( 0.f ) + {} + + Vector( const Vector& src ) + : x( src.x ) + , y( src.y ) + , z( src.z ) + {} + + Vector& operator=( const Vector& src ) + { + x = src.x; + y = src.y; + z = src.z; + return *this; + } + + float x, y, z; + }; + + using QAngle = Vector; +#endif + +#endif diff --git a/INCLUDES/GARRYSMOD/LUA/Types.h b/INCLUDES/GARRYSMOD/LUA/Types.h new file mode 100644 index 0000000..c795bf9 --- /dev/null +++ b/INCLUDES/GARRYSMOD/LUA/Types.h @@ -0,0 +1,124 @@ +#ifndef GARRYSMOD_LUA_TYPES_H +#define GARRYSMOD_LUA_TYPES_H + +namespace GarrysMod +{ + namespace Lua + { + namespace Type + { + enum + { +#ifdef GMOD_ALLOW_DEPRECATED + // Deprecated: Use `None` instead of `Invalid` + Invalid = -1, +#endif + + // Default Lua Types + None = -1, + Nil, + Bool, + LightUserData, + Number, + String, + Table, + Function, + UserData, + Thread, + + // GMod Types + Entity, + Vector, + Angle, + PhysObj, + Save, + Restore, + DamageInfo, + EffectData, + MoveData, + RecipientFilter, + UserCmd, + ScriptedVehicle, + Material, + Panel, + Particle, + ParticleEmitter, + Texture, + UserMsg, + ConVar, + IMesh, + Matrix, + Sound, + PixelVisHandle, + DLight, + Video, + File, + Locomotion, + Path, + NavArea, + SoundHandle, + NavLadder, + ParticleSystem, + ProjectedTexture, + PhysCollide, + SurfaceInfo, + + Type_Count + }; + +#if ( defined( GMOD ) || defined( GMOD_ALLOW_DEPRECATED ) ) + // You should use ILuaBase::GetTypeName instead of directly accessing this array + static const char* Name[] = + { + "nil", + "bool", + "lightuserdata", + "number", + "string", + "table", + "function", + "userdata", + "thread", + "entity", + "vector", + "angle", + "physobj", + "save", + "restore", + "damageinfo", + "effectdata", + "movedata", + "recipientfilter", + "usercmd", + "vehicle", + "material", + "panel", + "particle", + "particleemitter", + "texture", + "usermsg", + "convar", + "mesh", + "matrix", + "sound", + "pixelvishandle", + "dlight", + "video", + "file", + "locomotion", + "path", + "navarea", + "soundhandle", + "navladder", + "particlesystem", + "projectedtexture", + "physcollide", + "surfaceinfo", + nullptr + }; +#endif + } + } +} + +#endif diff --git a/INCLUDES/GARRYSMOD/LUA/UserData.h b/INCLUDES/GARRYSMOD/LUA/UserData.h new file mode 100644 index 0000000..7dbfa4d --- /dev/null +++ b/INCLUDES/GARRYSMOD/LUA/UserData.h @@ -0,0 +1,18 @@ +#ifndef GARRYSMOD_LUA_USERDATA_H +#define GARRYSMOD_LUA_USERDATA_H + +#ifdef GMOD_ALLOW_DEPRECATED + namespace GarrysMod + { + namespace Lua + { + struct UserData + { + void* data; + unsigned char type; + }; + } + } +#endif + +#endif diff --git a/MyTemplate.vstemplate b/MyTemplate.vstemplate new file mode 100644 index 0000000..c32db6d --- /dev/null +++ b/MyTemplate.vstemplate @@ -0,0 +1,27 @@ + + + gmod_binary_template + A very basic template for creating new binary modules for garry's mod, without needing to take time to set things up! + VC + + + 1000 + true + gmod_binary_template + true + Enabled + true + __TemplateIcon.ico + + + + gmod_binary_template.vcxproj.filters + main.cpp + INCLUDES\GARRYSMOD\LUA\Interface.h + INCLUDES\GARRYSMOD\LUA\LuaBase.h + INCLUDES\GARRYSMOD\LUA\SourceCompat.h + INCLUDES\GARRYSMOD\LUA\Types.h + INCLUDES\GARRYSMOD\LUA\UserData.h + + + \ No newline at end of file diff --git a/__TemplateIcon.ico b/__TemplateIcon.ico new file mode 100644 index 0000000..aae70d3 Binary files /dev/null and b/__TemplateIcon.ico differ diff --git a/gmod_binary_template.vcxproj b/gmod_binary_template.vcxproj new file mode 100644 index 0000000..641b898 --- /dev/null +++ b/gmod_binary_template.vcxproj @@ -0,0 +1,162 @@ + + + + + Debug + Win32 + + + Release + Win32 + + + Debug + x64 + + + Release + x64 + + + + 16.0 + Win32Proj + {$guid1$} + $safeprojectname$ + 10.0 + + + + DynamicLibrary + true + v143 + Unicode + + + DynamicLibrary + false + v143 + true + Unicode + + + DynamicLibrary + true + v143 + Unicode + + + DynamicLibrary + false + v143 + true + Unicode + + + + + + + + + + + + + + + + + + + + + $(ProjectDir)\includes\;$(IncludePath) + + + $(ProjectDir)\includes\;$(IncludePath) + + + $(ProjectDir)\includes\;$(IncludePath) + + + $(ProjectDir)\includes\;$(IncludePath) + + + + Level3 + true + WIN32;_DEBUG;_CONSOLE;%(PreprocessorDefinitions) + true + stdcpp20 + stdc17 + + + Console + true + + + + + Level3 + true + true + true + WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions) + true + stdcpp20 + stdc17 + + + Console + true + true + true + + + + + Level3 + true + _DEBUG;_CONSOLE;%(PreprocessorDefinitions) + true + stdcpp20 + stdc17 + + + Console + true + + + + + Level3 + true + true + true + NDEBUG;_CONSOLE;%(PreprocessorDefinitions) + true + stdcpp20 + stdc17 + + + Console + true + true + true + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/gmod_binary_template.vcxproj.filters b/gmod_binary_template.vcxproj.filters new file mode 100644 index 0000000..5943507 --- /dev/null +++ b/gmod_binary_template.vcxproj.filters @@ -0,0 +1,45 @@ + + + + + {4FC737F1-C7A5-4376-A066-2A32D752A2FF} + cpp;c;cc;cxx;c++;cppm;ixx;def;odl;idl;hpj;bat;asm;asmx + + + {93995380-89BD-4b04-88EB-625FBE52EBFB} + h;hh;hpp;hxx;h++;hm;inl;inc;ipp;xsd + + + {67DA6AB6-F800-4c08-8B7A-83BB121AAD01} + rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms + + + {a9720559-683c-4264-aba3-22b6cd55915a} + + + {6a72ed41-be72-4afa-b59c-c5fed17076cd} + + + + + Source Files + + + + + Source Files\GarrysMod\Lua + + + Source Files\GarrysMod\Lua + + + Source Files\GarrysMod\Lua + + + Source Files\GarrysMod\Lua + + + Source Files\GarrysMod\Lua + + + \ No newline at end of file diff --git a/main.cpp b/main.cpp new file mode 100644 index 0000000..eb8bf56 --- /dev/null +++ b/main.cpp @@ -0,0 +1,31 @@ +#include "GarrysMod/Lua/Interface.h" + +/* + require "HelloWorld" + print( TestFunction( 5, 17 ) ) +*/ + +using namespace GarrysMod::Lua; + +LUA_FUNCTION( MyExampleFunction ) { + double first_number = LUA->CheckNumber( 1 ); + double second_number = LUA->CheckNumber( 2 ); + + LUA->PushNumber( first_number + second_number ); + return 1; +} + +GMOD_MODULE_OPEN() { + LUA->PushSpecial( GarrysMod::Lua::SPECIAL_GLOB ); + LUA->PushString( "TestFunction" ); + LUA->PushCFunction( MyExampleFunction ); + LUA->SetTable( -3 ); // `_G.TestFunction = MyExampleFunction` + + return 0; +} + +GMOD_MODULE_CLOSE() { + return 0; +} + +