arcticfox1919 / LuaDardo

A Lua virtual machine written in Dart
Apache License 2.0
174 stars 33 forks source link

How to pass Table when Lua calls Dart function, and get it in Dart ? #22

Closed FengZi-lv closed 1 year ago

FengZi-lv commented 1 year ago

How to pass Table when Lua calls Dart function, and get it in Dart?

import 'package:lua_dardo/lua.dart';
import 'dart:math';

//  wrapper function must use this signature:int Function(LuaState ls)
//  the return is the number of returned values
int randomInt(LuaState ls) {
  int max = ls.checkInteger(1);
  ls.pop(1);
  // how do i get here { ["hello"] = "World", ["hello22"] = "World132414" }

  var random = Random();
  var randVal = random.nextInt(max);
  ls.pushInteger(randVal);
  return 1;
}

void main(List<String> arguments) {
  LuaState state = LuaState.newState();
  state.openLibs();

  state.pushDartFunction(randomInt);
  state.setGlobal('randomInt');

  // execute the Lua script to test the randomInt function
  state.loadString('''
rand_val = randomInt(10,{ ["hello"] = "World", ["hello22"] = "World132414" })
print('random value is '..rand_val)
''');
  state.call(0, 0);
}
maks commented 1 year ago

Hi, I covered passing a table from Lua into Dart in the article I wrote about using LuaDardo a few months ago, hopefully that can be of some help to you.

arcticfox1919 commented 1 year ago

@FengZi-lv It's easy!

int randomInt(LuaState ls) {
  int? max = ls.checkInteger(1);
  ls.getField(2, "hello");
  // This is a debugging method that looks at the stack
  ls.printStack();
  var hello = ls.toStr(-1);
  print(hello);
  ls.pop(1);

  ls.getField(2, "hello22");
  var hello22 = ls.toStr(-1);
  print(hello22);
  ls.pop(1);

  var random = Random();
  var randVal = random.nextInt(max!);
  ls.pushInteger(randVal);
  return 1;
}
maks commented 1 year ago

@arcticfox1919 thanks for the tip about getField() ! For some reason I hadn't noticed it before as when I wrote my article I just showed how to use the Lua "C API" getTable() but I see you actually already have using getField documented in the Readme too 👍🏻

Looking at your implementation of getTable it looks much simpler than the example one in the Lua book?

PS. also in your code example it looks like: int? max = ls.checkInteger(1); doesn't seem to be used for anything?

FengZi-lv commented 1 year ago

The problem has been solved, here is the workaround.

  /// Pushes a Dart function onto the Lua stack.
  /// @param name The name of the function in Lua.
  /// @param func The Dart function to push.
  /// @param args The arguments for the Dart function in the form of a map {"value_name":example_value}.
  ///             This is an example of a Map, the data in it will not be passed to lua, but the format of the Table passed in when the function is called should be consistent with the Map
  LuaState pushFunction(String name, Function func, Map<String, dynamic> args) {
    luaState.pushDartFunction((ls) {
      // Convert the Dart function to a Lua function.
      int counter = 1; // Counter for the arguments.
      Map<String, dynamic> params = {}; // List of arguments.
      var val; // Argument value.

      args.forEach((key, value) {
        // Iterate through the arguments.
        debugPrint(value.runtimeType);
        switch (value.runtimeType) {
          // Get the argument value based on its type.
          case String:
            val = ls.checkString(counter);
            break;
          case int:
            val = ls.checkInteger(counter);
            break;
          case double:
            val = ls.checkNumber(counter);
            break;
          default:
            val = {};
            var val0;
            value.forEach((k, v) {
              debugPrint('k,v,counter $k,$v,$counter');
              try {
                val0 = ls.checkInteger(counter);
              } catch (e) {
                try {
                  val0 = ls.checkNumber(counter);
                } catch (e) {
                  ls.getField(counter, k);
                  val0 = ls.checkString(-1);
                }
              }
              val[k] = val0;
            });
            break;
        }
        params[key] = val; // Add the argument to the list.
        counter++;
      });
      func(params); // Call the Dart function.
      ls.pushInteger(12); // Push the return value onto the Lua stack.
      Logger().i('Plugin `$name` called $args'); // Log the function call.
      return 1; // Return the number of return values.
    });
    luaState.setGlobal(name); // Store the function in a global variable.
    return luaState;
  }
arcticfox1919 commented 1 year ago

@maks It seems simpler, only because here { ["hello"] = "World", ["hello22"] = "World132414" } there is no variable name. In addition, the int? max = ls.checkInteger(1);here is retrieving the first parameter from the above function example: randomInt(10,{ ["hello"] = "World", ["hello22"] = "World132414" }). The checkInteger method attempts to get an integer from the first position of the stack, and it will throw an error if it doesn't exist.