Adding Lua: Difference between revisions

From Valve Developer Community
Jump to navigation Jump to search
mNo edit summary
mNo edit summary
Line 16: Line 16:
Once that is done you will need to make sure your game code calls the init and shutdown functions. In gameinterface.cpp add this into DLLInit before the return true statement (around line 557):
Once that is done you will need to make sure your game code calls the init and shutdown functions. In gameinterface.cpp add this into DLLInit before the return true statement (around line 557):


<source lang=cpp>
{{CodeBlock|lang=cpp|<nowiki>#ifdef GE_LUA
#ifdef GE_LUA
// Start LUA
// Start LUA
GELua()->InitDll();
GELua()->InitDll();
#endif
#endif</nowiki>}}
</source>


And in the DLLShutdown function add this:
And in the DLLShutdown function add this:


<source lang=cpp>
{{CodeBlock|lang=cpp|<nowiki>#ifdef GE_LUA
#ifdef GE_LUA
// Shutdown LUA, close all open gameplays
// Shutdown LUA, close all open gameplays
GELua()->ShutdownDll();
GELua()->ShutdownDll();
#endif
#endif</nowiki>
</source>
}}


Also make sure you include the manager header file up the top:
Also make sure you include the manager header file up the top:


<source lang=cpp>
{{CodeBlock|lang=cpp|<nowiki>#ifdef GE_LUA
#ifdef GE_LUA
#include "ge_luamanager.h"
#include "ge_luamanager.h"
#endif
#endif</nowiki>
</source>
}}


== Making Your own Lua Instance ==
== Making Your own Lua Instance ==
Line 48: Line 44:
Init gets called after Lua gets init and thus provides the best place to load your script.
Init gets called after Lua gets init and thus provides the best place to load your script.


<source lang=cpp>
{{CodeBlock|lang=cpp|<nowiki>
void MyLuaHandle::Init()
void MyLuaHandle::Init()
{
{
Line 79: Line 75:
CallLUA(GetLua(), 0, LUA_MULTRET, 0, luaFile );
CallLUA(GetLua(), 0, LUA_MULTRET, 0, luaFile );
m_bLuaLoaded = true;
m_bLuaLoaded = true;
}
}</nowiki>
</source>
}}


=== Shutdown ===
=== Shutdown ===
Line 90: Line 86:
RegGlobals allows us to register global variables in lua.
RegGlobals allows us to register global variables in lua.


<source lang=cpp>
{{CodeBlock|lang=cpp|<nowiki>
void MyLuaHandle::RegGlobals()
void MyLuaHandle::RegGlobals()
{
{
Line 112: Line 108:
LG_DEFINE_INT("HUD_PRINTCENTER",HUD_PRINTCENTER);
LG_DEFINE_INT("HUD_PRINTCENTER",HUD_PRINTCENTER);
}
}
</source>
</nowiki>}}


Macros provided allow for different types as well. LG_DEFINE_INT for int, LG_DEFINE_STRING for string and LG_DEFINE_BOOL for boolean.
Macros provided allow for different types as well. LG_DEFINE_INT for int, LG_DEFINE_STRING for string and LG_DEFINE_BOOL for boolean.
Line 120: Line 116:
Like Globals, RegFunctions is where you put all the c functions you want to expose to Lua.
Like Globals, RegFunctions is where you put all the c functions you want to expose to Lua.


<source lang=cpp>
{{CodeBlock|lang=cpp|<nowiki>
void MyLuaHandle::RegFunctions()
void MyLuaHandle::RegFunctions()
{
{
Line 128: Line 124:
REG_FUNCTION( GetTime );
REG_FUNCTION( GetTime );
}
}
</source>
</nowiki>}}


Again this has been shorten using a macro. And thus you will need to define this functions in another file.
Again this has been shorten using a macro. And thus you will need to define this functions in another file.


<source lang=cpp>
{{CodeBlock|lang=cpp|<nowiki>
extern "C"
extern "C"
{
{
Line 180: Line 176:
return 1;
return 1;
}
}
</source>
</nowiki>}}


Note: The function name must be the same as the one used in the macro with lua infront.
Note: The function name must be the same as the one used in the macro with lua infront.
Line 188: Line 184:
On the top of your new LuaHandle class you need to add a function allowing global access to your Lua instance. Add something like this:
On the top of your new LuaHandle class you need to add a function allowing global access to your Lua instance. Add something like this:


<source lang=cpp>
{{CodeBlock|lang=cpp|<nowiki>
MyLuaHandle* g_LuaHandle = NULL;
MyLuaHandle* g_LuaHandle = NULL;
MyLuaHandle *GetLuaHandle()
MyLuaHandle *GetLuaHandle()
Line 194: Line 190:
return g_LuaHandle;
return g_LuaHandle;
}
}
</source>
</nowiki>}}


