Adding Lua
Lua zu Source hinzuzufügen ist ziemlich einfach und mehrere Instanzen einzurichten ist noch einfacher.
Quellcode
Füge diese beiden Datein zu deinem Projekt hinzu:
Lua initialisieren
Sobald das erledigt ist, muss dein Code die init- und shutdown-Funktionen aufrufen. Füge in gameinterface.cpp dies in DLLInit vor den return true ein (um Zeile 557):
#ifdef GE_LUA
// LUA starten
GELua()->InitDll();
#endif
Und in der DLLShutdown-Funktion dies:
#ifdef GE_LUA
// LUA dtoppen, schließt alle offenen Gameplays
GELua()->ShutdownDll();
#endif
Gehe außerdem sicher, dden Manager-Header am Anfang einzubinden:
#ifdef GE_LUA
#include "ge_luamanager.h"
#endif
Eine eigene Lua-Instanz erstellen
Du musst eine eigene Klasse erzeugen, die von LuaHandle abgeleitet ist und Funktionalität für Init, Shutdown und RegFunctions und RegGlobals bereitstellt.
Initialisierung
Init wird aufgerufen, nachdem Lua initialisiert wurde und stellt somit die Beste Stelle zum Laden der Skripte dar.
void MyLuaHandle::Init()
{
const char* luaFile = "myLuaFile.lua";
// In den Puffer laden
FileHandle_t f = filesystem->Open( luaFile, "rb", "MOD" );
if (!f)
return;
// Datei in null-terminierten Puffer laden
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 ); // in lokalen Puffer lesen
buffer[fileSize] = '\0'; // terminieren der Datei
filesystem->Close( f ); // Schließen der Datei nach dem Lesevorgang
int error = luaL_loadbuffer( GetLua(), buffer, fileSize, luaFile );
if (error)
{
Warning("[LUA-ERR] %s\n", lua_tostring(GetLua(), -1));
lua_pop(GetLua(), 1); /* Fehlermeldung vom Stack abholen */
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 handhabt das Beenden Luas und sollte Funktionen in den Scripten aufrufen, um diese zu beenden.
RegGlobals
RegGlobals erlaubt es, globale Variablen in Lua zu registrieren.
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);
// Teamindikatoren
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-Typen
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);
}
Die gebotenen Macros erlauben auch verschiedene Typen. LG_DEFINE_INT für int, LG_DEFINE_STRING für string und LG_DEFINE_BOOL für boolean.
RegFunctions
Wie die Globalen ist RegFunctions das Mittel zum Bekanntmachen der C-Funktionen für Lua.
void MyLuaHandle::RegFunctions()
{
REG_FUNCTION( Msg );
REG_FUNCTION( ConMsg );
REG_FUNCTION( ClientPrintAll );
REG_FUNCTION( GetTime );
}
Auch dies wurde mit einem Makro abgekürzt. Und somit müssen die Funktionen in einer anderen Datei definiert werden.
extern "C"
{
#include <lua.h>
#include <lauxlib.h>
#include <lualib.h>
}
int luaClientPrintAll(lua_State *L)
{
int n = lua_gettop(L); /* Anzahl der Argumente */
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;
}
Die Instanz erzeugen
Am Anfang deiner neuen LuaHandle-Klasse musst du eine Funktion hinzugefügen, die einen globalen Zugriff auf die Lua-Instanz ermöglicht. Füge ungefähr sowas hinzu:
MyLuaHandle* g_LuaHandle = NULL;
MyLuaHandle *GetLuaHandle()
{
return g_LuaHandle;
}
Und im LuaHandle-Konstruktor musst die Instanz bei der Erzeugung gespeichert werden:
MyLuaHandle::MyLuaHandle() : LuaHandle()
{
g_LuaHandle = this;
Register();
}
Und letztendlich muss im GameRules-Konstruktor die neue Instanz erzeugt werden:
CGameRules::CGameRules()
{
// anderes Zeug hier
// die Lua GamePlay-Engine starten
if (!GetLuaHandle())
new MyLuaHandle();
}
Projekteinstellungen
In den Serverprojekteinstellungen muss GE_LUA den Präprozessoroptionen hinzugefügt werden (Configure properties -> c++ -> Preprocesser -> Preprocesser defines). Außerdem musst du die Lua-lib (sollte den gleichen Namen wie die lib-Datei haben, z. B. lua5.1.lib) den Linker-Einstellungen hinzufügen (Configure properties -> Linker -> Input -> Additional Dependencies )
Platziere die Lua-lib nun im src/lib-Verzeichnis. Nun sollte es kompilieren und du ein funktionierendes Lua haben.
Aufrufe von C zu Lua
Das ist etwas schwieriger und du must die Lua Dokumentation dafür konsultieren, aber hier ist ein Beispiel:
void CGELUAGamePlay::PostRoundBegin()
{
if (m_bLuaLoaded)
{
lua_getglobal(GetLua(), "RoundStart");
CallLUA(GetLua(), 0, 0, 0, "RoundStart");
}
}