feat(autogen): add meta and cframe
This commit is contained in:
parent
8f20c11b36
commit
b8ee828d29
7 changed files with 152 additions and 14 deletions
|
@ -163,6 +163,40 @@ void processField(CXCursor cur, ClassAnalysis* state) {
|
|||
anly.backingFieldType = x_clang_toString(clang_getTypeSpelling(type)).c_str();
|
||||
|
||||
state->properties.push_back(anly);
|
||||
|
||||
// For cframe, add member fields
|
||||
|
||||
std::optional<std::string> cframePositionDef = findAnnotation(cur, "OB::cframe_position_prop");
|
||||
if (cframePositionDef) {
|
||||
auto cframePosition = parseAnnotationString(cframePositionDef.value());
|
||||
|
||||
PropertyAnalysis cframeProp;
|
||||
cframeProp.backingFieldType = anly.backingFieldType;
|
||||
cframeProp.fieldName = anly.fieldName;
|
||||
cframeProp.name = cframePosition["name"];
|
||||
cframeProp.category = anly.category;
|
||||
cframeProp.cframeMember = CFrameMember_Position;
|
||||
cframeProp.onUpdateCallback = anly.onUpdateCallback;
|
||||
cframeProp.flags = PropertyFlag_NoSave;
|
||||
|
||||
state->properties.push_back(cframeProp);
|
||||
};
|
||||
|
||||
std::optional<std::string> cframeRotationDef = findAnnotation(cur, "OB::cframe_rotation_prop");
|
||||
if (cframeRotationDef) {
|
||||
auto cframeRotation = parseAnnotationString(cframeRotationDef.value());
|
||||
|
||||
PropertyAnalysis cframeProp;
|
||||
cframeProp.backingFieldType = anly.backingFieldType;
|
||||
cframeProp.fieldName = anly.fieldName;
|
||||
cframeProp.name = cframeRotation["name"];
|
||||
cframeProp.category = anly.category;
|
||||
cframeProp.cframeMember = CFrameMember_Rotation;
|
||||
cframeProp.onUpdateCallback = anly.onUpdateCallback;
|
||||
cframeProp.flags = PropertyFlag_NoSave;
|
||||
|
||||
state->properties.push_back(cframeProp);
|
||||
};
|
||||
}
|
||||
|
||||
void processClass(CXCursor cur, AnalysisState* state, std::string className, std::string srcRoot) {
|
||||
|
|
|
@ -17,13 +17,20 @@ enum PropertyFlags {
|
|||
PropertyFlag_Readonly = 1 << 3,
|
||||
};
|
||||
|
||||
enum CFrameMember {
|
||||
CFrameMember_None, // Not part of CFrame
|
||||
CFrameMember_Position,
|
||||
CFrameMember_Rotation
|
||||
};
|
||||
|
||||
struct PropertyAnalysis {
|
||||
std::string name;
|
||||
std::string fieldName;
|
||||
CFrameMember cframeMember = CFrameMember_None; // for cframe_position_prop etc.
|
||||
std::string backingFieldType;
|
||||
std::string onUpdateCallback;
|
||||
std::string category;
|
||||
PropertyFlags flags;
|
||||
PropertyFlags flags = (PropertyFlags)0;
|
||||
};
|
||||
|
||||
// https://stackoverflow.com/a/1448478/16255372
|
||||
|
|
|
@ -4,6 +4,14 @@
|
|||
#include <string>
|
||||
#include <variant>
|
||||
|
||||
std::map<std::string, std::string> CATEGORY_STR = {
|
||||
{ "appearance", "PROP_CATEGORY_APPEARENCE" },
|
||||
{ "data", "PROP_CATEGORY_DATA" },
|
||||
{ "behavior", "PROP_CATEGORY_BEHAVIOR" },
|
||||
{ "part", "PROP_CATEGORY_PART" },
|
||||
{ "surface", "PROP_CATEGORY_SURFACE" },
|
||||
};
|
||||
|
||||
std::map<std::string, std::string> MAPPED_TYPE = {
|
||||
{ "bool", "Data::Bool" },
|
||||
{ "int", "Data::Int" },
|
||||
|
@ -27,6 +35,19 @@ std::string castFromVariant(std::string valueStr, std::string fieldType) {
|
|||
return valueStr + ".get<" + (!mappedType.empty() ? mappedType : fieldType) + ">()";
|
||||
}
|
||||
|
||||
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 + ")";
|
||||
}
|
||||
|
||||
std::string mappedType = MAPPED_TYPE[fieldType];
|
||||
if (!mappedType.empty()) {
|
||||
return mappedType + "(" + valueStr + ")";
|
||||
}
|
||||
return valueStr;
|
||||
}
|
||||
|
||||
void writePropertySetHandler(std::ofstream& out, ClassAnalysis state) {
|
||||
out << "fallible<MemberNotFound, AssignToReadOnlyMember> " << state.name << "::InternalSetPropertyValue(std::string name, Data::Variant value) {";
|
||||
|
||||
|
@ -37,8 +58,14 @@ void writePropertySetHandler(std::ofstream& out, ClassAnalysis state) {
|
|||
|
||||
if (prop.flags & PropertyFlag_Readonly) {
|
||||
out << "\n return AssignToReadOnlyMember(\"" << state.name << "\", 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) {
|
||||
out << "\n this->" << prop.fieldName << " = CFrame::FromEulerAnglesXYZ(value.get<Vector3>()) + this->" << prop.fieldName << ".Position();";
|
||||
} else {
|
||||
out << "\n this->" << prop.fieldName << " = " << castFromVariant("value", prop.backingFieldType) << ";";
|
||||
if (!prop.onUpdateCallback.empty())
|
||||
out << "\n " << prop.onUpdateCallback << "(name);";
|
||||
}
|
||||
|
||||
out << "\n }";
|
||||
|
@ -50,6 +77,69 @@ void writePropertySetHandler(std::ofstream& out, ClassAnalysis state) {
|
|||
out << "\n};\n\n";
|
||||
}
|
||||
|
||||
void writePropertyGetHandler(std::ofstream& out, ClassAnalysis state) {
|
||||
out << "result<Data::Variant, MemberNotFound> " << state.name << "::InternalGetPropertyValue(std::string name) {";
|
||||
|
||||
out << "\n ";
|
||||
bool first = true;
|
||||
for (auto& prop : state.properties) {
|
||||
out << (first ? "" : " else ") << "if (name == \"" << prop.name << "\") {";
|
||||
|
||||
if (prop.cframeMember == CFrameMember_Position) {
|
||||
out << "\n return Data::Variant(" << prop.fieldName << ".Position());";
|
||||
} else if (prop.cframeMember == CFrameMember_Rotation) {
|
||||
out << "\n return Data::Variant(" << prop.fieldName << ".ToEulerAnglesXYZ());";
|
||||
} else {
|
||||
out << "\n return Data::Variant(" << castToVariant(prop.fieldName, prop.backingFieldType) << ");";
|
||||
}
|
||||
|
||||
out << "\n }";
|
||||
first = false;
|
||||
}
|
||||
|
||||
out << "\n return MemberNotFound(\"" << state.name << "\", name);";
|
||||
|
||||
out << "\n};\n\n";
|
||||
}
|
||||
|
||||
void writePropertyMetaHandler(std::ofstream& out, ClassAnalysis state) {
|
||||
out << "result<PropertyMeta, MemberNotFound> " << state.name << "::InternalGetPropertyMeta(std::string name) {";
|
||||
|
||||
out << "\n ";
|
||||
bool first = true;
|
||||
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";
|
||||
|
||||
std::string strFlags;
|
||||
if (prop.flags & PropertyFlag_Readonly)
|
||||
strFlags += " | PROP_READONLY";
|
||||
if (prop.flags & PropertyFlag_Hidden)
|
||||
strFlags += " | PROP_HIDDEN";
|
||||
if (prop.flags & PropertyFlag_NoSave)
|
||||
strFlags += " | PROP_NOSAVE";
|
||||
if (prop.flags & PropertyFlag_UnitFloat)
|
||||
strFlags += " | PROP_UNIT_FLOAT";
|
||||
if (!strFlags.empty()) strFlags = strFlags.substr(3); // Remove leading pipe
|
||||
else strFlags = "0"; // 0 == No option
|
||||
|
||||
std::string category = CATEGORY_STR[prop.category];
|
||||
if (category.empty()) category = "PROP_CATEGORY_DATA";
|
||||
|
||||
out << "\n return PropertyMeta { &" << type << "::TYPE, " << strFlags << ", " << category << " };";
|
||||
|
||||
out << "\n }";
|
||||
first = false;
|
||||
}
|
||||
|
||||
out << "\n return MemberNotFound(\"" << state.name << "\", name);";
|
||||
|
||||
out << "\n};\n\n";
|
||||
}
|
||||
|
||||
void writeCodeForClass(std::ofstream& out, ClassAnalysis& state) {
|
||||
std::string strFlags;
|
||||
if (state.flags & ClassFlag_NotCreatable)
|
||||
|
@ -61,6 +151,10 @@ void writeCodeForClass(std::ofstream& out, ClassAnalysis& state) {
|
|||
if (!strFlags.empty()) strFlags = strFlags.substr(3); // Remove leading pipe
|
||||
else strFlags = "0"; // 0 == No option
|
||||
|
||||
out << "/////////////////////////////////////////////////////////////////////////////////////////\n";
|
||||
out << "// This file was automatically generated by autogen, and should not be edited manually //\n";
|
||||
out << "/////////////////////////////////////////////////////////////////////////////////////////\n\n";
|
||||
|
||||
out << "#include \"" << state.headerPath << "\"\n\n";
|
||||
out << "const InstanceType " << state.name << "::TYPE = {\n"
|
||||
<< " .super = &" << state.baseClass << "::TYPE,\n"
|
||||
|
@ -75,4 +169,6 @@ void writeCodeForClass(std::ofstream& out, ClassAnalysis& state) {
|
|||
<< "};\n\n";
|
||||
|
||||
writePropertySetHandler(out, state);
|
||||
writePropertyGetHandler(out, state);
|
||||
writePropertyMetaHandler(out, state);
|
||||
}
|
|
@ -245,6 +245,11 @@ result<PropertyMeta, MemberNotFound> Instance::GetPropertyMeta(std::string 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<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.
|
||||
|
@ -282,7 +287,7 @@ void Instance::Serialize(pugi::xml_node parent) {
|
|||
pugi::xml_node propertiesNode = node.append_child("Properties");
|
||||
for (std::string name : GetProperties()) {
|
||||
PropertyMeta meta = GetPropertyMeta(name).expect("Meta of declared property is missing");
|
||||
if (meta.flags & (PropertyFlags::PROP_NOSAVE | PropertyFlags::PROP_READONLY)) continue; // This property should not be serialized. Skip...
|
||||
if (meta.flags & (PROP_NOSAVE | PROP_READONLY)) 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);
|
||||
|
|
|
@ -44,12 +44,11 @@ std::function<void(std::string name)> memberFunctionOf(void(T::*func)(std::strin
|
|||
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
|
||||
PROP_UNIT_FLOAT = 1 << 2, // Float between 0 and 1
|
||||
PROP_READONLY = 1 << 3, // Read only property, do not write
|
||||
};
|
||||
typedef int PropertyFlags;
|
||||
const PropertyFlags PROP_HIDDEN = 1 << 0; // Hidden from the editor
|
||||
const PropertyFlags PROP_NOSAVE = 1 << 1; // Do not serialize
|
||||
const PropertyFlags PROP_UNIT_FLOAT = 1 << 2; // Float between 0 and 1
|
||||
const PropertyFlags PROP_READONLY = 1 << 3; // Read only property, do not write
|
||||
|
||||
enum PropertyCategory {
|
||||
PROP_CATEGORY_APPEARENCE,
|
||||
|
@ -62,10 +61,7 @@ enum PropertyCategory {
|
|||
const int PROPERTY_CATEGORY_MAX = PROP_CATEGORY_SURFACE;
|
||||
|
||||
struct PropertyMeta {
|
||||
void* backingField;
|
||||
const Data::TypeInfo* type;
|
||||
FieldCodec codec;
|
||||
std::optional<std::function<void(std::string name)>> updateCallback;
|
||||
PropertyFlags flags;
|
||||
PropertyCategory category = PROP_CATEGORY_DATA;
|
||||
};
|
||||
|
|
|
@ -74,13 +74,13 @@ Part::Part(PartConstructParams params): Instance(&TYPE), cframe(CFrame::FromEule
|
|||
.type = &Vector3::TYPE,
|
||||
.codec = cframePositionCodec(),
|
||||
.updateCallback = memberFunctionOf(&Part::onUpdated, this),
|
||||
.flags = PropertyFlags::PROP_NOSAVE
|
||||
.flags = PROP_NOSAVE
|
||||
}}, { "Rotation", {
|
||||
.backingField = &cframe,
|
||||
.type = &Vector3::TYPE,
|
||||
.codec = cframeRotationCodec(),
|
||||
.updateCallback = memberFunctionOf(&Part::onUpdated, this),
|
||||
.flags = PropertyFlags::PROP_NOSAVE
|
||||
.flags = PROP_NOSAVE
|
||||
}}, { "Velocity", {
|
||||
.backingField = &velocity,
|
||||
.type = &Vector3::TYPE,
|
||||
|
|
|
@ -52,7 +52,7 @@ public:
|
|||
const static InstanceType TYPE;
|
||||
|
||||
Vector3 velocity;
|
||||
[[ def_prop(name="cframe"), cframe_position_prop(name="Position"), cframe_rotation_prop(name="Rotation") ]]
|
||||
[[ def_prop(name="CFrame"), cframe_position_prop(name="Position"), cframe_rotation_prop(name="Rotation") ]]
|
||||
CFrame cframe;
|
||||
[[ def_prop(name="Size", category=PART) ]]
|
||||
glm::vec3 size;
|
||||
|
|
Loading…
Add table
Reference in a new issue