And in your constructor of your LuaHandle add a call to set the instance when you make a new one:
And in your constructor of your LuaHandle add a call to set the instance when you make a new one:
<source lang=cpp>
{{CodeBlock|lang=cpp|<nowiki>
MyLuaHandle::MyLuaHandle() : LuaHandle()
MyLuaHandle::MyLuaHandle() : LuaHandle()
{
{
Line 203: Line 199:
Register();
Register();
}
}
</source>
</nowiki>}}


Note: Its important to have Register here other wise it wont work!
Note: Its important to have Register here other wise it wont work!


And finally in your game rules constructor make a new LuaHandle:
And finally in your game rules constructor make a new LuaHandle:
<source lang=cpp>
{{CodeBlock|lang=cpp|<nowiki>
CGameRules::CGameRules()
CGameRules::CGameRules()
{
{
Line 218: Line 214:
new MyLuaHandle();
new MyLuaHandle();
}
}
</source>
</nowiki>}}


== Project Settings ==
== Project Settings ==
Line 233: Line 229:
This is a bit harder and you will need to consult the lua documents for this but here is an example on how ges does it:
This is a bit harder and you will need to consult the lua documents for this but here is an example on how ges does it:


<source lang=cpp>
{{CodeBlock|lang=cpp|<nowiki>
void CGELUAGamePlay::PostRoundBegin()
void CGELUAGamePlay::PostRoundBegin()
{
{
Line 242: Line 238:
}
}
}
}
</source>
</nowiki>}}

Revision as of 17:27, 18 July 2023

English (en)Deutsch (de)Русский (ru)中文 (zh)Translate (Translate)

Stub

This article or section is a stub. You can help by expanding it.

Adding Lua Lua to Source Source is quite easy, and setting up multiple instances is even easier.

Source

Add these two source files to your project:

Init Lua

Once that is done you will need to make sure your game code calls the init and shutdown functions. In gameinterface.cpp add this into DLLInit before the return true statement (around line 557):

The source was not specified
C++
#ifdef GE_LUA // Start LUA GELua()->InitDll(); #endif

And in the DLLShutdown function add this:

The source was not specified
C++
#ifdef GE_LUA // Shutdown LUA, close all open gameplays GELua()->ShutdownDll(); #endif

Also make sure you include the manager header file up the top:

The source was not specified
C++
#ifdef GE_LUA #include "ge_luamanager.h" #endif

Making Your own Lua Instance

Now this is the fun part, making your own lua instance. You will need to make your own class that inherits from LuaHandle and provides functionality for Init, Shutdown, RegFunctions and RegGlobals.

Init

Init gets called after Lua gets init and thus provides the best place to load your script.

