Добавление Lua
Добавить Lua в Source очень просто, А создание несколько экземпляров ещё проще.
Contents
Исходники
Надо добавить два файла в ваш порект:
Инцализация
Теперь нужно сделают инициализацию и отключение lua. В gameinterface.cpp добавьте этот код в функции DLLInit перед return true строкой (557 строка):
#ifdef GE_LUA
// Start LUA
GELua()->InitDll();
#endif
И добавляем в функцию DLLShutdown:
#ifdef GE_LUA
// Shutdown LUA, close all open gameplays
GELua()->ShutdownDll();
#endif
Также убедитесь что вы подключение заголовочный файл.
#ifdef GE_LUA
#include "ge_luamanager.h"
#endif
Создаём Lua Экземпляр
Это самое интересная часть, создание lua экземпляра . Вам необходимо создать класс которые наследуется от LuaHandle и имеет функции Init, Shutdown, RegFunctions and RegGlobals.
Init
Init вызываетстся после инициализации Lua и таким образом это лучшее место для загрузки скрипта.
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 тут обрабатывается завершение lua.
RegGlobals
RegGlobals регистрирует глобальные переменные 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
Как и Globals, RegFunctions здесь все C функции которые вы хотите что бы работали в 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.
Создания экземпляра
Вверху нового LuaHandle класса вам нужно добавить функцию добавляющий доступ к Lua экземпляру. Типа этого:
MyLuaHandle* g_LuaHandle = NULL;
MyLuaHandle *GetLuaHandle()
{
return g_LuaHandle;
}
И в конструкторе твоего LuaHandle добавить вызов экземпляра :
MyLuaHandle::MyLuaHandle() : LuaHandle()
{
g_LuaHandle = this;
Register();
}
Note: Its important to have Register here other wise it wont work! И наконец в вашем game rules создать новый LuaHandle:
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, 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");
}
}