Enums unter LUA
-
Hallo!
Hab schon versucht meine Frage im LUA-Forum zu stellen, aber da ist nicht so viel los.. dehsalb versuch ichs hier.
Ich möchte gerne Enums und consts unter C++ und in der .lua-Datei benutzen, dazu hab ich das tutorial hier gefunden, aber das geht nicht so ganz:
http://lua-users.org/wiki/BindingEnumsToLuaMein Code sieht so aus:
#define LUA_ENUM(L, name, val) \ lua_pushlstring(L, #name, sizeof(#name)-1); \ lua_pushnumber(L, val); \ lua_settable(L, -3); void RegisterLuaEnums() { lua_newtable(g_LS); { LUA_ENUM(g_LS, "WPN_NONE", WPN_NONE); // und noch weitere enums ... } } int scGetEnumValue(lua_State* L, int argno) { int e; lua_pushvalue(L, argno); lua_gettable(L, lua_upvalueindex(1)); // hier kommt ein Fehler e = lua_tonumber(L, -1); lua_pop(L, 1); return e; } // die testfunktion, mit lua_register auf "en" definiert int t(lua_State* L) { cout << scGetEnumValue(L, 1); lua_settop(L, 0); return 0; }
Und so sieht die lua-datei aus:
function InitDM() g_DMStart = GetTime(); g_LastASCreated = GetTime(); en("WPN_LASER"); end
Wenn ich jetzt en("...") aufrufe, dann kommt der fehler in der oben markierten zeile:
Unbehandelte Ausnahme bei 0x00431a83 in DixTrek.exe: 0xC0000005: Zugriffsverletzung-Leseposition 0x00000000.
Mehr kann ich nicht rausholen, ich komm nicht in die Funktion, hab nur die release-lib eingebundenKann mir jemand helfen, wie man das richtig machen muss?
Ich kenn mich nicht so gut mit tabellen und so unter lua aus, ich kann nur funktionen binden und lua bzw. c funktionen untereinander mit parametern aufrufen, aber es wär nich schlecht, als parameter auch enums zu übergeben, sonst muss ich immer gucken, welche Enum welchen WertIch hoffe, ihr könnt mir helfen, Gruß, Maxi
-
Bei mir sieht das so aus:
lua.newTable(); // Ein paar andere Sachen, Funktionen registrieren... lua.pushString("normal"); lua.pushNumber(0); lua.rawSetTable(-3); lua.pushString("italic"); lua.pushNumber(1); lua.rawSetTable(-3); lua.pushString("bold"); lua.pushNumber(2); lua.rawSetTable(-3); lua.pushString("underlined"); lua.pushNumber(4); lua.rawSetTable(-3);
In Lua kann ich die dann z.B. so benutzen:
report:SetFont("Arial", 10, report.bold + report.italic);
lua ist ein Object der Klasse CXLua. Das ist bei mir eine Klasse, die das Lua-API-Kapselt. Die verwendeten Funktionen sehen so aus:
void CXLua::newTable () { lua_newtable(m_luaState); } void CXLua::pushString (const std::string& str) { lua_pushlstring(m_luaState, str.c_str(), str.size()); } void CXLua::pushNumber (double number) { lua_pushnumber(m_luaState, number); } void CXLua::rawSetTable (int index) { lua_rawset(m_luaState, index); }
Ich verwende Lua 4
-
Ich weis zwar nicht, wie das mit Enums unter LUA geht, aber ich kann dir sagen, was da schief geht:
Die Funktion lua_upvalueindex kann nur von einer Funktion aufgerufen werden, die vorher als C Closure definiert wurde und das machst du nirgends (geht mit lua_pushcclosure). Ich leg dir mal folgendes Kapitel ans Herz:
-
@frenki: Das sieht schonmal ganz gut aus, aber muss man denn lua nicht noch irgendwie sagen, das die tabelle "report" heißt oder so? Sonst weiß lua doch gar nicht, was report ist, oder?
@flofri: Ich werds mir heute nachmittag mal anschauen, wie das gehen könnte
-
Ja, natürlich muss man die Table einer Variablen zuweisen.
Ich habe das bei mir so gamcht, das ich für jede meiner C++ Klassen, die ich in Lua zur Verfügung stellen will, eine Lua-Table erstelle. Dazu gibt es dann eine Art Konstruktor, der diese Table liefert.
Das sieht dann z.B. ungefähr so aus:
report = Report("MyReport.rep"); -- "Kontruktor"-Aufruf. Liefert die Lua-Table. report:SetPageSize(21.0, 29.7); -- Funktionen der Table benutzen. report:SetMargins(2.0, 1.5, 1.5, 2.0); sql = Sql("select blah from laber"); -- Anderer Konstruktor while sql:HasData() do -- und wieder die Member-Funktionen AKA Table-Funktionen doSomethingWithRecord(sql); sql:Fetch(); -- Verwenden. end
Das hat für mich den Vorteil, dass ich unter Lua dieselbe Schnittstelle zu den Klassen habe wie in den C++ Klassen. Also keine umgewöhnung
Der Code da oben, ist also aus meinen "Konatruktor" für die Lua-Table, die das eigentliche C++ Objekt repräsentiert. Die Lua-Table bekommt einen Zeiger auf das C++ Objekt gespeichert. Damit mir niemand diesen Zeiger von einem Script aus überschreiben kann, ist er durch eine Tag-Methode geschützt.
-
danke schön, jetzt klappts bei mir auch wunderbar.
Wieviele enums kann lua eigentlich zumuten, und wieviele registrierte funktionen kann lua vertragen, ohne dass die performance in den keller rutscht?
wie isn das bei Baldurs gate oder so, wieviele funktionen kann da das script aufrufen?
-
Es gibt keine Begrenzung. Du kannst soviele Funktionen, enums, whatever speichern, wie du Speicher hast
Eine Lua-Table ist ja einfach nur eine Hash-Table. Es spielt also für die Performance keine grosse Rolle, wieviele Funktionen du registrierst. Ein Funktionsaufruf ist immer nur ein Lookup in die Hash-Table.
Natürlich kostet das Registrieren der Funktionen selbst Zeit. Vor allem, wenn man das so wie ich macht, und für jedes Objekt eine Tabelle erstellt, weil man dort ja die Funktionen für jede Tabelle (also bei jedem "Konstruktor"-Aufruf) neu registrieren muss. Darum benutze ich hier eine eigene Statische Hash-Map und benutze die Tag-Methode GetTable um die Funktionen selbst zu liefern. Das spart mir das ständige neu Registrieren der immerselben Funktionen. Funktionsadressen ändern sich zur Laufzeit des Programmens schliesslich nicht