How do I run Lua scripts on Android in a Java application?

后端 未结 4 836
孤街浪徒
孤街浪徒 2021-02-01 09:29

I\'m developing an Android game in Java which uses Lua scripts. To execute these scripts, I\'m using LuaJ with Java\'s ScriptEngine class. For example...

ScriptE         


        
相关标签:
4条回答
  • 2021-02-01 09:34

    However, this is apparently not supported on Android

    Correct.

    something to do with android not having a full blown JVM, I read somewhere

    Correct. If you look at the JavaDocs, you will see that javax.script does not exist in the Android SDK.

    Maybe I'll give this a try: https://github.com/damonkohler/sl4a

    That is one option. Another is to embed the Lua interpreter in your app via the NDK, as in this sample application.

    0 讨论(0)
  • 2021-02-01 09:36

    Instead of LuaJ you can (also) use LuaJava together with Lua compiled for Android using the NDK. This allows Lua full access to whatever is available from Java. Take a look at this example to see how to get started.

    Lua 5.1.4 + LuaJava compiled are provided in the libs directory (a single libluajava.so file) if you do not want to fiddle with the NDK, but it is relatively easy to set up anyway.

    0 讨论(0)
  • 2021-02-01 09:46

    To use Lua on Android, you can use JNLua + Lua 5.2 (implemented in C). The only Android port with JSR 223 (javax.script) support is here: https://github.com/danke-sra/jnlua-android

    Using this port, you can do what you want:

    ScriptEngine scriptEngine = new LuaScriptEngineFactory().getEngine(); scriptEngine.eval("lua statements");

    0 讨论(0)
  • 2021-02-01 09:57

    I found a way of using LuaJ on Android! :-)

    The key is to use the LuaJ API directly as opposed to through javax.script. It's a little tricky to figure out as there's no tutorials, so here's a before and after so that others don't have to go through picking through the LuaJ source code and JavaDoc. I really hope this helps someone as it drove me bonkers!

    Note: "secretgame" isn't the actual name of my game ;-)

    After:

    package secretgame.scripting;
    
    import java.io.ByteArrayInputStream;
    import java.io.IOException;
    import java.io.InputStream;
    import java.util.ArrayList;
    
    import org.luaj.vm2.LuaClosure;
    import org.luaj.vm2.LuaTable;
    import org.luaj.vm2.LuaValue;
    import org.luaj.vm2.Prototype;
    import org.luaj.vm2.compiler.LuaC;
    import org.luaj.vm2.lib.jse.CoerceJavaToLua;
    import org.luaj.vm2.lib.jse.JsePlatform;
    
    import secretgame.SecretGameException;
    import secretgame.events.EventArgs;
    import secretgame.levels.Level;
    
    public class DirectLuaj implements Lua
    {
      private final Level level;
      private final ScriptTools scriptTools;
      private final ScriptEvents scriptEvents;
      private int nextId = 0;
      private ArrayList<LuaClosure> scripts = new ArrayList<LuaClosure>();
    
      public DirectLuaj(Level level, ScriptTools scriptTools,
          ScriptEvents scriptEvents)
      {
        this.level = level;
        this.scriptTools = scriptTools;
        this.scriptEvents = scriptEvents;
      }
    
      @Override
      public int add(String scriptText) throws SecretGameException
      {
        try {
          InputStream input = new ByteArrayInputStream(scriptText.getBytes());
          Prototype p = LuaC.compile(input, "script");
          LuaValue g = JsePlatform.standardGlobals();
          LuaClosure c = new LuaClosure(p, g);
          scripts.add(c);
        }
        catch (IOException e) {
          throw new SecretGameException("compile failed", e);
        }
    
        return nextId++;
      }
    
      @Override
      public void run(int id, EventArgs args) throws SecretGameException
      {
        LuaClosure script = scripts.get(id);
    
        LuaTable bindings = new LuaTable();
    
        bindings.set("java", toLua(scriptTools));
        bindings.set("level", toLua(level));
        bindings.set("args", toLua(args));
        bindings.set("events", toLua(scriptEvents));
    
        script.setfenv(bindings);
    
        script.call();
      }
    
      private LuaValue toLua(Object javaValue) {
        return javaValue == null? LuaValue.NIL:
                javaValue instanceof LuaValue? (LuaValue) javaValue:
                CoerceJavaToLua.coerce(javaValue);
      }
    }
    

    Before:

    package secretgame.scripting;
    
    import java.util.ArrayList;
    
    import javax.script.Bindings;
    import javax.script.Compilable;
    import javax.script.CompiledScript;
    import javax.script.ScriptEngine;
    import javax.script.ScriptEngineManager;
    import javax.script.ScriptException;
    
    import secretgame.SecretGameException;
    import secretgame.events.EventArgs;
    import secretgame.levels.Level;
    
    // sadly this won't work on Android because there's no such thing
    // as javax.script in Dalvik ... dumb Android java :|
    public class JavaxScriptingLua implements Lua
    {
      private ScriptEngine scriptEngine;
      private final Level level;
      private final ScriptTools scriptTools;
      private final ScriptEvents scriptEvents;
      private int nextId = 0;
      private ArrayList<CompiledScript> scripts = new ArrayList<CompiledScript>();
    
      public JavaxScriptingLua(Level level, ScriptTools scriptTools, ScriptEvents scriptEvents)
      {
        this.level = level;
        this.scriptTools = scriptTools;
        this.scriptEvents = scriptEvents;
    
        ScriptEngineManager sem = new ScriptEngineManager();
        scriptEngine = sem.getEngineByExtension(".lua");
      }
    
      public int add(String scriptText) throws SecretGameException
      {
        try {
          CompiledScript script = ((Compilable)scriptEngine).compile(scriptText);
          scripts.add(script);
        }
        catch (ScriptException e) {
          throw new SecretGameException("could not compile lua.", e);
        }
    
        return nextId++;
      }
    
      public void run(int id, EventArgs args) throws SecretGameException
      {    
        Bindings bindings = scriptEngine.createBindings();
    
        bindings.put("java", scriptTools);
        bindings.put("level", level);
        bindings.put("args", args);
        bindings.put("events", scriptEvents);
    
        try {
          scripts.get(id).eval(bindings);
        }
        catch (ScriptException e) {
          throw new SecretGameException("could not run script.", e);
        }
      }
    }
    
    0 讨论(0)
提交回复
热议问题