Issue detecting if script is being loaded as a module vs being run
TheElementalOfDestruction opened this issue ยท 4 comments
MC Version: 1.12.2
CC Version: 1.82.3
According to this stack overflow answer (which I have confirmed myself to work), you should be able to tell if the code is being loaded ( i.e. require('script'
) or being run directly.
To test that this actually works, you can create two files in the same folder: a.lua
and b.lua
. Here is how they are defined:
a.lua
print(pcall(debug.getlocal, 4, 1))
b.lua
a = require('./a')
Remember these two files, because we are going to be using them multiple times.
Now, if you were to open a lua interpreter, this is the output you would get:
C:\...> lua a.lua
false bad argument #1 to 'debug.getlocal' (level out of range)
C:\...> lua b.txt
true nil
However, if you were to repeat this same process on a CC: Tweeked computer, this is what would happen:
> a.lua
true nil
> b.lua
true nil
See the problem here?
Can you do anything to fix this?
So the code in the above SO question makes lots of assumptions about how the Lua interpreter works, which don't really hold up in ComputerCraft.
The above code pretty much asks "is this the first function the whole Lua VM runs?", which is only true within CC's internal start up code. We actually need to ask "was this run via shell.run
?".
I wrote this code a while back, which can be used to detect if the program was run with require
, os.loadAPI
, or shell.run
. It does rely on a couple of Lua 5.1 features, so doesn't work on 5.2+, but should be sufficient for CC:
local function get_type()
if not shell then return "os.loadAPI" end
if not package then return "shell.run" end -- Compat for old versions of CC
-- Locate the sentinel value, and check that it's currently within the table
-- somewhere.
package.preload["__sentinel"] = function() return package.loaded["__sentinel"] end
local sentinel = require("__sentinel")
for k, v in pairs(package.loaded) do
if k ~= "__sentinel" and v == sentinel then return "require" end
end
return "shell.run"
end
print(get_type())
a = require('./a')
On a side note, you shouldn't be loading modules like this. require
works a bit like Python or Java's import
though no relative import. You need to pass in a dot-separated path, such as require("a")
or require("cc.expect")
, not a file path.
That was a specific example to ensure it imported the exact file I wanted. I usually have the issue of require("a")
not working at all if the file is created using edit a
because the default path is /
, and the require function starts at /rom/
The require
function should start relative to the current program's directory, so assuming a
and b
are in the same directory everything should work fine.
However, require
is a little broken when used within the lua
REPL, as the current program resides within rom/programs
(so it tries to find rom/programs/b
instead). require
should print out the list of paths it tried, so it should be possible to work out what's going wrong for you.
I should probably fix the REPL behaviour TBH, it's confused far too many people.
This one's been fixed for a while. Woops.