Wren-Lua communication

(Note: the full Wren-side API can be found on GitLab)

There are many scenarios where you may want to share data between Lua and Wren. This API provides a way to do so.

A Wren script can register an object for invocation from Lua. Any (non-underscore-prefixed) method on this object can then be called by Lua.

This is done with the LuaInterface.register_object. This function takes two arguments:

  • string: The name of the object to register
  • object: The object itself

On the Lua side, this function can later be called with the blt.wren_io.invoke function. This takes four or more arguments:

  • The ID of the mod where the object was registered. For the current mod, use ModInstance.id which works even if the user has renamed your mod's folder. Like ModPath this changes, so store it in a local as soon as your script runs.
  • The name of the object - corresponds to the first argument of the register_object call in Wren.
  • An options table, or nil. This is basically just reserved for future use, leave it at nil for now.
  • The name of the method to call.

Then there should be the same number of arguments as the Wren function has. Since Wren distinguishes functions based on the number of arguments they have, this must be the correct number of arguments otherwise the call will fail with a method not found error.

Note: you can have multiple Wren functions with the same name, and how many arguments you supply determines which one gets run.

The calls are unidirectional - while Lua can call a Wren function, Wren cannot call a Lua function. This is because at any one time there may be multiple running Lua instances. If you have to send a message from Wren to Lua, you should implement some kind of polling system where Lua repeatedly asks Wren if it's got any new data. You should make sure this won't crash if something occurs while starting a heist, however (since you may get a message based on an action that the previous Lua instance took).

Example:

import "base/native/LuaInterface_001" for LuaInterface

class TestObject {
    construct new() {}

    my_func(a, b, c) {
        return ["Hello, World", "Values you passed: %(a) %(b) %(c)"]
    }
}

LuaInterface.register_object("MyObject", TestObject.new())

And then call that function in Lua:

local mod_id = ModInstance.id -- Do this outside of any hook, this changes like ModPath!

local options = nil -- May be a table in the future
local list = blt.wren_io.invoke(mod_id, "MyObject", options, "my_func", "a", 123, "b")
-- List is: {"Hello, World", "Values you passed: a 123 b"}