LuaDatei->ApplicationsFunktion->Luafunktion->ApplicationsFunktion=Fehler
-
Hi,
Vorweg: Ich benutze Lua (5.0)
Ich habe es erfolgreich umgesetzt, dass ich eine LuaDatei(Beispiel.lua) ausführen kann, die wiederrum die ApplicationsFunktion DoLuaFunctionBeispiel [in Lua heißt sie Start()] aufruft, die mit Hilfe meines selbstegeschriebenen LuaManagers die LuaFunktion Testfunktion(a,b,c,d,e) aufruft.
Doch dann wollte ich aus meiner Testfunktion heraus die Applications-Funktion play aufrufen, doch das funktioniert nicht.
Also nochmal:
LuaDatei[Beispiel.lua] ->
DoLuaFunctionBeispiel ->
LuaFunktion Testfunktion [in Media/Scripts/Sounds/Funktion.lua] ->
Play = error in lua_pcallBeispiel.lua
Play ("Ich","werde","ausgefuehrt"); Start();Die Applications-Funktion Play führe ich auch hier aus, um zu verdeutlichen, dass die Applications-Funktion Play generell funktioniert.
DoLuaFunctionBeispiel
int UMLua_Sounds::DoLuaFunctionBeispiel( lua_State* L ) { std::vector<float> numberV; numberV.push_back(100); numberV.push_back(200); numberV.push_back(400); std::vector<bool> boolV; boolV.push_back(true); std::vector<std::string> stringV; stringV.push_back("Stringeling"); LuaMgr.DoFunction("Testfunktion","Media/Scripts/Sounds/Funktion.lua",L, 5,numberV,boolV,stringV); // Schiebt die Results nach oben auf den Stack! std::string NewString = LuaMgr.getStringParameter(L,1); float NewFloat = LuaMgr.getFloatParameter(L,2); float NewFloat2 = LuaMgr.getFloatParameter(L,3); bool NewBool = LuaMgr.getBoolParameter(L,4); std::string NewString2 = LuaMgr.getStringParameter(L,5); std::cout << "Der zurueckgegebene String: " << NewString << " und die zurueckgegebende Zahl: " << NewFloat << "\n"; std::cout << "und die zurueckgegebende Zahl2: " << NewFloat2 << " und der zurückgegebene Bool: " << NewBool << "\n"; std::cout << "Der zurueckgegebene String2: " << NewString2; return 0; }LuaMgr.DoFunction
/* Führt eine LuaFunktion aus. Die Results werden auf den Stack gepusht und können mit get*Parameter abgerufen werden.*/ void UMLuaManager::DoFunction (std::string FunctionName, std::string FilenameANDroot, lua_State* RealL, int Results, std::vector<float> NumberV, std::vector<bool> BoolV, std::vector<std::string> StringV) { lua_State *L = lua_open(); luaopen_base(L); luaopen_io(L); luaopen_string(L); luaopen_math(L); int Parameter = 0; std::vector<float>::iterator iF; std::vector<bool>::iterator iB; std::vector<std::string>::iterator iS; if (luaL_loadfile(L, FilenameANDroot.c_str()) || lua_pcall(L, 0, 0, 0)) { lua_close(L); } lua_getglobal(L, FunctionName.c_str()); for(iF=NumberV.begin();iF<NumberV.end();iF++) { lua_pushnumber(L, (*iF)); Parameter++; } for(iB=BoolV.begin();iB<BoolV.end();iB++) { lua_pushboolean(L, (*iB)); Parameter++; } for(iS=StringV.begin();iS<StringV.end();iS++) { lua_pushstring(L, (*iS).c_str()); Parameter++; } [i] if (lua_pcall(L, Parameter, Results, 0) != 0) { std::string Error = lua_tostring(L,lua_gettop( L )); std::cout << Error << std::endl ; lua_close(L); return; }[/i] for (int i=0;i<Results;i++) { if (lua_isnumber(L,lua_gettop( L ) -Results +1 +i)) { float Number = lua_tonumber(L,lua_gettop( L ) -Results +1 +i); lua_pushnumber(RealL,Number); } else if (lua_isboolean(L,lua_gettop( L ) -Results +1 +i)) { bool Boolean = lua_toboolean(L,lua_gettop( L ) -Results +1 +i); lua_pushboolean(RealL,Boolean); } else if (lua_isstring(L,lua_gettop( L ) -Results +1 +i)) { std::string Stringl = lua_tostring(L,lua_gettop( L ) -Results +1 +i); lua_pushstring(RealL,Stringl.c_str()); } else { return; } } lua_close(L); };Hier ist vorallem der if-block mit dem lua_pcall zu beachten. Wenn ich in der Lua-Funktion "Testfunktion" die Applications-Funktion Play aufrufe, dann wird der ifblock ausgeführt und gibt einen fehler aus.
Function.lua
function Testfunktion (a,b,c,d,e) [i]Play ("Ich","werde","ausgefuehrt");[/i] Wert1 = a+b+c; print (Wert1); if d == true then print(e) end Stringchen = "Teststring"; return Stringchen, 100, 666, true, "String123"; endBesonders zu beachten ist hier die Playzeile. Ohne den aufruf der Play-funktion funkioniert alles wunderbar. Mit Aufruf der Playfunktion, funktioniert lua_pcall nicht und gibt eine entsprechende Fehlermeldung aus.
Konsolenausgabe OHNE Play ("Ich","werde","ausgefuehrt");
Ich werde ausgeführt //Durch Play in Beispiel.lua 700 // Durch print(Wert1) in Function.lua Stringeling // Durch print(e) in Function.lua Der zurueckgegebene String: Teststring und die zurueckgegebene Zahl: 100 .... // Durch std::cout am Ende von DoLuaFunctionBeispielFunktioniert soweit also hervorragend^^
Doch jetzt:
Konsolenausgabe MIT Play ("Ich","werde","ausgefuehrt");
Ich werde ausgeführt //Durch Play in Beispiel.lua attempt to call global 'Play' (A nil value)Habe ich irgendetwas falsch gemacht, oder geht das einfach von Lua aus nicht? Wie löse ich mein Problem?
-
doch das geht von lua aus

Ich denke es liegt an folgendem: In Manager::DoFunction erstellst du ein neues Lua-Objekt. Diesem Lua-Objekt ist nur deine eine Datei bekannt, die du geladen hast. SOnst nichts, keine App-Funktionen und sowas. Dadurch kennt der neue Lua-State (also das L in DoFunction) keine Play-Funktion, weil sie nicht registriert wurde.
Lösung:
Dein Lua-Manager sollte einen member lua_State m_L haben, auf den alle Methoden zugreifen. Normalerweise braucht man nur einen lua_State pro programm. Was passiert, wenn du eine lua-Datei mehrmals lädst weiß ich nicht, aber du kannst ja selber noch intern checken, ob die datei mit der funktion bereits geladen wurde.Auf alle Fälle wichtig: Benutze nur ein lua_State-Objekt. Dann sollte es funktionieren.
-
Das werde ich probieren, danke

-
Ich hab gerade irgendwie das problem, dass ich nicht weiß, wie ich den parameter eine Applications-Funktion, die von Lua aufgerufen werden kann, meinem m_L zuweisen kann.
int UMLua_Sounds::DoLuaFunctionBeispiel( lua_State* L ) { lua_add(L,LuaMgr.M_L); }soetwas ähnliches schwebt mir vor, dass halt die Parameter vom "lua_State* L" auf mein M_L übertragen werden. Oder zumindest so ähnlich. Schließlich will ich doch nur ein einziges lua_State in meinem Programm.
Edit: Kann es sein, dass sich alle lua_States sich einen Stack teilen?^^ Ich hab in DoFunktion einfach ein paar sachen auf den m_L stack geschoben und ich konnte sie bei DoLuaFunctionBeispiel´s L einfach vom Stack holen...
Edit2: Ich kann jetzt von der Luafunktion die Applicationsfunktion aufrufen. Nochmals vielen dank :), aber trotzdem hätte ich noch gerne eine kleine Erläuterung dazu
-
du scheinst es glaub ich noch nicht richtig kapiert zu haben...
ALs Fausregel: In deinem Programm darf nur einmal lua_open() vorkommen. Mach es zB so, dass dein lua-manager ein singleton ist, der das lua_State kapselt. Alle die das dann brauchen kommen über die singleton instanz auf das L. Es ist nicht nötig, L als parameter zu übergeben, das L sollte sowieso überall gleich sein, kannst du also auch in einem manager oder billig in einer globalen variablen speichern, die in diesem falle nicht unbedingt hässlich sein muss.
-
Ich habs (eigentlich) schon kapiert, aber ich glaube, Applications-Funktionen, die von Lua aufgerufen werden sollen, MÜSSEN den parameter (lua_State* L) übergeben bekommen, da die funktion zum "anmelden" der App-Funktion (lua_pushcfunction) eine Funktion mit dem parameter (lua_State* L) braucht.
Aus den Untiefen des Lua-quellcodes geklaut:
#define lua_pushcfunction(L,f) lua_pushcclosure(L, f, 0) LUA_API void lua_pushcclosure (lua_State *L, lua_CFunction fn, int n) typedef int (*lua_CFunction) (lua_State *L);Ich habe es dennoch versucht und stoße auf den fehler:
'lua_pushcclosure': Konvertierung des Parameters 2 von 'int' in 'lua_CFunction' nicht möglichint UMLua_Sounds::DoLuaFunctionBeispiel() //Kein Parameter! { ... }LuaMgr.InitFunction( UMLua_Sounds::DoLuaFunctionBeispiel , "Start" );/*Meldet eine Funktion bei Lua an. 1 Parameter[C++Funktion]. 2 Parameter[LuaFunktionsname]*/ void UMLuaManager::InitFunction(int CppFunction, std::string LuaFuncName) { lua_pushcfunction(m_L, CppFunction); lua_setglobal(m_L, LuaFuncName.c_str()); };Als das ganze noch mit dem parameter (lua_State* L) war, ging es noch...
Tut mir leid wenn ich mich ein bisschen dumm anstelle, aber ich bin auch eigentlich noch ein Anfänger
-
Black'Tea schrieb:
...aber ich glaube, Applications-Funktionen, die von Lua aufgerufen werden sollen, MÜSSEN den parameter (lua_State* L) übergeben bekommen, da die funktion zum "anmelden" der App-Funktion (lua_pushcfunction) eine Funktion mit dem parameter (lua_State* L) braucht.
Ja, das stimmt. Über dieses L kannst du dann mittels lua_gettop parameter usw. die von lua kommen abrufen. D.h. alle Funktionen, die Lua aufrufen soll, dürfen nur von dieser Signatur sein. Richtig.
Black'Tea schrieb:
Aus den Untiefen des Lua-quellcodes geklaut:
#define lua_pushcfunction(L,f) lua_pushcclosure(L, f, 0) LUA_API void lua_pushcclosure (lua_State *L, lua_CFunction fn, int n) typedef int (*lua_CFunction) (lua_State *L);Das brauchst du nicht, die Makros sind schon richtig so. Du kannst ruhig lua_pushcfunction nehmen.
Dein Problem ist glaub ich folgendes, was du nicht verstehst:
Was ist denn das für ein Parameter, den alle App-Funktionen bekommen, die Lua aufrufen soll?
Dieser Parameter ist der Kontext von Lua, also quasi dein Lua-Objekt. Der Zeiger wird auf den gleichen Bereich zeigen, wie dein m_L, denn es ist ja so:App: Lua_pcall(m_L, irgendneFunktionOderSo,...)
dann läuft eine lua-Funktion ab, die in einer Datei gespeichert ist. Alles auf dem Kontext von m_L. Dann:
Lua: Play("irgendwas", "nochwas", 4)Play wurde vorher mittels lua_pushcfunction(m_L, Play) oder so registriert, d.h. dein m_L kennt die Funktion Play (ansonsten gibts "attempt to call nil value" oder so). Dein Play gehört wieder zur App:
Play(lua_State* L) { ... }
Diese Play-Funktion erhält nun den Kontext als parameter, auf dem die lua-Funktion lief. Und auf welchem Kontext lief die funktion? Ja, genau auf dem Kontext von dem sie auferufen wurde. Und das ist m_L. Das heißt also, das L ist einfach dein Parameter, mit dem du die wirklichen parameter für die Funmktion bekommen kannst. (lua_gettop, lua_tostring usw)Oder anders: nur ein lua_open(); im Programm reicht vollkommen. Alle L, ob Parameter, variable, sonstwas , werden immer den Wert haben, den lua_open zurückgegeben hat, weil alles auf dem selben Kontext läuft.
Ich hoffe, ich konnte es einigermaßen erklären

