Jump to content

Lua methods called from Editor


Rick
 Share

Recommended Posts

Does anyone know the Lua code in that is used to call engine Lua functions from say the editor? I'm using the following but the editor gives me access violation:

 

lua_getglobal(L, "LuaFunctionName");
lua_pcall(L, 0, 0, 0);

 

If Josh is able to show how say the editor is calling lua function from C++ or BMax that should help.

Link to comment
Share on other sites

I can't figure out why this isn't working:

 

int state = lua_type(L, -1);

 

Is telling me a function (the one I push) is on the stack, but any call to it (lua_pcall(L, 0, 0, 0):( gives the Editor the ACCESS VIOLATION error.

 

The fact that getglobal seems to be finding the function seems good, but not sure what else the call is expecting to make the editor crash.

 

Also, those ACCESS VIOLATION errors I assume is from a lack of error handling so would be nice if we had more graceful error checking around Lua.

Link to comment
Share on other sites

				Local size:Int
			size=luastate.StackSize()
			lua_getglobal(luastate.L,"UpdatePhysicsHook")
			If lua_isfunction(luastate.L,-1)
				luastate.PushObject(Self)
				luastate.invoke(1,0)
			EndIf
			luastate.SetStackSize(size)

 

	Method StackSize:Int()
	Return lua_gettop(L)
EndMethod

Method SetStackSize(size:Int) {hidden}
	Local currentsize:Int=StackSize()
	If size<currentsize
		lua_pop(L,currentsize-size)
	EndIf
EndMethod

 

Method Invoke:Int(in:Int=0,out:Int=0)
	Local error:String
	Local result:Int
	Local time:Int
	Local dummy:Object
	Local debugmode:Int
	?debug
	debugmode=True
	?

	If debugmode
		result=lua_pcall(L,in,out,0)
	Else
		Try
			result=lua_pcall(L,in,out,0)
		Catch dummy:Object
			HandleException()
		EndTry
	EndIf
	If result
		HandleError()
		Return False
	EndIf
	If autogc
		If CollectGarbageFrequency>0
			time=MilliSecs()
			If time-lastcollectgarbagetime>CollectGarbageFrequency
				lastcollectgarbagetime=time
			'	CollectGarbage()
			EndIf
		EndIf
	EndIf

	Return True
EndMethod

My job is to make tools you love, with the features you want, and performance you can't live without.

Link to comment
Share on other sites

Thanks for that. Still gives me the error. If I misspell the function name it fails the is_function call so I know it's finding the function, and pushing it on the stack but it just fails when calling.

 

This is Lua 5.1 right? I'm currently using the binaries so I guess I'll get the source and use that in my project so I can step through the pcall method and see if I can get any more details around the error.

 

It seems odd that the error would be coming from the editor and not my DLL though. The editor is single threaded right? I mean while I'm in my DLL making lua calls nothing should be happening on the Lua side of the editor calling model scripts right?

 

It's erroring internally to Lua at:

 

void luaV_execute (lua_State *L, int nexeccalls) {
 LClosure *cl;
 StkId base;
 TValue *k;
 const Instruction *pc;
reentry:  /* entry point */
 pc = L->savedpc;
 cl = &clvalue(L->ci->func)->l;
 base = L->base;
 k = cl->p->k;
 /* main loop of interpreter */
 for (; {
   const Instruction i = *pc++;                   // access violation error here

 

Of course I have no idea of the internal workings of Lua but pc doesn't seem to be null or 0. It has what seems to be a valid address but when this tries to increase it, the failure happens.

 

I wouldn't think it would be any sort of cross process issue as I thought the lua_State was meant to be self contained and passed around at will.

Link to comment
Share on other sites

So Josh you are using 5.1 right? Nothing special modified of the Lua version that you are using? This all works fine if lua.exe (the binary you can download of lua) is running my script, so it almost leads me to believe that it's the implementation of Lua in the editor and any slight Lua modifications that may have been made (to the Lua library itself)?

 

There was another strange quirk I noticed where getting the first thing on the stack of a function call wasn't the first argument but a function, which wasn't the case in lua.exe when running a test script.

 

I think at one point you gave me the person who did this implementation of Lua for you. Would that person still be associated with LE and would I be able to ask that person a question around this? Or if you know of any Lua change would you happen to have the changed Lua library that I could use in my C++ program?

 

It just seems like this is something specific to the engine's version of Lua.

 

 

Going to give Engine.exe to see if that gives the same results. Never used Engine.exe before so will have to see how that works.

Link to comment
Share on other sites

Looks like the same thing happens in Engine.exe. Guess I'll try creating my own exe that does this and see if that works.

 

While I'm stepping through running this via Editor/Engine vs the lua.exe I'm able to see the variable that is messed up. I just don't know why it's messed up. It seems to be the lua_State variable is slightly different when ran from Editor/Engine vs lua.exe.

 

It just makes no sense how you can call that method and it works, but when I call it, it doesn't. The lua_State variable must lose something when it gets xfered to my DLL, but why wouldn't it do the same from lua.exe. Frustrating as this is the last piece of getting RakNet working in Lua and me getting multiplayer in my game.

 

 

I guess tonight I'll try returning network message and bitstream from the Update and handle the function mapping on the Lua side. Should give the same result.

Link to comment
Share on other sites

Hi Rick

 

i never tried put loop inside lua execute function, i think this isn't good.

In my code i have luaV_execute defined as separated exec for external lua function and in native code when i call OnUpdate loop on any object (i.e. gui element) i call this external lua function in loop. From my point of view, your partly published code, look like recursive call => stack overflow or crash.

 

When you want look on my implementation (but in Delphi) you look here: http://sites.google.com/site/andygfxproject/free-pascal/final3d-sdl-ngine source are on bottom of page.

 

Note: Yes I'm always around here, but now i work more for mobiles and Tablets with Monkey.

[HW] C2D Q6600, 4GB RAM, NV8800GTX, Vista Ultimate x64

[sW] Blide Plus, BlitzMax, Delphi, C++, 3DWS 5.53, Leadwerks 2.xx

 

76561197970156808.pngAndyGFX.png

Link to comment
Share on other sites

Hey Andy, I'm actually not looping in the lua execute function that I listed. That's how Lua has that method define as is part of the Lua API. I didn't touch it, was just showing where the error was happening inside Lua.

 

What I actually do in my DLL is that I have an Update method that is exposed to Lua. In the main game loop in Lua I call this Update method. The Update method is looking for packets over the network via RakNet and if it finds one it notes the message id, and finds the lua function name I've registered to that ID which is stored in the DLL. Then it attempts to call that.

 

It's strange because this all works great from lua.exe (prebuilt lua interpreter you can download). It's only when I try it from LE's lua when I get the error. The other thing that's strange is that the first parameter of a C function called from Lua is not the real first parameter I've passed in from Lua when using LE, but it is when called from lua.exe which loads a lua file and runs it. In LE I have to start with index 2 instead of 1 when looking at the first parameter. That tells me something strange is going on with LE's implementation of Lua.

 

I think the editor is built using BMax, and engine might be also, so maybe the BMax version of Lua isn't exactly the same as the C version? Not sure.

 

Tonight I'm going to try and just return the message id, and the data inside that message from the Update method and I'll just do the function mapping on the Lua side. It's not ideal in my mind but it should work.

 

The link that you posted, that's not LE though right? That's SDL? Are you using prebuilt lua library and DLL as the interpreter or is there a Delphi port of Lua?

Link to comment
Share on other sites

Man I can't get a value returned to Lua from the DLL either to do this the other way I was thinking. I know this used to work as I'm looking at my example from the old forum. I was so close to getting this thing online, but now it's looking like I'm going to have to rewrite it in C++.

 

static int NetUpdate(lua_State* L)
{
RakNet::MessageID msg = -1;
RakNet::BitStream* reader = NULL;

// check for new packets
for (packet=peer->Receive(); packet; peer->DeallocatePacket(packet), packet=peer->Receive())
{
	// assign the message
	msg = packet->data[0];

	// assign the bitstream
	reader = new RakNet::BitStream(packet->data,packet->length,false);
	reader->IgnoreBytes(sizeof(RakNet::MessageID));

	// special case for connection. need to save off the servers address so we can send data to it later
	switch(packet->data[0])
	{
		case ID_CONNECTION_REQUEST_ACCEPTED:

			WriteLog("Connection request accepted");
			serverAddress = packet->systemAddress;
			break;
	}
}

// hardcode just to test
lua_pushnumber(L, 5);

return 1;
}

 

package.loadlib("C:\\Leadwerks Engine SDK\\RakNetLua.dll", "luaopen_raknet")()

local msgID = raknet.Update()

Notify(msgID)

 

Just prints out nothing (nil)

Link to comment
Share on other sites

This is very strange because i have used same method to return value from native code to lua script.

 

Try add check inside C code if it's really function pointer returned from lua stack.

 

state = lua_type(L,-1); 

 

state constants are:

 

 LUA_TNIL           = 0;
 LUA_TBOOLEAN       = 1;
 LUA_TLIGHTUSERDATA = 2;
 LUA_TNUMBER        = 3;
 LUA_TSTRING        = 4;
 LUA_TTABLE         = 5;
 LUA_TFUNCTION      = 6;
 LUA_TUSERDATA	     = 7;
 LUA_TTHREAD	       = 8;

[HW] C2D Q6600, 4GB RAM, NV8800GTX, Vista Ultimate x64

[sW] Blide Plus, BlitzMax, Delphi, C++, 3DWS 5.53, Leadwerks 2.xx

 

76561197970156808.pngAndyGFX.png

Link to comment
Share on other sites

I will give this a try tonight

 

This is very strange because i have used same method to return value from native code to lua script.

 

With LE and Lua or with some other implementation of Lua outside of LE. If withing LE I'd love to see what code you have for that. What exact version of Lua (patch version also) and a working example if you have one because this all works when done from lua.exe but not when done from LE as the host of Lua.

Link to comment
Share on other sites

WHen you want see how work my code, you can download it here: https://sites.google.com/site/andygfxproject/free-pascal/final3d-sdl-ngine/Final3D_SDL_nGine.rar?attredirects=0&d=1

 

Run: F3D_DEMO_scene_render.exe and press F1 or F3D_DEMO_gui_with_lua.exe - GUI has used call function from native code.

 

LUAfile:

 

..\Final3D_SDL_nGine\bin\data\scripts\editor\editor_gui.lua

 

...
GUI.SetHSlider_OnChange("WIN_01","HSlider_01","fnc_Hslider_onchange");
...

 

and fnc is defined:

 

function fnc_Hslider_onchange()
local val = GUI.GetHSliderValue("WIN_01","HSlider_01");
print(val);
end;

 

and now GUI.GetHSliderValue in native code: wF3D_GUI.pas

 

F3D.ScriptEngine.AddListFunction('GetHSliderValue', @lua_GUI_HSlider_GetValue);

 

function lua_GUI_HSlider_GetValue(L: lua_state): integer; cdecl;
var w_name: string;
   i_name: string;

   w_id, i_id: integer;
begin
   w_name := lua.luaL_check_string(L, 1);
   i_name := lua.luaL_check_string(L, 2);

   w_id := F3D.GUI.FindWindowByName(w_name);
   if w_id >= 0 then
   begin
       i_id := F3D.GUI.Window[w_id].FindHSliderByName(i_name);
       if i_id >= 0 then
       begin
           lua.lua_pushnumber(L, F3D.GUI.Window[w_id].HSlider[i_id].value);
       end;
   end;
   result := 1;
end;

 

Maybe your function isnt properly defined. I have used this steps

 

1) F3D.ScriptEngine.StartList('GUI');

 

procedure TF3D_ScriptEngine.StartList(name: pchar);
begin

   if (self.enabled = false) then exit;

   lua_pushstring(VM, name);
   lua_newtable(VM);
end;

 

2) Add functions to GUI table;

 

...
// HSLIDER
   F3D.ScriptEngine.AddListFunction('SetHSlider_OnChange', @lua_GUI_HSlider_OnChange);
   F3D.ScriptEngine.AddListFunction('GetHSliderValue', @lua_GUI_HSlider_GetValue);
...

 

 

 

procedure TF3D_ScriptEngine.AddFunction(name: pchar; fnc: pointer);
begin

   if (self.enabled = false) then exit;

   lua_pushstring(VM, name);
   lua_pushcclosure(VM, fnc, 0);
   lua_settable(VM, LUA_GLOBALSINDEX);
end;

 

3) F3D.ScriptEngine.EndList(); (F3D_ScriptEngine.pas)

 

procedure TF3D_ScriptEngine.EndList();
begin

   if (self.enabled = false) then exit;

   lua_settable(VM, LUA_GLOBALSINDEX);
end;

 

I have used Lua 5.1 and bum dll, for linux was used lua.so

[HW] C2D Q6600, 4GB RAM, NV8800GTX, Vista Ultimate x64

[sW] Blide Plus, BlitzMax, Delphi, C++, 3DWS 5.53, Leadwerks 2.xx

 

76561197970156808.pngAndyGFX.png

Link to comment
Share on other sites

@Andy but that's using SDL and not LE right? So the Lua implementation might be different. Like I was saying it works all fine with Lua.exe only when using with LE.

 

@Josh, hmm that might be it. I don't know anything about LuaJIT, but perhaps it does some things slightly different. So LuaJIT is a complete replacement from just normal Lua? I bet this it though because I remember not having these issues when you first introduced Lua and I seem to remember you switched over to LuaJIT some time after. I'll use LuaJIT in my DLL and see if that makes the difference. If so, we'll have to really specify it uses LuaJIT instead of just Lua because then clearly there would be some slight differences.

Link to comment
Share on other sites

Well that was it! I thought I was going crazy. Thanks Josh for pointing this out. I forgot that you switched to that. Thanks Andy and everyone else who helped. All working nicely now.

 

Asking over at RakNet if he minds me giving my custom DLL away as it still requires the RakNet dll to work and people would still have to go through him to get that. This might be useful for others and it's really simple to use. This is just for client stuff via Lua though, the server would still be pure RakNet (ie. in C++ or .NET or whatever supported RakNet language you want to use).

Link to comment
Share on other sites

  • 1 month later...

Man I can't get a value returned to Lua from the DLL either to do this the other way I was thinking. I know this used to work as I'm looking at my example from the old forum. I was so close to getting this thing online, but now it's looking like I'm going to have to rewrite it in C++.

 

static int NetUpdate(lua_State* L)
{
RakNet::MessageID msg = -1;
RakNet::BitStream* reader = NULL;

// check for new packets
for (packet=peer->Receive(); packet; peer->DeallocatePacket(packet), packet=peer->Receive())
{
	// assign the message
	msg = packet->data[0];

	// assign the bitstream
	reader = new RakNet::BitStream(packet->data,packet->length,false);
	reader->IgnoreBytes(sizeof(RakNet::MessageID));

	// special case for connection. need to save off the servers address so we can send data to it later
	switch(packet->data[0])
	{
		case ID_CONNECTION_REQUEST_ACCEPTED:

			WriteLog("Connection request accepted");
			serverAddress = packet->systemAddress;
			break;
	}
}

// hardcode just to test
lua_pushnumber(L, 5);

return 1;
}

 

package.loadlib("C:\\Leadwerks Engine SDK\\RakNetLua.dll", "luaopen_raknet")()

local msgID = raknet.Update()

Notify(msgID)

 

Just prints out nothing (nil)

 

 

try with

static int _cdecl NetUpdate(lua_State* L)
{
...
}

 

May be that the name convention is not recognized by Lua!

In "C + +" all are decorated like @@foo(ZER_@) but not in "C"

 

 

Can you tell me if it works like that?

 

I'm interested;-)

 

Gabriel

Link to comment
Share on other sites

Join the conversation

You can post now and register later. If you have an account, sign in now to post with your account.
Note: Your post will require moderator approval before it will be visible.

Guest
Reply to this topic...

×   Pasted as rich text.   Paste as plain text instead

  Only 75 emoji are allowed.

×   Your link has been automatically embedded.   Display as a link instead

×   Your previous content has been restored.   Clear editor

×   You cannot paste images directly. Upload or insert images from URL.

 Share

×
×
  • Create New...