Adding Lua: Difference between revisions
No edit summary |
|||
Line 208: | Line 208: | ||
Now place the lua lib into the src/lib folder. And you should be able to compile and now have a working Lua. | 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: | |||
<pre> | |||
void CGELUAGamePlay::PostRoundBegin() | |||
{ | |||
if (m_bLuaLoaded) | |||
{ | |||
lua_getglobal(GetLua(), "RoundStart"); | |||
CallLUA(GetLua(), 0, 0, 0, "RoundStart"); | |||
} | |||
} | |||
</pre> | |||
[[Category:Programming]] | [[Category:Programming]] |
Revision as of 06:10, 14 June 2009
Adding Lua to Source SDK is quite easy and setting up multiple instances is even easier.
First think you need to do is download the two source files and add them to your project:
http://developer.valvesoftware.com/wiki/LuaManager_CPP
http://developer.valvesoftware.com/wiki/LuaManager_H
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 700)
#ifdef GE_LUA // Start LUA GELua()->InitDll(); #endif
And in the DLLShutdown function add this:
#ifdef GE_LUA // Shutdown LUA, close all open gameplays GELua()->ShutdownDll(); #endif
Also make sure you include the manager header file up the top:
#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 inherets from LuaHandle and provides functionality for InitDll, Shutdown, RegFunctions and RegGlobals.
InitDll
InitDll gets called after Lua gets init and thus provides the best place to load your script.
void MyLuaHandle::InitDll() { 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) { SetState( GAMESTATE_NONE ); 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 gameplay, no gameplay in effect!\n"); return; } CallLUA(GetLua(), 0, LUA_MULTRET, 0, luaFile ); m_bLuaLoaded = true; }
Shutdown
Shutdown handles the shuting 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.
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.
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.
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:
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:
MyLuaHandle::MyLuaHandle() { g_GamePlay = 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:
// 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, mines 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:
void CGELUAGamePlay::PostRoundBegin() { if (m_bLuaLoaded) { lua_getglobal(GetLua(), "RoundStart"); CallLUA(GetLua(), 0, 0, 0, "RoundStart"); } }