Noch was:

Ich hab gerade irgendwie das problem, dass ich nicht weiß, wie ich den parameter eine Applications-Funktion, die von Lua aufgerufen werden kann, meinem m_L zuweisen kann.
Brauchst du ja gar nciht, weil dein L als Parameter das gleiche ist wie dein m_L. Denn deine lua-funktion wurde auf dem kontext m_L aufgerufen. Kannste dir sozusagen auch so vorstellen:
m_L->pcall(function, 0, 0);
So, genug gesagt
-
Hehe, jetzt hab ich das glaub ich komplett verstanden, sehr ausführlich, danke

Kannst du mir noch kurz erläutern, wie ich luascripte kompilieren kann, damit mein Programm nicht immer zur Laufzeit die ausführen muss, sondern den Inhalt der Datein sozusagen schon im Speicher hat, so dass er ganz schnell abgerufen werden kann?
letzenendes will ich eine Setup.lua haben, die vollgestopf ist mit den Befehlen
ReadFile ("Media\Scripts\Sounds\Beispiel.lua"); ReadFile ("Media\Scripts\Sounds\Funktion.lua"); ...int UMLuaManager::ReadFile(lua_State* L) { ... return 0; }
-
mit luac (das ist der lua-compiler) kannst du die scripts vorkompilieren, und dann mittels luaL_dofile oder luaL_loadfile und lua_pcall dann aufrufen.