feat(lua): connect to signal

This commit is contained in:
maelstrom 2025-05-11 11:26:44 +02:00
parent 7d54e06b06
commit b9dc280311
3 changed files with 69 additions and 41 deletions

View file

@ -2,12 +2,10 @@
#include "datatypes/base.h"
#include "meta.h"
#include "lua.h"
#include <luajit-2.1/lauxlib.h>
#include <luajit-2.1/lua.h>
#include <pugixml.hpp>
#include <memory>
SignalSource::SignalSource() {}
SignalSource::SignalSource() : std::shared_ptr<Signal>(std::make_shared<Signal>()) {}
SignalSource::~SignalSource() = default;
Signal::Signal() {}
@ -16,16 +14,22 @@ Signal::~Signal() = default;
SignalConnection::~SignalConnection() = default;
// Only used for its address
int __savedThreads;
int __savedThreads = 0;
LuaSignalConnection::LuaSignalConnection(lua_State* L) {
// Create thread from function at top of stack
thread = lua_newthread(L);
lua_xmove(L, thread, 1);
// Save thread so it doesn't get GC'd
lua_pushlightuserdata(thread, &__savedThreads);
lua_gettable(thread, LUA_REGISTRYINDEX);
// https://stackoverflow.com/a/31952046/16255372
// Create the table
if (__savedThreads == 0) {
lua_newtable(thread);
__savedThreads = luaL_ref(thread, LUA_REGISTRYINDEX);
}
// Save thread so it doesn't get GC'd
lua_rawgeti(thread, LUA_REGISTRYINDEX, __savedThreads);
lua_pushthread(thread); // key
lua_pushboolean(thread, true); // value
lua_rawset(thread, -3); // set
@ -35,8 +39,7 @@ LuaSignalConnection::LuaSignalConnection(lua_State* L) {
LuaSignalConnection::~LuaSignalConnection() {
// Remove thread so that it can get properly GC'd
lua_pushlightuserdata(thread, &__savedThreads);
lua_gettable(thread, LUA_REGISTRYINDEX);
lua_rawgeti(thread, LUA_REGISTRYINDEX, __savedThreads);
lua_pushthread(thread); // key
lua_pushnil(thread); // value
@ -69,12 +72,16 @@ void CSignalConnection::Call(std::vector<Data::Variant> args) {
//
void Signal::Connect(std::function<void(std::vector<Data::Variant>)> callback) {
connections.push_back(std::dynamic_pointer_cast<SignalConnection>(std::make_shared<CSignalConnection>(CSignalConnection(callback))));
SignalConnectionRef Signal::Connect(std::function<void(std::vector<Data::Variant>)> callback) {
auto conn = std::dynamic_pointer_cast<SignalConnection>(std::make_shared<CSignalConnection>(CSignalConnection(callback)));
connections.push_back(conn);
return SignalConnectionRef(conn);
}
void Signal::Connect(lua_State* state) {
connections.push_back(std::dynamic_pointer_cast<SignalConnection>(std::make_shared<LuaSignalConnection>(LuaSignalConnection(state))));
SignalConnectionRef Signal::Connect(lua_State* state) {
auto conn = std::dynamic_pointer_cast<SignalConnection>(std::make_shared<LuaSignalConnection>(LuaSignalConnection(state)));
connections.push_back(conn);
return SignalConnectionRef(conn);
}
void Signal::Fire(std::vector<Data::Variant> args) {
@ -104,6 +111,8 @@ void SignalConnection::Disconnect() {
//
static int signal_Connect(lua_State*);
static int signal_gc(lua_State*);
static int signal_index(lua_State*);
static int signal_tostring(lua_State*);
@ -114,26 +123,6 @@ static const struct luaL_Reg signal_metatable [] = {
{NULL, NULL} /* end of array */
};
static int signal_gc(lua_State* L) {
// Destroy the contained shared_ptr
auto userdata = (std::weak_ptr<Signal>*)luaL_checkudata(L, 1, "__mt_signal");
delete userdata;
lua_pop(L, 1);
return 0;
}
// __index(t,k)
static int signal_index(lua_State* L) {
auto userdata = (std::weak_ptr<Signal>*)luaL_checkudata(L, 1, "__mt_signal");
std::weak_ptr<Signal> signal = *userdata;
std::string key(lua_tostring(L, 2));
lua_pop(L, 2);
return luaL_error(L, "'%s' is not a valid member of %s", key.c_str(), "Signal");
}
Data::SignalRef::SignalRef(std::weak_ptr<Signal> ref) : signal(ref) {}
Data::SignalRef::~SignalRef() = default;
@ -159,8 +148,8 @@ void Data::SignalRef::Serialize(pugi::xml_node node) const {
void Data::SignalRef::PushLuaValue(lua_State* L) const {
int n = lua_gettop(L);
auto userdata = (std::weak_ptr<Signal>*)lua_newuserdata(L, sizeof(void*));
new(userdata) std::weak_ptr(signal);
auto userdata = (std::weak_ptr<Signal>*)lua_newuserdata(L, sizeof(std::weak_ptr<Signal>));
new(userdata) std::weak_ptr<Signal>(signal);
// Create the instance's metatable
luaL_newmetatable(L, "__mt_signal");
@ -175,12 +164,47 @@ result<Data::Variant, LuaCastError> Data::SignalRef::FromLuaValue(lua_State* L,
return Data::Variant(Data::SignalRef(*userdata));
}
static int signal_gc(lua_State* L) {
// Destroy the contained shared_ptr
auto userdata = (std::weak_ptr<Signal>*)luaL_checkudata(L, 1, "__mt_signal");
delete userdata;
lua_pop(L, 1);
return 0;
}
// __index(t,k)
static int signal_index(lua_State* L) {
auto userdata = (std::weak_ptr<Signal>*)luaL_checkudata(L, 1, "__mt_signal");
std::weak_ptr<Signal> signal = *userdata;
std::string key(lua_tostring(L, 2));
lua_pop(L, 2);
if (key == "Connect") {
lua_pushcfunction(L, signal_Connect);
return 1;
}
return luaL_error(L, "'%s' is not a valid member of %s", key.c_str(), "Signal");
}
static int signal_tostring(lua_State* L) {
lua_pop(L, 1);
lua_pushstring(L, "Signal");
return 1;
}
static int signal_Connect(lua_State* L) {
auto userdata = (std::weak_ptr<Signal>*)luaL_checkudata(L, 1, "__mt_signal");
std::shared_ptr<Signal> signal = (*userdata).lock();
luaL_checktype(L, 2, LUA_TFUNCTION);
SignalConnectionRef ref = signal->Connect(L);
ref.PushLuaValue(L);
return 1;
}
//
static int signalconnection_gc(lua_State*);
@ -238,8 +262,8 @@ void Data::SignalConnectionRef::Serialize(pugi::xml_node node) const {
void Data::SignalConnectionRef::PushLuaValue(lua_State* L) const {
int n = lua_gettop(L);
auto userdata = (std::weak_ptr<SignalConnection>*)lua_newuserdata(L, sizeof(void*));
new(userdata) std::weak_ptr(signalConnection);
auto userdata = (std::weak_ptr<SignalConnection>*)lua_newuserdata(L, sizeof(std::weak_ptr<SignalConnection>));
new(userdata) std::weak_ptr<SignalConnection>(signalConnection);
// Create the instance's metatable
luaL_newmetatable(L, "__mt_signalconnection");

View file

@ -15,6 +15,8 @@
class Instance;
class Signal;
namespace Data { class SignalConnectionRef; }
class SignalConnection : public std::enable_shared_from_this<SignalConnection> {
protected:
std::weak_ptr<Signal> parentSignal;
@ -60,8 +62,8 @@ public:
void DisconnectAll();
void Fire(std::vector<Data::Variant> args);
void Connect(std::function<void(std::vector<Data::Variant>)> callback);
void Connect(lua_State*);
Data::SignalConnectionRef Connect(std::function<void(std::vector<Data::Variant>)> callback);
Data::SignalConnectionRef Connect(lua_State*);
};
class SignalSource : public std::shared_ptr<Signal> {

View file

@ -15,7 +15,9 @@ int script_wait(lua_State*);
int script_delay(lua_State*);
Script::Script(): Instance(&TYPE) {
source = "print \"Hello, world!\"\nwait(1)print \"Wait success! :D\"";
source = "workspace.Part.OnParentUpdated:Connect(function()\n\
print(\"Yeux d'enfants\")\n\
end)";
}
Script::~Script() {