Does a trick like this exist for lua modules?

Hi all, I have a bit of an odd question.
When importing lua modules, they go into a local variable scope, and you need to access its function using that namespace.

local mymod = require("mymodule")
mymod.myfunc()

Is there a way to trick it so that you can access those functions directly, like if they were global?
I recall reading an article at some point that had something along these lines, but I can’t find that article again nor I’m sure it was solving this particular issue.

Why exactly do you want to achieve this? The way you want to go for is a bad approach 99% of the time.

Yes, there is a trick for it and I can explain it in detail if you really want to do it.

There’s no trick that I know of. But you can set up each function you need manually. This is a common optimization technique that eliminates the table lookup that you would otherwise do on each call.

local math_abs = math.abs
local math_cos = math.cos
local math_pi = math.pi
local math_sin = math.sin
local math_sqrt = math.sqrt

If I remember correctly, in later versions of Lua there’s an API which allows you to modify local scopes.

You can do whatever you want in the required file. You can declare global functions in the required file. There is no requirement to return a table with the functions.

-- mymodule.lua
function greet(name)
    print("Hello", name)
end
require("mymodule")
greet("Bob") -- Hello Bob
2 Likes

As britzl said there isn’t a need for any tricks, this is just how lua works.

Default for lua is to put it into your global scope, we always declare it as local as to not get weird side effects. Which is what theHandgun eluded too. You can put things within the global scope, but you should probably avoid it as to not get weird errors or conflicts. I want to avoid putting things within the global so much that I use superstict to ensure I can’t.

But I do also in my projects I use the exact method Britzl showed to have a couple of helpful functions (mainly for debug purpose).

2 Likes

I believe I need to give a bit more context here.

I know I can require modules into the global state as britzl suggested and also know that I can reassign through a local variable the scope of functions.

What I’m trying to achieve here is giving access to certain functions in a more direct way, providing. a better experience for writers, without having to write a full on DSL and without polluting the global scope.
I want my writer to be able to write a lua script with a simple require at the top and maybe a sunction call and then just type

walk_to_clicked()
say "This is a good spot!"
face_left()
say "Joing me"
walk_to {"Bernie", 100, 50}

In this case the user experience has more weight for me than what is normally considered “bad practice”.

Now I think I found what I’m looking for, although it still feels a bit convoluted, through setfenv.
Will need to experiement with it.

1 Like

I would try setfenv too, and set up a sandbox to run user code in a special context with all the desired functions in the context’s global table.

You may be able to catch calls to require in that context (perhaps only allowing certain modules), and add the module content to the context’s global table. As an alternative, you could have custom functions in the global table that does more or less the same, so instead of require "speech" the user would call load_speech_api().

I’ve only read about how to set up a secure Lua sandbox when using Lua in a game engine, but never done it myself. There are several sandbox implementations on Github — maybe they can be helpful.

1 Like

Like Goose mentions, the setfenv() is probably what you are after then.

reading your example I remembered this:
GitHub - HalfstarDev/matchanovel: A visual novel framework library for Defold. created by @Halfstar
I don’t know how they implemented but it follows the same principles of Ren’py ( I think?). On a script (here a .txt) your writers can do almost anything related to their roles.

a.name = "Alice"
a.sprite = "alice.png"

show.transition = "fade"
show.duration = 1.2
show.above = "back"

pos_right.x = 0.75
pos_right.y = 0

show a at=pos_right

a: Hello.
a: How are you?

just mixed some examples from the doc.
I think this is a great way of working as a writer.

1 Like