Search code examples
javalualuajluajava

LuaJ (Java Lua Library): Calling Lua functions in other files from a Lua file


To begin, I'm aware of this question, but I don't think it quite fits what I'm doing. Either way, the answer is a bit confusing my opinion. I'd like to find an answer for my problem that's more specific to what I'm doing.

The goal here is for the lua file chatterToolsTest to successfully print "Test success" to the console. Unfortunately, my current approach isn't quite working. Can someone please help? I'm not the best at Lua, so maybe my Lua code is just wrong in this case. Please check out the snippets below.

Another constraint: I can't enable to use of modules from the java-side. Any referencing done between the two Lua files has to be obtained through Lua only. This is because I'm developing a modding system for a Java project and need the Lua to be able to work with minimal change on the Java-side.

Please keep in mind that I'm not storing my Lua files inside of the JAR file or any packages, they are contained in a folder in the root working directory of the Java program, like a folder of resources.

chatterToolsTest.lua:

function main()
  print("Test start.");

  local test = require("chatterTools");
  chatterTools:test();
end

chatterTools.lua, the class called by chatterToolsTest.lua:

function test()
  print("Test success");
end

Both of these files are in a folder called world/NOKORIWARE/lua/:

And lastly, here's the Java test class using LuaJ that calls them:

public class LuaTest {
    public static void main(String args[]) {
        new LuaTest().run("NOKORIWARE/lua/chatterToolsTest.lua", "main");
    }

    private Globals buildGlobals() {
        Globals globals = new Globals();

        globals.load(new JseBaseLib());
        globals.load(new PackageLib());
        globals.load(new Bit32Lib());
        globals.load(new TableLib());
        globals.load(new StringLib());
        globals.load(new JseMathLib());
        globals.load(new WhitelistedLuajavaLib());

        LoadState.install(globals);
        LuaC.install(globals);

        return globals;
    }

    /**
     * Runs the given lua file. It must be relative to the lua path.
     */
    private void run(String luaPath, String functionName, Object... arguments) {
        LuaValue[] coercedValues = null;

        if (arguments != null) {
            //Coerce arguments into LuaValues
            coercedValues = new LuaValue[arguments.length];

            for (int i = 0; i < arguments.length; i++) {
                coercedValues[i] = CoerceJavaToLua.coerce(arguments[i]);
            }
        }

        //Configure lua file
        Globals globals = buildGlobals();
        globals.get("dofile").call(LuaValue.valueOf("./world/" + luaPath));

        //Call the passed-in function of the lua file.
        try {
            LuaValue call = globals.get(functionName);
            if (arguments != null) {
                call.invoke(coercedValues);
            }else {
                call.invoke();
            }
        } catch (Exception e) {
            e.printStackTrace();
            TinyFileDialog.showMessageDialog("Caught " + e.getClass().getName(), e.getMessage(), TinyFileDialog.Icon.INFORMATION);
        }
    }
}

This is the error that's printed when I run the Java program:

org.luaj.vm2.LuaError: @./world/NOKORIWARE/lua/chatterToolsTest.lua:4 module 'chatterTools' not found: chatterTools
    no field package.preload['chatterTools']
    chatterTools.lua
    no class 'chatterTools'
    at org.luaj.vm2.LuaValue.error(Unknown Source)
    at org.luaj.vm2.lib.PackageLib$require.call(Unknown Source)
    at org.luaj.vm2.LuaClosure.execute(Unknown Source)
    at org.luaj.vm2.LuaClosure.onInvoke(Unknown Source)
    at org.luaj.vm2.LuaClosure.invoke(Unknown Source)
    at org.luaj.vm2.LuaValue.invoke(Unknown Source)
    at nokori.robotfarm.test.LuaTest.run(LuaTest.java:64)
    at nokori.robotfarm.test.LuaTest.main(LuaTest.java:21)

Any help or links to relevant resources is appreciated.


Solution

  • The default LuaJ working directory is the same as Java's. Once I figured that out, I was able to correctly use require().

    chatterTools.lua was changed to this:

    local chatterTools = {}
    
    function chatterTools.test()
      print("Test success");
    end
    
    return chatterTools;
    

    And finally chatterToolsTest.lua had to be changed like this:

    function main()
      print(package.path);
    
      local chatterTools = require("world.NOKORIWARE.lua.chatterTools");
      chatterTools:test();
    end
    

    Lua handles packages like above, so instead of world/NOKORIWARE/lua/chatterTools.lua it turns into what you see in the require() call.

    After these changes, I ran the program and got the following:

    ?.lua
    Test success
    

    All of this considered, this solution is a lot more straight-forward than the answer in the question I linked at the start of this question. Hopefully this will help some of you out there.

    To read more on how I figured this out, check these resources out:

    how to call function between 2 .lua

    https://forums.coronalabs.com/topic/38127-how-to-call-a-function-from-another-lua-file/