Storing arbitrary types as a global? #1
-
Would it be possible to store arbitrary first-party types as globals via public void Open(Lua lua, bool leaveOnStack)
{
IGuildChannel? channel = _context.Bot.GetChannel(_context.GuildId, _context.ChannelId);
var guild = _context.Bot.GetGuild(_context.GuildId)!;
lua.Execute(@$"
ctx = {{
author = {{
id = ""{_context.Author.Id}""
name = ""{_context.Author.Name}""
nick = {(string.IsNullOrWhiteSpace(_context.Author.Nick) ? $"\"{_context.Author.Nick}\"" : "nil")}
tag = ""{_context.Author.Tag}""
avatar = ""{_context.Author.GetGuildAvatarUrl()}""
created = {_context.Author.CreatedAt().ToUnixTimeSeconds()}
}}
channel = {{
id = ""{_context.ChannelId}""
type = {(channel is not null ? $"\"{channel.Type}\"" : "nil")}
name = {(channel is not null ? $"\"{channel.Name}\"" : "nil")}
created = {_context.ChannelId.CreatedAt.ToUnixTimeSeconds()}
}}
guild = {{
id = ""{guild.Id}""
name = ""{guild.Name}""
created = ""{guild.CreatedAt().ToUnixTimeSeconds()}""
}}
}}");
} This allows scripts to access |
Beta Was this translation helpful? Give feedback.
Replies: 1 comment 1 reply
-
UD DescriptorsYes, this functionality is already supported with user data descriptors. However, I haven't yet implemented the attribute-based approach for it. It requires significant effort to ensure efficient and customizable implementation, which means that, for now, you'll need to manually implement the necessary boilerplate code yourself. Here's a simple example that demonstrates getting and setting a .NET property with Lua through a descriptor: using (var lua = new Lua())
{
lua.Marshaler.UserDataDescriptorProvider.SetDescriptor(typeof(MyClass), new MyClassUserDataDecriptor());
lua.SetGlobal("myclass", new MyClass());
lua.Execute("myclass.text = 'Hello, World!'");
var result = lua.Evaluate<string>("return myclass.text");
Console.WriteLine(result); // Hello, World!
} Remaining Code
public class MyClass
{
public string? Text { get; set; }
} public class MyClassUserDataDecriptor : CallbackBasedUserDataDescriptor
{
public override string MetatableName => nameof(MyClass);
// Specifies which callbacks the descriptor supports
public override CallbackUserDataDescriptorFlags Flags
{
get
{
// Supports both getting and setting properties;
return CallbackUserDataDescriptorFlags.Index | CallbackUserDataDescriptorFlags.NewIndex;
}
}
public override int Index(Lua lua, LuaStackValue userData, LuaStackValue key)
{
var instance = userData.GetValue<MyClass>()!;
// Check for `myclass.key`:
if (key.Type == LuaType.String)
{
// This could be done with Reflection, for example:
switch (key.GetValue<string>())
{
case "text":
{
lua.Stack.Push(instance.Text);
return 1; // The amount of values returned, i.e. the amount of values we pushed onto the stack.
}
}
}
return 0;
}
public override int NewIndex(Lua lua, LuaStackValue userData, LuaStackValue key, LuaStackValue value)
{
var instance = userData.GetValue<MyClass>()!;
// Check for `myclass.key = value`:
if (key.Type == LuaType.String)
{
// This could be done with Reflection, for example:
switch (key.GetValue<string>())
{
case "text":
{
if (!value.TryGetValue<string>(out var stringValue))
lua.RaiseArgumentTypeError(value.Index, "string");
instance.Text = stringValue;
return 1; // The amount of values returned, i.e. the amount of values we pushed onto the stack.
}
}
}
return 0;
}
}
Creating the TablesInstead of using Execute() with interpolated strings to create tables, I suggest using
Here's an example of how this could look like: using (var ctxTable = lua.CreateTable())
{
using (var authorTable = lua.CreateTable())
{
authorTable.SetValue("id", id);
authorTable.SetValue("name", name);
ctxTable.SetValue("author", authorTable);
}
using (var channelTable = lua.CreateTable())
{
channelTable.SetValue("id", id);
channelTable.SetValue("name", name);
ctxTable.SetValue("channel", channelTable);
}
lua.SetGlobal("ctx", ctxTable);
}
I hope this proves helpful, and thank you for giving the library a try! |
Beta Was this translation helpful? Give feedback.
UD Descriptors
Yes, this functionality is already supported with user data descriptors.
However, I haven't yet implemented the attribute-based approach for it. It requires significant effort to ensure efficient and customizable implementation, which means that, for now, you'll need to manually implement the necessary boilerplate code yourself.
Here's a simple example that demonstrates getting and setting a .NET property with Lua through a descriptor: