Adding Lua

From Valve Developer Community
< De
Jump to navigation Jump to search
English (en)Deutsch (de)Русский (ru)中文 (zh)Translate (Translate)

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;
}
Note.pngHinweis:Der Funktionsname muss dem Namen entsprechen, der im Macro mit lua infront verwendet wird.

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();
}
Note.pngHinweis:Es ist wichtig, Register hier zu haben, da es sonst nicht funktioniert!

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 )

Note.pngHinweis:Gehe sicher, dass du dies für Release und Debug machst.

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");
	}
}