feat: instance and property serialization
This commit is contained in:
parent
3c2eae2028
commit
37aafe48f4
19 changed files with 161 additions and 31 deletions
|
@ -23,14 +23,15 @@ find_package(GLUT REQUIRED)
|
||||||
include_directories(${GLUT_INCLUDE_DIRS})
|
include_directories(${GLUT_INCLUDE_DIRS})
|
||||||
|
|
||||||
find_package(glfw3 REQUIRED)
|
find_package(glfw3 REQUIRED)
|
||||||
|
|
||||||
find_package(OpenGL)
|
find_package(OpenGL)
|
||||||
|
|
||||||
find_package(glm CONFIG REQUIRED)
|
find_package(glm CONFIG REQUIRED)
|
||||||
|
|
||||||
find_package(assimp REQUIRED)
|
find_package(assimp REQUIRED)
|
||||||
|
|
||||||
find_package(ReactPhysics3D REQUIRED)
|
find_package(ReactPhysics3D REQUIRED)
|
||||||
|
find_package(pugixml REQUIRED)
|
||||||
|
|
||||||
|
# PkgConfig packages
|
||||||
|
# find_package(PkgConfig REQUIRED)
|
||||||
|
# pkg_check_modules(PUGIXML REQUIRED pugixml)
|
||||||
|
|
||||||
file(MAKE_DIRECTORY bin)
|
file(MAKE_DIRECTORY bin)
|
||||||
|
|
||||||
|
@ -39,7 +40,7 @@ include_directories("include")
|
||||||
file(GLOB_RECURSE SOURCES "src/*.cpp" "src/*.h")
|
file(GLOB_RECURSE SOURCES "src/*.cpp" "src/*.h")
|
||||||
add_library(openblocks ${SOURCES})
|
add_library(openblocks ${SOURCES})
|
||||||
set_target_properties(openblocks PROPERTIES OUTPUT_NAME "openblocks")
|
set_target_properties(openblocks PROPERTIES OUTPUT_NAME "openblocks")
|
||||||
target_link_libraries(openblocks ${SDL2_LIBRARIES} ${GLEW_LIBRARIES} ${GLUT_LIBRARIES} OpenGL::GL OpenGL::GLU glfw glm::glm assimp ReactPhysics3D::ReactPhysics3D)
|
target_link_libraries(openblocks ${SDL2_LIBRARIES} ${GLEW_LIBRARIES} ${GLUT_LIBRARIES} ${PUGIXML_LIBRARIES} OpenGL::GL OpenGL::GLU glfw glm::glm assimp ReactPhysics3D::ReactPhysics3D pugixml::pugixml)
|
||||||
|
|
||||||
# add_executable(client "client/src/main.cpp" $<TARGET_OBJECTS:openblocks>)
|
# add_executable(client "client/src/main.cpp" $<TARGET_OBJECTS:openblocks>)
|
||||||
# include_directories("src")
|
# include_directories("src")
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
|
|
||||||
add_executable(client "src/main.cpp" $<TARGET_OBJECTS:openblocks>)
|
add_executable(client "src/main.cpp" $<TARGET_OBJECTS:openblocks>)
|
||||||
include_directories("../src")
|
include_directories("../src")
|
||||||
target_link_libraries(client ${SDL2_LIBRARIES} ${GLEW_LIBRARIES} ${GLUT_LIBRARIES} OpenGL::GL OpenGL::GLU glfw glm::glm assimp ReactPhysics3D::ReactPhysics3D)
|
target_link_libraries(client ${SDL2_LIBRARIES} ${GLEW_LIBRARIES} ${GLUT_LIBRARIES} OpenGL::GL OpenGL::GLU glfw glm::glm assimp ReactPhysics3D::ReactPhysics3D pugixml::pugixml)
|
10
deps.txt
Normal file
10
deps.txt
Normal file
|
@ -0,0 +1,10 @@
|
||||||
|
glm
|
||||||
|
opengl
|
||||||
|
assimp
|
||||||
|
sdl2
|
||||||
|
glfw
|
||||||
|
glut
|
||||||
|
glew
|
||||||
|
qt6
|
||||||
|
reactphysics3d
|
||||||
|
pugixml
|
|
@ -66,7 +66,7 @@ else()
|
||||||
qt5_create_translation(QM_FILES ${CMAKE_SOURCE_DIR} ${TS_FILES})
|
qt5_create_translation(QM_FILES ${CMAKE_SOURCE_DIR} ${TS_FILES})
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
target_link_libraries(editor PRIVATE Qt${QT_VERSION_MAJOR}::Widgets ${SDL2_LIBRARIES} ${GLEW_LIBRARIES} ${GLUT_LIBRARIES} OpenGL::GL OpenGL::GLU glfw glm::glm assimp ReactPhysics3D::ReactPhysics3D)
|
target_link_libraries(editor PRIVATE Qt${QT_VERSION_MAJOR}::Widgets ${SDL2_LIBRARIES} ${GLEW_LIBRARIES} ${GLUT_LIBRARIES} OpenGL::GL OpenGL::GLU glfw glm::glm assimp ReactPhysics3D::ReactPhysics3D pugixml::pugixml)
|
||||||
|
|
||||||
# Qt for iOS sets MACOSX_BUNDLE_GUI_IDENTIFIER automatically since Qt 6.1.
|
# Qt for iOS sets MACOSX_BUNDLE_GUI_IDENTIFIER automatically since Qt 6.1.
|
||||||
# If you are developing for iOS or macOS you should consider setting an
|
# If you are developing for iOS or macOS you should consider setting an
|
||||||
|
|
|
@ -11,7 +11,6 @@
|
||||||
#include <reactphysics3d/collision/RaycastInfo.h>
|
#include <reactphysics3d/collision/RaycastInfo.h>
|
||||||
#include <vector>
|
#include <vector>
|
||||||
|
|
||||||
#include "GLFW/glfw3.h"
|
|
||||||
#include "physics/util.h"
|
#include "physics/util.h"
|
||||||
#include "qcursor.h"
|
#include "qcursor.h"
|
||||||
#include "qevent.h"
|
#include "qevent.h"
|
||||||
|
|
|
@ -14,6 +14,8 @@
|
||||||
|
|
||||||
#include "common.h"
|
#include "common.h"
|
||||||
#include "editorcommon.h"
|
#include "editorcommon.h"
|
||||||
|
#include "objects/base/instance.h"
|
||||||
|
#include "objects/datamodel.h"
|
||||||
#include "physics/simulation.h"
|
#include "physics/simulation.h"
|
||||||
#include "objects/part.h"
|
#include "objects/part.h"
|
||||||
#include "qitemselectionmodel.h"
|
#include "qitemselectionmodel.h"
|
||||||
|
@ -61,6 +63,14 @@ MainWindow::MainWindow(QWidget *parent)
|
||||||
ui->actionToggleSimulation->setIcon(QIcon::fromTheme("media-playback-start"));
|
ui->actionToggleSimulation->setIcon(QIcon::fromTheme("media-playback-start"));
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
connect(ui->actionSave, &QAction::triggered, this, [&]() {
|
||||||
|
pugi::xml_document doc;
|
||||||
|
pugi::xml_node node = doc.append_child("openblocks");
|
||||||
|
workspace()->Serialize(&node);
|
||||||
|
|
||||||
|
doc.print(std::cout);
|
||||||
|
});
|
||||||
|
|
||||||
// ui->explorerView->Init(ui);
|
// ui->explorerView->Init(ui);
|
||||||
|
|
||||||
|
|
|
@ -1,12 +1,20 @@
|
||||||
#include "propertiesmodel.h"
|
#include "propertiesmodel.h"
|
||||||
#include "datatypes/base.h"
|
#include "datatypes/base.h"
|
||||||
|
#include "datatypes/cframe.h"
|
||||||
#include "objects/base/member.h"
|
#include "objects/base/member.h"
|
||||||
#include "qnamespace.h"
|
#include "qnamespace.h"
|
||||||
|
|
||||||
PropertiesModel::PropertiesModel(InstanceRef selectedItem, QWidget *parent)
|
PropertiesModel::PropertiesModel(InstanceRef selectedItem, QWidget *parent)
|
||||||
: QAbstractItemModel(parent)
|
: QAbstractItemModel(parent)
|
||||||
, selectedItem(selectedItem) {
|
, selectedItem(selectedItem) {
|
||||||
this->propertiesList = selectedItem->GetProperties();
|
this->propertiesList.reserve(selectedItem->GetProperties().size());
|
||||||
|
for (std::string name : selectedItem->GetProperties()) {
|
||||||
|
PropertyMeta meta = selectedItem->GetPropertyMeta(name).value();
|
||||||
|
// Don't show CFrames in properties
|
||||||
|
if (meta.type == &Data::CFrame::TYPE) continue;
|
||||||
|
|
||||||
|
this->propertiesList.push_back(name);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
PropertiesModel::~PropertiesModel() = default;
|
PropertiesModel::~PropertiesModel() = default;
|
||||||
|
@ -102,7 +110,7 @@ QModelIndex PropertiesModel::parent(const QModelIndex &index) const {
|
||||||
}
|
}
|
||||||
|
|
||||||
int PropertiesModel::rowCount(const QModelIndex &parent) const {
|
int PropertiesModel::rowCount(const QModelIndex &parent) const {
|
||||||
return !parent.isValid() ? selectedItem->GetProperties().size() : 0;
|
return !parent.isValid() ? this->propertiesList.size() : 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
int PropertiesModel::columnCount(const QModelIndex &parent) const {
|
int PropertiesModel::columnCount(const QModelIndex &parent) const {
|
||||||
|
|
|
@ -2,9 +2,10 @@
|
||||||
|
|
||||||
#define IMPL_WRAPPER_CLASS(CLASS_NAME, WRAPPED_TYPE, TYPE_NAME) Data::CLASS_NAME::CLASS_NAME(WRAPPED_TYPE in) : value(in) {} \
|
#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::~CLASS_NAME() = default; \
|
||||||
Data::CLASS_NAME::operator WRAPPED_TYPE() { return value; } \
|
Data::CLASS_NAME::operator const WRAPPED_TYPE() const { return value; } \
|
||||||
const Data::TypeInfo Data::CLASS_NAME::TYPE = { .name = TYPE_NAME, }; \
|
const Data::TypeInfo Data::CLASS_NAME::TYPE = { .name = TYPE_NAME, }; \
|
||||||
const Data::TypeInfo& Data::CLASS_NAME::GetType() const { return Data::CLASS_NAME::TYPE; };
|
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::Base::~Base() {};
|
||||||
|
|
||||||
|
@ -24,6 +25,10 @@ const Data::String Data::Null::ToString() const {
|
||||||
return Data::String("null");
|
return Data::String("null");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void Data::Null::Serialize(pugi::xml_node* node) const {
|
||||||
|
node->text().set("null");
|
||||||
|
}
|
||||||
|
|
||||||
const Data::String Data::Bool::ToString() const {
|
const Data::String Data::Bool::ToString() const {
|
||||||
return Data::String(value ? "true" : "false");
|
return Data::String(value ? "true" : "false");
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,5 +1,6 @@
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
|
#include <pugixml.hpp>
|
||||||
#include <string>
|
#include <string>
|
||||||
|
|
||||||
|
|
||||||
|
@ -8,11 +9,12 @@
|
||||||
public: \
|
public: \
|
||||||
CLASS_NAME(WRAPPED_TYPE); \
|
CLASS_NAME(WRAPPED_TYPE); \
|
||||||
~CLASS_NAME(); \
|
~CLASS_NAME(); \
|
||||||
operator WRAPPED_TYPE(); \
|
operator const WRAPPED_TYPE() const; \
|
||||||
virtual const TypeInfo& GetType() const override; \
|
virtual const TypeInfo& GetType() const override; \
|
||||||
static const TypeInfo TYPE; \
|
static const TypeInfo TYPE; \
|
||||||
\
|
\
|
||||||
virtual const Data::String ToString() const override; \
|
virtual const Data::String ToString() const override; \
|
||||||
|
virtual void Serialize(pugi::xml_node* node) const override; \
|
||||||
};
|
};
|
||||||
|
|
||||||
namespace Data {
|
namespace Data {
|
||||||
|
@ -27,6 +29,7 @@ namespace Data {
|
||||||
virtual ~Base();
|
virtual ~Base();
|
||||||
virtual const TypeInfo& GetType() const = 0;
|
virtual const TypeInfo& GetType() const = 0;
|
||||||
virtual const Data::String ToString() const = 0;
|
virtual const Data::String ToString() const = 0;
|
||||||
|
virtual void Serialize(pugi::xml_node* node) const = 0;
|
||||||
};
|
};
|
||||||
|
|
||||||
class Null : Base {
|
class Null : Base {
|
||||||
|
@ -37,6 +40,7 @@ namespace Data {
|
||||||
static const TypeInfo TYPE;
|
static const TypeInfo TYPE;
|
||||||
|
|
||||||
virtual const Data::String ToString() const override;
|
virtual const Data::String ToString() const override;
|
||||||
|
virtual void Serialize(pugi::xml_node* node) const override;
|
||||||
};
|
};
|
||||||
|
|
||||||
DEF_WRAPPER_CLASS(Bool, bool)
|
DEF_WRAPPER_CLASS(Bool, bool)
|
||||||
|
|
|
@ -40,7 +40,7 @@ Data::CFrame::CFrame(Data::Vector3 position, Data::Vector3 lookAt, Data::Vector3
|
||||||
|
|
||||||
Data::CFrame::~CFrame() = default;
|
Data::CFrame::~CFrame() = default;
|
||||||
const Data::TypeInfo Data::CFrame::TYPE = {
|
const Data::TypeInfo Data::CFrame::TYPE = {
|
||||||
.name = "CFrame",
|
.name = "CoordinateFrame",
|
||||||
};
|
};
|
||||||
|
|
||||||
const Data::TypeInfo& Data::CFrame::GetType() const { return Data::Vector3::TYPE; };
|
const Data::TypeInfo& Data::CFrame::GetType() const { return Data::Vector3::TYPE; };
|
||||||
|
@ -79,4 +79,21 @@ Data::CFrame Data::CFrame::operator +(Data::Vector3 vector) const {
|
||||||
|
|
||||||
Data::CFrame Data::CFrame::operator -(Data::Vector3 vector) const {
|
Data::CFrame Data::CFrame::operator -(Data::Vector3 vector) const {
|
||||||
return *this + -vector;
|
return *this + -vector;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Serialization
|
||||||
|
|
||||||
|
void Data::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()));
|
||||||
|
node->append_child("R00").text().set(std::to_string(this->rotation[0][0]));
|
||||||
|
node->append_child("R01").text().set(std::to_string(this->rotation[1][0]));
|
||||||
|
node->append_child("R02").text().set(std::to_string(this->rotation[2][0]));
|
||||||
|
node->append_child("R10").text().set(std::to_string(this->rotation[0][1]));
|
||||||
|
node->append_child("R11").text().set(std::to_string(this->rotation[1][1]));
|
||||||
|
node->append_child("R12").text().set(std::to_string(this->rotation[2][1]));
|
||||||
|
node->append_child("R20").text().set(std::to_string(this->rotation[0][2]));
|
||||||
|
node->append_child("R21").text().set(std::to_string(this->rotation[1][2]));
|
||||||
|
node->append_child("R22").text().set(std::to_string(this->rotation[2][2]));
|
||||||
|
}
|
||||||
|
|
|
@ -31,6 +31,7 @@ namespace Data {
|
||||||
static const TypeInfo TYPE;
|
static const TypeInfo TYPE;
|
||||||
|
|
||||||
virtual const Data::String ToString() const override;
|
virtual const Data::String ToString() const override;
|
||||||
|
virtual void Serialize(pugi::xml_node* parent) const override;
|
||||||
|
|
||||||
operator glm::mat4() const;
|
operator glm::mat4() const;
|
||||||
operator rp::Transform() const;
|
operator rp::Transform() const;
|
||||||
|
|
|
@ -5,4 +5,10 @@ Data::String Data::Variant::ToString() const {
|
||||||
return std::visit([](auto&& it) {
|
return std::visit([](auto&& it) {
|
||||||
return it.ToString();
|
return it.ToString();
|
||||||
}, this->wrapped);
|
}, this->wrapped);
|
||||||
|
}
|
||||||
|
|
||||||
|
void Data::Variant::Serialize(pugi::xml_node* node) const {
|
||||||
|
std::visit([&](auto&& it) {
|
||||||
|
it.Serialize(node);
|
||||||
|
}, this->wrapped);
|
||||||
}
|
}
|
|
@ -30,5 +30,6 @@ namespace Data {
|
||||||
template <typename T> Variant(T obj) : wrapped(obj) {}
|
template <typename T> Variant(T obj) : wrapped(obj) {}
|
||||||
template <typename T> T get() { return std::get<T>(wrapped); }
|
template <typename T> T get() { return std::get<T>(wrapped); }
|
||||||
Data::String ToString() const;
|
Data::String ToString() const;
|
||||||
|
void Serialize(pugi::xml_node* node) const;
|
||||||
};
|
};
|
||||||
}
|
}
|
|
@ -41,4 +41,12 @@ Data::Vector3 Data::Vector3::Cross(Data::Vector3 other) const {
|
||||||
|
|
||||||
float Data::Vector3::Dot(Data::Vector3 other) const {
|
float Data::Vector3::Dot(Data::Vector3 other) const {
|
||||||
return glm::dot(this->vector, other.vector);
|
return glm::dot(this->vector, other.vector);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Serialization
|
||||||
|
|
||||||
|
void Data::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()));
|
||||||
|
}
|
||||||
|
|
|
@ -24,6 +24,7 @@ namespace Data {
|
||||||
static Data::Vector3 ONE;
|
static Data::Vector3 ONE;
|
||||||
|
|
||||||
virtual const Data::String ToString() const override;
|
virtual const Data::String ToString() const override;
|
||||||
|
virtual void Serialize(pugi::xml_node* node) const override;
|
||||||
|
|
||||||
operator glm::vec3() const;
|
operator glm::vec3() const;
|
||||||
operator rp::Vector3() const;
|
operator rp::Vector3() const;
|
||||||
|
|
|
@ -140,4 +140,27 @@ std::vector<std::string> Instance::GetProperties() {
|
||||||
|
|
||||||
cachedMemberList = memberList;
|
cachedMemberList = memberList;
|
||||||
return memberList;
|
return memberList;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Serialization
|
||||||
|
|
||||||
|
void Instance::Serialize(pugi::xml_node* parent) {
|
||||||
|
pugi::xml_node node = parent->append_child("Item");
|
||||||
|
node.append_attribute("class").set_value(this->GetClass()->className);
|
||||||
|
|
||||||
|
// Add properties
|
||||||
|
pugi::xml_node propertiesNode = node.append_child("Properties");
|
||||||
|
for (std::string name : GetProperties()) {
|
||||||
|
PropertyMeta meta = GetPropertyMeta(name).value();
|
||||||
|
if (meta.flags & PropertyFlags::PROP_NOSAVE) continue; // This property should not be serialized. Skip...
|
||||||
|
|
||||||
|
pugi::xml_node propertyNode = propertiesNode.append_child(meta.type->name);
|
||||||
|
propertyNode.append_attribute("name").set_value(name);
|
||||||
|
GetPropertyValue(name)->Serialize(&propertyNode);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Add children
|
||||||
|
for (InstanceRef child : this->children) {
|
||||||
|
child->Serialize(&node);
|
||||||
|
}
|
||||||
}
|
}
|
|
@ -11,6 +11,7 @@
|
||||||
#include <map>
|
#include <map>
|
||||||
#include <vector>
|
#include <vector>
|
||||||
#include <../include/expected.hpp>
|
#include <../include/expected.hpp>
|
||||||
|
#include <pugixml.hpp>
|
||||||
|
|
||||||
#include "member.h"
|
#include "member.h"
|
||||||
|
|
||||||
|
@ -68,6 +69,9 @@ public:
|
||||||
tl::expected<PropertyMeta, MemberNotFound> GetPropertyMeta(std::string name);
|
tl::expected<PropertyMeta, MemberNotFound> GetPropertyMeta(std::string name);
|
||||||
// Returning a list of property names feels kinda janky. Is this really the way to go?
|
// Returning a list of property names feels kinda janky. Is this really the way to go?
|
||||||
std::vector<std::string> GetProperties();
|
std::vector<std::string> GetProperties();
|
||||||
|
|
||||||
|
// Serialization
|
||||||
|
void Serialize(pugi::xml_node* parent);
|
||||||
};
|
};
|
||||||
|
|
||||||
typedef std::shared_ptr<Instance> InstanceRef;
|
typedef std::shared_ptr<Instance> InstanceRef;
|
||||||
|
|
|
@ -15,21 +15,27 @@ struct FieldCodec {
|
||||||
Data::Variant (*read)(void* source);
|
Data::Variant (*read)(void* source);
|
||||||
};
|
};
|
||||||
|
|
||||||
template <typename T, typename U>
|
|
||||||
void _writeCodec(Data::Variant source, void* destination) {
|
|
||||||
*(U*)destination = (U)source.get<T>();
|
|
||||||
}
|
|
||||||
|
|
||||||
template <typename T, typename U>
|
|
||||||
Data::Variant _readCodec(void* source) {
|
|
||||||
return T(*(U*)source);
|
|
||||||
}
|
|
||||||
|
|
||||||
template <typename T, typename U>
|
template <typename T, typename U>
|
||||||
constexpr FieldCodec fieldCodecOf() {
|
constexpr FieldCodec fieldCodecOf() {
|
||||||
return FieldCodec {
|
return FieldCodec {
|
||||||
.write = &_writeCodec<T, U>,
|
.write = [](Data::Variant source, void* destination) {
|
||||||
.read = &_readCodec<T, U>,
|
*(U*)destination = (U)source.get<T>();
|
||||||
|
},
|
||||||
|
.read = [](void* source) -> Data::Variant {
|
||||||
|
return T(*(U*)source);
|
||||||
|
},
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename T>
|
||||||
|
constexpr FieldCodec fieldCodecOf() {
|
||||||
|
return FieldCodec {
|
||||||
|
.write = [](Data::Variant source, void* destination) {
|
||||||
|
*(T*)destination = source.get<T>();
|
||||||
|
},
|
||||||
|
.read = [](void* source) -> Data::Variant {
|
||||||
|
return *(T*)source;
|
||||||
|
},
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -38,11 +44,17 @@ std::function<void(std::string name)> memberFunctionOf(void(T::*func)(std::strin
|
||||||
return std::bind(func, obj, std::placeholders::_1);
|
return std::bind(func, obj, std::placeholders::_1);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
enum PropertyFlags {
|
||||||
|
PROP_HIDDEN = 1 << 0, // Hidden from the editor
|
||||||
|
PROP_NOSAVE = 1 << 1, // Do not serialize
|
||||||
|
};
|
||||||
|
|
||||||
struct PropertyMeta {
|
struct PropertyMeta {
|
||||||
void* backingField;
|
void* backingField;
|
||||||
const Data::TypeInfo* type;
|
const Data::TypeInfo* type;
|
||||||
FieldCodec codec;
|
FieldCodec codec;
|
||||||
std::optional<std::function<void(std::string name)>> updateCallback;
|
std::optional<std::function<void(std::string name)>> updateCallback;
|
||||||
|
PropertyFlags flags;
|
||||||
};
|
};
|
||||||
|
|
||||||
typedef std::variant<PropertyMeta> MemberMeta;
|
typedef std::variant<PropertyMeta> MemberMeta;
|
||||||
|
|
|
@ -63,9 +63,29 @@ Part::Part(PartConstructParams params): Instance(&TYPE), cframe(Data::CFrame(par
|
||||||
this->memberMap = std::make_unique<MemberMap>(MemberMap {
|
this->memberMap = std::make_unique<MemberMap>(MemberMap {
|
||||||
.super = std::move(this->memberMap),
|
.super = std::move(this->memberMap),
|
||||||
.members = {
|
.members = {
|
||||||
{ "Anchored", { .backingField = &anchored, .type = &Data::Bool::TYPE, .codec = fieldCodecOf<Data::Bool, bool>(), .updateCallback = memberFunctionOf(&Part::onUpdated, this) } },
|
{ "Anchored", {
|
||||||
{ "Position", { .backingField = &cframe, .type = &Data::Vector3::TYPE, .codec = cframePositionCodec(), .updateCallback = memberFunctionOf(&Part::onUpdated, this) } },
|
.backingField = &anchored,
|
||||||
{ "Rotation", { .backingField = &cframe, .type = &Data::Vector3::TYPE, .codec = cframeRotationCodec(), .updateCallback = memberFunctionOf(&Part::onUpdated, this) } }
|
.type = &Data::Bool::TYPE,
|
||||||
|
.codec = fieldCodecOf<Data::Bool, bool>(),
|
||||||
|
.updateCallback = memberFunctionOf(&Part::onUpdated, this)
|
||||||
|
} }, { "Position", {
|
||||||
|
.backingField = &cframe,
|
||||||
|
.type = &Data::Vector3::TYPE,
|
||||||
|
.codec = cframePositionCodec(),
|
||||||
|
.updateCallback = memberFunctionOf(&Part::onUpdated, this),
|
||||||
|
.flags = PropertyFlags::PROP_NOSAVE
|
||||||
|
} }, { "Rotation", {
|
||||||
|
.backingField = &cframe,
|
||||||
|
.type = &Data::Vector3::TYPE,
|
||||||
|
.codec = cframeRotationCodec(),
|
||||||
|
.updateCallback = memberFunctionOf(&Part::onUpdated, this),
|
||||||
|
.flags = PropertyFlags::PROP_NOSAVE
|
||||||
|
} }, { "CFrame", {
|
||||||
|
.backingField = &cframe,
|
||||||
|
.type = &Data::CFrame::TYPE,
|
||||||
|
.codec = fieldCodecOf<Data::CFrame>(),
|
||||||
|
.updateCallback = memberFunctionOf(&Part::onUpdated, this),
|
||||||
|
} }
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
Loading…
Add table
Reference in a new issue