feat(autogen): convert classes to new autogen annotations

This commit is contained in:
maelstrom 2025-04-26 13:19:47 +02:00
parent b8ee828d29
commit a2e2210998
31 changed files with 148 additions and 343 deletions

View file

@ -24,7 +24,8 @@ std::map<std::string, std::string> parseAnnotationString(std::string src) {
int i = 0;
for (; i < src.length(); i++) {
if (src[i] == ' ' && (stage != 2 || !quoted)) continue; // Ignore spaces if not in stage 2 and quoted
if (src[i] == ' ' && (stage != 2 || !quoted)) continue; // Ignore spaces if not in stage 2 and quoted
if (src[i] == ',' && stage == 0) continue; // Let empty commas slip by
if (stage < 2 && (src[i] >= 'a' && src[i] <= 'z' || src[i] >= 'A' && src[i] <= 'Z' || src[i] >= '0' && src[i] <= '9' || src[i] == '_')) {
currentIdent += src[i];
stage = 1;
@ -228,6 +229,8 @@ void processClass(CXCursor cur, AnalysisState* state, std::string className, std
if (result.count("hidden"))
anly.flags = anly.flags | ClassFlag_Hidden;
anly.abstract = result.count("abstract") > 0;
anly.explorerIcon = result["explorer_icon"];
// Find annotated fields

View file

@ -46,6 +46,7 @@ struct ClassAnalysis {
std::string name;
std::string baseClass;
std::string headerPath;
bool abstract = false;
std::vector<PropertyAnalysis> properties;
ClassFlags flags = (ClassFlags)0;
std::string explorerIcon;

View file

@ -18,6 +18,7 @@ std::map<std::string, std::string> MAPPED_TYPE = {
{ "float", "Data::Float" },
{ "std::string", "Data::String" },
{ "std::weak_ptr<Instance>", "Data::InstanceRef" },
{ "std::weak_ptr<Part>", "Data::InstanceRef" },
{ "glm::vec3", "Vector3" },
};
@ -57,7 +58,7 @@ void writePropertySetHandler(std::ofstream& out, ClassAnalysis state) {
out << (first ? "" : " else ") << "if (name == \"" << prop.name << "\") {";
if (prop.flags & PropertyFlag_Readonly) {
out << "\n return AssignToReadOnlyMember(\"" << state.name << "\", name)";
out << "\n return AssignToReadOnlyMember(GetClass()->className, name)";
} else if (prop.cframeMember == CFrameMember_Position) {
out << "\n this->" << prop.fieldName << " = this->" << prop.fieldName << ".Rotation() + value.get<Vector3>();";
} else if (prop.cframeMember == CFrameMember_Rotation) {
@ -72,7 +73,8 @@ void writePropertySetHandler(std::ofstream& out, ClassAnalysis state) {
first = false;
}
out << "\n return MemberNotFound(\"" << state.name << "\", name);";
out << "\n return " << state.baseClass << "::InternalSetPropertyValue(name, value);";
// out << "\n return MemberNotFound(\"" << state.name << "\", name);";
out << "\n};\n\n";
}
@ -97,11 +99,23 @@ void writePropertyGetHandler(std::ofstream& out, ClassAnalysis state) {
first = false;
}
out << "\n return MemberNotFound(\"" << state.name << "\", name);";
out << "\n return " << state.baseClass << "::InternalGetPropertyValue(name);";
// out << "\n return MemberNotFound(\"" << state.name << "\", name);";
out << "\n};\n\n";
}
void writePropertiesList(std::ofstream& out, ClassAnalysis state) {
out << "std::vector<string> " << state.name << "::InternalGetProperties() {\n";
out << " std::vector<string> properties = " << state.baseClass << "::InternalGetProperties();\n";
for (auto& prop : state.properties) {
out << " properties.push_back(\"" << prop.name << "\")l\n";
}
out << "};\n\n";
}
void writePropertyMetaHandler(std::ofstream& out, ClassAnalysis state) {
out << "result<PropertyMeta, MemberNotFound> " << state.name << "::InternalGetPropertyMeta(std::string name) {";
@ -135,7 +149,8 @@ void writePropertyMetaHandler(std::ofstream& out, ClassAnalysis state) {
first = false;
}
out << "\n return MemberNotFound(\"" << state.name << "\", name);";
out << "\n return " << state.baseClass << "::InternalGetPropertyMeta(name);";
// out << "\n return MemberNotFound(\"" << state.name << "\", name);";
out << "\n};\n\n";
}
@ -143,7 +158,7 @@ void writePropertyMetaHandler(std::ofstream& out, ClassAnalysis state) {
void writeCodeForClass(std::ofstream& out, ClassAnalysis& state) {
std::string strFlags;
if (state.flags & ClassFlag_NotCreatable)
strFlags += " | INSTANCE_NOT_CREATABLE";
strFlags += " | INSTANCE_NOTCREATABLE";
if (state.flags & ClassFlag_Service)
strFlags += " | INSTANCE_SERVICE";
if (state.flags & ClassFlag_Hidden)
@ -155,11 +170,15 @@ void writeCodeForClass(std::ofstream& out, ClassAnalysis& state) {
out << "// This file was automatically generated by autogen, and should not be edited manually //\n";
out << "/////////////////////////////////////////////////////////////////////////////////////////\n\n";
std::string constructorStr;
if (state.abstract) constructorStr = "nullptr";
else constructorStr = "&" + state.name + "::Create";
out << "#include \"" << state.headerPath << "\"\n\n";
out << "const InstanceType " << state.name << "::TYPE = {\n"
<< " .super = &" << state.baseClass << "::TYPE,\n"
<< " .className = \"" << state.name << "\",\n"
<< " .constructor = &" << state.name << "::CreateGeneric,\n"
<< " .constructor = " << constructorStr << ",\n"
<< " .explorerIcon = \"" << state.explorerIcon << "\",\n"
<< " .flags = " << strFlags << ",\n"
<< "};\n\n";
@ -168,6 +187,9 @@ void writeCodeForClass(std::ofstream& out, ClassAnalysis& state) {
<< " return &TYPE;\n"
<< "};\n\n";
// Special case for our Service class
if (state.baseClass == "Service") state.baseClass = "Instance";
writePropertySetHandler(out, state);
writePropertyGetHandler(out, state);
writePropertyMetaHandler(out, state);

View file

@ -71,6 +71,7 @@ int main(int argc, char** argv) {
}
printf("[AUTOGEN] Generating cpp files...\n");
fs::create_directories(argv[3]); // Make sure generated dir exists before we try writing to it
for (auto& [_, clazz] : state.classes) {
fs::path outPath = fs::path(argv[3]) / ("class_" + clazz.name + ".cpp");
std::ofstream outStream(outPath);
@ -79,6 +80,20 @@ int main(int argc, char** argv) {
outStream.close();
}
// // Write __all__.cpp file
// fs::path outPath = fs::path(argv[3]) / "__all__.cpp";
// std::ofstream outStream(outPath);
// // TODO: replace these with just direct filenames that can be converted by
// // CMake itself
// for (auto& [_, clazz] : state.classes) {
// std::string includeName = "class_" + clazz.name + ".cpp";
// outStream << "#include \"" << includeName << "\"\n";
// }
// outStream.close();
flushCaches(argv[3]);
}

View file

@ -20,7 +20,7 @@ add_custom_target(build_autogen ALL
COMMAND "${CMAKE_BINARY_DIR}/autogen/autogen" "${CMAKE_CURRENT_SOURCE_DIR}/src" "${CMAKE_CURRENT_SOURCE_DIR}/src/objects" "${CMAKE_BINARY_DIR}/generated"
)
file(GLOB_RECURSE SOURCES "src/*.cpp" "src/*.h" "${CMAKE_BINARY_DIR}/generated/*.cpp")
file(GLOB_RECURSE SOURCES "src/*.cpp" "src/*.h" "${CMAKE_BINARY_DIR}/generated/__all__.cpp")
add_library(openblocks STATIC ${SOURCES})
set_target_properties(openblocks PROPERTIES OUTPUT_NAME "openblocks")
target_link_libraries(openblocks ${GLEW_LIBRARIES} ${LUAJIT_LIBRARIES} OpenGL::GL ReactPhysics3D::ReactPhysics3D pugixml::pugixml)

View file

@ -4,6 +4,9 @@
#ifdef __AUTOGEN__
#define def_inst(...) clang::annotate("OB::def_inst", #__VA_ARGS__)
#define INSTANCE [[ def_inst() ]]
#define INSTANCE_WITH(...) [[ def_inst(__VA_ARGS__) ]]
#define INSTANCE_SERVICE(...) [[ def_inst(__VA_ARGS__, service) ]]
#define def_prop(...) clang::annotate("OB::def_prop", #__VA_ARGS__)
@ -11,14 +14,18 @@
#define cframe_rotation_prop(...) clang::annotate("OB::cframe_rotation_prop", #__VA_ARGS__)
#else
#define def_inst(...)
#define INSTANCE
#define INSTANCE_WITH(...)
#define INSTANCE_SERVICE(...)
#define def_prop(...)
#define cframe_position_prop(...)
#define cframe_rotation_prop(...)
#endif
#define AUTOGEN_PREAMBLE \
private: \
protected: \
result<PropertyMeta, MemberNotFound> InternalGetPropertyMeta(std::string name) override; \
fallible<MemberNotFound, AssignToReadOnlyMember> InternalSetPropertyValue(std::string name, Data::Variant value) override; \
result<Data::Variant, MemberNotFound> InternalGetPropertyValue(std::string name) override; \
std::vector<std::string> InternalGetProperties() override; \
private:

View file

@ -43,15 +43,6 @@ constexpr FieldCodec classNameCodec() {
Instance::Instance(const InstanceType* type) {
this->name = type->className;
this->memberMap = std::make_unique<MemberMap>( MemberMap {
.super = std::nullopt,
.members = {
{ "Name", { .backingField = &name, .type = &Data::String::TYPE, .codec = fieldCodecOf<Data::String, std::string>() } },
{ "Parent", { .backingField = &parent, .type = &Data::InstanceRef::TYPE, .codec = fieldCodecOf<Data::InstanceRef, std::weak_ptr<Instance>>() } },
{ "ClassName", { .backingField = const_cast<InstanceType*>(type), .type = &Data::String::TYPE, .codec = classNameCodec(), .flags = (PropertyFlags)(PROP_READONLY | PROP_NOSAVE) } },
}
});
}
Instance::~Instance () {
@ -195,83 +186,66 @@ void Instance::OnWorkspaceRemoved(std::shared_ptr<Workspace> oldWorkspace) {
// Properties
result<Data::Variant, MemberNotFound> Instance::GetPropertyValue(std::string name) {
auto meta_ = GetPropertyMeta(name);
if (!meta_) return MemberNotFound(GetClass()->className, name);
auto meta = meta_.expect();
return meta.codec.read(meta.backingField);
return InternalGetPropertyValue(name);
}
fallible<MemberNotFound, AssignToReadOnlyMember> Instance::SetPropertyValue(std::string name, Data::Variant value) {
// Handle special case: Parent
if (name == "Parent") {
Data::InstanceRef ref = value.get<Data::InstanceRef>();
std::weak_ptr<Instance> inst = ref;
SetParent(inst.expired() ? std::nullopt : std::make_optional(inst.lock()));
return {};
}
if (InternalSetPropertyValue(name, value).isSuccess())
return {};
auto meta_ = GetPropertyMeta(name);
if (!meta_) return MemberNotFound(GetClass()->className, name);
auto meta = meta_.expect();
if (meta.flags & PROP_READONLY) AssignToReadOnlyMember(GetClass()->className, name);
meta.codec.write(value, meta.backingField);
if (meta.updateCallback) meta.updateCallback.value()(name);
sendPropertyUpdatedSignal(shared_from_this(), name, value);
return {};
auto result = InternalSetPropertyValue(name, value);
if (result.isSuccess()) sendPropertyUpdatedSignal(shared_from_this(), name, value);
return result;
}
result<PropertyMeta, MemberNotFound> Instance::GetPropertyMeta(std::string name) {
MemberMap* current = &*memberMap;
while (true) {
// We look for the property in current member map
auto it = current->members.find(name);
// It is found, return it
if (it != current->members.end())
return it->second;
// It is not found, If there are no other maps to search, return null
if (!current->super.has_value())
return MemberNotFound(GetClass()->className, name);
// Search in the parent
current = current->super->get();
}
return InternalGetPropertyMeta(name);
}
result<Data::Variant, MemberNotFound> Instance::InternalGetPropertyValue(std::string name) { return MemberNotFound(GetClass()->className, name); }
fallible<MemberNotFound, AssignToReadOnlyMember> Instance::InternalSetPropertyValue(std::string name, Data::Variant value) { return MemberNotFound(GetClass()->className, name); }
result<Data::Variant, MemberNotFound> Instance::InternalGetPropertyValue(std::string name) {
if (name == "Name") {
return Data::Variant(Data::String(this->name));
} else if (name == "Parent") {
return Data::Variant(Data::InstanceRef(this->parent));
} else if (name == "ClassName") {
return Data::Variant(Data::String(GetClass()->className));
}
return MemberNotFound(GetClass()->className, name);
}
fallible<MemberNotFound, AssignToReadOnlyMember> Instance::InternalSetPropertyValue(std::string name, Data::Variant value) {
if (name == "Name") {
this->name = (std::string)value.get<Data::String>();
} else if (name == "Parent") {
std::weak_ptr<Instance> ref = value.get<Data::InstanceRef>();
SetParent(ref.expired() ? std::nullopt : std::make_optional(ref.lock()));
} else if (name == "ClassName") {
return AssignToReadOnlyMember(GetClass()->className, name);
}
return MemberNotFound(GetClass()->className, name);
}
std::vector<std::string> Instance::InternalGetProperties() {
std::vector<std::string> members;
members.push_back("Name");
members.push_back("Parent");
members.push_back("ClassName");
return members;
}
result<PropertyMeta, MemberNotFound> Instance::InternalGetPropertyMeta(std::string name) { return MemberNotFound(GetClass()->className, name); }
void Instance::UpdateProperty(std::string name) {
PropertyMeta meta = GetPropertyMeta(name).expect();
if (!meta.updateCallback) return; // Nothing to update, exit.
meta.updateCallback.value()(name);
// TODO: temporary workaround because I'm too lazy to implement this in autogen
InternalSetPropertyValue(name, InternalGetPropertyValue(name).expect()).expect();
// PropertyMeta meta = GetPropertyMeta(name).expect();
// if (!meta.updateCallback) return; // Nothing to update, exit.
// meta.updateCallback.value()(name);
}
std::vector<std::string> Instance::GetProperties() {
if (cachedMemberList.has_value()) return cachedMemberList.value();
std::vector<std::string> memberList;
MemberMap* current = &*memberMap;
do {
for (auto const& [key, _] : current->members) {
// Don't add it if it's already in the list
if (std::find(memberList.begin(), memberList.end(), key) == memberList.end())
memberList.push_back(key);
}
if (!current->super.has_value())
break;
current = &*current->super.value();
} while (true);
std::vector<std::string> memberList = InternalGetProperties();
cachedMemberList = memberList;
return memberList;

View file

@ -65,7 +65,6 @@ private:
friend JointInstance; // This isn't ideal, but oh well
protected:
bool parentLocked = false;
std::unique_ptr<MemberMap> memberMap;
Instance(const InstanceType*);
virtual ~Instance();
@ -73,6 +72,7 @@ protected:
virtual result<Data::Variant, MemberNotFound> InternalGetPropertyValue(std::string name);
virtual fallible<MemberNotFound, AssignToReadOnlyMember> InternalSetPropertyValue(std::string name, Data::Variant value);
virtual result<PropertyMeta, MemberNotFound> InternalGetPropertyMeta(std::string name);
virtual std::vector<std::string> InternalGetProperties();
virtual void OnParentUpdated(std::optional<std::shared_ptr<Instance>> oldParent, std::optional<std::shared_ptr<Instance>> newParent);
virtual void OnAncestryChanged(std::optional<std::shared_ptr<Instance>> child, std::optional<std::shared_ptr<Instance>> newParent);

View file

@ -66,9 +66,4 @@ struct PropertyMeta {
PropertyCategory category = PROP_CATEGORY_DATA;
};
typedef std::variant<PropertyMeta> MemberMeta;
struct MemberMap {
std::optional<std::unique_ptr<MemberMap>> super;
std::map<std::string, PropertyMeta> members;
};
typedef std::variant<PropertyMeta> MemberMeta;

View file

@ -13,16 +13,6 @@
#include <memory>
#include <optional>
const InstanceType DataModel::TYPE = {
.super = &Instance::TYPE,
.className = "DataModel",
.constructor = nullptr,
};
const InstanceType* DataModel::GetClass() {
return &TYPE;
}
DataModel::DataModel()
: Instance(&TYPE) {
this->name = "Place";

View file

@ -2,6 +2,7 @@
#include "error/instance.h"
#include "error/result.h"
#include "objects/annotation.h"
#include "objects/base/instance.h"
#include "objects/base/refstate.h"
#include <memory>
@ -12,7 +13,8 @@ class DataModel;
class Service;
// The root instance to all objects in the hierarchy
class DataModel : public Instance {
class INSTANCE_WITH(abstract) DataModel : public Instance {
AUTOGEN_PREAMBLE
private:
void DeserializeService(pugi::xml_node node);
static void cloneService(std::shared_ptr<DataModel> target, std::shared_ptr<Service>, RefState<_RefStatePropertyCell>);

View file

@ -23,17 +23,6 @@ static CFrame XYZToZXY(glm::vec3(0, 0, 0), -glm::vec3(1, 0, 0), glm::vec3(0, 0,
static rp3d::PhysicsCommon common;
static rp3d::PhysicsWorld* world = common.createPhysicsWorld();
const InstanceType Handles::TYPE = {
.super = &Instance::TYPE,
.className = "Handles",
// .constructor = &Workspace::Create,
// .explorerIcon = "",
};
const InstanceType* Handles::GetClass() {
return &TYPE;
}
Handles::Handles(): Instance(&TYPE) {
}

View file

@ -2,6 +2,7 @@
#include "base.h"
#include "datatypes/cframe.h"
#include "objects/annotation.h"
#include "objects/base/service.h"
#include "objects/part.h"
#include <array>
@ -30,7 +31,8 @@ enum HandlesType {
RotateHandles,
};
class Handles : public Instance {
class INSTANCE_WITH(abstract) Handles : public Instance {
AUTOGEN_PREAMBLE
public:
const static InstanceType TYPE;

View file

@ -11,42 +11,7 @@
#include <reactphysics3d/engine/PhysicsWorld.h>
#include "ptr_helpers.h"
const InstanceType JointInstance::TYPE = {
.super = &Instance::TYPE,
.className = "JointInstance",
};
const InstanceType* JointInstance::GetClass() {
return &TYPE;
}
JointInstance::JointInstance(const InstanceType* type): Instance(type) {
this->memberMap = std::make_unique<MemberMap>(MemberMap {
.super = std::move(this->memberMap),
.members = {
{ "Part0", {
.backingField = &part0,
.type = &Data::InstanceRef::TYPE,
.codec = fieldCodecOf<Data::InstanceRef, std::weak_ptr<Instance>>(),
.updateCallback = memberFunctionOf(&JointInstance::onUpdated, this),
}}, { "Part1", {
.backingField = &part1,
.type = &Data::InstanceRef::TYPE,
.codec = fieldCodecOf<Data::InstanceRef, std::weak_ptr<Instance>>(),
.updateCallback = memberFunctionOf(&JointInstance::onUpdated, this),
}}, { "C0", {
.backingField = &c0,
.type = &CFrame::TYPE,
.codec = fieldCodecOf<CFrame>(),
.updateCallback = memberFunctionOf(&JointInstance::onUpdated, this),
}}, { "C1", {
.backingField = &c1,
.type = &CFrame::TYPE,
.codec = fieldCodecOf<CFrame>(),
.updateCallback = memberFunctionOf(&JointInstance::onUpdated, this),
}},
}
});
}
JointInstance::~JointInstance() {

View file

@ -1,13 +1,16 @@
#pragma once
#include "objects/base/instance.h"
#include "../annotation.h"
#include <memory>
#include <optional>
class Part;
class Workspace;
class JointInstance : public Instance {
class INSTANCE_SERVICE() JointInstance : public Instance {
AUTOGEN_PREAMBLE
std::weak_ptr<Part> oldPart0;
std::weak_ptr<Part> oldPart1;
protected:
@ -23,9 +26,13 @@ protected:
public:
const static InstanceType TYPE;
[[ def_prop(name="Part0", on_update=onUpdated) ]]
std::weak_ptr<Part> part0;
[[ def_prop(name="Part1", on_update=onUpdated) ]]
std::weak_ptr<Part> part1;
[[ def_prop(name="C0", on_update=onUpdated) ]]
CFrame c0;
[[ def_prop(name="C1", on_update=onUpdated) ]]
CFrame c1;
JointInstance(const InstanceType*);

View file

@ -10,16 +10,6 @@
#include <reactphysics3d/constraint/FixedJoint.h>
#include <reactphysics3d/engine/PhysicsWorld.h>
const InstanceType Snap::TYPE = {
.super = &JointInstance::TYPE,
.className = "Snap",
.constructor = &Snap::Create,
};
const InstanceType* Snap::GetClass() {
return &TYPE;
}
Snap::Snap(): JointInstance(&TYPE) {
}

View file

@ -1,10 +1,13 @@
#pragma once
#include "objects/annotation.h"
#include "objects/base/instance.h"
#include "objects/joint/jointinstance.h"
#include <memory>
class Snap : public JointInstance {
class INSTANCE Snap : public JointInstance {
AUTOGEN_PREAMBLE
rp::FixedJoint* joint = nullptr;
virtual void buildJoint() override;

View file

@ -10,16 +10,6 @@
#include <reactphysics3d/constraint/FixedJoint.h>
#include <reactphysics3d/engine/PhysicsWorld.h>
const InstanceType Weld::TYPE = {
.super = &JointInstance::TYPE,
.className = "Weld",
.constructor = &Weld::Create,
};
const InstanceType* Weld::GetClass() {
return &TYPE;
}
Weld::Weld(): JointInstance(&TYPE) {
}

View file

@ -1,10 +1,13 @@
#pragma once
#include "objects/annotation.h"
#include "objects/base/instance.h"
#include "objects/joint/jointinstance.h"
#include <memory>
class Weld : public JointInstance {
class INSTANCE Weld : public JointInstance {
AUTOGEN_PREAMBLE
rp::FixedJoint* joint = nullptr;
virtual void buildJoint() override;

View file

@ -2,18 +2,6 @@
#include "workspace.h"
#include <memory>
const InstanceType JointsService::TYPE = {
.super = &Instance::TYPE,
.className = "JointsService",
.constructor = &JointsService::Create,
.flags = INSTANCE_NOTCREATABLE | INSTANCE_SERVICE | INSTANCE_HIDDEN,
};
const InstanceType* JointsService::GetClass() {
return &TYPE;
}
JointsService::JointsService(): Service(&TYPE) {
}

View file

@ -1,8 +1,10 @@
#pragma once
#include "objects/annotation.h"
#include "objects/base/service.h"
class JointsService : public Service {
class INSTANCE_SERVICE() JointsService : public Service {
AUTOGEN_PREAMBLE
private:
std::optional<std::shared_ptr<Workspace>> jointWorkspace();
protected:

View file

@ -55,102 +55,7 @@ Part::Part(): Part(PartConstructParams { .size = glm::vec3(2, 1.2, 4), .color =
Part::Part(PartConstructParams params): Instance(&TYPE), cframe(CFrame::FromEulerAnglesXYZ((Vector3)params.rotation) + params.position),
size(params.size), color(params.color), anchored(params.anchored), locked(params.locked) {
this->memberMap = std::make_unique<MemberMap>(MemberMap {
.super = std::move(this->memberMap),
.members = {
{ "Anchored", {
.backingField = &anchored,
.type = &Data::Bool::TYPE,
.codec = fieldCodecOf<Data::Bool, bool>(),
.updateCallback = memberFunctionOf(&Part::onUpdated, this),
.category = PROP_CATEGORY_BEHAVIOR,
}}, { "Locked", {
.backingField = &locked,
.type = &Data::Bool::TYPE,
.codec = fieldCodecOf<Data::Bool, bool>(),
.category = PROP_CATEGORY_BEHAVIOR,
}}, { "Position", {
.backingField = &cframe,
.type = &Vector3::TYPE,
.codec = cframePositionCodec(),
.updateCallback = memberFunctionOf(&Part::onUpdated, this),
.flags = PROP_NOSAVE
}}, { "Rotation", {
.backingField = &cframe,
.type = &Vector3::TYPE,
.codec = cframeRotationCodec(),
.updateCallback = memberFunctionOf(&Part::onUpdated, this),
.flags = PROP_NOSAVE
}}, { "Velocity", {
.backingField = &velocity,
.type = &Vector3::TYPE,
.codec = fieldCodecOf<Vector3>(),
.updateCallback = memberFunctionOf(&Part::onUpdated, this),
}}, { "CFrame", {
.backingField = &cframe,
.type = &CFrame::TYPE,
.codec = fieldCodecOf<CFrame>(),
.updateCallback = memberFunctionOf(&Part::onUpdated, this),
}}, { "Size", {
.backingField = &size,
.type = &Vector3::TYPE,
.codec = fieldCodecOf<Vector3, glm::vec3>(),
.updateCallback = memberFunctionOf(&Part::onUpdated, this),
.category = PROP_CATEGORY_PART,
}}, { "Color", {
.backingField = &color,
.type = &Color3::TYPE,
.codec = fieldCodecOf<Color3>(),
.category = PROP_CATEGORY_APPEARENCE,
}}, { "Transparency", {
.backingField = &transparency,
.type = &Data::Float::TYPE,
.codec = fieldCodecOf<Data::Float, float>(),
.flags = PROP_UNIT_FLOAT,
.category = PROP_CATEGORY_APPEARENCE,
}},
// Surfaces
{ "TopSurface", {
.backingField = &topSurface,
.type = &Data::Int::TYPE, // Replace with enum
.codec = fieldCodecOf<Data::Int, int>(),
.flags = PROP_HIDDEN,
.category = PROP_CATEGORY_SURFACE,
}}, { "BottomSurface", {
.backingField = &bottomSurface,
.type = &Data::Int::TYPE, // Replace with enum
.codec = fieldCodecOf<Data::Int, int>(),
.flags = PROP_HIDDEN,
.category = PROP_CATEGORY_SURFACE,
}}, { "FrontSurface", {
.backingField = &frontSurface,
.type = &Data::Int::TYPE, // Replace with enum
.codec = fieldCodecOf<Data::Int, int>(),
.flags = PROP_HIDDEN,
.category = PROP_CATEGORY_SURFACE,
}}, { "BackSurface", {
.backingField = &backSurface,
.type = &Data::Int::TYPE, // Replace with enum
.codec = fieldCodecOf<Data::Int, int>(),
.flags = PROP_HIDDEN,
.category = PROP_CATEGORY_SURFACE,
}}, { "RightSurface", {
.backingField = &rightSurface,
.type = &Data::Int::TYPE, // Replace with enum
.codec = fieldCodecOf<Data::Int, int>(),
.flags = PROP_HIDDEN,
.category = PROP_CATEGORY_SURFACE,
}}, { "LeftSurface", {
.backingField = &leftSurface,
.type = &Data::Int::TYPE, // Replace with enum
.codec = fieldCodecOf<Data::Int, int>(),
.flags = PROP_HIDDEN,
.category = PROP_CATEGORY_SURFACE,
}},
}
});
}
Part::~Part() {

View file

@ -28,7 +28,7 @@ struct PartConstructParams {
class Snap;
class [[ def_inst(explorer_icon="part") ]] Part : public Instance {
class INSTANCE_WITH(explorer_icon="part") Part : public Instance {
AUTOGEN_PREAMBLE
protected:
// Joints where this part is Part0
@ -51,10 +51,11 @@ protected:
public:
const static InstanceType TYPE;
[[ def_prop(name="Velocity", on_update=onUpdated) ]]
Vector3 velocity;
[[ def_prop(name="CFrame"), cframe_position_prop(name="Position"), cframe_rotation_prop(name="Rotation") ]]
[[ def_prop(name="CFrame", on_update=onUpdated), cframe_position_prop(name="Position"), cframe_rotation_prop(name="Rotation") ]]
CFrame cframe;
[[ def_prop(name="Size", category=PART) ]]
[[ def_prop(name="Size", category=PART, on_update=onUpdated) ]]
glm::vec3 size;
[[ def_prop(name="Color", category=APPEARANCE) ]]
Color3 color;
@ -62,7 +63,7 @@ public:
float transparency = 0.f;
bool selected = false;
[[ def_prop(name="Anchored", category=BEHAVIOR) ]]
[[ def_prop(name="Anchored", category=BEHAVIOR, on_update=onUpdated) ]]
bool anchored = false;
[[ def_prop(name="Locked", category=BEHAVIOR) ]]
bool locked = false;
@ -87,7 +88,7 @@ public:
static inline std::shared_ptr<Part> New() { return std::make_shared<Part>(); };
static inline std::shared_ptr<Part> New(PartConstructParams params) { return std::make_shared<Part>(params); };
static inline InstanceRef CreateGeneric() { return std::make_shared<Part>(); };
static inline InstanceRef Create() { return std::make_shared<Part>(); };
virtual const InstanceType* GetClass() override;
inline Vector3 position() { return cframe.Position(); }

View file

@ -6,30 +6,7 @@
#include "objects/workspace.h"
#include "lua.h"
const InstanceType Script::TYPE = {
.super = &Instance::TYPE,
.className = "Script",
.constructor = &Script::Create,
.explorerIcon = "script",
};
const InstanceType* Script::GetClass() {
return &TYPE;
}
Script::Script(): Instance(&TYPE) {
this->memberMap = std::make_unique<MemberMap>(MemberMap {
.super = std::move(this->memberMap),
.members = {
{ "Source", {
.backingField = &source,
.type = &Data::String::TYPE,
.codec = fieldCodecOf<Data::String, std::string>(),
.flags = PROP_HIDDEN,
}},
}
});
source = "print \"Hello, world!\"";
}

View file

@ -1,15 +1,18 @@
#pragma once
#include "objects/annotation.h"
#include "objects/base/instance.h"
#include <memory>
class Script : public Instance {
class INSTANCE_WITH(explorer_icon="script") Script : public Instance {
AUTOGEN_PREAMBLE
public:
const static InstanceType TYPE;
Script();
~Script();
[[ def_prop(name="Source", hidden) ]]
std::string source;
void Run();
void Stop();

View file

@ -16,17 +16,6 @@ std::string unsafe_globals[] = {
"loadfile", "loadstring", "load", "dofile", "getfenv", "setfenv"
};
const InstanceType ScriptContext::TYPE = {
.super = &Instance::TYPE,
.className = "ScriptContext",
.constructor = &ScriptContext::Create,
.flags = INSTANCE_NOTCREATABLE | INSTANCE_SERVICE | INSTANCE_HIDDEN,
};
const InstanceType* ScriptContext::GetClass() {
return &TYPE;
}
ScriptContext::ScriptContext(): Service(&TYPE) {
}

View file

@ -1,10 +1,11 @@
#pragma once
#include "objects/annotation.h"
#include "objects/base/service.h"
#include "lua.h"
class ScriptContext : public Service {
private:
class INSTANCE_SERVICE() ScriptContext : public Service {
AUTOGEN_PREAMBLE
protected:
void InitService() override;
bool initialized = false;

View file

@ -2,17 +2,6 @@
#include "objects/script.h"
#include "objects/workspace.h"
const InstanceType ServerScriptService::TYPE = {
.super = &Instance::TYPE,
.className = "ServerScriptService",
.constructor = &ServerScriptService::Create,
.flags = INSTANCE_NOTCREATABLE | INSTANCE_SERVICE,
};
const InstanceType* ServerScriptService::GetClass() {
return &TYPE;
}
ServerScriptService::ServerScriptService(): Service(&TYPE) {
}

View file

@ -1,11 +1,12 @@
#pragma once
#include "objects/annotation.h"
#include "objects/base/service.h"
// Container class for server scripts
// Also handles/manages running server scripts on run
class ServerScriptService : public Service {
private:
class INSTANCE_SERVICE() ServerScriptService : public Service {
AUTOGEN_PREAMBLE
protected:
void InitService() override;
void OnRun() override;

View file

@ -5,18 +5,6 @@
#include "physics/util.h"
#include <reactphysics3d/engine/PhysicsCommon.h>
const InstanceType Workspace::TYPE = {
.super = &Instance::TYPE,
.className = "Workspace",
.constructor = &Workspace::Create,
.explorerIcon = "workspace",
.flags = INSTANCE_NOTCREATABLE | INSTANCE_SERVICE,
};
const InstanceType* Workspace::GetClass() {
return &TYPE;
}
rp::PhysicsCommon* Workspace::physicsCommon = new rp::PhysicsCommon;
Workspace::Workspace(): Service(&TYPE) {

View file

@ -1,5 +1,6 @@
#pragma once
#include "objects/annotation.h"
#include "objects/base/service.h"
#include <memory>
#include <reactphysics3d/body/RigidBody.h>
@ -29,7 +30,9 @@ class Weld;
typedef std::function<FilterResult(std::shared_ptr<Part>)> RaycastFilter;
class Workspace : public Service {
class INSTANCE_SERVICE(explorer_icon="workspace") Workspace : public Service {
AUTOGEN_PREAMBLE
rp::PhysicsWorld* physicsWorld = nullptr;
static rp::PhysicsCommon* physicsCommon;