refactor(datatypes): complete refactor of how datatypes work and removal of wrapper classes for bool, string etc.

This commit is contained in:
maelstrom 2025-05-31 23:08:05 +02:00
parent c8880e0edc
commit 5f6ff971d2
39 changed files with 831 additions and 804 deletions

View file

@ -9,10 +9,6 @@
using namespace data;
static std::map<std::string, std::string> MAPPED_TYPE = {
{ "bool", "Data::Bool" },
{ "int", "Data::Int" },
{ "float", "Data::Float" },
{ "std::string", "Data::String" },
{ "glm::vec3", "Vector3" },
};
@ -30,16 +26,36 @@ static std::map<std::string, std::string> LUA_TEST_FUNCS = {
{ "std::string", "lua_isstring" },
};
static std::map<std::string, std::string> LUA_PUSH_FUNCS = {
{ "bool", "lua_pushboolean" },
{ "int", "lua_pushinteger" },
{ "float", "lua_pushnumber" },
// Handled specially
// { "std::string", "lua_pushstring" },
};
static std::string getLuaMethodFqn(std::string className, std::string methodName) {
return "__lua_impl__" + className + "__" + methodName;
}
static std::string getMtName(std::string type) {
if (type.starts_with("Data::"))
return "__mt_" + type.substr(6);
// if (type.starts_with("Data::"))
// return "__mt_" + type.substr(6);
return "__mt_" + type;
}
static std::string pushLuaValue(std::string type, std::string expr) {
if (type == "std::string")
return "lua_pushstring(L, " + expr + ".c_str())";
std::string mappedType = MAPPED_TYPE[type];
if (mappedType != "")
return mappedType + "(" + expr + ").PushLuaValue(L)";
std::string pushFunc = LUA_PUSH_FUNCS[type];
if (pushFunc != "")
return pushFunc + "(L, " + expr + ")";
return expr + ".PushLuaValue(L)";
}
static void writeLuaGetArgument(std::ofstream& out, std::string type, int narg, bool member) {
std::string varname = "arg" + std::to_string(narg);
narg += 1; // Arguments start at 1
@ -69,7 +85,7 @@ static void writeLuaTestArgument(std::ofstream& out, std::string type, int narg,
}
static void writeLuaMethodImpls(std::ofstream& out, ClassAnalysis& state) {
std::string fqn = "Data::" + state.name;
std::string fqn = "" + state.name;
// Collect all method names to account for overloaded functions
std::map<std::string, std::vector<MethodAnalysis>> methods;
@ -132,11 +148,7 @@ static void writeLuaMethodImpls(std::ofstream& out, ClassAnalysis& state) {
// Return result
if (methodImpl.returnType != "void") {
std::string mappedType = MAPPED_TYPE[methodImpl.returnType];
if (mappedType == "")
out << " result.PushLuaValue(L);\n";
else
out << " " << mappedType << "(result).PushLuaValue(L);\n";
out << " " << pushLuaValue(methodImpl.returnType, "result") << ";\n";
}
if (methodImpl.returnType == "void")
@ -205,11 +217,7 @@ static void writeLuaMethodImpls(std::ofstream& out, ClassAnalysis& state) {
// Return result
if (methodImpl.returnType != "void") {
std::string mappedType = MAPPED_TYPE[methodImpl.returnType];
if (mappedType == "")
out << " result.PushLuaValue(L);\n";
else
out << " " << mappedType << "(result).PushLuaValue(L);\n";
out << " " << pushLuaValue(methodImpl.returnType, "result") << ";\n";
}
if (methodImpl.returnType == "void")
@ -228,7 +236,7 @@ static void writeLuaMethodImpls(std::ofstream& out, ClassAnalysis& state) {
}
static void writeLuaValueGenerator(std::ofstream& out, ClassAnalysis& state) {
std::string fqn = "Data::" + state.name;
std::string fqn = state.name;
out << "static int data_gc(lua_State*);\n"
"static int data_index(lua_State*);\n"
@ -240,12 +248,9 @@ static void writeLuaValueGenerator(std::ofstream& out, ClassAnalysis& state) {
" {NULL, NULL} /* end of array */\n"
"};\n\n";
out << "void Data::" << state.name << "::PushLuaValue(lua_State* L) const {\n"
out << "void " << state.name << "::PushLuaValue(lua_State* L) const {\n"
" int n = lua_gettop(L);\n"
// " // I'm torn... should this be Data::Variant, or Data::Base?\n"
// " // If I ever decouple typing from Data::Base, I'll switch it to variant,\n"
// " // otherwise, it doesn't make much sense to represent it as one\n"
" " << fqn << "** userdata = (" << fqn << "**)lua_newuserdata(L, sizeof(" << fqn << "));\n"
" *userdata = new " << fqn << "(*this);\n"
@ -257,11 +262,11 @@ static void writeLuaValueGenerator(std::ofstream& out, ClassAnalysis& state) {
"}\n\n";
out << "result<Data::Variant, LuaCastError> Data::" << state.name << "::FromLuaValue(lua_State* L, int idx) {\n"
out << "result<Variant, LuaCastError> " << state.name << "::FromLuaValue(lua_State* L, int idx) {\n"
" " << fqn << "** userdata = (" << fqn << "**) luaL_testudata(L, idx, \"" << getMtName(state.name) << "\");\n"
" if (userdata == nullptr)\n"
" return LuaCastError(lua_typename(L, idx), \"" << state.name << "\");\n"
" return Data::Variant(**userdata);\n"
" return Variant(**userdata);\n"
"}\n\n";
// Indexing methods and properties
@ -292,7 +297,7 @@ static void writeLuaValueGenerator(std::ofstream& out, ClassAnalysis& state) {
valueExpr = "this_->" + prop.backingSymbol + "()";
// This largely depends on the type
out << " " << type << "(" << valueExpr << ").PushLuaValue(L);\n";
out << " " << pushLuaValue(type, valueExpr) << ";\n";
out << " return 1;\n";
out << " }";
@ -334,7 +339,7 @@ static void writeLuaValueGenerator(std::ofstream& out, ClassAnalysis& state) {
}
static void writeLuaLibraryGenerator(std::ofstream& out, ClassAnalysis& state) {
std::string fqn = "Data::" + state.name;
std::string fqn = state.name;
out << "static int lib_index(lua_State*);\n"
"static const struct luaL_Reg lib_metatable [] = {\n"
@ -342,7 +347,7 @@ static void writeLuaLibraryGenerator(std::ofstream& out, ClassAnalysis& state) {
" {NULL, NULL} /* end of array */\n"
"};\n\n";
out << "void Data::" << state.name << "::PushLuaLibrary(lua_State* L) {\n"
out << "void " << state.name << "::PushLuaLibrary(lua_State* L) {\n"
" lua_getglobal(L, \"_G\");\n"
" lua_pushstring(L, \"" << state.name << "\");\n"
"\n"
@ -382,7 +387,7 @@ static void writeLuaLibraryGenerator(std::ofstream& out, ClassAnalysis& state) {
else if (prop.backingType == PropertyBackingType::Method)
valueExpr = fqn + "::" + prop.backingSymbol + "()";
out << " " << type << "(" << valueExpr << ").PushLuaValue(L);\n";
out << " " << pushLuaValue(type, valueExpr) << ";\n";
out << " return 1;\n";
out << " }";
@ -408,22 +413,19 @@ static void writeLuaLibraryGenerator(std::ofstream& out, ClassAnalysis& state) {
}
void data::writeCodeForClass(std::ofstream& out, std::string headerPath, ClassAnalysis& state) {
std::string fqn = "Data::" + state.name;
out << "#define __AUTOGEN_EXTRA_INCLUDES__\n";
out << "#include \"" << headerPath << "\"\n\n";
out << "#include \"datatypes/meta.h\"\n";
out << "#include \"datatypes/variant.h\"\n";
out << "#include <pugixml.hpp>\n";
out << "#include \"lua.h\"\n\n";
out << "const Data::TypeInfo " << fqn << "::TYPE = {\n"
out << "const TypeInfo " << state.name << "::TYPE = {\n"
<< " .name = \"" << state.serializedName << "\",\n"
<< " .deserializer = &" << fqn << "::Deserialize,\n";
if (state.hasFromString) out << " .fromString = &" << fqn << "::FromString,\n";
out << " .fromLuaValue = &" << fqn << "::FromLuaValue,\n"
<< "};\n\n";
out << "const Data::TypeInfo& " << fqn << "::GetType() const {\n"
<< " return TYPE;\n"
<< " .serializer = toVariantFunction(&" << state.name << "::Serialize),"
<< " .deserializer = &" << state.name << "::Deserialize,\n"
<< " .toString = toVariantFunction(&" << state.name << "::ToString),";
if (state.hasFromString) out << " .fromString = &" << state.name << "::FromString,\n";
out << " .pushLuaValue = toVariantFunction(&" << state.name << "::PushLuaValue),"
<< " .fromLuaValue = &" << state.name << "::FromLuaValue,\n"
<< "};\n\n";
writeLuaMethodImpls(out, state);

View file

@ -54,7 +54,7 @@ int processHeader(fs::path srcRoot, fs::path srcPath, fs::path outPath) {
fs::path relpath = fs::relative(srcPath, srcRoot);
printf("[AUTOGEN] Processing file %s...\n", relpath.c_str());
object::analyzeClasses(cursor, srcRoot, &objectAnlyState);
data::analyzeClasses(cursor, srcRoot, &dataAnlyState);
analyzeClasses(cursor, srcRoot, &dataAnlyState);
fs::create_directories(outPath.parent_path()); // Make sure generated dir exists before we try writing to it
@ -72,7 +72,7 @@ int processHeader(fs::path srcRoot, fs::path srcPath, fs::path outPath) {
}
for (auto& [_, clazz] : dataAnlyState.classes) {
data::writeCodeForClass(outStream, relpath, clazz);
writeCodeForClass(outStream, relpath, clazz);
}
outStream.close();

View file

@ -16,13 +16,17 @@ static std::map<std::string, std::string> CATEGORY_STR = {
};
static std::map<std::string, std::string> MAPPED_TYPE = {
{ "bool", "Data::Bool" },
{ "int", "Data::Int" },
{ "float", "Data::Float" },
{ "std::string", "Data::String" },
{ "glm::vec3", "Vector3" },
};
static std::map<std::string, std::string> TYPEINFO_REFS = {
{ "glm::vec3", "Vector3::TYPE" },
{ "bool", "BOOL_TYPE" },
{ "int", "INT_TYPE" },
{ "float", "FLOAT_TYPE" },
{ "std::string", "STRING_TYPE" },
};
static std::map<std::string, std::monostate> ENUM_TYPES = {
{ "SurfaceType", std::monostate() }
};
@ -40,7 +44,7 @@ static std::string parseWeakPtr(std::string weakPtrType) {
static std::string castFromVariant(std::string valueStr, std::string fieldType) {
// Manual exception for now, enums will get their own system eventually
if (fieldType == "SurfaceType") {
return "(SurfaceType)(int)" + valueStr + ".get<Data::Int>()";
return "(SurfaceType)(int)" + valueStr + ".get<int>()";
}
std::string mappedType = MAPPED_TYPE[fieldType];
@ -50,13 +54,13 @@ static std::string castFromVariant(std::string valueStr, std::string fieldType)
static std::string castToVariant(std::string valueStr, std::string fieldType) {
// Manual exception for now, enums will get their own system eventually
if (fieldType == "SurfaceType") {
return "Data::Int((int)" + valueStr + ")";
return "(int)" + valueStr;
}
// std::shared_ptr<Instance>
std::string subtype = parseWeakPtr(fieldType);
if (!subtype.empty()) {
return "Data::Variant(" + valueStr + ".expired() ? Data::InstanceRef() : Data::InstanceRef(std::dynamic_pointer_cast<Instance>(" + valueStr + ".lock())))";
return "Variant(" + valueStr + ".expired() ? InstanceRef() : InstanceRef(std::dynamic_pointer_cast<Instance>(" + valueStr + ".lock())))";
}
std::string mappedType = MAPPED_TYPE[fieldType];
@ -67,7 +71,7 @@ static std::string castToVariant(std::string valueStr, std::string fieldType) {
}
static void writePropertySetHandler(std::ofstream& out, ClassAnalysis state) {
out << "fallible<MemberNotFound, AssignToReadOnlyMember> " << state.name << "::InternalSetPropertyValue(std::string name, Data::Variant value) {";
out << "fallible<MemberNotFound, AssignToReadOnlyMember> " << state.name << "::InternalSetPropertyValue(std::string name, Variant value) {";
out << "\n ";
bool first = true;
@ -83,7 +87,7 @@ static void writePropertySetHandler(std::ofstream& out, ClassAnalysis state) {
} else if (prop.cframeMember == CFrameMember_Rotation) {
out << "\n this->" << prop.fieldName << " = CFrame::FromEulerAnglesXYZ(value.get<Vector3>()) + this->" << prop.fieldName << ".Position();";
} else if (!subtype.empty()) {
out << "\n std::weak_ptr<Instance> ref = value.get<Data::InstanceRef>();"
out << "\n std::weak_ptr<Instance> ref = value.get<InstanceRef>();"
<< "\n this->" << prop.fieldName << " = ref.expired() ? std::weak_ptr<" << subtype << ">() : std::dynamic_pointer_cast<" << subtype << ">(ref.lock());";
} else {
out << "\n this->" << prop.fieldName << " = " << castFromVariant("value", prop.backingFieldType) << ";";
@ -128,7 +132,7 @@ static void writePropertyUpdateHandler(std::ofstream& out, ClassAnalysis state)
}
static void writePropertyGetHandler(std::ofstream& out, ClassAnalysis state) {
out << "result<Data::Variant, MemberNotFound> " << state.name << "::InternalGetPropertyValue(std::string name) {";
out << "result<Variant, MemberNotFound> " << state.name << "::InternalGetPropertyValue(std::string name) {";
out << "\n ";
bool first = true;
@ -136,11 +140,11 @@ static void writePropertyGetHandler(std::ofstream& out, ClassAnalysis state) {
out << (first ? "" : " else ") << "if (name == \"" << prop.name << "\") {";
if (prop.cframeMember == CFrameMember_Position) {
out << "\n return Data::Variant(" << prop.fieldName << ".Position());";
out << "\n return Variant(" << prop.fieldName << ".Position());";
} else if (prop.cframeMember == CFrameMember_Rotation) {
out << "\n return Data::Variant(" << prop.fieldName << ".ToEulerAnglesXYZ());";
out << "\n return Variant(" << prop.fieldName << ".ToEulerAnglesXYZ());";
} else {
out << "\n return Data::Variant(" << castToVariant(prop.fieldName, prop.backingFieldType) << ");";
out << "\n return Variant(" << castToVariant(prop.fieldName, prop.backingFieldType) << ");";
}
out << "\n }";
@ -153,7 +157,7 @@ static void writePropertyGetHandler(std::ofstream& out, ClassAnalysis state) {
for (auto& signal : state.signals) {
out << (first ? "" : " else ") << "if (name == \"" << signal.name << "\") {";
out << "\n return Data::Variant(Data::SignalRef(" << signal.sourceFieldName << "));";
out << "\n return Variant(SignalRef(" << signal.sourceFieldName << "));";
out << "\n }";
first = false;
@ -186,10 +190,10 @@ static void writePropertyMetaHandler(std::ofstream& out, ClassAnalysis state) {
for (auto& prop : state.properties) {
out << (first ? "" : " else ") << "if (name == \"" << prop.name << "\") {";
std::string type = MAPPED_TYPE[prop.backingFieldType];
if (type.empty()) type = prop.backingFieldType;
if (type == "SurfaceType") type = "Data::Int";
if (!parseWeakPtr(prop.backingFieldType).empty()) type = "Data::InstanceRef";
std::string typeInfo = TYPEINFO_REFS[prop.backingFieldType];
if (typeInfo.empty()) typeInfo = prop.backingFieldType + "::TYPE";
if (!parseWeakPtr(prop.backingFieldType).empty()) typeInfo = "InstanceRef::TYPE";
if (prop.backingFieldType == "SurfaceType") typeInfo = "INT_TYPE";
std::string strFlags;
if (prop.flags & PropertyFlag_Readonly)
@ -206,7 +210,7 @@ static void writePropertyMetaHandler(std::ofstream& out, ClassAnalysis state) {
std::string category = CATEGORY_STR[prop.category];
if (category.empty()) category = "PROP_CATEGORY_DATA";
out << "\n return PropertyMeta { &" << type << "::TYPE, " << strFlags << ", " << category << " };";
out << "\n return PropertyMeta { &" << typeInfo << ", " << strFlags << ", " << category << " };";
out << "\n }";
first = false;
@ -220,8 +224,8 @@ static void writePropertyMetaHandler(std::ofstream& out, ClassAnalysis state) {
std::string strFlags;
strFlags += "PROP_READONLY";
strFlags += "| PROP_HIDDEN";
strFlags += "| PROP_NOSAVE";
strFlags += " | PROP_HIDDEN";
strFlags += " | PROP_NOSAVE";
out << "\n return PropertyMeta { &SignalRef::TYPE, " << strFlags << " };";
@ -252,7 +256,8 @@ void object::writeCodeForClass(std::ofstream& out, std::string headerPath, Class
out << "#define __AUTOGEN_EXTRA_INCLUDES__\n";
out << "#include \"" << state.headerPath << "\"\n\n";
out << "#include \"datatypes/meta.h\"\n\n";
out << "#include \"datatypes/variant.h\"\n\n";
out << "#include \"datatypes/primitives.h\"\n\n";
out << "const InstanceType " << state.name << "::TYPE = {\n"
<< " .super = &" << state.baseClass << "::TYPE,\n"
<< " .className = \"" << state.name << "\",\n"

View file

@ -1,7 +1,7 @@
// TEMPORARY COMMON DATA FOR DIFFERENT INTERNAL COMPONENTS
#include "objects/datamodel.h"
#include "datatypes/meta.h"
#include "datatypes/variant.h"
#include "common.h"
#include <memory>
@ -34,7 +34,7 @@ void addSelectionListener(SelectionUpdateHandler handler) {
selectionUpdateListeners.push_back(handler);
}
void sendPropertyUpdatedSignal(std::shared_ptr<Instance> instance, std::string property, Data::Variant newValue) {
void sendPropertyUpdatedSignal(std::shared_ptr<Instance> instance, std::string property, Variant newValue) {
for (PropertyUpdateHandler handler : propertyUpdatelisteners) {
handler(instance, property, newValue);
}

View file

@ -12,7 +12,7 @@ class Instance;
typedef std::function<void(std::shared_ptr<Instance> object, std::optional<std::shared_ptr<Instance>> oldParent, std::optional<std::shared_ptr<Instance>> newParent)> HierarchyPreUpdateHandler;
typedef std::function<void(std::shared_ptr<Instance> object, std::optional<std::shared_ptr<Instance>> oldParent, std::optional<std::shared_ptr<Instance>> newParent)> HierarchyPostUpdateHandler;
typedef std::function<void(std::vector<std::shared_ptr<Instance>> oldSelection, std::vector<std::shared_ptr<Instance>> newSelection, bool fromExplorer)> SelectionUpdateHandler;
typedef std::function<void(std::shared_ptr<Instance> instance, std::string property, Data::Variant newValue)> PropertyUpdateHandler;
typedef std::function<void(std::shared_ptr<Instance> instance, std::string property, Variant newValue)> PropertyUpdateHandler;
// TEMPORARY COMMON DATA FOR VARIOUS INTERNAL COMPONENTS
@ -28,5 +28,5 @@ void setSelection(std::vector<std::shared_ptr<Instance>> newSelection, bool from
const std::vector<std::shared_ptr<Instance>> getSelection();
void addSelectionListener(SelectionUpdateHandler handler);
void sendPropertyUpdatedSignal(std::shared_ptr<Instance> instance, std::string property, Data::Variant newValue);
void sendPropertyUpdatedSignal(std::shared_ptr<Instance> instance, std::string property, Variant newValue);
void addPropertyUpdateListener(PropertyUpdateHandler handler);

View file

@ -26,8 +26,7 @@
#define AUTOGEN_PREAMBLE_DATA \
public: \
virtual const TypeInfo& GetType() const override; \
static const TypeInfo TYPE; \
virtual void PushLuaValue(lua_State*) const override; \
static result<Data::Variant, LuaCastError> FromLuaValue(lua_State*, int idx); \
virtual void PushLuaValue(lua_State*) const; \
static result<Variant, LuaCastError> FromLuaValue(lua_State*, int idx); \
private:

View file

@ -1,162 +0,0 @@
#include "base.h"
#include "error/data.h"
#include "meta.h"
#include <ios>
#include <sstream>
#include <pugixml.hpp>
#include "lua.h"
#define IMPL_WRAPPER_CLASS(CLASS_NAME, WRAPPED_TYPE, TYPE_NAME) Data::CLASS_NAME::CLASS_NAME(WRAPPED_TYPE in) : value(in) {} \
Data::CLASS_NAME::~CLASS_NAME() = default; \
Data::CLASS_NAME::operator const WRAPPED_TYPE() const { return value; } \
const Data::TypeInfo Data::CLASS_NAME::TYPE = { \
.name = TYPE_NAME, \
.deserializer = &Data::CLASS_NAME::Deserialize, \
.fromString = &Data::CLASS_NAME::FromString, \
.fromLuaValue = &Data::CLASS_NAME::FromLuaValue, \
}; \
const Data::TypeInfo& Data::CLASS_NAME::GetType() const { return Data::CLASS_NAME::TYPE; }; \
void Data::CLASS_NAME::Serialize(pugi::xml_node node) const { node.text().set(std::string(this->ToString())); }
Data::Base::~Base() {};
Data::Null::Null() {};
Data::Null::~Null() = default;
const Data::TypeInfo Data::Null::TYPE = {
.name = "null",
.deserializer = &Data::Null::Deserialize,
};
const Data::TypeInfo& Data::Null::GetType() const { return Data::Null::TYPE; };
const Data::String Data::Null::ToString() const {
return Data::String("null");
}
void Data::Null::Serialize(pugi::xml_node node) const {
node.text().set("null");
}
Data::Variant Data::Null::Deserialize(pugi::xml_node node) {
return Data::Null();
}
void Data::Null::PushLuaValue(lua_State* L) const {
lua_pushnil(L);
}
result<Data::Variant, LuaCastError> Data::Null::FromLuaValue(lua_State* L, int idx) {
return Data::Variant(Data::Null());
}
//
IMPL_WRAPPER_CLASS(Bool, bool, "bool")
IMPL_WRAPPER_CLASS(Int, int, "int")
IMPL_WRAPPER_CLASS(Float, float, "float")
IMPL_WRAPPER_CLASS(String, std::string, "string")
// ToString
const Data::String Data::Bool::ToString() const {
return Data::String(value ? "true" : "false");
}
const Data::String Data::Int::ToString() const {
return Data::String(std::to_string(value));
}
const Data::String Data::Float::ToString() const {
std::stringstream stream;
stream << std::noshowpoint << value;
return Data::String(stream.str());
}
const Data::String Data::String::ToString() const {
return *this;
}
// Deserialize
Data::Variant Data::Bool::Deserialize(pugi::xml_node node) {
return Data::Bool(node.text().as_bool());
}
Data::Variant Data::Int::Deserialize(pugi::xml_node node) {
return Data::Int(node.text().as_int());
}
Data::Variant Data::Float::Deserialize(pugi::xml_node node) {
return Data::Float(node.text().as_float());
}
Data::Variant Data::String::Deserialize(pugi::xml_node node) {
return Data::String(node.text().as_string());
}
// FromString
std::optional<Data::Variant> Data::Bool::FromString(std::string string) {
return Data::Bool(string[0] == 't' || string[0] == 'T' || string[0] == '1' || string[0] == 'y' || string[0] == 'Y');
}
std::optional<Data::Variant> Data::Int::FromString(std::string string) {
char* endPos;
int value = (int)std::strtol(string.c_str(), &endPos, 10);
if (endPos == string.c_str()) return std::nullopt;
return Data::Int(value);
}
std::optional<Data::Variant> Data::Float::FromString(std::string string) {
char* endPos;
float value = std::strtof(string.c_str(), &endPos);
if (endPos == string.c_str()) return std::nullopt;
return Data::Float(value);
}
std::optional<Data::Variant> Data::String::FromString(std::string string) {
return Data::String(string);
}
// PushLuaValue
void Data::Bool::PushLuaValue(lua_State* L) const {
lua_pushboolean(L, *this);
}
void Data::Int::PushLuaValue(lua_State* L) const {
lua_pushinteger(L, *this);
}
void Data::Float::PushLuaValue(lua_State* L) const {
lua_pushnumber(L, *this);
}
void Data::String::PushLuaValue(lua_State* L) const {
lua_pushstring(L, value.c_str());
}
// FromLuaValue
result<Data::Variant, LuaCastError> Data::Bool::FromLuaValue(lua_State* L, int idx) {
if (!lua_isboolean(L, idx))
return LuaCastError(lua_typename(L, idx), "boolean");
return Data::Variant(Data::Bool(lua_toboolean(L, idx)));
}
result<Data::Variant, LuaCastError> Data::Int::FromLuaValue(lua_State* L, int idx) {
if (!lua_isnumber(L, idx))
return LuaCastError(lua_typename(L, idx), "integer");
return Data::Variant(Data::Int((int)lua_tonumber(L, idx)));
}
result<Data::Variant, LuaCastError> Data::Float::FromLuaValue(lua_State* L, int idx) {
if (!lua_isnumber(L, idx))
return LuaCastError(lua_typename(L, idx), "float");
return Data::Variant(Data::Float((float)lua_tonumber(L, idx)));
}
result<Data::Variant, LuaCastError> Data::String::FromLuaValue(lua_State* L, int idx) {
if (!lua_tostring(L, idx))
return LuaCastError(lua_typename(L, idx), "string");
return Data::Variant(Data::String(lua_tostring(L, idx)));
}

View file

@ -10,67 +10,20 @@ extern "C" { typedef struct lua_State lua_State; }
namespace pugi { class xml_node; };
#define DEF_WRAPPER_CLASS(CLASS_NAME, WRAPPED_TYPE) class CLASS_NAME : public Data::Base { \
WRAPPED_TYPE value; \
public: \
CLASS_NAME(WRAPPED_TYPE); \
~CLASS_NAME(); \
operator const WRAPPED_TYPE() const; \
virtual const TypeInfo& GetType() const override; \
static const TypeInfo TYPE; \
\
virtual const Data::String ToString() const override; \
virtual void Serialize(pugi::xml_node node) const override; \
virtual void PushLuaValue(lua_State*) const override; \
\
static Data::Variant Deserialize(pugi::xml_node node); \
static std::optional<Data::Variant> FromString(std::string); \
static result<Data::Variant, LuaCastError> FromLuaValue(lua_State*, int idx); \
};
class Variant;
typedef std::function<void(Variant, pugi::xml_node)> Serializer;
typedef std::function<Variant(pugi::xml_node)> Deserializer;
typedef std::function<std::string(Variant)> ToString;
typedef std::function<std::optional<Variant>(std::string)> FromString;
typedef std::function<result<Variant, LuaCastError>(lua_State*, int idx)> FromLuaValue;
typedef std::function<void(Variant self, lua_State*)> PushLuaValue;
namespace Data {
class Variant;
typedef std::function<Data::Variant(pugi::xml_node)> Deserializer;
typedef std::function<std::optional<Data::Variant>(std::string)> FromString;
typedef std::function<result<Data::Variant, LuaCastError>(lua_State*, int idx)> FromLuaValue;
struct TypeInfo {
std::string name;
Deserializer deserializer;
FromString fromString;
FromLuaValue fromLuaValue;
};
class String;
class Base {
public:
virtual ~Base();
virtual const TypeInfo& GetType() const = 0;
virtual const Data::String ToString() const = 0;
virtual void Serialize(pugi::xml_node node) const = 0;
virtual void PushLuaValue(lua_State*) const = 0;
};
class Null : Base {
public:
Null();
~Null();
virtual const TypeInfo& GetType() const override;
static const TypeInfo TYPE;
virtual const Data::String ToString() const override;
virtual void Serialize(pugi::xml_node node) const override;
virtual void PushLuaValue(lua_State*) const override;
static Data::Variant Deserialize(pugi::xml_node node);
static result<Data::Variant, LuaCastError> FromLuaValue(lua_State*, int idx);
};
DEF_WRAPPER_CLASS(Bool, bool)
DEF_WRAPPER_CLASS(Int, int)
DEF_WRAPPER_CLASS(Float, float)
DEF_WRAPPER_CLASS(String, std::string)
};
#undef DEF_WRAPPER_CLASS
struct TypeInfo {
std::string name;
Serializer serializer;
Deserializer deserializer;
ToString toString;
FromString fromString;
PushLuaValue pushLuaValue;
FromLuaValue fromLuaValue;
};

View file

@ -6,18 +6,18 @@
#include <glm/gtc/quaternion.hpp>
#include <glm/matrix.hpp>
#include <reactphysics3d/mathematics/Transform.h>
#include "datatypes/meta.h"
#include "datatypes/variant.h"
#include <pugixml.hpp>
#define GLM_ENABLE_EXPERIMENTAL
#include <glm/gtx/euler_angles.hpp>
// #include "meta.h" // IWYU pragma: keep
// #include "variant.h" // IWYU pragma: keep
const Data::CFrame Data::CFrame::IDENTITY(glm::vec3(0, 0, 0), glm::mat3(1.f));
const Data::CFrame Data::CFrame::YToZ(glm::vec3(0, 0, 0), glm::mat3(glm::vec3(1, 0, 0), glm::vec3(0, 0, 1), glm::vec3(0, 1, 0)));
const CFrame CFrame::IDENTITY(glm::vec3(0, 0, 0), glm::mat3(1.f));
const CFrame CFrame::YToZ(glm::vec3(0, 0, 0), glm::mat3(glm::vec3(1, 0, 0), glm::vec3(0, 0, 1), glm::vec3(0, 1, 0)));
Data::CFrame::CFrame() : Data::CFrame::CFrame(glm::vec3(0, 0, 0), glm::mat3(1.f)) {}
CFrame::CFrame() : CFrame::CFrame(glm::vec3(0, 0, 0), glm::mat3(1.f)) {}
Data::CFrame::CFrame(float x, float y, float z, float R00, float R01, float R02, float R10, float R11, float R12, float R20, float R21, float R22)
CFrame::CFrame(float x, float y, float z, float R00, float R01, float R02, float R10, float R11, float R12, float R20, float R21, float R22)
: translation(x, y, z)
, rotation({
// { R00, R01, R02 },
@ -29,17 +29,17 @@ Data::CFrame::CFrame(float x, float y, float z, float R00, float R01, float R02,
}) {
}
Data::CFrame::CFrame(glm::vec3 translation, glm::mat3 rotation)
CFrame::CFrame(glm::vec3 translation, glm::mat3 rotation)
: translation(translation)
, rotation(rotation) {
}
Data::CFrame::CFrame(Vector3 position, glm::quat quat)
CFrame::CFrame(Vector3 position, glm::quat quat)
: translation(position)
, rotation(quat) {
}
Data::CFrame::CFrame(const rp::Transform& transform) : Data::CFrame::CFrame(rpToGlm(transform.getPosition()), rpToGlm(transform.getOrientation())) {
CFrame::CFrame(const rp::Transform& transform) : CFrame::CFrame(rpToGlm(transform.getPosition()), rpToGlm(transform.getOrientation())) {
}
glm::mat3 lookAt(Vector3 position, Vector3 lookAt, Vector3 up) {
@ -52,35 +52,35 @@ glm::mat3 lookAt(Vector3 position, Vector3 lookAt, Vector3 up) {
return { s, u, -f };
}
Data::CFrame::CFrame(Vector3 position, Vector3 lookAt, Vector3 up)
CFrame::CFrame(Vector3 position, Vector3 lookAt, Vector3 up)
: translation(position)
, rotation(::lookAt(position, lookAt, up)) {
}
Data::CFrame::~CFrame() = default;
CFrame::~CFrame() = default;
const Data::String Data::CFrame::ToString() const {
const std::string CFrame::ToString() const {
return std::to_string(X()) + ", " + std::to_string(Y()) + ", " + std::to_string(Z());
}
Data::CFrame Data::CFrame::pointToward(Vector3 position, Vector3 toward) {
return Data::CFrame(position, position + toward, (abs(toward.Dot(Vector3(0, 1, 0))) > 0.999) ? Vector3(0, 0, 1) : Vector3(0, 1, 0));
CFrame CFrame::pointToward(Vector3 position, Vector3 toward) {
return CFrame(position, position + toward, (abs(toward.Dot(Vector3(0, 1, 0))) > 0.999) ? Vector3(0, 0, 1) : Vector3(0, 1, 0));
}
Data::CFrame Data::CFrame::pointAligned(Vector3 position, Vector3 toward, Vector3 up, Vector3 right) {
return Data::CFrame(position, position + toward, (abs(toward.Dot(up)) > 0.999) ? right : up);
CFrame CFrame::pointAligned(Vector3 position, Vector3 toward, Vector3 up, Vector3 right) {
return CFrame(position, position + toward, (abs(toward.Dot(up)) > 0.999) ? right : up);
}
Data::CFrame::operator glm::mat4() const {
CFrame::operator glm::mat4() const {
// Always make sure to translate the position first, then rotate. Matrices work backwards
return glm::translate(glm::mat4(1.0f), this->translation) * glm::mat4(this->rotation);
}
Data::CFrame::operator rp::Transform() const {
CFrame::operator rp::Transform() const {
return rp::Transform(glmToRp(translation), glmToRp(rotation));
}
Vector3 Data::CFrame::ToEulerAnglesXYZ() {
Vector3 CFrame::ToEulerAnglesXYZ() {
float x;
float y;
float z;
@ -88,37 +88,37 @@ Vector3 Data::CFrame::ToEulerAnglesXYZ() {
return Vector3(x, y, z);
}
Data::CFrame Data::CFrame::FromEulerAnglesXYZ(Vector3 vector) {
CFrame CFrame::FromEulerAnglesXYZ(Vector3 vector) {
glm::mat3 mat = glm::eulerAngleXYZ(vector.X(), vector.Y(), vector.Z());
return Data::CFrame((glm::vec3)Vector3::ZERO, mat);
return CFrame((glm::vec3)Vector3::ZERO, mat);
}
Data::CFrame Data::CFrame::Inverse() const {
CFrame CFrame::Inverse() const {
return CFrame { -translation * glm::transpose(glm::inverse(rotation)), glm::inverse(rotation) };
}
// Operators
Data::CFrame Data::CFrame::operator *(Data::CFrame otherFrame) const {
CFrame CFrame::operator *(CFrame otherFrame) const {
return CFrame { this->translation + this->rotation * otherFrame.translation, this->rotation * otherFrame.rotation };
}
Vector3 Data::CFrame::operator *(Vector3 vector) const {
Vector3 CFrame::operator *(Vector3 vector) const {
return this->translation + this->rotation * vector;
}
Data::CFrame Data::CFrame::operator +(Vector3 vector) const {
CFrame CFrame::operator +(Vector3 vector) const {
return CFrame { this->translation + glm::vec3(vector), this->rotation };
}
Data::CFrame Data::CFrame::operator -(Vector3 vector) const {
CFrame CFrame::operator -(Vector3 vector) const {
return *this + -vector;
}
// Serialization
void Data::CFrame::Serialize(pugi::xml_node node) const {
void CFrame::Serialize(pugi::xml_node node) const {
node.append_child("X").text().set(std::to_string(this->X()));
node.append_child("Y").text().set(std::to_string(this->Y()));
node.append_child("Z").text().set(std::to_string(this->Z()));
@ -134,8 +134,8 @@ void Data::CFrame::Serialize(pugi::xml_node node) const {
}
Data::Variant Data::CFrame::Deserialize(pugi::xml_node node) {
return Data::CFrame(
Variant CFrame::Deserialize(pugi::xml_node node) {
return CFrame(
node.child("X").text().as_float(),
node.child("Y").text().as_float(),
node.child("Z").text().as_float(),

View file

@ -9,66 +9,62 @@
namespace reactphysics3d { class Transform; };
namespace Data {
class DEF_DATA_(name="CoordinateFrame") CFrame : public Base {
AUTOGEN_PREAMBLE_DATA
class DEF_DATA_(name="CoordinateFrame") CFrame {
AUTOGEN_PREAMBLE_DATA
glm::vec3 translation;
glm::mat3 rotation;
CFrame(glm::vec3, glm::mat3);
public:
// CFrame(float x, float y, float z);
// CFrame(const glm::vec3&);
// CFrame(const rp::Vector3&);
DEF_DATA_CTOR CFrame();
DEF_DATA_CTOR CFrame(float x, float y, float z, float R00, float R01, float R02, float R10, float R11, float R12, float R20, float R21, float R22);
DEF_DATA_CTOR CFrame(Vector3 , Vector3 lookAt, Vector3 up = Vector3(0, 1, 0));
CFrame(const reactphysics3d::Transform&);
CFrame(Vector3 position, glm::quat quat);
~CFrame();
glm::vec3 translation;
glm::mat3 rotation;
// Same as CFrame(position, position + toward), but makes sure that up and toward are not linearly dependant
static CFrame pointToward(Vector3 position, Vector3 toward);
// Creates a cframe looking at position + toward, whilst aligning its up to up.
// If up and toward are approximately linearly dependent (their absolute dot product > 0.999),
// then the right is used instead
// Up and right must NOT be linearly dependent
static CFrame pointAligned(Vector3 position, Vector3 toward, Vector3 up, Vector3 right);
CFrame(glm::vec3, glm::mat3);
public:
// CFrame(float x, float y, float z);
// CFrame(const glm::vec3&);
// CFrame(const rp::Vector3&);
DEF_DATA_CTOR CFrame();
DEF_DATA_CTOR CFrame(float x, float y, float z, float R00, float R01, float R02, float R10, float R11, float R12, float R20, float R21, float R22);
DEF_DATA_CTOR CFrame(Vector3 , Vector3 lookAt, Vector3 up = Vector3(0, 1, 0));
CFrame(const reactphysics3d::Transform&);
CFrame(Vector3 position, glm::quat quat);
~CFrame();
DEF_DATA_PROP static const CFrame IDENTITY;
static const CFrame YToZ;
// Same as CFrame(position, position + toward), but makes sure that up and toward are not linearly dependant
static CFrame pointToward(Vector3 position, Vector3 toward);
// Creates a cframe looking at position + toward, whilst aligning its up to up.
// If up and toward are approximately linearly dependent (their absolute dot product > 0.999),
// then the right is used instead
// Up and right must NOT be linearly dependent
static CFrame pointAligned(Vector3 position, Vector3 toward, Vector3 up, Vector3 right);
virtual const Data::String ToString() const override;
virtual void Serialize(pugi::xml_node parent) const override;
static Data::Variant Deserialize(pugi::xml_node node);
DEF_DATA_PROP static const CFrame IDENTITY;
static const CFrame YToZ;
static void PushLuaLibrary(lua_State*);
virtual const std::string ToString() const;
virtual void Serialize(pugi::xml_node parent) const;
static Variant Deserialize(pugi::xml_node node);
operator glm::mat4() const;
operator reactphysics3d::Transform() const;
static void PushLuaLibrary(lua_State*);
//inline static CFrame identity() { }
DEF_DATA_PROP inline Vector3 Position() const { return translation; }
DEF_DATA_PROP inline CFrame Rotation() const { return CFrame { glm::vec3(0, 0, 0), rotation }; }
DEF_DATA_METHOD CFrame Inverse() const;
DEF_DATA_PROP inline float X() const { return translation.x; }
DEF_DATA_PROP inline float Y() const { return translation.y; }
DEF_DATA_PROP inline float Z() const { return translation.z; }
operator glm::mat4() const;
operator reactphysics3d::Transform() const;
DEF_DATA_PROP inline Vector3 RightVector() { return glm::column(rotation, 0); }
DEF_DATA_PROP inline Vector3 UpVector() { return glm::column(rotation, 1); }
DEF_DATA_PROP inline Vector3 LookVector() { return -glm::column(rotation, 2); }
//inline static CFrame identity() { }
DEF_DATA_PROP inline Vector3 Position() const { return translation; }
DEF_DATA_PROP inline CFrame Rotation() const { return CFrame { glm::vec3(0, 0, 0), rotation }; }
DEF_DATA_METHOD CFrame Inverse() const;
DEF_DATA_PROP inline float X() const { return translation.x; }
DEF_DATA_PROP inline float Y() const { return translation.y; }
DEF_DATA_PROP inline float Z() const { return translation.z; }
DEF_DATA_METHOD Vector3 ToEulerAnglesXYZ();
DEF_DATA_METHOD static CFrame FromEulerAnglesXYZ(Vector3);
DEF_DATA_PROP inline Vector3 RightVector() { return glm::column(rotation, 0); }
DEF_DATA_PROP inline Vector3 UpVector() { return glm::column(rotation, 1); }
DEF_DATA_PROP inline Vector3 LookVector() { return -glm::column(rotation, 2); }
// Operators
DEF_DATA_OP Data::CFrame operator *(Data::CFrame) const;
DEF_DATA_OP Vector3 operator *(Vector3) const;
DEF_DATA_OP Data::CFrame operator +(Vector3) const;
DEF_DATA_OP Data::CFrame operator -(Vector3) const;
};
}
DEF_DATA_METHOD Vector3 ToEulerAnglesXYZ();
DEF_DATA_METHOD static CFrame FromEulerAnglesXYZ(Vector3);
using Data::CFrame;
// Operators
DEF_DATA_OP CFrame operator *(CFrame) const;
DEF_DATA_OP Vector3 operator *(Vector3) const;
DEF_DATA_OP CFrame operator +(Vector3) const;
DEF_DATA_OP CFrame operator -(Vector3) const;
};

View file

@ -1,21 +1,21 @@
#include "color3.h"
#include "datatypes/meta.h"
#include "datatypes/variant.h"
#include <pugixml.hpp>
#include <sstream>
#include <iomanip>
Data::Color3::Color3(float r, float g, float b) : r(std::clamp(r, 0.f, 1.f)), g(std::clamp(g, 0.f, 1.f)), b(std::clamp(b, 0.f, 1.f)) {};
Data::Color3::Color3(const glm::vec3& vec) : r(std::clamp(vec.x, 0.f, 1.f)), g(std::clamp(vec.y, 0.f, 1.f)), b(std::clamp(vec.z, 0.f, 1.f)) {};
Color3::Color3(float r, float g, float b) : r(std::clamp(r, 0.f, 1.f)), g(std::clamp(g, 0.f, 1.f)), b(std::clamp(b, 0.f, 1.f)) {};
Color3::Color3(const glm::vec3& vec) : r(std::clamp(vec.x, 0.f, 1.f)), g(std::clamp(vec.y, 0.f, 1.f)), b(std::clamp(vec.z, 0.f, 1.f)) {};
Data::Color3::~Color3() = default;
Color3::~Color3() = default;
const Data::String Data::Color3::ToString() const {
const std::string Color3::ToString() const {
return std::to_string(int(r*256)) + ", " + std::to_string(int(g*256)) + ", " + std::to_string(int(b*256));
}
Data::Color3::operator glm::vec3() const { return glm::vec3(r, g, b); };
Color3::operator glm::vec3() const { return glm::vec3(r, g, b); };
std::string Data::Color3::ToHex() const {
std::string Color3::ToHex() const {
std::stringstream ss;
ss << "FF" << std::hex << std::uppercase << std::setfill('0')
<< std::setw(2) << int(r*255)
@ -25,7 +25,7 @@ std::string Data::Color3::ToHex() const {
}
Data::Color3 Data::Color3::FromHex(std::string hex) {
Color3 Color3::FromHex(std::string hex) {
float r = float(std::stoi(hex.substr(2, 2), nullptr, 16)) / 255;
float g = float(std::stoi(hex.substr(4, 2), nullptr, 16)) / 255;
float b = float(std::stoi(hex.substr(6, 2), nullptr, 16)) / 255;
@ -35,10 +35,10 @@ Data::Color3 Data::Color3::FromHex(std::string hex) {
// Serialization
void Data::Color3::Serialize(pugi::xml_node node) const {
void Color3::Serialize(pugi::xml_node node) const {
node.text().set(this->ToHex());
}
Data::Variant Data::Color3::Deserialize(pugi::xml_node node) {
Variant Color3::Deserialize(pugi::xml_node node) {
return Color3::FromHex(node.text().get());
}

View file

@ -4,34 +4,30 @@
#include "datatypes/annotation.h"
#include <glm/ext/vector_float3.hpp>
namespace Data {
class DEF_DATA Color3 : public Base {
AUTOGEN_PREAMBLE_DATA
class DEF_DATA Color3 {
AUTOGEN_PREAMBLE_DATA
float r;
float g;
float b;
public:
DEF_DATA_CTOR Color3(float r, float g, float b);
Color3(const glm::vec3&);
~Color3();
float r;
float g;
float b;
DEF_DATA_METHOD static Color3 FromHex(std::string hex);
public:
DEF_DATA_CTOR Color3(float r, float g, float b);
Color3(const glm::vec3&);
~Color3();
virtual const Data::String ToString() const override;
DEF_DATA_METHOD std::string ToHex() const;
virtual void Serialize(pugi::xml_node node) const override;
static Data::Variant Deserialize(pugi::xml_node node);
DEF_DATA_METHOD static Color3 FromHex(std::string hex);
static void PushLuaLibrary(lua_State*);
virtual const std::string ToString() const;
DEF_DATA_METHOD std::string ToHex() const;
virtual void Serialize(pugi::xml_node node) const;
static Variant Deserialize(pugi::xml_node node);
operator glm::vec3() const;
static void PushLuaLibrary(lua_State*);
DEF_DATA_PROP inline float R() const { return r; }
DEF_DATA_PROP inline float G() const { return g; }
DEF_DATA_PROP inline float B() const { return b; }
};
}
operator glm::vec3() const;
using Data::Color3;
DEF_DATA_PROP inline float R() const { return r; }
DEF_DATA_PROP inline float G() const { return g; }
DEF_DATA_PROP inline float B() const { return b; }
};

View file

@ -1,48 +0,0 @@
#include "meta.h"
#include "datatypes/base.h"
#include "datatypes/cframe.h"
#include "datatypes/ref.h"
#include "logger.h"
#include "panic.h"
#include <pugixml.hpp>
#include <variant>
Data::String Data::Variant::ToString() const {
return std::visit([](auto&& it) {
return it.ToString();
}, this->wrapped);
}
void Data::Variant::Serialize(pugi::xml_node node) const {
std::visit([&](auto&& it) {
it.Serialize(node);
}, this->wrapped);
}
void Data::Variant::PushLuaValue(lua_State* state) const {
return std::visit([&](auto&& it) {
return it.PushLuaValue(state);
}, this->wrapped);
}
Data::Variant Data::Variant::Deserialize(pugi::xml_node node) {
if (Data::TYPE_MAP.count(node.name()) == 0) {
Logger::fatalErrorf("Unknown type for property: '%s'", node.name());
panic();
}
const Data::TypeInfo* type = Data::TYPE_MAP[node.name()];
return type->deserializer(node);
}
std::map<std::string, const Data::TypeInfo*> Data::TYPE_MAP = {
{ "null", &Data::Null::TYPE },
{ "bool", &Data::Bool::TYPE },
{ "int", &Data::Int::TYPE },
{ "float", &Data::Float::TYPE },
{ "string", &Data::String::TYPE },
{ "Vector3", &Data::Vector3::TYPE },
{ "CoordinateFrame", &Data::CFrame::TYPE },
{ "Color3", &Data::Color3::TYPE },
{ "Ref", &Data::InstanceRef::TYPE },
};

View file

@ -1,49 +0,0 @@
#pragma once
#include <variant>
#include <map>
#include "base.h"
#include "datatypes/color3.h"
#include "datatypes/ref.h"
#include "datatypes/signal.h"
#include "vector.h"
#include "cframe.h"
// #define __VARIANT_TYPE std::variant< \
// Null, \
// Bool, \
// Int, \
// Float, \
// String \
// >
namespace Data {
typedef std::variant<
Null,
Bool,
Int,
Float,
String,
Vector3,
CFrame,
Color3,
InstanceRef,
SignalRef,
SignalConnectionRef
> __VARIANT_TYPE;
class Variant {
__VARIANT_TYPE wrapped;
public:
template <typename T> Variant(T obj) : wrapped(obj) {}
template <typename T> T get() { return std::get<T>(wrapped); }
Data::String ToString() const;
void Serialize(pugi::xml_node node) const;
void PushLuaValue(lua_State* state) const;
static Data::Variant Deserialize(pugi::xml_node node);
};
// Map of all data types to their type names
extern std::map<std::string, const TypeInfo*> TYPE_MAP;
}

View file

@ -0,0 +1,211 @@
#include "primitives.h"
#include "variant.h"
#include <pugixml.hpp>
#include "lua.h"
#include <sstream>
// null
void Null_Serialize(Variant self, pugi::xml_node node) {
node.text().set("null");
}
Variant Null_Deserialize(pugi::xml_node node) {
return std::monostate();
}
const std::string Null_ToString(Variant self) {
return "null";
}
const std::optional<Variant> Null_FromString(std::string str) {
return std::monostate();
}
void Null_PushLuaValue(Variant self, lua_State* L) {
lua_pushnil(L);
}
result<Variant, LuaCastError> Null_FromLuaValue(lua_State* L, int idx) {
return Variant(std::monostate());
}
const TypeInfo NULL_TYPE {
"null",
Null_Serialize,
Null_Deserialize,
Null_ToString,
Null_FromString,
Null_PushLuaValue,
Null_FromLuaValue,
};
// /null
// bool
void Bool_Serialize(Variant self, pugi::xml_node node) {
node.text().set(self.get<bool>() ? "true" : "false");
}
Variant Bool_Deserialize(pugi::xml_node node) {
return node.text().as_bool();
}
const std::string Bool_ToString(Variant self) {
return self.get<bool>() ? "true" : "false";
}
const std::optional<Variant> Bool_FromString(std::string string) {
return string[0] == 't' || string[0] == 'T' || string[0] == '1' || string[0] == 'y' || string[0] == 'Y';
}
void Bool_PushLuaValue(Variant self, lua_State* L) {
lua_pushboolean(L, self.get<bool>());
}
result<Variant, LuaCastError> Bool_FromLuaValue(lua_State* L, int idx) {
if (!lua_isboolean(L, idx))
return LuaCastError(lua_typename(L, idx), "boolean");
return Variant(lua_toboolean(L, idx));
}
const TypeInfo BOOL_TYPE {
"bool",
Bool_Serialize,
Bool_Deserialize,
Bool_ToString,
Bool_FromString,
Bool_PushLuaValue,
Bool_FromLuaValue,
};
// /bool
// int
void Int_Serialize(Variant self, pugi::xml_node node) {
node.text().set(self.get<int>());
}
Variant Int_Deserialize(pugi::xml_node node) {
return node.text().as_int();
}
const std::string Int_ToString(Variant self) {
return std::to_string(self.get<int>());
}
const std::optional<Variant> Int_FromString(std::string string) {
char* endPos;
int value = (int)std::strtol(string.c_str(), &endPos, 10);
if (endPos == string.c_str()) return std::nullopt;
return value;
}
void Int_PushLuaValue(Variant self, lua_State* L) {
lua_pushinteger(L, self.get<int>());
}
result<Variant, LuaCastError> Int_FromLuaValue(lua_State* L, int idx) {
if (!lua_isnumber(L, idx))
return LuaCastError(lua_typename(L, idx), "integer");
return Variant((int)lua_tonumber(L, idx));
}
const TypeInfo INT_TYPE {
"int",
Int_Serialize,
Int_Deserialize,
Int_ToString,
Int_FromString,
Int_PushLuaValue,
Int_FromLuaValue,
};
// /int
// float
void Float_Serialize(Variant self, pugi::xml_node node) {
node.text().set(self.get<float>());
}
Variant Float_Deserialize(pugi::xml_node node) {
return node.text().as_float();
}
const std::string Float_ToString(Variant self) {
std::stringstream stream;
stream << std::noshowpoint << self.get<float>();
return stream.str();
}
const std::optional<Variant> Float_FromString(std::string string) {
char* endPos;
float value = std::strtof(string.c_str(), &endPos);
if (endPos == string.c_str()) return std::nullopt;
return value;
}
void Float_PushLuaValue(Variant self, lua_State* L) {
lua_pushnumber(L, self.get<float>());
}
result<Variant, LuaCastError> Float_FromLuaValue(lua_State* L, int idx) {
if (!lua_isnumber(L, idx))
return LuaCastError(lua_typename(L, idx), "float");
return Variant((float)lua_tonumber(L, idx));
}
const TypeInfo FLOAT_TYPE {
"float",
Float_Serialize,
Float_Deserialize,
Float_ToString,
Float_FromString,
Float_PushLuaValue,
Float_FromLuaValue,
};
// /float
// string
void String_Serialize(Variant self, pugi::xml_node node) {
node.text().set(self.get<std::string>());
}
Variant String_Deserialize(pugi::xml_node node) {
return node.text().as_string();
}
const std::string String_ToString(Variant self) {
return self.get<std::string>();
}
const std::optional<Variant> String_FromString(std::string string) {
return string;
}
void String_PushLuaValue(Variant self, lua_State* L) {
lua_pushstring(L, self.get<std::string>().c_str());
}
result<Variant, LuaCastError> String_FromLuaValue(lua_State* L, int idx) {
if (!lua_tostring(L, idx))
return LuaCastError(lua_typename(L, idx), "string");
return Variant(lua_tostring(L, idx));
}
const TypeInfo STRING_TYPE {
"string",
String_Serialize,
String_Deserialize,
String_ToString,
String_FromString,
String_PushLuaValue,
String_FromLuaValue,
};
// /string

View file

@ -0,0 +1,9 @@
#pragma once
#include "base.h"
extern const TypeInfo NULL_TYPE;
extern const TypeInfo BOOL_TYPE;
extern const TypeInfo INT_TYPE;
extern const TypeInfo FLOAT_TYPE;
extern const TypeInfo STRING_TYPE;

View file

@ -2,7 +2,7 @@
#include "datatypes/base.h"
#include "error/data.h"
#include "logger.h"
#include "meta.h" // IWYU pragma: keep
#include "variant.h" // IWYU pragma: keep
#include <memory>
#include <optional>
#include "objects/base/instance.h"
@ -10,34 +10,36 @@
#include "objects/base/member.h"
#include <pugixml.hpp>
Data::InstanceRef::InstanceRef() {};
Data::InstanceRef::InstanceRef(std::weak_ptr<Instance> instance) : ref(instance) {};
Data::InstanceRef::~InstanceRef() = default;
InstanceRef::InstanceRef() {};
InstanceRef::InstanceRef(std::weak_ptr<Instance> instance) : ref(instance) {};
InstanceRef::~InstanceRef() = default;
const Data::TypeInfo Data::InstanceRef::TYPE = {
const TypeInfo InstanceRef::TYPE = {
.name = "Ref",
.deserializer = &Data::InstanceRef::Deserialize,
.fromLuaValue = &Data::InstanceRef::FromLuaValue,
.serializer = toVariantFunction(&InstanceRef::Serialize),
.deserializer = &InstanceRef::Deserialize,
.toString = toVariantFunction(&InstanceRef::ToString),
.fromString = nullptr,
.pushLuaValue = toVariantFunction(&InstanceRef::PushLuaValue),
.fromLuaValue = &InstanceRef::FromLuaValue,
};
const Data::TypeInfo& Data::InstanceRef::GetType() const { return Data::InstanceRef::TYPE; };
const Data::String Data::InstanceRef::ToString() const {
const std::string InstanceRef::ToString() const {
return ref.expired() ? "" : ref.lock()->name;
}
Data::InstanceRef::operator std::weak_ptr<Instance>() {
InstanceRef::operator std::weak_ptr<Instance>() {
return ref;
}
// Serialization
void Data::InstanceRef::Serialize(pugi::xml_node node) const {
void InstanceRef::Serialize(pugi::xml_node node) const {
// Handled by Instance
panic();
}
Data::Variant Data::InstanceRef::Deserialize(pugi::xml_node node) {
Variant InstanceRef::Deserialize(pugi::xml_node node) {
// Handled by Instance
panic();
}
@ -52,7 +54,7 @@ static const struct luaL_Reg metatable [] = {
{NULL, NULL} /* end of array */
};
void Data::InstanceRef::PushLuaValue(lua_State* L) const {
void InstanceRef::PushLuaValue(lua_State* L) const {
if (ref.expired()) return lua_pushnil(L);
int n = lua_gettop(L);
@ -70,14 +72,14 @@ void Data::InstanceRef::PushLuaValue(lua_State* L) const {
lua_setmetatable(L, n+1);
}
result<Data::Variant, LuaCastError> Data::InstanceRef::FromLuaValue(lua_State* L, int idx) {
result<Variant, LuaCastError> InstanceRef::FromLuaValue(lua_State* L, int idx) {
if (lua_isnil(L, idx))
return Data::Variant(Data::InstanceRef());
return Variant(InstanceRef());
if (!lua_isuserdata(L, idx))
return LuaCastError(lua_typename(L, idx), "Instance");
// TODO: overhaul this to support other types
auto userdata = (std::shared_ptr<Instance>**)lua_touserdata(L, idx);
return Data::Variant(Data::InstanceRef(**userdata));
return Variant(InstanceRef(**userdata));
}
static int inst_gc(lua_State* L) {
@ -99,7 +101,7 @@ static int inst_index(lua_State* L) {
// Read property
std::optional<PropertyMeta> meta = inst->GetPropertyMeta(key);
if (meta) {
Data::Variant value = inst->GetPropertyValue(key).expect();
Variant value = inst->GetPropertyValue(key).expect();
value.PushLuaValue(L);
return 1;
}
@ -107,7 +109,7 @@ static int inst_index(lua_State* L) {
// Look for child
std::optional<std::shared_ptr<Instance>> child = inst->FindFirstChild(key);
if (child) {
Data::InstanceRef(child.value()).PushLuaValue(L);
InstanceRef(child.value()).PushLuaValue(L);
return 1;
}
@ -129,7 +131,7 @@ static int inst_newindex(lua_State* L) {
if (key == "Parent" && inst->IsParentLocked())
return luaL_error(L, "Cannot set property Parent (%s) of %s, parent is locked", inst->GetParent() ? inst->GetParent().value()->name.c_str() : "NULL", inst->GetClass()->className.c_str());
result<Data::Variant, LuaCastError> value = meta->type->fromLuaValue(L, -1);
result<Variant, LuaCastError> value = meta->type->fromLuaValue(L, -1);
lua_pop(L, 3);
if (value.isError())

View file

@ -6,23 +6,20 @@
class Instance;
namespace Data {
class InstanceRef : public Base {
std::weak_ptr<Instance> ref;
public:
InstanceRef();
InstanceRef(std::weak_ptr<Instance>);
~InstanceRef();
class InstanceRef {
std::weak_ptr<Instance> ref;
public:
InstanceRef();
InstanceRef(std::weak_ptr<Instance>);
~InstanceRef();
virtual const TypeInfo& GetType() const override;
static const TypeInfo TYPE;
static const TypeInfo TYPE;
operator std::weak_ptr<Instance>();
operator std::weak_ptr<Instance>();
virtual const Data::String ToString() const override;
virtual void Serialize(pugi::xml_node node) const override;
virtual void PushLuaValue(lua_State*) const override;
static Data::Variant Deserialize(pugi::xml_node node);
static result<Data::Variant, LuaCastError> FromLuaValue(lua_State*, int idx);
};
}
virtual const std::string ToString() const;
virtual void Serialize(pugi::xml_node node) const;
virtual void PushLuaValue(lua_State*) const;
static Variant Deserialize(pugi::xml_node node);
static result<Variant, LuaCastError> FromLuaValue(lua_State*, int idx);
};

View file

@ -1,6 +1,6 @@
#include "signal.h"
#include "datatypes/base.h"
#include "meta.h"
#include "variant.h"
#include "lua.h"
#include <cstdio>
#include <luajit-2.1/lauxlib.h>
@ -53,13 +53,13 @@ static void stackdump(lua_State* L) {
fflush(stdout);
}
void LuaSignalConnection::Call(std::vector<Data::Variant> args) {
void LuaSignalConnection::Call(std::vector<Variant> args) {
lua_State* thread = lua_newthread(state);
// Push function
lua_rawgeti(thread, LUA_REGISTRYINDEX, function);
for (Data::Variant arg : args) {
for (Variant arg : args) {
arg.PushLuaValue(thread);
}
@ -74,11 +74,11 @@ void LuaSignalConnection::Call(std::vector<Data::Variant> args) {
//
CSignalConnection::CSignalConnection(std::function<void(std::vector<Data::Variant>)> func, std::weak_ptr<Signal> parent) : SignalConnection(parent) {
CSignalConnection::CSignalConnection(std::function<void(std::vector<Variant>)> func, std::weak_ptr<Signal> parent) : SignalConnection(parent) {
this->function = func;
}
void CSignalConnection::Call(std::vector<Data::Variant> args) {
void CSignalConnection::Call(std::vector<Variant> args) {
function(args);
}
@ -86,7 +86,7 @@ void CSignalConnection::Call(std::vector<Data::Variant> args) {
SignalConnectionHolder::SignalConnectionHolder() : heldConnection() {}
SignalConnectionHolder::SignalConnectionHolder(std::shared_ptr<SignalConnection> connection) : heldConnection(connection) {}
SignalConnectionHolder::SignalConnectionHolder(Data::SignalConnectionRef other) : heldConnection(other) {}
SignalConnectionHolder::SignalConnectionHolder(SignalConnectionRef other) : heldConnection(other) {}
SignalConnectionHolder::~SignalConnectionHolder() {
// printf("Prediscon!\n");
@ -97,7 +97,7 @@ SignalConnectionHolder::~SignalConnectionHolder() {
//
SignalConnectionRef Signal::Connect(std::function<void(std::vector<Data::Variant>)> callback) {
SignalConnectionRef Signal::Connect(std::function<void(std::vector<Variant>)> callback) {
auto conn = std::dynamic_pointer_cast<SignalConnection>(std::make_shared<CSignalConnection>(callback, weak_from_this()));
connections.push_back(conn);
return SignalConnectionRef(conn);
@ -109,7 +109,7 @@ SignalConnectionRef Signal::Connect(lua_State* state) {
return SignalConnectionRef(conn);
}
SignalConnectionRef Signal::Once(std::function<void(std::vector<Data::Variant>)> callback) {
SignalConnectionRef Signal::Once(std::function<void(std::vector<Variant>)> callback) {
auto conn = std::dynamic_pointer_cast<SignalConnection>(std::make_shared<CSignalConnection>(callback, weak_from_this()));
onceConnections.push_back(conn);
return SignalConnectionRef(conn);
@ -132,7 +132,7 @@ int Signal::Wait(lua_State* thread) {
return lua_yield(thread, 0);
}
void Signal::Fire(std::vector<Data::Variant> args) {
void Signal::Fire(std::vector<Variant> args) {
for (std::shared_ptr<SignalConnection> connection : connections) {
connection->Call(args);
}
@ -148,7 +148,7 @@ void Signal::Fire(std::vector<Data::Variant> args) {
auto prevThreads = std::move(waitingThreads);
waitingThreads = std::vector<std::pair<int, lua_State*>>();
for (auto& [threadId, thread] : prevThreads) {
for (Data::Variant arg : args) {
for (Variant arg : args) {
arg.PushLuaValue(thread);
}
@ -165,7 +165,7 @@ void Signal::Fire(std::vector<Data::Variant> args) {
}
void Signal::Fire() {
return Fire(std::vector<Data::Variant> {});
return Fire(std::vector<Variant> {});
}
void Signal::DisconnectAll() {
@ -222,29 +222,27 @@ static const struct luaL_Reg signal_metatable [] = {
{NULL, NULL} /* end of array */
};
Data::SignalRef::SignalRef(std::weak_ptr<Signal> ref) : signal(ref) {}
Data::SignalRef::~SignalRef() = default;
SignalRef::SignalRef(std::weak_ptr<Signal> ref) : signal(ref) {}
SignalRef::~SignalRef() = default;
const Data::TypeInfo Data::SignalRef::TYPE = {
const TypeInfo SignalRef::TYPE = {
.name = "Signal",
.fromLuaValue = &Data::SignalRef::FromLuaValue,
.fromLuaValue = &SignalRef::FromLuaValue,
};
const Data::TypeInfo& Data::SignalRef::GetType() const { return Data::SignalRef::TYPE; };
const Data::String Data::SignalRef::ToString() const {
return Data::String("Signal");
const std::string SignalRef::ToString() const {
return "Signal";
}
Data::SignalRef::operator std::weak_ptr<Signal>() {
SignalRef::operator std::weak_ptr<Signal>() {
return signal;
}
void Data::SignalRef::Serialize(pugi::xml_node node) const {
void SignalRef::Serialize(pugi::xml_node node) const {
// Not serializable
}
void Data::SignalRef::PushLuaValue(lua_State* L) const {
void SignalRef::PushLuaValue(lua_State* L) const {
int n = lua_gettop(L);
auto userdata = (std::weak_ptr<Signal>**)lua_newuserdata(L, sizeof(std::weak_ptr<Signal>));
@ -257,10 +255,10 @@ void Data::SignalRef::PushLuaValue(lua_State* L) const {
lua_setmetatable(L, n+1);
}
result<Data::Variant, LuaCastError> Data::SignalRef::FromLuaValue(lua_State* L, int idx) {
result<Variant, LuaCastError> 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));
return Variant(SignalRef(**userdata));
}
static int signal_gc(lua_State* L) {
@ -343,29 +341,27 @@ static const struct luaL_Reg signalconnection_metatable [] = {
{NULL, NULL} /* end of array */
};
Data::SignalConnectionRef::SignalConnectionRef(std::weak_ptr<SignalConnection> ref) : signalConnection(ref) {}
Data::SignalConnectionRef::~SignalConnectionRef() = default;
SignalConnectionRef::SignalConnectionRef(std::weak_ptr<SignalConnection> ref) : signalConnection(ref) {}
SignalConnectionRef::~SignalConnectionRef() = default;
const Data::TypeInfo Data::SignalConnectionRef::TYPE = {
const TypeInfo SignalConnectionRef::TYPE = {
.name = "Signal",
.fromLuaValue = &Data::SignalConnectionRef::FromLuaValue,
.fromLuaValue = &SignalConnectionRef::FromLuaValue,
};
const Data::TypeInfo& Data::SignalConnectionRef::GetType() const { return Data::SignalConnectionRef::TYPE; };
const Data::String Data::SignalConnectionRef::ToString() const {
return Data::String("Connection");
const std::string SignalConnectionRef::ToString() const {
return "Connection";
}
Data::SignalConnectionRef::operator std::weak_ptr<SignalConnection>() {
SignalConnectionRef::operator std::weak_ptr<SignalConnection>() {
return signalConnection;
}
void Data::SignalConnectionRef::Serialize(pugi::xml_node node) const {
void SignalConnectionRef::Serialize(pugi::xml_node node) const {
// Not serializable
}
void Data::SignalConnectionRef::PushLuaValue(lua_State* L) const {
void SignalConnectionRef::PushLuaValue(lua_State* L) const {
int n = lua_gettop(L);
auto userdata = (std::weak_ptr<SignalConnection>**)lua_newuserdata(L, sizeof(std::weak_ptr<SignalConnection>));
@ -378,10 +374,10 @@ void Data::SignalConnectionRef::PushLuaValue(lua_State* L) const {
lua_setmetatable(L, n+1);
}
result<Data::Variant, LuaCastError> Data::SignalConnectionRef::FromLuaValue(lua_State* L, int idx) {
result<Variant, LuaCastError> 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));
return Variant(SignalConnectionRef(**userdata));
}
static int signalconnection_tostring(lua_State* L) {

View file

@ -15,7 +15,7 @@
class Instance;
class Signal;
namespace Data { class SignalConnectionRef; }
class SignalConnectionRef;
class SignalConnection : public std::enable_shared_from_this<SignalConnection> {
protected:
@ -23,7 +23,7 @@ protected:
SignalConnection(std::weak_ptr<Signal> parent);
virtual void Call(std::vector<Data::Variant>) = 0;
virtual void Call(std::vector<Variant>) = 0;
friend Signal;
public:
inline bool Connected() { return !parentSignal.expired(); };
@ -33,13 +33,13 @@ public:
};
class CSignalConnection : public SignalConnection {
std::function<void(std::vector<Data::Variant>)> function;
std::function<void(std::vector<Variant>)> function;
friend Signal;
protected:
void Call(std::vector<Data::Variant>) override;
void Call(std::vector<Variant>) override;
public:
CSignalConnection(std::function<void(std::vector<Data::Variant>)>, std::weak_ptr<Signal> parent);
CSignalConnection(std::function<void(std::vector<Variant>)>, std::weak_ptr<Signal> parent);
};
class LuaSignalConnection : public SignalConnection {
@ -48,7 +48,7 @@ class LuaSignalConnection : public SignalConnection {
friend Signal;
protected:
void Call(std::vector<Data::Variant>) override;
void Call(std::vector<Variant>) override;
public:
LuaSignalConnection(lua_State*, std::weak_ptr<Signal> parent);
LuaSignalConnection (const LuaSignalConnection&) = delete;
@ -63,7 +63,7 @@ class SignalConnectionHolder {
public:
SignalConnectionHolder();
SignalConnectionHolder(std::shared_ptr<SignalConnection>);
SignalConnectionHolder(Data::SignalConnectionRef other);
SignalConnectionHolder(SignalConnectionRef other);
~SignalConnectionHolder();
// Prevent SignalConnectionHolder being accidentally copied, making it useless
@ -90,12 +90,12 @@ public:
Signal& operator= (const Signal&) = delete;
void DisconnectAll();
void Fire(std::vector<Data::Variant> args);
void Fire(std::vector<Variant> args);
void Fire();
Data::SignalConnectionRef Connect(std::function<void(std::vector<Data::Variant>)> callback);
Data::SignalConnectionRef Connect(lua_State*);
Data::SignalConnectionRef Once(std::function<void(std::vector<Data::Variant>)> callback);
Data::SignalConnectionRef Once(lua_State*);
SignalConnectionRef Connect(std::function<void(std::vector<Variant>)> callback);
SignalConnectionRef Connect(lua_State*);
SignalConnectionRef Once(std::function<void(std::vector<Variant>)> callback);
SignalConnectionRef Once(lua_State*);
int Wait(lua_State*);
};
@ -105,43 +105,36 @@ public:
virtual ~SignalSource();
};
namespace Data {
class SignalRef : public Data::Base {
std::weak_ptr<Signal> signal;
class SignalRef {
std::weak_ptr<Signal> signal;
public:
SignalRef(std::weak_ptr<Signal>);
~SignalRef();
public:
SignalRef(std::weak_ptr<Signal>);
~SignalRef();
virtual const TypeInfo& GetType() const override;
static const TypeInfo TYPE;
static const TypeInfo TYPE;
operator std::weak_ptr<Signal>();
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);
};
virtual const std::string ToString() const;
virtual void Serialize(pugi::xml_node node) const;
virtual void PushLuaValue(lua_State*) const;
static result<Variant, LuaCastError> FromLuaValue(lua_State*, int idx);
};
class SignalConnectionRef : public Data::Base {
std::weak_ptr<SignalConnection> signalConnection;
class SignalConnectionRef {
std::weak_ptr<SignalConnection> signalConnection;
public:
SignalConnectionRef(std::weak_ptr<SignalConnection>);
~SignalConnectionRef();
public:
SignalConnectionRef(std::weak_ptr<SignalConnection>);
~SignalConnectionRef();
virtual const TypeInfo& GetType() const override;
static const TypeInfo TYPE;
static const TypeInfo TYPE;
operator std::weak_ptr<SignalConnection>();
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;
virtual const std::string ToString() const;
virtual void Serialize(pugi::xml_node node) const;
virtual void PushLuaValue(lua_State*) const;
static result<Variant, LuaCastError> FromLuaValue(lua_State*, int idx);
};

View file

@ -0,0 +1,68 @@
#include "variant.h"
#include "datatypes/base.h"
#include "datatypes/cframe.h"
#include "datatypes/primitives.h"
#include "datatypes/ref.h"
#include "datatypes/signal.h"
#include "datatypes/vector.h"
#include "logger.h"
#include "panic.h"
#include <pugixml.hpp>
#include <string>
#include <variant>
[[noreturn]] inline void unreachable() {
#if defined(_MSC_VER) && !defined(__clang__) // MSVC
__assume(false);
#else // GCC, Clang
__builtin_unreachable();
#endif
}
const TypeInfo* VARIANT_TYPES[] {
&NULL_TYPE,
&BOOL_TYPE,
&INT_TYPE,
&FLOAT_TYPE,
&STRING_TYPE,
&Vector3::TYPE,
&CFrame::TYPE,
&Color3::TYPE,
&InstanceRef::TYPE,
&SignalRef::TYPE,
&SignalConnectionRef::TYPE,
};
std::string Variant::ToString() const {
return VARIANT_TYPES[wrapped.index()]->toString(*this);
}
void Variant::Serialize(pugi::xml_node node) const {
VARIANT_TYPES[wrapped.index()]->serializer(*this, node);
}
void Variant::PushLuaValue(lua_State* state) const {
VARIANT_TYPES[wrapped.index()]->pushLuaValue(*this, state);
}
Variant Variant::Deserialize(pugi::xml_node node) {
if (TYPE_MAP.count(node.name()) == 0) {
Logger::fatalErrorf("Unknown type for property: '%s'", node.name());
panic();
}
const TypeInfo* type = TYPE_MAP[node.name()];
return type->deserializer(node);
}
std::map<std::string, const TypeInfo*> TYPE_MAP = {
{ "null", &NULL_TYPE },
{ "bool", &BOOL_TYPE },
{ "int", &INT_TYPE },
{ "float", &FLOAT_TYPE },
{ "string", &STRING_TYPE },
{ "Vector3", &Vector3::TYPE },
{ "CoordinateFrame", &CFrame::TYPE },
{ "Color3", &Color3::TYPE },
{ "Ref", &InstanceRef::TYPE },
};

View file

@ -0,0 +1,61 @@
#pragma once
#include <variant>
#include <map>
#include "base.h"
#include "datatypes/color3.h"
#include "datatypes/ref.h"
#include "datatypes/signal.h"
#include "vector.h"
#include "cframe.h"
// #define __VARIANT_TYPE std::variant< \
// Null, \
// Bool, \
// Int, \
// Float, \
// String \
// >
typedef std::variant<
std::monostate,
bool,
int,
float,
std::string,
Vector3,
CFrame,
Color3,
InstanceRef,
SignalRef,
SignalConnectionRef
> __VARIANT_TYPE;
class Variant {
__VARIANT_TYPE wrapped;
public:
template <typename T> Variant(T obj) : wrapped(obj) {}
template <typename T> T get() { return std::get<T>(wrapped); }
std::string ToString() const;
void Serialize(pugi::xml_node node) const;
void PushLuaValue(lua_State* state) const;
static Variant Deserialize(pugi::xml_node node);
};
template <typename T, typename R, typename ...Args>
std::function<R(Variant, Args...)> toVariantFunction(R(T::*f)(Args...)) {
return [f](Variant var, Args... args) {
return (var.get<T>().*f)(args...);
};
}
template <typename T, typename R, typename ...Args>
std::function<R(Variant, Args...)> toVariantFunction(R(T::*f)(Args...) const) {
return [f](Variant var, Args... args) {
return (var.get<T>().*f)(args...);
};
}
// Map of all data types to their type names
extern std::map<std::string, const TypeInfo*> TYPE_MAP;

View file

@ -7,91 +7,91 @@
#include <string>
#include <pugixml.hpp>
#include "datatypes/base.h"
#include "datatypes/meta.h"
#include "datatypes/variant.h"
#include <sstream>
namespace rp = reactphysics3d;
Data::Vector3::Vector3() : vector(glm::vec3(0, 0, 0)) {};
Data::Vector3::Vector3(const glm::vec3& src) : vector(src) {};
Data::Vector3::Vector3(const rp::Vector3& src) : vector(glm::vec3(src.x, src.y, src.z)) {};
Data::Vector3::Vector3(float x, const float y, float z) : vector(glm::vec3(x, y, z)) {};
Vector3::Vector3() : vector(glm::vec3(0, 0, 0)) {};
Vector3::Vector3(const glm::vec3& src) : vector(src) {};
Vector3::Vector3(const rp::Vector3& src) : vector(glm::vec3(src.x, src.y, src.z)) {};
Vector3::Vector3(float x, const float y, float z) : vector(glm::vec3(x, y, z)) {};
Data::Vector3::~Vector3() = default;
Vector3::~Vector3() = default;
Data::Vector3 Data::Vector3::ZERO(0, 0, 0);
Data::Vector3 Data::Vector3::ONE(1, 1, 1);
Vector3 Vector3::ZERO(0, 0, 0);
Vector3 Vector3::ONE(1, 1, 1);
const Data::String Data::Vector3::ToString() const {
const std::string Vector3::ToString() const {
// https://stackoverflow.com/a/46424921/16255372
std::stringstream stream;
stream << std::setprecision(8) << std::noshowpoint << X() << ", " << Y() << ", " << Z();
return stream.str();
}
Data::Vector3::operator glm::vec3() const { return vector; };
Data::Vector3::operator rp::Vector3() const { return rp::Vector3(X(), Y(), Z()); };
Vector3::operator glm::vec3() const { return vector; };
Vector3::operator rp::Vector3() const { return rp::Vector3(X(), Y(), Z()); };
// Operators
Data::Vector3 Data::Vector3::operator *(float scale) const {
return Data::Vector3(this->X() * scale, this->Y() * scale, this->Z() * scale);
Vector3 Vector3::operator *(float scale) const {
return Vector3(this->X() * scale, this->Y() * scale, this->Z() * scale);
}
Data::Vector3 Data::Vector3::operator /(float scale) const {
return Data::Vector3(this->X() / scale, this->Y() / scale, this->Z() / scale);
Vector3 Vector3::operator /(float scale) const {
return Vector3(this->X() / scale, this->Y() / scale, this->Z() / scale);
}
// Component-wise
Data::Vector3 Data::Vector3::operator *(Data::Vector3 other) const {
return Data::Vector3(this->X() * other.X(), this->Y() * other.Y(), this->Z() * other.Z());
Vector3 Vector3::operator *(Vector3 other) const {
return Vector3(this->X() * other.X(), this->Y() * other.Y(), this->Z() * other.Z());
}
Data::Vector3 Data::Vector3::operator +(Data::Vector3 other) const {
return Data::Vector3(this->X() + other.X(), this->Y() + other.Y(), this->Z() + other.Z());
Vector3 Vector3::operator +(Vector3 other) const {
return Vector3(this->X() + other.X(), this->Y() + other.Y(), this->Z() + other.Z());
}
Data::Vector3 Data::Vector3::operator -(Data::Vector3 other) const {
return Data::Vector3(this->X() - other.X(), this->Y() - other.Y(), this->Z() - other.Z());
Vector3 Vector3::operator -(Vector3 other) const {
return Vector3(this->X() - other.X(), this->Y() - other.Y(), this->Z() - other.Z());
}
Data::Vector3 Data::Vector3::operator -() const {
return Data::Vector3(-this->X(), -this->Y(), -this->Z());
Vector3 Vector3::operator -() const {
return Vector3(-this->X(), -this->Y(), -this->Z());
}
bool Data::Vector3::operator ==(Data::Vector3 other) const {
bool Vector3::operator ==(Vector3 other) const {
return this->X() == other.X() && this->Y() == other.Y() && this->Z() == other.Z();
}
bool Data::Vector3::operator <(Data::Vector3 other) const {
bool Vector3::operator <(Vector3 other) const {
return X() < other.X() && Y() < other.Y() && Z() < other.Z();
}
bool Data::Vector3::operator >(Data::Vector3 other) const {
bool Vector3::operator >(Vector3 other) const {
return X() > other.X() && Y() > other.Y() && Z() > other.Z();
}
Data::Vector3 Data::Vector3::Cross(Data::Vector3 other) const {
Vector3 Vector3::Cross(Vector3 other) const {
return glm::cross(this->vector, other.vector);
}
float Data::Vector3::Dot(Data::Vector3 other) const {
float Vector3::Dot(Vector3 other) const {
return glm::dot(this->vector, other.vector);
}
// Serialization
void Data::Vector3::Serialize(pugi::xml_node node) const {
void Vector3::Serialize(pugi::xml_node node) const {
node.append_child("X").text().set(std::to_string(this->X()));
node.append_child("Y").text().set(std::to_string(this->Y()));
node.append_child("Z").text().set(std::to_string(this->Z()));
}
Data::Variant Data::Vector3::Deserialize(pugi::xml_node node) {
return Data::Vector3(node.child("X").text().as_float(), node.child("Y").text().as_float(), node.child("Z").text().as_float());
Variant Vector3::Deserialize(pugi::xml_node node) {
return Vector3(node.child("X").text().as_float(), node.child("Y").text().as_float(), node.child("Z").text().as_float());
}
std::optional<Data::Variant> Data::Vector3::FromString(std::string string) {
std::optional<Variant> Vector3::FromString(std::string string) {
float components[3];
for (int i = 0; i < 3; i++) {
@ -109,5 +109,5 @@ std::optional<Data::Variant> Data::Vector3::FromString(std::string string) {
components[i] = value;
}
return Data::Vector3(components[0], components[1], components[2]);
return Vector3(components[0], components[1], components[2]);
}

View file

@ -7,59 +7,55 @@
namespace reactphysics3d { class Vector3; };
namespace Data {
class DEF_DATA Vector3 : public Base {
AUTOGEN_PREAMBLE_DATA
glm::vec3 vector;
class DEF_DATA Vector3 {
AUTOGEN_PREAMBLE_DATA
glm::vec3 vector;
public:
DEF_DATA_CTOR Vector3();
DEF_DATA_CTOR Vector3(float x, float y, float z);
Vector3(const glm::vec3&);
Vector3(const reactphysics3d::Vector3&);
~Vector3();
DEF_DATA_PROP static Vector3 ZERO;
DEF_DATA_PROP static Vector3 ONE;
virtual const std::string ToString() const;
virtual void Serialize(pugi::xml_node node) const;
static Variant Deserialize(pugi::xml_node node);
static std::optional<Variant> FromString(std::string);
public:
DEF_DATA_CTOR Vector3();
DEF_DATA_CTOR Vector3(float x, float y, float z);
Vector3(const glm::vec3&);
Vector3(const reactphysics3d::Vector3&);
~Vector3();
static void PushLuaLibrary(lua_State*);
DEF_DATA_PROP static Data::Vector3 ZERO;
DEF_DATA_PROP static Data::Vector3 ONE;
operator glm::vec3() const;
operator reactphysics3d::Vector3() const;
virtual const Data::String ToString() const override;
virtual void Serialize(pugi::xml_node node) const override;
DEF_DATA_PROP inline float X() const { return vector.x; }
DEF_DATA_PROP inline float Y() const { return vector.y; }
DEF_DATA_PROP inline float Z() const { return vector.z; }
DEF_DATA_METHOD inline float Magnitude() const { return glm::length(vector); }
DEF_DATA_METHOD inline Vector3 Unit() const { return glm::normalize(vector); }
DEF_DATA_METHOD inline Vector3 Abs() const { return glm::abs(vector); }
static Data::Variant Deserialize(pugi::xml_node node);
static std::optional<Data::Variant> FromString(std::string);
static void PushLuaLibrary(lua_State*);
DEF_DATA_METHOD Vector3 Cross(Vector3) const;
DEF_DATA_METHOD float Dot(Vector3) const;
operator glm::vec3() const;
operator reactphysics3d::Vector3() const;
// Operators
DEF_DATA_OP Vector3 operator *(float) const;
DEF_DATA_OP Vector3 operator /(float) const;
DEF_DATA_OP Vector3 operator *(Vector3) const; // Component-wise
DEF_DATA_OP Vector3 operator +(Vector3) const;
DEF_DATA_OP Vector3 operator -(Vector3) const;
DEF_DATA_OP Vector3 operator -() const;
DEF_DATA_PROP inline float X() const { return vector.x; }
DEF_DATA_PROP inline float Y() const { return vector.y; }
DEF_DATA_PROP inline float Z() const { return vector.z; }
DEF_DATA_METHOD inline float Magnitude() const { return glm::length(vector); }
DEF_DATA_METHOD inline Data::Vector3 Unit() const { return glm::normalize(vector); }
DEF_DATA_METHOD inline Data::Vector3 Abs() const { return glm::abs(vector); }
DEF_DATA_OP bool operator <(Vector3) const;
DEF_DATA_OP bool operator >(Vector3) const;
DEF_DATA_METHOD Data::Vector3 Cross(Data::Vector3) const;
DEF_DATA_METHOD float Dot(Data::Vector3) const;
// Operators
DEF_DATA_OP Data::Vector3 operator *(float) const;
DEF_DATA_OP Data::Vector3 operator /(float) const;
DEF_DATA_OP Data::Vector3 operator *(Data::Vector3) const; // Component-wise
DEF_DATA_OP Data::Vector3 operator +(Data::Vector3) const;
DEF_DATA_OP Data::Vector3 operator -(Data::Vector3) const;
DEF_DATA_OP Data::Vector3 operator -() const;
DEF_DATA_OP bool operator ==(Vector3) const;
};
DEF_DATA_OP bool operator <(Data::Vector3) const;
DEF_DATA_OP bool operator >(Data::Vector3) const;
DEF_DATA_OP bool operator ==(Data::Vector3) const;
};
}
using Data::Vector3;
inline void printVec(Data::Vector3 vec) {
inline void printVec(Vector3 vec) {
printf("(%f, %f, %f)\n", vec.X(), vec.Y(), vec.Z());
}

View file

@ -37,8 +37,8 @@
#define AUTOGEN_PREAMBLE \
protected: \
virtual result<PropertyMeta, MemberNotFound> InternalGetPropertyMeta(std::string name) override; \
virtual fallible<MemberNotFound, AssignToReadOnlyMember> InternalSetPropertyValue(std::string name, Data::Variant value) override; \
virtual result<Data::Variant, MemberNotFound> InternalGetPropertyValue(std::string name) override; \
virtual fallible<MemberNotFound, AssignToReadOnlyMember> InternalSetPropertyValue(std::string name, Variant value) override; \
virtual result<Variant, MemberNotFound> InternalGetPropertyValue(std::string name) override; \
virtual void InternalUpdateProperty(std::string name) override; \
virtual std::vector<std::string> InternalGetProperties() override; \
public: \

View file

@ -1,6 +1,7 @@
#include "instance.h"
#include "common.h"
#include "datatypes/meta.h"
#include "datatypes/primitives.h"
#include "datatypes/variant.h"
#include "datatypes/base.h"
#include "datatypes/ref.h"
#include "error/instance.h"
@ -96,7 +97,7 @@ void Instance::updateAncestry(std::optional<std::shared_ptr<Instance>> updatedCh
}
OnAncestryChanged(updatedChild, newParent);
AncestryChanged->Fire({updatedChild.has_value() ? Data::InstanceRef(updatedChild.value()) : Data::InstanceRef(), newParent.has_value() ? Data::InstanceRef(newParent.value()) : Data::InstanceRef()});
AncestryChanged->Fire({updatedChild.has_value() ? InstanceRef(updatedChild.value()) : InstanceRef(), newParent.has_value() ? InstanceRef(newParent.value()) : InstanceRef()});
// Old workspace used to exist, and workspaces differ
if (!oldWorkspace.expired() && oldWorkspace != _workspace) {
@ -179,11 +180,11 @@ void Instance::OnWorkspaceRemoved(std::shared_ptr<Workspace> oldWorkspace) {
// Properties
result<Data::Variant, MemberNotFound> Instance::GetPropertyValue(std::string name) {
result<Variant, MemberNotFound> Instance::GetPropertyValue(std::string name) {
return InternalGetPropertyValue(name);
}
fallible<MemberNotFound, AssignToReadOnlyMember> Instance::SetPropertyValue(std::string name, Data::Variant value, bool sendUpdateEvent) {
fallible<MemberNotFound, AssignToReadOnlyMember> Instance::SetPropertyValue(std::string name, Variant value, bool sendUpdateEvent) {
auto result = InternalSetPropertyValue(name, value);
if (result.isSuccess() && sendUpdateEvent) {
InternalUpdateProperty(name);
@ -197,33 +198,33 @@ result<PropertyMeta, MemberNotFound> Instance::GetPropertyMeta(std::string name)
}
result<Data::Variant, MemberNotFound> Instance::InternalGetPropertyValue(std::string name) {
result<Variant, MemberNotFound> Instance::InternalGetPropertyValue(std::string name) {
if (name == "Name") {
return Data::Variant(Data::String(this->name));
return Variant(this->name);
} else if (name == "Parent") {
return Data::Variant(Data::InstanceRef(this->parent));
return Variant(InstanceRef(this->parent));
} else if (name == "ClassName") {
return Data::Variant(Data::String(GetClass()->className));
return Variant(GetClass()->className);
}
return MemberNotFound(GetClass()->className, name);
}
result<PropertyMeta, MemberNotFound> Instance::InternalGetPropertyMeta(std::string name) {
if (name == "Name") {
return PropertyMeta { &Data::String::TYPE };
return PropertyMeta { &STRING_TYPE };
} else if (name == "Parent") {
return PropertyMeta { &Data::InstanceRef::TYPE, PROP_NOSAVE };
return PropertyMeta { &InstanceRef::TYPE, PROP_NOSAVE };
} else if (name == "ClassName") {
return PropertyMeta { &Data::String::TYPE, PROP_NOSAVE | PROP_READONLY };
return PropertyMeta { &STRING_TYPE, PROP_NOSAVE | PROP_READONLY };
}
return MemberNotFound(GetClass()->className, name);
}
fallible<MemberNotFound, AssignToReadOnlyMember> Instance::InternalSetPropertyValue(std::string name, Data::Variant value) {
fallible<MemberNotFound, AssignToReadOnlyMember> Instance::InternalSetPropertyValue(std::string name, Variant value) {
if (name == "Name") {
this->name = (std::string)value.get<Data::String>();
this->name = (std::string)value.get<std::string>();
} else if (name == "Parent") {
std::weak_ptr<Instance> ref = value.get<Data::InstanceRef>();
std::weak_ptr<Instance> ref = value.get<InstanceRef>();
SetParent(ref.expired() ? std::nullopt : std::make_optional(ref.lock()));
} else if (name == "ClassName") {
return AssignToReadOnlyMember(GetClass()->className, name);
@ -273,8 +274,8 @@ void Instance::Serialize(pugi::xml_node parent, RefStateSerialize state) {
propertyNode.append_attribute("name").set_value(name);
// Update std::shared_ptr<Instance> properties using map above
if (meta.type == &Data::InstanceRef::TYPE) {
std::weak_ptr<Instance> refWeak = GetPropertyValue(name).expect("Declared property is missing").get<Data::InstanceRef>();
if (meta.type == &InstanceRef::TYPE) {
std::weak_ptr<Instance> refWeak = GetPropertyValue(name).expect("Declared property is missing").get<InstanceRef>();
if (refWeak.expired()) continue;
auto ref = refWeak.lock();
@ -333,7 +334,7 @@ result<std::shared_ptr<Instance>, NoSuchInstance> Instance::Deserialize(pugi::xm
}
// Update std::shared_ptr<Instance> properties using map above
if (meta_.expect().type == &Data::InstanceRef::TYPE) {
if (meta_.expect().type == &InstanceRef::TYPE) {
if (propertyNode.text().empty())
continue;
@ -342,17 +343,17 @@ result<std::shared_ptr<Instance>, NoSuchInstance> Instance::Deserialize(pugi::xm
if (remappedRef) {
// If the instance has already been remapped, set the new value
object->SetPropertyValue(propertyName, Data::InstanceRef(remappedRef)).expect();
object->SetPropertyValue(propertyName, InstanceRef(remappedRef)).expect();
} else {
// Otheriise, queue this property to be updated later, and keep its current value
auto& refs = state->refsAwaitingRemap[refId];
refs.push_back(std::make_pair(object, propertyName));
state->refsAwaitingRemap[refId] = refs;
object->SetPropertyValue(propertyName, Data::InstanceRef()).expect();
object->SetPropertyValue(propertyName, InstanceRef()).expect();
}
} else {
Data::Variant value = Data::Variant::Deserialize(propertyNode);
Variant value = Variant::Deserialize(propertyNode);
object->SetPropertyValue(propertyName, value).expect("Declared property was missing");
}
}
@ -363,7 +364,7 @@ result<std::shared_ptr<Instance>, NoSuchInstance> Instance::Deserialize(pugi::xm
// Remap queued properties
for (std::pair<std::shared_ptr<Instance>, std::string> ref : state->refsAwaitingRemap[remappedId]) {
ref.first->SetPropertyValue(ref.second, Data::InstanceRef(object)).expect();
ref.first->SetPropertyValue(ref.second, InstanceRef(object)).expect();
}
state->refsAwaitingRemap[remappedId].clear();
@ -435,8 +436,8 @@ std::optional<std::shared_ptr<Instance>> Instance::Clone(RefStateClone state) {
if (meta.flags & (PROP_READONLY | PROP_NOSAVE)) continue;
// Update std::shared_ptr<Instance> properties using map above
if (meta.type == &Data::InstanceRef::TYPE) {
std::weak_ptr<Instance> refWeak = GetPropertyValue(property).expect().get<Data::InstanceRef>();
if (meta.type == &InstanceRef::TYPE) {
std::weak_ptr<Instance> refWeak = GetPropertyValue(property).expect().get<InstanceRef>();
if (refWeak.expired()) continue;
auto ref = refWeak.lock();
@ -444,17 +445,17 @@ std::optional<std::shared_ptr<Instance>> Instance::Clone(RefStateClone state) {
if (remappedRef) {
// If the instance has already been remapped, set the new value
newInstance->SetPropertyValue(property, Data::InstanceRef(remappedRef)).expect();
newInstance->SetPropertyValue(property, InstanceRef(remappedRef)).expect();
} else {
// Otheriise, queue this property to be updated later, and keep its current value
auto& refs = state->refsAwaitingRemap[ref];
refs.push_back(std::make_pair(newInstance, property));
state->refsAwaitingRemap[ref] = refs;
newInstance->SetPropertyValue(property, Data::InstanceRef(ref)).expect();
newInstance->SetPropertyValue(property, InstanceRef(ref)).expect();
}
} else {
Data::Variant value = GetPropertyValue(property).expect();
Variant value = GetPropertyValue(property).expect();
newInstance->SetPropertyValue(property, value).expect();
}
}
@ -464,7 +465,7 @@ std::optional<std::shared_ptr<Instance>> Instance::Clone(RefStateClone state) {
// Remap queued properties
for (std::pair<std::shared_ptr<Instance>, std::string> ref : state->refsAwaitingRemap[shared_from_this()]) {
ref.first->SetPropertyValue(ref.second, Data::InstanceRef(newInstance)).expect();
ref.first->SetPropertyValue(ref.second, InstanceRef(newInstance)).expect();
}
state->refsAwaitingRemap[shared_from_this()].clear();
@ -485,9 +486,9 @@ std::vector<std::pair<std::string, std::shared_ptr<Instance>>> Instance::GetRefe
for (std::string property : propertyNames) {
PropertyMeta meta = GetPropertyMeta(property).expect();
if (meta.type != &Data::InstanceRef::TYPE) continue;
if (meta.type != &InstanceRef::TYPE) continue;
std::weak_ptr<Instance> ref = GetPropertyValue(property).expect().get<Data::InstanceRef>();
std::weak_ptr<Instance> ref = GetPropertyValue(property).expect().get<InstanceRef>();
if (ref.expired()) continue;
referenceProperties.push_back(std::make_pair(property, ref.lock()));
}

View file

@ -69,8 +69,8 @@ protected:
Instance(const InstanceType*);
virtual ~Instance();
virtual result<Data::Variant, MemberNotFound> InternalGetPropertyValue(std::string name);
virtual fallible<MemberNotFound, AssignToReadOnlyMember> InternalSetPropertyValue(std::string name, Data::Variant value);
virtual result<Variant, MemberNotFound> InternalGetPropertyValue(std::string name);
virtual fallible<MemberNotFound, AssignToReadOnlyMember> InternalSetPropertyValue(std::string name, Variant value);
virtual result<PropertyMeta, MemberNotFound> InternalGetPropertyMeta(std::string name);
virtual void InternalUpdateProperty(std::string name);
virtual std::vector<std::string> InternalGetProperties();
@ -114,8 +114,8 @@ public:
std::string GetFullName();
// Properties
result<Data::Variant, MemberNotFound> GetPropertyValue(std::string name);
fallible<MemberNotFound, AssignToReadOnlyMember> SetPropertyValue(std::string name, Data::Variant value, bool sendUpdateEvent = true);
result<Variant, MemberNotFound> GetPropertyValue(std::string name);
fallible<MemberNotFound, AssignToReadOnlyMember> SetPropertyValue(std::string name, Variant value, bool sendUpdateEvent = true);
result<PropertyMeta, MemberNotFound> GetPropertyMeta(std::string name);
// Manually trigger the update of a property. Useful internally when setting properties directly
void UpdateProperty(std::string name);

View file

@ -24,7 +24,7 @@ enum PropertyCategory {
const int PROPERTY_CATEGORY_MAX = PROP_CATEGORY_SURFACE_INPUT;
struct PropertyMeta {
const Data::TypeInfo* type;
const TypeInfo* type;
PropertyFlags flags;
PropertyCategory category = PROP_CATEGORY_DATA;
};

View file

@ -5,7 +5,7 @@
#include "objects/base/service.h"
#include "objects/meta.h"
#include "objects/script/serverscriptservice.h"
#include "datatypes/meta.h"
#include "datatypes/variant.h"
#include "workspace.h"
#include "logger.h"
#include "panic.h"
@ -131,8 +131,8 @@ std::shared_ptr<DataModel> DataModel::CloneModel() {
if (meta.flags & (PROP_READONLY | PROP_NOSAVE)) continue;
// Update std::shared_ptr<Instance> properties using map above
if (meta.type == &Data::InstanceRef::TYPE) {
std::weak_ptr<Instance> refWeak = GetPropertyValue(property).expect().get<Data::InstanceRef>();
if (meta.type == &InstanceRef::TYPE) {
std::weak_ptr<Instance> refWeak = GetPropertyValue(property).expect().get<InstanceRef>();
if (refWeak.expired()) continue;
auto ref = refWeak.lock();
@ -140,17 +140,17 @@ std::shared_ptr<DataModel> DataModel::CloneModel() {
if (remappedRef) {
// If the instance has already been remapped, set the new value
newModel->SetPropertyValue(property, Data::InstanceRef(remappedRef)).expect();
newModel->SetPropertyValue(property, InstanceRef(remappedRef)).expect();
} else {
// Otheriise, queue this property to be updated later, and keep its current value
auto& refs = state->refsAwaitingRemap[ref];
refs.push_back(std::make_pair(newModel, property));
state->refsAwaitingRemap[ref] = refs;
newModel->SetPropertyValue(property, Data::InstanceRef(ref)).expect();
newModel->SetPropertyValue(property, InstanceRef(ref)).expect();
}
} else {
Data::Variant value = GetPropertyValue(property).expect();
Variant value = GetPropertyValue(property).expect();
newModel->SetPropertyValue(property, value).expect();
}
}
@ -160,7 +160,7 @@ std::shared_ptr<DataModel> DataModel::CloneModel() {
// Remap queued properties
for (std::pair<std::shared_ptr<Instance>, std::string> ref : state->refsAwaitingRemap[shared_from_this()]) {
ref.first->SetPropertyValue(ref.second, Data::InstanceRef(newModel)).expect();
ref.first->SetPropertyValue(ref.second, InstanceRef(newModel)).expect();
}
// Clone services

View file

@ -41,10 +41,10 @@ void Script::Run() {
// Initialize script globals
lua_getglobal(Lt, "_G");
Data::InstanceRef(dataModel().value()).PushLuaValue(Lt);
InstanceRef(dataModel().value()).PushLuaValue(Lt);
lua_setfield(Lt, -2, "game");
Data::InstanceRef(dataModel().value()->GetService<Workspace>()).PushLuaValue(Lt);
InstanceRef(dataModel().value()->GetService<Workspace>()).PushLuaValue(Lt);
lua_setfield(Lt, -2, "workspace");
lua_pushlightuserdata(Lt, scriptContext.get());

View file

@ -43,9 +43,9 @@ void ScriptContext::InitService() {
// luaopen_debug(state);
luaopen_bit(state);
Data::Vector3::PushLuaLibrary(state);
Data::CFrame::PushLuaLibrary(state);
Data::Color3::PushLuaLibrary(state);
Vector3::PushLuaLibrary(state);
CFrame::PushLuaLibrary(state);
Color3::PushLuaLibrary(state);
// TODO: custom os library

View file

@ -1,5 +1,5 @@
#include "workspace.h"
#include "datatypes/meta.h"
#include "datatypes/variant.h"
#include "datatypes/ref.h"
#include "datatypes/vector.h"
#include "objects/base/instance.h"
@ -33,11 +33,11 @@ void PhysicsEventListener::onContact(const rp::CollisionCallback::CallbackData&
auto part1 = reinterpret_cast<Part*>(pair.getBody2()->getUserData())->shared<Part>();
if (type == reactphysics3d::CollisionCallback::ContactPair::EventType::ContactStart) {
part0->Touched->Fire({ (Data::Variant)Data::InstanceRef(part1) });
part1->Touched->Fire({ (Data::Variant)Data::InstanceRef(part0) });
part0->Touched->Fire({ (Variant)InstanceRef(part1) });
part1->Touched->Fire({ (Variant)InstanceRef(part0) });
} else if (type == reactphysics3d::CollisionCallback::ContactPair::EventType::ContactExit) {
part0->TouchEnded->Fire({ (Data::Variant)Data::InstanceRef(part1) });
part1->TouchEnded->Fire({ (Data::Variant)Data::InstanceRef(part0) });
part0->TouchEnded->Fire({ (Variant)InstanceRef(part1) });
part1->TouchEnded->Fire({ (Variant)InstanceRef(part0) });
}
}
}

View file

@ -1,7 +1,7 @@
#include "partassembly.h"
#include "common.h"
#include "datatypes/cframe.h"
#include "datatypes/meta.h"
#include "datatypes/variant.h"
#include "datatypes/vector.h"
#include "math_helper.h"
#include "objects/base/instance.h"
@ -49,7 +49,7 @@ void PartAssembly::SetOrigin(CFrame newOrigin) {
for (auto part : parts) {
part->cframe = newOrigin * (_assemblyOrigin.Inverse() * part->cframe);
part->UpdateProperty("CFrame");
// sendPropertyUpdatedSignal(part, "CFrame", Data::Variant(part->cframe));
// sendPropertyUpdatedSignal(part, "CFrame", Variant(part->cframe));
}
_assemblyOrigin = newOrigin;
@ -59,7 +59,7 @@ void PartAssembly::TransformBy(CFrame transform) {
for (auto part : parts) {
part->cframe = transform * part->cframe;
part->UpdateProperty("CFrame");
sendPropertyUpdatedSignal(part, "CFrame", Data::Variant(part->cframe));
sendPropertyUpdatedSignal(part, "CFrame", Variant(part->cframe));
}
_assemblyOrigin = transform * _assemblyOrigin;
@ -69,7 +69,7 @@ void PartAssembly::Scale(Vector3 newSize, bool scaleUp) {
if (parts.size() == 1) {
parts[0]->size = newSize;
parts[0]->UpdateProperty("Size");
sendPropertyUpdatedSignal(parts[0], "Size", Data::Variant((Data::Vector3)parts[0]->size));
sendPropertyUpdatedSignal(parts[0], "Size", Variant((Vector3)parts[0]->size));
_bounds = newSize;
return;
}
@ -82,10 +82,10 @@ void PartAssembly::Scale(Vector3 newSize, bool scaleUp) {
localOff = localOff * factor;
part->cframe = part->cframe.Rotation() + _assemblyOrigin * localOff;
part->UpdateProperty("CFrame");
sendPropertyUpdatedSignal(part, "CFrame", Data::Variant(part->cframe));
sendPropertyUpdatedSignal(part, "CFrame", Variant(part->cframe));
part->size *= factor;
part->UpdateProperty("Size");
sendPropertyUpdatedSignal(part, "Size", Data::Variant((Data::Vector3)part->size));
sendPropertyUpdatedSignal(part, "Size", Variant((Vector3)part->size));
}
_bounds = _bounds * factor;

View file

@ -8,5 +8,5 @@ namespace Data { class CFrame; class Color3; };
void renderInit(GLFWwindow* window, int width, int height);
void render(GLFWwindow* window);
void setViewport(int width, int height);
void addDebugRenderCFrame(Data::CFrame);
void addDebugRenderCFrame(Data::CFrame, Data::Color3);
void addDebugRenderCFrame(CFrame);
void addDebugRenderCFrame(CFrame, Color3);

View file

@ -20,6 +20,6 @@ enum SurfaceType {
SurfaceMotor = 7,
};
namespace Data { class Vector3; } using Data::Vector3;
class Vector3;
NormalId faceFromNormal(Vector3);
Vector3 normalFromFace(NormalId);

View file

@ -17,7 +17,7 @@
#include "physics/util.h"
#include "rendering/renderer.h"
#include "rendering/shader.h"
#include "datatypes/meta.h"
#include "datatypes/variant.h"
#define PI 3.14159
#define M_mainWindow dynamic_cast<MainWindow*>(window())

View file

@ -1,7 +1,8 @@
#include "panes/propertiesview.h"
#include "common.h"
#include "datatypes/base.h"
#include "datatypes/meta.h"
#include "datatypes/variant.h"
#include "datatypes/primitives.h"
#include "objects/base/member.h"
#include <QColorDialog>
@ -49,7 +50,7 @@ public:
std::string propertyName = !isComposite ? view->itemFromIndex(index)->data(0, Qt::DisplayRole).toString().toStdString()
: view->itemFromIndex(index.parent())->data(0, Qt::DisplayRole).toString().toStdString();
PropertyMeta meta = inst->GetPropertyMeta(propertyName).expect();
Data::Variant currentValue = inst->GetPropertyValue(propertyName).expect();
Variant currentValue = inst->GetPropertyValue(propertyName).expect();
if (isComposite) {
if (meta.type == &Vector3::TYPE) {
@ -65,9 +66,9 @@ public:
return nullptr;
}
if (meta.type == &Data::Float::TYPE) {
if (meta.type == &FLOAT_TYPE) {
QDoubleSpinBox* spinBox = new QDoubleSpinBox(parent);
spinBox->setValue(currentValue.get<Data::Float>());
spinBox->setValue(currentValue.get<float>());
if (meta.flags & PROP_UNIT_FLOAT) {
spinBox->setMinimum(0);
@ -76,14 +77,14 @@ public:
}
return spinBox;
} else if (meta.type == &Data::Int::TYPE) {
} else if (meta.type == &INT_TYPE) {
QSpinBox* spinBox = new QSpinBox(parent);
spinBox->setValue(currentValue.get<Data::Int>());
spinBox->setValue(currentValue.get<int>());
return spinBox;
} else if (meta.type == &Data::String::TYPE) {
} else if (meta.type == &STRING_TYPE) {
QLineEdit* lineEdit = new QLineEdit(parent);
lineEdit->setText(QString::fromStdString(currentValue.get<Data::String>()));
lineEdit->setText(QString::fromStdString(currentValue.get<std::string>()));
return lineEdit;
} else if (meta.type == &Color3::TYPE) {
@ -115,7 +116,7 @@ public:
std::string propertyName = !index.parent().parent().isValid() ? view->itemFromIndex(index)->data(0, Qt::DisplayRole).toString().toStdString()
: view->itemFromIndex(index.parent())->data(0, Qt::DisplayRole).toString().toStdString();
PropertyMeta meta = inst->GetPropertyMeta(propertyName).expect();
Data::Variant currentValue = inst->GetPropertyValue(propertyName).expect();
Variant currentValue = inst->GetPropertyValue(propertyName).expect();
if (isComposite) {
if (meta.type == &Vector3::TYPE) {
@ -131,18 +132,18 @@ public:
return;
}
if (meta.type == &Data::Float::TYPE) {
if (meta.type == &FLOAT_TYPE) {
QDoubleSpinBox* spinBox = dynamic_cast<QDoubleSpinBox*>(editor);
spinBox->setValue(currentValue.get<Data::Float>());
} else if (meta.type == &Data::Int::TYPE) {
spinBox->setValue(currentValue.get<float>());
} else if (meta.type == &INT_TYPE) {
QSpinBox* spinBox = dynamic_cast<QSpinBox*>(editor);
spinBox->setValue(currentValue.get<Data::Int>());
} else if (meta.type == &Data::String::TYPE) {
spinBox->setValue(currentValue.get<int>());
} else if (meta.type == &STRING_TYPE) {
QLineEdit* lineEdit = dynamic_cast<QLineEdit*>(editor);
lineEdit->setText(QString::fromStdString((std::string)currentValue.get<Data::String>()));
lineEdit->setText(QString::fromStdString((std::string)currentValue.get<std::string>()));
} else if (meta.type == &Color3::TYPE) {
QColorDialog* colorDialog = dynamic_cast<QColorDialog*>(editor);
@ -186,20 +187,20 @@ public:
return;
}
if (meta.type == &Data::Float::TYPE) {
if (meta.type == &FLOAT_TYPE) {
QDoubleSpinBox* spinBox = dynamic_cast<QDoubleSpinBox*>(editor);
inst->SetPropertyValue(propertyName, Data::Float((float)spinBox->value())).expect();
inst->SetPropertyValue(propertyName, (float)spinBox->value()).expect();
model->setData(index, spinBox->value());
} else if (meta.type == &Data::Int::TYPE) {
} else if (meta.type == &INT_TYPE) {
QSpinBox* spinBox = dynamic_cast<QSpinBox*>(editor);
inst->SetPropertyValue(propertyName, Data::Int((float)spinBox->value())).expect();
inst->SetPropertyValue(propertyName, (int)spinBox->value()).expect();
model->setData(index, spinBox->value());
} else if (meta.type == &Data::String::TYPE) {
} else if (meta.type == &STRING_TYPE) {
QLineEdit* lineEdit = dynamic_cast<QLineEdit*>(editor);
inst->SetPropertyValue(propertyName, Data::String(lineEdit->text().toStdString())).expect();
inst->SetPropertyValue(propertyName, lineEdit->text().toStdString()).expect();
model->setData(index, lineEdit->text());
} else if (meta.type == &Color3::TYPE) {
QColorDialog* colorDialog = dynamic_cast<QColorDialog*>(editor);
@ -212,7 +213,7 @@ public:
} else if (meta.type->fromString) {
QLineEdit* lineEdit = dynamic_cast<QLineEdit*>(editor);
std::optional<Data::Variant> parsedResult = meta.type->fromString(lineEdit->text().toStdString());
std::optional<Variant> parsedResult = meta.type->fromString(lineEdit->text().toStdString());
if (!parsedResult) return;
inst->SetPropertyValue(propertyName, parsedResult.value()).expect();
model->setData(index, QString::fromStdString(parsedResult.value().ToString()));
@ -296,7 +297,7 @@ void PropertiesView::setSelected(std::optional<std::shared_ptr<Instance>> instan
for (std::string property : properties) {
PropertyMeta meta = inst->GetPropertyMeta(property).expect();
Data::Variant currentValue = inst->GetPropertyValue(property).expect();
Variant currentValue = inst->GetPropertyValue(property).expect();
if (meta.type == &CFrame::TYPE || meta.flags & PROP_HIDDEN) continue;
@ -304,8 +305,8 @@ void PropertiesView::setSelected(std::optional<std::shared_ptr<Instance>> instan
item->setFlags(item->flags() | Qt::ItemIsEditable | Qt::ItemIsSelectable);
item->setData(0, Qt::DisplayRole, QString::fromStdString(property));
if (meta.type == &Data::Bool::TYPE) {
item->setCheckState(1, (bool)currentValue.get<Data::Bool>() ? Qt::CheckState::Checked : Qt::CheckState::Unchecked);
if (meta.type == &BOOL_TYPE) {
item->setCheckState(1, (bool)currentValue.get<bool>() ? Qt::CheckState::Checked : Qt::CheckState::Unchecked);
} else if (meta.type == &Color3::TYPE) {
Color3 color = currentValue.get<Color3>();
item->setData(1, Qt::DecorationRole, QColor::fromRgbF(color.R(), color.G(), color.B()));
@ -352,12 +353,12 @@ void PropertiesView::propertyChanged(QTreeWidgetItem *item, int column) {
std::string propertyName = item->data(0, Qt::DisplayRole).toString().toStdString();
PropertyMeta meta = inst->GetPropertyMeta(propertyName).expect();
if (meta.type == &Data::Bool::TYPE) {
inst->SetPropertyValue(propertyName, Data::Bool(item->checkState(1) == Qt::Checked)).expect();
if (meta.type == &BOOL_TYPE) {
inst->SetPropertyValue(propertyName, item->checkState(1) == Qt::Checked).expect();
}
}
void PropertiesView::rebuildCompositeProperty(QTreeWidgetItem *item, const Data::TypeInfo* type, Data::Variant value) {
void PropertiesView::rebuildCompositeProperty(QTreeWidgetItem *item, const TypeInfo* type, Variant value) {
if (type == &Vector3::TYPE) {
// https://forum.qt.io/post/266837
foreach(auto i, item->takeChildren()) delete i;
@ -384,13 +385,13 @@ void PropertiesView::rebuildCompositeProperty(QTreeWidgetItem *item, const Data:
}
// static auto lastUpdateTime = std::chrono::steady_clock::now();
void PropertiesView::onPropertyUpdated(std::shared_ptr<Instance> inst, std::string property, Data::Variant newValue) {
void PropertiesView::onPropertyUpdated(std::shared_ptr<Instance> inst, std::string property, Variant newValue) {
// if (!currentInstance || currentInstance->expired() || instance != currentInstance->lock()) return;
// if (std::chrono::duration_cast<std::chrono::milliseconds>(std::chrono::steady_clock::now() - lastUpdateTime).count() < 1000) return;
// lastUpdateTime = std::chrono::steady_clock::now();
PropertyMeta meta = inst->GetPropertyMeta(property).expect();
Data::Variant currentValue = inst->GetPropertyValue(property).expect();
Variant currentValue = inst->GetPropertyValue(property).expect();
if (meta.type == &CFrame::TYPE) return;
@ -401,10 +402,10 @@ void PropertiesView::onPropertyUpdated(std::shared_ptr<Instance> inst, std::stri
if (item->data(0, Qt::DisplayRole).toString().toStdString() != property) continue;
if (meta.type == &Data::Bool::TYPE) {
if (meta.type == &BOOL_TYPE) {
// This is done because otherwise propertyChanged will catch this change erroneously
ignorePropertyUpdates = true;
item->setCheckState(1, (bool)currentValue.get<Data::Bool>() ? Qt::CheckState::Checked : Qt::CheckState::Unchecked);
item->setCheckState(1, (bool)currentValue.get<bool>() ? Qt::CheckState::Checked : Qt::CheckState::Unchecked);
ignorePropertyUpdates = false;
} else if (meta.type == &Color3::TYPE) {
Color3 color = currentValue.get<Color3>();

View file

@ -15,8 +15,8 @@ class PropertiesView : public QTreeWidget {
std::weak_ptr<Instance> currentInstance;
void propertyChanged(QTreeWidgetItem *item, int column);
void activateProperty(QTreeWidgetItem *item, int column);
void rebuildCompositeProperty(QTreeWidgetItem *item, const Data::TypeInfo*, Data::Variant);
void onPropertyUpdated(std::shared_ptr<Instance> instance, std::string property, Data::Variant newValue);
void rebuildCompositeProperty(QTreeWidgetItem *item, const TypeInfo*, Variant);
void onPropertyUpdated(std::shared_ptr<Instance> instance, std::string property, Variant newValue);
friend PropertiesItemDelegate;
protected:

View file

@ -16,7 +16,7 @@
#include <qtextformat.h>
#include "mainwindow.h"
#include "objects/script.h"
#include "datatypes/meta.h"
#include "datatypes/variant.h"
#include <QPalette>
#include <QStyleHints>
@ -115,9 +115,9 @@ ScriptDocument::ScriptDocument(std::shared_ptr<Script> script, QWidget* parent):
setWindowTitle(QString::fromStdString(script->name));
// Add detector for script deletion to automatically close this document
scriptDeletionHandler = script->AncestryChanged->Connect([this, script](std::vector<Data::Variant> args) {
std::weak_ptr<Instance> child = args[0].get<Data::InstanceRef>();
std::weak_ptr<Instance> newParent = args[1].get<Data::InstanceRef>();
scriptDeletionHandler = script->AncestryChanged->Connect([this, script](std::vector<Variant> args) {
std::weak_ptr<Instance> child = args[0].get<InstanceRef>();
std::weak_ptr<Instance> newParent = args[1].get<InstanceRef>();
if (child.expired() || child.lock() != script || !newParent.expired()) return;
dynamic_cast<MainWindow*>(window())->closeScriptDocument(script);