[Lua] Fill table with script file

Started by
9 comments, last by Wyrframe 5 years, 12 months ago

Hello everyone! I need to fill lua table with functions from script file like this:


function init() 
  
end

function update()
  
end

I need to create table on stack and fill it with this functions from specified file. How can I do this?

Advertisement

The easiest approach is probably to do:


return {
	init: function()
	end,

	update: function()
	end
}

That will push the table onto the stack as a return value when you call the chunk (using luaL_dofile for example).


function makeFunctor(params)
  local table = { }
  function table.method1(params)
    ...
  end
  function table.method2(params)
    ...
  end
  return table
end

Or like this. Read up on https://www.lua.org/manual/5.1/manual.html#2.5.9 . Also, what is your use case, because there may be a better way to do it both visually and structurally?

RIP GameDev.net: launched 2 unusably-broken forum engines in as many years, and now has ceased operating as a forum at all, happy to remain naught but an advertising platform with an attached social media presense, headed by a staff who by their own admission have no idea what their userbase wants or expects.Here's to the good times; shame they exist in the past.

Just realized what you actually probably meant. You want to load a script file, and populate a table with the functions that script file "declares"?

This isn't possible the way Lua works, without some knowledge about how the script file is structured. Any fragment of source (be it a single string or a whole text file which to the lua parser is functionally a single string) gets compiled to, itself, be a function. When executed, all the top-level declarations in the source file get executed. So in your source file, each "function X() end" declaration is equivalent to "X = function() end", that is to say, assigning to the global variable "X". Identifying changes made to the global table is not an entirely solvable problem within the confines of Lua.

But what you can do is what I and havsmontret suggested; have the script file itself return a table at the end; that will be the return value of doFile or what have you, and you can use that as the module the script file is supposed to implement.

RIP GameDev.net: launched 2 unusably-broken forum engines in as many years, and now has ceased operating as a forum at all, happy to remain naught but an advertising platform with an attached social media presense, headed by a staff who by their own admission have no idea what their userbase wants or expects.Here's to the good times; shame they exist in the past.

Thank you, guys! This approach is fine too.

 

Quote

Also, what is your use case, because there may be a better way to do it both visually and structurally?

This is for quests in my game. Quest needs only to have few basic functions which I wanted to place in file and populate quest-table with it. I wanted to create quest instances on C++ side. But as I see this is not a good way of doing this.

I've figured out how to do what I want:

 


luaL_dofile(L, "script.lua");

// now we have 'init', 'update' etc in global table

// create new quest-table
lua_newtable(L);

// copy needed functions into quest table
lua_pushstring(L, "init");
lua_getglobal(L, "init");
lua_settable(L, -3);

lua_pushstring(L, "update");
lua_getglobal(L, "update");
lua_settable(L, -3);

lua_setglobal(L, "QuestN"); // there we have to generate unique quest id

Further improvement: check if we have needed functions after script execution. Also we have to check if function does not exist in a script. To do this we have to do something like this


lua_pushnil(L);
lua_setglobal("init");

lua_pushnil(L);
lua_setglobal("update");

luaL_dofile(L, "script.lua");
 
lua_getglobal(L, "init");
if(lua_isnil(L, 1)) throw exception("...");
lua_pop(L, 1);

lua_getglobal(L, "update");
if(lua_isnil(L, 1)) throw exception("...");
lua_pop(L, 1);

...
  

 

It's brittle, but if you're the only person who'll be maintaining quests like this, documentation should get you over that hurdle.

The problems are going to come in if two quests both accidentally assign different values to a global variable in common between them. Among other things, you probably want to introduce some data hygiene, which is going to be particularly necessary for serialization (read: save/load).

RIP GameDev.net: launched 2 unusably-broken forum engines in as many years, and now has ceased operating as a forum at all, happy to remain naught but an advertising platform with an attached social media presense, headed by a staff who by their own admission have no idea what their userbase wants or expects.Here's to the good times; shame they exist in the past.

One feature that might be useful to you here is "Lua environments".

http://lua-users.org/wiki/EnvironmentsTutorial

https://www.lua.org/pil/14.html

These allow each file/function to operate with a different set of global variables, so that your globals from one file won't "leak" into another file.

21 hours ago, Wyrframe said:

you probably want to introduce some data hygiene

Yeah, I hate global variables and will punish script writers if they want to use them. Every function used by quest will accept "self" argument, and user can do anything with it. 

 

21 hours ago, Hodgman said:

One feature that might be useful to you here is "Lua environments".

As I said above, using globals in my project is forbidden. I warn users about it in docs for scripts.

 

11 hours ago, Hodgman said:

One feature that might be useful to you here is "Lua environments". [...] These allow each file/function to operate with a different set of global variables, so that your globals from one file won't "leak" into another file.

Right, I keep forgetting they were improved to the point of actually being useful in 5.2.

13 minutes ago, mrDIMAS said:

Yeah, I hate global variables and will punish script writers if they want to use them. Every function used by quest will accept "self" argument, and user can do anything with it.

Fair dues, but due to the way Lua is written, it's easy to accidentally create a global that you meant to be a local temporary (by forgetting to pre-declare it as `local ...`). You may want to use an Environment setup not to capture and preserve globals, but to log warnings whenever an unexpected global is accidentally created.

RIP GameDev.net: launched 2 unusably-broken forum engines in as many years, and now has ceased operating as a forum at all, happy to remain naught but an advertising platform with an attached social media presense, headed by a staff who by their own admission have no idea what their userbase wants or expects.Here's to the good times; shame they exist in the past.

This topic is closed to new replies.

Advertisement