|
|
@@ -233,7 +233,12 @@ Console.WriteLine(results[i]);
|
|
|
return add(1, 2)
|
|
|
```
|
|
|
|
|
|
-Additionally, `LuaFunction` operates asynchronously. Therefore, you can define a function that waits for an operation in Lua, such as the example below:
|
|
|
+> [!TIP]
|
|
|
+> Defining functions with `LuaFunction` can be somewhat verbose. When adding multiple functions, it is recommended to use the Source Generator with the `[LuaObject]` attribute. For more details, see the [LuaObject](#luaobject) section.
|
|
|
+
|
|
|
+## Integration with async/await
|
|
|
+
|
|
|
+`LuaFunction` operates asynchronously. Therefore, you can define a function that waits for an operation in Lua, such as the example below:
|
|
|
|
|
|
```cs
|
|
|
// Define a function that waits for the given number of seconds using Task.Delay
|
|
|
@@ -298,6 +303,146 @@ for (int i = 0; i < 10; i++)
|
|
|
}
|
|
|
```
|
|
|
|
|
|
+## LuaObject
|
|
|
+
|
|
|
+By applying the `[LuaObject]` attribute, you can create custom classes that run within Lua. Adding this attribute to a class that you wish to use in Lua allows the Source Generator to automatically generate the code required for interaction from Lua.
|
|
|
+
|
|
|
+The following is an example implementation of a wrapper class for `System.Numerics.Vector3` that can be used in Lua:
|
|
|
+
|
|
|
+```cs
|
|
|
+using System.Numerics;
|
|
|
+using Lua;
|
|
|
+
|
|
|
+var state = LuaState.Create();
|
|
|
+
|
|
|
+// Add an instance of the defined LuaObject as a global variable
|
|
|
+// (Implicit conversion to LuaValue is automatically defined for classes with the LuaObject attribute)
|
|
|
+state.Environment["Vector3"] = new LuaVector3();
|
|
|
+
|
|
|
+await state.DoFileAsync("vector3_sample.lua");
|
|
|
+
|
|
|
+// Add LuaObject attribute and partial keyword
|
|
|
+[LuaObject]
|
|
|
+public partial class LuaVector3
|
|
|
+{
|
|
|
+ Vector3 vector;
|
|
|
+
|
|
|
+ // Add LuaMember attribute to members that will be used in Lua
|
|
|
+ // The argument specifies the name used in Lua (if omitted, the member name is used)
|
|
|
+ [LuaMember("x")]
|
|
|
+ public float X
|
|
|
+ {
|
|
|
+ get => vector.X;
|
|
|
+ set => vector = vector with { X = value };
|
|
|
+ }
|
|
|
+
|
|
|
+ [LuaMember("y")]
|
|
|
+ public float Y
|
|
|
+ {
|
|
|
+ get => vector.Y;
|
|
|
+ set => vector = vector with { Y = value };
|
|
|
+ }
|
|
|
+
|
|
|
+ [LuaMember("z")]
|
|
|
+ public float Z
|
|
|
+ {
|
|
|
+ get => vector.Z;
|
|
|
+ set => vector = vector with { Z = value };
|
|
|
+ }
|
|
|
+
|
|
|
+ // Static methods are treated as regular Lua functions
|
|
|
+ [LuaMember("create")]
|
|
|
+ public static LuaVector3 Create(float x, float y, float z)
|
|
|
+ {
|
|
|
+ return new LuaVector3()
|
|
|
+ {
|
|
|
+ vector = new Vector3(x, y, z)
|
|
|
+ };
|
|
|
+ }
|
|
|
+
|
|
|
+ // Instance methods implicitly receive the instance (this) as the first argument
|
|
|
+ // In Lua, this is accessed with instance:method() syntax
|
|
|
+ [LuaMember("normalized")]
|
|
|
+ public LuaVector3 Normalized()
|
|
|
+ {
|
|
|
+ return new LuaVector3()
|
|
|
+ {
|
|
|
+ vector = Vector3.Normalize(vector)
|
|
|
+ };
|
|
|
+ }
|
|
|
+}
|
|
|
+```
|
|
|
+
|
|
|
+```lua
|
|
|
+-- vector3_sample.lua
|
|
|
+
|
|
|
+local v1 = Vector3.create(1, 2, 3)
|
|
|
+-- 1 2 3
|
|
|
+print(v1.x, v1.y, v1.z)
|
|
|
+
|
|
|
+local v2 = v1:normalized()
|
|
|
+-- 0.26726123690605164 0.5345224738121033 0.8017836809158325
|
|
|
+print(v2.x, v2.y, v2.z)
|
|
|
+```
|
|
|
+
|
|
|
+The types of fields/properties with the `[LuaMember]` attribute, as well as the argument and return types of methods, must be either `LuaValue` or convertible to/from `LuaValue`.
|
|
|
+
|
|
|
+Return types such as `void`, `Task/Task<T>`, `ValueTask/ValueTask<T>`, `UniTask/UniTask<T>`, and `Awaitable/Awaitable<T>` are also supported.
|
|
|
+
|
|
|
+If the type is not supported, the Source Generator will output a compile-time error.
|
|
|
+
|
|
|
+### LuaMetamethod
|
|
|
+
|
|
|
+By adding the `[LuaMetamethod]` attribute, you can designate a C# method to be used as a Lua metamethod.
|
|
|
+
|
|
|
+Here is an example that adds the `__add`, `__sub`, and `__tostring` metamethods to the `LuaVector3` class:
|
|
|
+
|
|
|
+```cs
|
|
|
+[LuaObject]
|
|
|
+public partial class LuaVector3
|
|
|
+{
|
|
|
+ // The previous implementation is omitted
|
|
|
+
|
|
|
+ [LuaMetamethod(LuaObjectMetamethod.Add)]
|
|
|
+ public static LuaVector3 Add(LuaVector3 a, LuaVector3 b)
|
|
|
+ {
|
|
|
+ return new LuaVector3()
|
|
|
+ {
|
|
|
+ vector = a.vector + b.vector
|
|
|
+ };
|
|
|
+ }
|
|
|
+
|
|
|
+ [LuaMetamethod(LuaObjectMetamethod.Sub)]
|
|
|
+ public static LuaVector3 Sub(LuaVector3 a, LuaVector3 b)
|
|
|
+ {
|
|
|
+ return new LuaVector3()
|
|
|
+ {
|
|
|
+ vector = a.vector - b.vector
|
|
|
+ };
|
|
|
+ }
|
|
|
+
|
|
|
+ [LuaMetamethod(LuaObjectMetamethod.ToString)]
|
|
|
+ public override string ToString()
|
|
|
+ {
|
|
|
+ return vector.ToString();
|
|
|
+ }
|
|
|
+}
|
|
|
+```
|
|
|
+
|
|
|
+```lua
|
|
|
+local v1 = Vector3.create(1, 1, 1)
|
|
|
+local v2 = Vector3.create(2, 2, 2)
|
|
|
+
|
|
|
+print(v1) -- <1, 1, 1>
|
|
|
+print(v2) -- <2, 2, 2>
|
|
|
+
|
|
|
+print(v1 + v2) -- <3, 3, 3>
|
|
|
+print(v1 - v2) -- <-1, -1, -1>
|
|
|
+```
|
|
|
+
|
|
|
+> [!NOTE]
|
|
|
+> `__index` and `__newindex` cannot be set as they are used internally by the code generated by `[LuaObject]`.
|
|
|
+
|
|
|
## Module Loading
|
|
|
|
|
|
In Lua, you can load modules using the `require` function. In regular Lua, modules are managed by searchers within the `package.searchers` function list. In Lua-CSharp, this is replaced by the `ILuaModuleLoader` interface.
|