[LUA Api] Eigene Userdata

Cromon

Erfahrenes Mitglied
Hallo zusammen!

Zuerst einmal vorneweg: Ich entschuldige mich, wenn meine Fragestellung vielleicht etwas verworren ist, das liegt wohl daran, dass mir selbst noch nicht ganz alles klar ist ;)

Wie der Titel schon andeutet arbeite ich gerade in meiner Applikation an einer Schnittstelle für LUA-Dateien. Ich habe da auch schon ein paar Sachen gemacht, scheitere jedoch an einem Punkt. Ich erläutere das am besten mal anhand eines abstrakten Beispiels.

Wenn sich ein Spieler bewegt und in ein anderes Gebiet kommt, so wird in meinem HookManager nach Funktionen gesucht, die registriert wurden und aufgerufen werden sollen, wenn oben genanntes Ereignis eintritt. In den Schnittstellen für die in C++ geschriebenen DLLs funktioniert das einwandfrei, bei den LUA-Dateien hapert es noch etwas.

Was bereits einwandfrei funktioniert sind die Funktion um einen Hook zu registrieren, dies geschieht dann im Luascript mit RegisterHook(typ, "Funktionsname").

Der erste Versuch war es nun dass dem Script nur die Areaid übergeben wird, das hat soweit geklappt dann mit folgendem Aufruf:
Code:
void LuaHookMgr::OnAreaChanged(ui32 areaid, Player* plr)
{
	list<string>::iterator itr = m_functions[ON_AREA_CHANGED].begin();
	list<string>::iterator end = m_functions[ON_AREA_CHANGED].end();

	for( ; itr != end; ++itr)
	{
		lua_getfield(state, LUA_GLOBALSINDEX, (*itr).c_str());
		if(lua_isnil(state, -1))
		{
			Log->Warning("LuaEngine", "Tried to call undefined hookfunction '%s'", (*itr).c_str());
			continue;
		}
		lua_pushinteger(state, areaid);
		lua_call(state, 1, 0);
	}
}

Und als Beispiel-LUAdatei:
Code:
function AreaChanged(areaid)
	if(areaid ~= 0) then
		print(areaid)
	end
end

RegisterHook(4, "AreaChanged")

Soweit war ich schonmal ganz zufrieden, allerdings fehlt mir da noch etwas. Ich habe bewusst 2 Parameter bei OnAreaChanged und die möchte ich eigentlich auch beide an das LUA-Script übergeben. Oder anders gesagt, ich möchte dem LUA-Script die Möglichkeit geben mit Player zu interagieren. Hier funktioniert aber etwas bei mir nicht.

Ich habe das folgende versucht:
Code:
void LuaHookMgr::OnAreaChanged(ui32 areaid, Player* plr)
{
	list<string>::iterator itr = m_functions[ON_AREA_CHANGED].begin();
	list<string>::iterator end = m_functions[ON_AREA_CHANGED].end();

	LPlayer* lp = (LPlayer*)lua_newuserdata(state, sizeof(LPlayer));
	lp->origplr = plr;

	for( ; itr != end; ++itr)
	{
		lua_getfield(state, LUA_GLOBALSINDEX, (*itr).c_str());
		if(lua_isnil(state, -1))
		{
			Log->Warning("LuaEngine", "Tried to call undefined hookfunction '%s'", (*itr).c_str());
			continue;
		}
		lua_pushlightuserdata(state, lp);
		lua_pushinteger(state, areaid);
		lua_call(state, 1, 0);
	}
}

Ausserdem habe ich noch eine lua_lib gemacht (sagt man dem so?), die folgendermassen aussieht und auch geladen wird:
Code:
static luaL_reg playerLibs[] = 
{
	{ "broadcast", PlayerBroadcast },
	{ 0, 0},
};

Mit der Funktion PlayerBroadcast:
Code:
int PlayerBroadcast(lua_State* st)
{
	LPlayer* lp = (LPlayer*)lua_touserdata(st, 1);
	if(lp && lp->origplr)
	{
		if(lua_isstring(st, 2))
			lp->origplr->BlueSystemMessage(lua_tostring(st, 2));
	}
	return 0;
}

Wenn ich dann allerdings folgendes Script verwende, erhalte ich einen Panic-Error, dass ich versucht hätte etwas vom Typ "userdata" zu indizieren:
Code:
function AreaChanged(plr, areaid)
	if(areaid ~= 0) then
		Player.Broadcast(plr, areaid)
	end
end

RegisterHook(4, "AreaChanged")

Ich habe mittlerweile stundenlang in der Referenz der LUA-C-API verbracht aber ich bring es beim besten Willen nicht fertig dem Script sozusagen eine Variable eigenen Typs zu übergeben mit der ich dann später weiterarbeiten kann!

Mit besten Grüssen
Cromon
 
Hallo!

Was genau meinst du mit "bekannt gemacht"? Ich habe grundsätzlich einfach folgende Aktion durchgeführt:
Code:
luaL_openlib(l, "Player", playerLibs, 0);

Dein erster Link sieht sehr interessant aus, das werde ich mir mal genauer anschauen, danke dafür!

Gruss
Cromon
 
Ah, wunderbar, alles erleigt und geklappt!

Wenn ich das mal so etwas plump sagen darf: Echt n'fettes Dankeschön für den tollen Link mit luabind!

Mit der Library geht das wirklich wunderbar!

Code:
void LuaHookMgr::OnAreaChanged(ui32 areaid, Player* plr)
{
	list<string>::iterator itr = m_functions[ON_AREA_CHANGED].begin();
	list<string>::iterator end = m_functions[ON_AREA_CHANGED].end();

	LPlayer* lp = (LPlayer*)lua_newuserdata(state, sizeof(LPlayer));
	lp->origplr = plr;

	for( ; itr != end; ++itr)
	{
		luabind::call_function<Player>(state, (*itr).c_str(), *plr, areaid);
	}
}

Und die Registrierung:
Code:
	luabind::open(l);
	module(l)
	[
		class_<Player>("Player")
		.def(constructor<ui64>())
		.def("Broadcast", &PlayerBroadcast)
	];
 
Ah, wunderbar, alles erleigt und geklappt!

Wenn ich das mal so etwas plump sagen darf: Echt n'fettes Dankeschön für den tollen Link mit luabind!
Gut zu hören, keine Ursache. :)

Ich selbst hab mit luabind noch nichts gemacht, nur mit Swig (weil ich da nicht soviel selbst schreiben muss und meinen C++ Code auch sehr einfach in anderen Sprachen nutzen kann).

Gruß
 
Zurück