feat(lua): signals implemented
This commit is contained in:
parent
b0119ac89a
commit
7d54e06b06
8 changed files with 270 additions and 12 deletions
|
@ -119,6 +119,27 @@ static void processField(CXCursor cur, ClassAnalysis* state) {
|
|||
};
|
||||
}
|
||||
|
||||
static void processSignal(CXCursor cur, ClassAnalysis* state) {
|
||||
std::optional<std::string> signalDef = findAnnotation(cur, "OB::def_signal");
|
||||
if (!signalDef) return;
|
||||
|
||||
SignalAnalysis anly;
|
||||
|
||||
auto result = parseAnnotationString(signalDef.value());
|
||||
std::string fieldName = x_clang_toString(clang_getCursorDisplayName(cur));
|
||||
|
||||
anly.name = result["name"];
|
||||
anly.sourceFieldName = fieldName;
|
||||
|
||||
// if name field is not provided, use fieldName instead, but capitalize the first character
|
||||
if (anly.name == "") {
|
||||
anly.name = fieldName;
|
||||
anly.name[0] = std::toupper(anly.name[0]);
|
||||
}
|
||||
|
||||
state->signals.push_back(anly);
|
||||
}
|
||||
|
||||
static void processClass(CXCursor cur, AnalysisState* state, std::string className, std::string srcRoot) {
|
||||
ClassAnalysis anly;
|
||||
|
||||
|
@ -159,6 +180,7 @@ static void processClass(CXCursor cur, AnalysisState* state, std::string classNa
|
|||
if (kind != CXCursor_FieldDecl) return CXChildVisit_Continue;
|
||||
|
||||
processField(cur, &anly);
|
||||
processSignal(cur, &anly);
|
||||
|
||||
return CXChildVisit_Continue;
|
||||
});
|
||||
|
|
|
@ -36,6 +36,11 @@ struct PropertyAnalysis {
|
|||
PropertyFlags flags = (PropertyFlags)0;
|
||||
};
|
||||
|
||||
struct SignalAnalysis {
|
||||
std::string name;
|
||||
std::string sourceFieldName;
|
||||
};
|
||||
|
||||
// https://stackoverflow.com/a/1448478/16255372
|
||||
inline ClassFlags operator|(ClassFlags a, ClassFlags b) {
|
||||
return static_cast<ClassFlags>(static_cast<int>(a) | static_cast<int>(b));
|
||||
|
@ -51,6 +56,7 @@ struct ClassAnalysis {
|
|||
std::string headerPath;
|
||||
bool abstract = false;
|
||||
std::vector<PropertyAnalysis> properties;
|
||||
std::vector<SignalAnalysis> signals;
|
||||
ClassFlags flags = (ClassFlags)0;
|
||||
std::string explorerIcon;
|
||||
};
|
||||
|
|
|
@ -146,6 +146,18 @@ static void writePropertyGetHandler(std::ofstream& out, ClassAnalysis state) {
|
|||
out << "\n }";
|
||||
first = false;
|
||||
}
|
||||
|
||||
// Handle signals
|
||||
out << "\n ";
|
||||
first = true;
|
||||
for (auto& signal : state.signals) {
|
||||
out << (first ? "" : " else ") << "if (name == \"" << signal.name << "\") {";
|
||||
|
||||
out << "\n return Data::Variant(Data::SignalRef(" << signal.sourceFieldName << "));";
|
||||
|
||||
out << "\n }";
|
||||
first = false;
|
||||
}
|
||||
|
||||
out << "\n return " << state.baseClass << "::InternalGetPropertyValue(name);";
|
||||
// out << "\n return MemberNotFound(\"" << state.name << "\", name);";
|
||||
|
@ -199,6 +211,23 @@ static void writePropertyMetaHandler(std::ofstream& out, ClassAnalysis state) {
|
|||
out << "\n }";
|
||||
first = false;
|
||||
}
|
||||
|
||||
// Handle signals
|
||||
out << "\n ";
|
||||
first = true;
|
||||
for (auto& signal : state.signals) {
|
||||
out << (first ? "" : " else ") << "if (name == \"" << signal.name << "\") {";
|
||||
|
||||
std::string strFlags;
|
||||
strFlags += "PROP_READONLY";
|
||||
strFlags += "| PROP_HIDDEN";
|
||||
strFlags += "| PROP_NOSAVE";
|
||||
|
||||
out << "\n return PropertyMeta { &SignalRef::TYPE, " << strFlags << " };";
|
||||
|
||||
out << "\n }";
|
||||
first = false;
|
||||
}
|
||||
|
||||
out << "\n return " << state.baseClass << "::InternalGetPropertyMeta(name);";
|
||||
// out << "\n return MemberNotFound(\"" << state.name << "\", name);";
|
||||
|
|
|
@ -5,6 +5,7 @@
|
|||
#include "base.h"
|
||||
#include "datatypes/color3.h"
|
||||
#include "datatypes/ref.h"
|
||||
#include "datatypes/signal.h"
|
||||
#include "vector.h"
|
||||
#include "cframe.h"
|
||||
|
||||
|
@ -26,7 +27,9 @@ namespace Data {
|
|||
Vector3,
|
||||
CFrame,
|
||||
Color3,
|
||||
InstanceRef
|
||||
InstanceRef,
|
||||
SignalRef,
|
||||
SignalConnectionRef
|
||||
> __VARIANT_TYPE;
|
||||
|
||||
class Variant {
|
||||
|
|
|
@ -1,7 +1,10 @@
|
|||
#include "signal.h"
|
||||
#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() {}
|
||||
|
@ -67,11 +70,11 @@ 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>(callback)));
|
||||
connections.push_back(std::dynamic_pointer_cast<SignalConnection>(std::make_shared<CSignalConnection>(CSignalConnection(callback))));
|
||||
}
|
||||
|
||||
void Signal::Connect(lua_State* state) {
|
||||
connections.push_back(std::dynamic_pointer_cast<SignalConnection>(std::make_shared<LuaSignalConnection>(state)));
|
||||
connections.push_back(std::dynamic_pointer_cast<SignalConnection>(std::make_shared<LuaSignalConnection>(LuaSignalConnection(state))));
|
||||
}
|
||||
|
||||
void Signal::Fire(std::vector<Data::Variant> args) {
|
||||
|
@ -97,4 +100,162 @@ void SignalConnection::Disconnect() {
|
|||
it++;
|
||||
}
|
||||
parentSignal = {};
|
||||
}
|
||||
|
||||
//
|
||||
|
||||
static int signal_gc(lua_State*);
|
||||
static int signal_index(lua_State*);
|
||||
static int signal_tostring(lua_State*);
|
||||
static const struct luaL_Reg signal_metatable [] = {
|
||||
{"__gc", signal_gc},
|
||||
{"__index", signal_index},
|
||||
{"__tostring", signal_tostring},
|
||||
{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;
|
||||
|
||||
const Data::TypeInfo Data::SignalRef::TYPE = {
|
||||
.name = "Signal",
|
||||
.fromLuaValue = &Data::SignalRef::FromLuaValue,
|
||||
};
|
||||
|
||||
const Data::TypeInfo& Data::SignalRef::GetType() const { return Data::SignalRef::TYPE; };
|
||||
|
||||
const Data::String Data::SignalRef::ToString() const {
|
||||
return Data::String("Signal");
|
||||
}
|
||||
|
||||
Data::SignalRef::operator std::weak_ptr<Signal>() {
|
||||
return signal;
|
||||
}
|
||||
|
||||
void Data::SignalRef::Serialize(pugi::xml_node node) const {
|
||||
// Not serializable
|
||||
}
|
||||
|
||||
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);
|
||||
|
||||
// Create the instance's metatable
|
||||
luaL_newmetatable(L, "__mt_signal");
|
||||
luaL_register(L, NULL, signal_metatable);
|
||||
|
||||
lua_setmetatable(L, n+1);
|
||||
}
|
||||
|
||||
result<Data::Variant, LuaCastError> Data::SignalRef::FromLuaValue(lua_State* L, int idx) {
|
||||
auto userdata = (std::weak_ptr<Signal>*)luaL_checkudata(L, 1, "__mt_signal");
|
||||
lua_pop(L, 1);
|
||||
return Data::Variant(Data::SignalRef(*userdata));
|
||||
}
|
||||
|
||||
static int signal_tostring(lua_State* L) {
|
||||
lua_pop(L, 1);
|
||||
lua_pushstring(L, "Signal");
|
||||
return 1;
|
||||
}
|
||||
|
||||
//
|
||||
|
||||
static int signalconnection_gc(lua_State*);
|
||||
static int signalconnection_index(lua_State*);
|
||||
static int signalconnection_tostring(lua_State*);
|
||||
static const struct luaL_Reg signalconnection_metatable [] = {
|
||||
{"__gc", signalconnection_gc},
|
||||
{"__index", signalconnection_index},
|
||||
{"__tostring", signalconnection_tostring},
|
||||
{NULL, NULL} /* end of array */
|
||||
};
|
||||
|
||||
|
||||
static int signalconnection_gc(lua_State* L) {
|
||||
// Destroy the contained shared_ptr
|
||||
auto userdata = (std::weak_ptr<SignalConnection>*)luaL_checkudata(L, 1, "__mt_signalconnection");
|
||||
delete userdata;
|
||||
lua_pop(L, 1);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
// __index(t,k)
|
||||
static int signalconnection_index(lua_State* L) {
|
||||
auto userdata = (std::weak_ptr<SignalConnection>*)luaL_checkudata(L, 1, "__mt_signalconnection");
|
||||
std::weak_ptr<SignalConnection> signalConnection = *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(), "SignalConnection");
|
||||
}
|
||||
|
||||
Data::SignalConnectionRef::SignalConnectionRef(std::weak_ptr<SignalConnection> ref) : signalConnection(ref) {}
|
||||
Data::SignalConnectionRef::~SignalConnectionRef() = default;
|
||||
|
||||
const Data::TypeInfo Data::SignalConnectionRef::TYPE = {
|
||||
.name = "Signal",
|
||||
.fromLuaValue = &Data::SignalConnectionRef::FromLuaValue,
|
||||
};
|
||||
|
||||
const Data::TypeInfo& Data::SignalConnectionRef::GetType() const { return Data::SignalConnectionRef::TYPE; };
|
||||
|
||||
const Data::String Data::SignalConnectionRef::ToString() const {
|
||||
return Data::String("Connection");
|
||||
}
|
||||
|
||||
Data::SignalConnectionRef::operator std::weak_ptr<SignalConnection>() {
|
||||
return signalConnection;
|
||||
}
|
||||
|
||||
void Data::SignalConnectionRef::Serialize(pugi::xml_node node) const {
|
||||
// Not serializable
|
||||
}
|
||||
|
||||
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);
|
||||
|
||||
// Create the instance's metatable
|
||||
luaL_newmetatable(L, "__mt_signalconnection");
|
||||
luaL_register(L, NULL, signalconnection_metatable);
|
||||
|
||||
lua_setmetatable(L, n+1);
|
||||
}
|
||||
|
||||
result<Data::Variant, LuaCastError> Data::SignalConnectionRef::FromLuaValue(lua_State* L, int idx) {
|
||||
auto userdata = (std::weak_ptr<SignalConnection>*)luaL_checkudata(L, 1, "__mt_signalconnection");
|
||||
lua_pop(L, 1);
|
||||
return Data::Variant(Data::SignalConnectionRef(*userdata));
|
||||
}
|
||||
|
||||
static int signalconnection_tostring(lua_State* L) {
|
||||
lua_pop(L, 1);
|
||||
lua_pushstring(L, "SignalConnection");
|
||||
return 1;
|
||||
}
|
|
@ -1,6 +1,7 @@
|
|||
#pragma once
|
||||
|
||||
#include "base.h"
|
||||
#include "datatypes/annotation.h"
|
||||
#include <functional>
|
||||
#include <memory>
|
||||
#include <vector>
|
||||
|
@ -18,16 +19,16 @@ class SignalConnection : public std::enable_shared_from_this<SignalConnection> {
|
|||
protected:
|
||||
std::weak_ptr<Signal> parentSignal;
|
||||
|
||||
virtual ~SignalConnection();
|
||||
|
||||
virtual void Call(std::vector<Data::Variant>);
|
||||
virtual void Call(std::vector<Data::Variant>) = 0;
|
||||
friend Signal;
|
||||
public:
|
||||
inline bool Connected() { return !parentSignal.expired(); };
|
||||
void Disconnect();
|
||||
|
||||
virtual ~SignalConnection();
|
||||
};
|
||||
|
||||
class CSignalConnection : protected SignalConnection {
|
||||
class CSignalConnection : public SignalConnection {
|
||||
std::function<void(std::vector<Data::Variant>)> function;
|
||||
|
||||
CSignalConnection(std::function<void(std::vector<Data::Variant>)>);
|
||||
|
@ -37,15 +38,16 @@ protected:
|
|||
void Call(std::vector<Data::Variant>) override;
|
||||
};
|
||||
|
||||
class LuaSignalConnection : protected SignalConnection {
|
||||
class LuaSignalConnection : public SignalConnection {
|
||||
lua_State* thread;
|
||||
|
||||
LuaSignalConnection(lua_State*);
|
||||
~LuaSignalConnection();
|
||||
|
||||
friend Signal;
|
||||
protected:
|
||||
void Call(std::vector<Data::Variant>) override;
|
||||
public:
|
||||
~LuaSignalConnection();
|
||||
};
|
||||
|
||||
class Signal {
|
||||
|
@ -71,9 +73,40 @@ public:
|
|||
namespace Data {
|
||||
class SignalRef : public Data::Base {
|
||||
std::weak_ptr<Signal> signal;
|
||||
|
||||
public:
|
||||
SignalRef(std::weak_ptr<Signal>);
|
||||
~SignalRef();
|
||||
|
||||
virtual const TypeInfo& GetType() const override;
|
||||
static const TypeInfo TYPE;
|
||||
|
||||
operator std::weak_ptr<Signal>();
|
||||
|
||||
virtual const Data::String ToString() const override;
|
||||
virtual void Serialize(pugi::xml_node node) const override;
|
||||
virtual void PushLuaValue(lua_State*) const override;
|
||||
static result<Data::Variant, LuaCastError> FromLuaValue(lua_State*, int idx);
|
||||
};
|
||||
|
||||
class SignalConnectionRef : public Data::Base {
|
||||
std::weak_ptr<Signal> signal;
|
||||
std::weak_ptr<SignalConnection> signalConnection;
|
||||
|
||||
public:
|
||||
SignalConnectionRef(std::weak_ptr<SignalConnection>);
|
||||
~SignalConnectionRef();
|
||||
|
||||
virtual const TypeInfo& GetType() const override;
|
||||
static const TypeInfo TYPE;
|
||||
|
||||
operator std::weak_ptr<SignalConnection>();
|
||||
|
||||
virtual const Data::String ToString() const override;
|
||||
virtual void Serialize(pugi::xml_node node) const override;
|
||||
virtual void PushLuaValue(lua_State*) const override;
|
||||
static result<Data::Variant, LuaCastError> FromLuaValue(lua_State*, int idx);
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
using Data::SignalRef;
|
||||
using Data::SignalConnectionRef;
|
|
@ -6,12 +6,14 @@
|
|||
#ifdef __AUTOGEN__
|
||||
#define def_inst(...) clang::annotate("OB::def_inst", #__VA_ARGS__)
|
||||
#define def_prop(...) clang::annotate("OB::def_prop", #__VA_ARGS__)
|
||||
#define def_signal(...) clang::annotate("OB::def_signal", #__VA_ARGS__)
|
||||
#define def_prop_category(...) clang::annotate("OB::def_prop_category", #__VA_ARGS__)
|
||||
#define cframe_position_prop(...) clang::annotate("OB::cframe_position_prop", #__VA_ARGS__)
|
||||
#define cframe_rotation_prop(...) clang::annotate("OB::cframe_rotation_prop", #__VA_ARGS__)
|
||||
#else
|
||||
#define def_inst(...)
|
||||
#define def_prop(...)
|
||||
#define def_signal(...)
|
||||
#define def_prop_category(...)
|
||||
#define cframe_position_prop(...)
|
||||
#define cframe_rotation_prop(...)
|
||||
|
@ -26,6 +28,8 @@
|
|||
#define DEF_INST_SERVICE_(...) [[ def_inst(__VA_ARGS__, service) ]]
|
||||
#define DEF_PROP [[ def_prop() ]]
|
||||
#define DEF_PROP_(...) [[ def_prop(__VA_ARGS__) ]]
|
||||
#define DEF_SIGNAL [[ def_signal() ]]
|
||||
#define DEF_SIGNAL_(...) [[ def_signal(__VA_ARGS__) ]]
|
||||
|
||||
// Categories
|
||||
#define DEF_PROP_CATEGORY(CATEGORY) [[ def_prop_category(category=CATEGORY) ]]
|
||||
|
|
|
@ -92,7 +92,7 @@ public:
|
|||
DEF_PROP float frontParamB = 0.5;
|
||||
DEF_PROP float backParamB = 0.5;
|
||||
|
||||
SignalSource OnParentUpdated;
|
||||
DEF_SIGNAL SignalSource OnParentUpdated;
|
||||
|
||||
rp::RigidBody* rigidBody = nullptr;
|
||||
|
||||
|
|
Loading…
Add table
Reference in a new issue