The source was not specified
C++
void MyLuaHandle::Init() { const char* luaFile = "myLuaFile.lua"; //Load into buffer FileHandle_t f = filesystem->Open( luaFile, "rb", "MOD" ); if (!f) return; // load file into a null-terminated buffer int fileSize = filesystem->Size(f); unsigned bufSize = ((IFileSystem *)filesystem)->GetOptimalReadSize( f, fileSize + 1 ); char *buffer = (char*)((IFileSystem *)filesystem)->AllocOptimalReadBuffer( f, bufSize ); Assert(buffer); ((IFileSystem *)filesystem)->ReadEx( buffer, bufSize, fileSize, f ); // read into local buffer buffer[fileSize] = '\0'; // null terminate file as EOF filesystem->Close( f ); // close file after reading int error = luaL_loadbuffer( GetLua(), buffer, fileSize, luaFile ); if (error) { Warning("[LUA-ERR] %s\n", lua_tostring(GetLua(), -1)); lua_pop(GetLua(), 1); /* pop error message from the stack */ Warning("[LUA-ERR] One or more errors occured while loading lua script!\n"); return; } CallLUA(GetLua(), 0, LUA_MULTRET, 0, luaFile ); m_bLuaLoaded = true; }

Shutdown

Shutdown handles the shutting down of Lua and should do things in here like call shutdown functions in your script.

RegGlobals

RegGlobals allows us to register global variables in lua.

The source was not specified
C++
void MyLuaHandle::RegGlobals() { LG_DEFINE_INT("FOR_ALL_PLAYERS", -1); LG_DEFINE_INT("INVALID_ENTITY", -1); LG_DEFINE_INT("NULL", 0); LG_DEFINE_INT("GE_MAX_HEALTH", MAX_HEALTH); LG_DEFINE_INT("GE_MAX_ARMOR", MAX_ARMOR); LG_DEFINE_INT("MAX_PLAYERS", gpGlobals->maxClients); //Team Indices LG_DEFINE_INT("TEAM_NONE",TEAM_UNASSIGNED); LG_DEFINE_INT("TEAM_SPECTATOR",TEAM_SPECTATOR); LG_DEFINE_INT("TEAM_MI6",TEAM_MI6); LG_DEFINE_INT("TEAM_JANUS",TEAM_JANUS); //ClientPrintAll Types LG_DEFINE_INT("HUD_PRINTNOTIFY",HUD_PRINTNOTIFY); LG_DEFINE_INT("HUD_PRINTCONSOLE",HUD_PRINTCONSOLE); LG_DEFINE_INT("HUD_PRINTTALK",HUD_PRINTTALK); LG_DEFINE_INT("HUD_PRINTCENTER",HUD_PRINTCENTER); }

Macros provided allow for different types as well. LG_DEFINE_INT for int, LG_DEFINE_STRING for string and LG_DEFINE_BOOL for boolean.

RegFunctions

Like Globals, RegFunctions is where you put all the c functions you want to expose to Lua.

The source was not specified
C++
void MyLuaHandle::RegFunctions() { REG_FUNCTION( Msg ); REG_FUNCTION( ConMsg ); REG_FUNCTION( ClientPrintAll ); REG_FUNCTION( GetTime ); }

Again this has been shorten using a macro. And thus you will need to define this functions in another file.

The source was not specified
C++
extern "C" { #include <lua.h> #include <lauxlib.h> #include <lualib.h> } int luaClientPrintAll(lua_State *L) { int n = lua_gettop(L); /* number of arguments */ switch(n) { case 2: UTIL_ClientPrintAll( lua_tointeger(L,1), lua_tostring(L,2)); break; case 3: UTIL_ClientPrintAll( lua_tointeger(L,1), lua_tostring(L,2),lua_tostring(L,3)); break; case 4: UTIL_ClientPrintAll( lua_tointeger(L,1), lua_tostring(L,2),lua_tostring(L,3),lua_tostring(L,4)); break; case 5: UTIL_ClientPrintAll( lua_tointeger(L,1), lua_tostring(L,2),lua_tostring(L,3),lua_tostring(L,4),lua_tostring(L,5)); break; case 6: UTIL_ClientPrintAll( lua_tointeger(L,1), lua_tostring(L,2),lua_tostring(L,3),lua_tostring(L,4),lua_tostring(L,5),lua_tostring(L,6)); break; } return 0; } int luaMsg(lua_State *L) { Msg("%s\n",lua_tostring(L,1)); return 0; } int luaConMsg(lua_State *L) { return luaMsg(L); } int luaGetTime(lua_State *L) { lua_pushnumber( L, gpGlobals->curtime ); return 1; }

Note: The function name must be the same as the one used in the macro with lua infront.

Creating The Instance

On the top of your new LuaHandle class you need to add a function allowing global access to your Lua instance. Add something like this:

The source was not specified
C++
MyLuaHandle* g_LuaHandle = NULL; MyLuaHandle *GetLuaHandle() { return g_LuaHandle; }

And in your constructor of your LuaHandle add a call to set the instance when you make a new one:

The source was not specified
C++
MyLuaHandle::MyLuaHandle() : LuaHandle() { g_LuaHandle = this; Register(); }

Note: Its important to have Register here other wise it wont work!

And finally in your game rules constructor make a new LuaHandle:

The source was not specified
C++
CGameRules::CGameRules() { //other stuff here // Start our LUA GamePlay Engine if (!GetLuaHandle()) new MyLuaHandle(); }

Project Settings

In the server project settings you need to add GE_LUA to the preprocesser options (Configure properties -> c++ -> Preprocesser -> Preprocesser defines). Also you will need to add the lua lib (should be the same name as the lib file, mine's lua5.1.lib) to the linker settings (Configure properties -> Linker -> Input -> Additional Dependencies )

Note: Make sure you do this for both release and debug.

Now place the lua lib into the src/lib folder. And you should be able to compile and now have a working Lua.

Creating Calls from c into Lua

This is a bit harder and you will need to consult the lua documents for this but here is an example on how ges does it:

The source was not specified
C++
void CGELUAGamePlay::PostRoundBegin() { if (m_bLuaLoaded) { lua_getglobal(GetLua(), "RoundStart"); CallLUA(GetLua(), 0, 0, 0, "RoundStart"); } }