Prefab Generator Refactor
This commit is contained in:
@@ -12,13 +12,9 @@ target_sources(prefabtool
|
||||
PRIVATE
|
||||
${DAWN_SHARED_SOURCES}
|
||||
${DAWN_TOOL_SOURCES}
|
||||
PrefabAssetParser.cpp
|
||||
PrefabTool.cpp
|
||||
PrefabGen.cpp
|
||||
PrefabChildParser.cpp
|
||||
PrefabParser.cpp
|
||||
PrefabRegistry.cpp
|
||||
PrefabComponentParser.cpp
|
||||
)
|
||||
|
||||
# Includes
|
||||
|
@@ -1,102 +0,0 @@
|
||||
// Copyright (c) 2023 Dominic Masters
|
||||
//
|
||||
// This software is released under the MIT License.
|
||||
// https://opensource.org/licenses/MIT
|
||||
|
||||
#pragma once
|
||||
#include "util/string.hpp"
|
||||
|
||||
namespace Dawn {
|
||||
static inline std::string rawParser(std::string v, std::string *error) {
|
||||
return v;
|
||||
};
|
||||
|
||||
static inline std::string stringParser(std::string v, std::string *error) {
|
||||
return "\"" + v + "\"";
|
||||
};
|
||||
|
||||
static inline std::string floatParser(std::string v, std::string *error) {
|
||||
v = stringTrim(v);
|
||||
|
||||
// Make sure number contains decimal
|
||||
if(v.find(".") == std::string::npos) {
|
||||
v += ".0";
|
||||
}
|
||||
// Make sure number contains a number before the decimal
|
||||
if(v.find(".") == 0) {
|
||||
v = "0" + v;
|
||||
}
|
||||
// Make sure ends with f
|
||||
if(v.find("f") == std::string::npos) {
|
||||
v += "f";
|
||||
}
|
||||
return v;
|
||||
};
|
||||
|
||||
static inline std::string intParser(std::string v, std::string *error) {
|
||||
v = stringTrim(v);
|
||||
return v;
|
||||
}
|
||||
|
||||
static inline std::string boolParser(std::string v, std::string *error) {
|
||||
v = stringTrim(v);
|
||||
if(v == "true") return "true";
|
||||
if(v == "false") return "false";
|
||||
*error = "Invalid bool value: " + v;
|
||||
return std::string("");
|
||||
}
|
||||
|
||||
static inline std::string vec2Parser(std::string v, std::string *error) {
|
||||
// Split string by comma into two strings that we pass into float
|
||||
auto split = stringSplit(v, ",");
|
||||
if(split.size() != 2) {
|
||||
*error = "Invalid vec2 value: " + v;
|
||||
return std::string("");
|
||||
}
|
||||
return std::string(
|
||||
"glm::vec2(" +
|
||||
floatParser(split[0], error) + ", " +
|
||||
floatParser(split[1], error) +
|
||||
")"
|
||||
);
|
||||
};
|
||||
|
||||
|
||||
static inline std::string vec3Parser(std::string v, std::string *error) {
|
||||
// Split string by comma into two strings that we pass into float
|
||||
auto split = stringSplit(v, ",");
|
||||
if(split.size() != 3) {
|
||||
*error = "Invalid vec3 value: " + v;
|
||||
return std::string("");
|
||||
}
|
||||
return std::string(
|
||||
"glm::vec3(" +
|
||||
floatParser(split[0], error) + ", " +
|
||||
floatParser(split[1], error) + ", " +
|
||||
floatParser(split[2], error) +
|
||||
")"
|
||||
);
|
||||
};
|
||||
|
||||
|
||||
static inline std::string vec4Parser(std::string v, std::string *error) {
|
||||
// Split string by comma into two strings that we pass into float
|
||||
auto split = stringSplit(v, ",");
|
||||
if(split.size() != 4) {
|
||||
*error = "Invalid vec4 value: " + v;
|
||||
return std::string("");
|
||||
}
|
||||
return std::string(
|
||||
"glm::vec4(" +
|
||||
floatParser(split[0], error) + ", " +
|
||||
floatParser(split[1], error) + ", " +
|
||||
floatParser(split[2], error) + ", " +
|
||||
floatParser(split[3], error) +
|
||||
")"
|
||||
);
|
||||
};
|
||||
|
||||
static inline std::string colorParser(std::string v, std::string *error) {
|
||||
return rawParser(v, error);
|
||||
}
|
||||
}
|
@@ -1,36 +0,0 @@
|
||||
// Copyright (c) 2023 Dominic Masters
|
||||
//
|
||||
// This software is released under the MIT License.
|
||||
// https://opensource.org/licenses/MIT
|
||||
|
||||
#include "PrefabAssetParser.hpp"
|
||||
|
||||
using namespace Dawn;
|
||||
|
||||
std::vector<std::string> PrefabAssetParser::getRequiredAttributes() {
|
||||
return { "type", "name" };
|
||||
}
|
||||
|
||||
std::map<std::string, std::string> PrefabAssetParser::getOptionalAttributes() {
|
||||
return { };
|
||||
}
|
||||
|
||||
int32_t PrefabAssetParser::onParse(
|
||||
Xml *node,
|
||||
std::map<std::string, std::string> values,
|
||||
struct PrefabAsset *out,
|
||||
std::string *error
|
||||
) {
|
||||
out->fileName = values["name"];
|
||||
|
||||
if(values["type"] == "texture") {
|
||||
out->type = PREFAB_ASSET_TYPE_TEXTURE;
|
||||
} else if(values["type"] == "truetype") {
|
||||
out->type = PREFAB_ASSET_TYPE_TRUETYPE_FONT;
|
||||
} else {
|
||||
*error = "Unknown asset type '" + values["type"] + "'";
|
||||
return 1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
@@ -1,33 +0,0 @@
|
||||
// Copyright (c) 2023 Dominic Masters
|
||||
//
|
||||
// This software is released under the MIT License.
|
||||
// https://opensource.org/licenses/MIT
|
||||
|
||||
#pragma once
|
||||
#include "util/XmlParser.hpp"
|
||||
|
||||
namespace Dawn {
|
||||
enum PrefabAssetType {
|
||||
PREFAB_ASSET_TYPE_TEXTURE,
|
||||
PREFAB_ASSET_TYPE_TRUETYPE_FONT
|
||||
};
|
||||
|
||||
struct PrefabAsset {
|
||||
PrefabAssetType type;
|
||||
std::string fileName;
|
||||
std::string usageName;
|
||||
};
|
||||
|
||||
class PrefabAssetParser : public XmlParser<PrefabAsset> {
|
||||
public:
|
||||
virtual std::vector<std::string> getRequiredAttributes();
|
||||
virtual std::map<std::string, std::string> getOptionalAttributes();
|
||||
|
||||
virtual int32_t onParse(
|
||||
Xml *node,
|
||||
std::map<std::string, std::string> values,
|
||||
struct PrefabAsset *out,
|
||||
std::string *error
|
||||
);
|
||||
};
|
||||
}
|
@@ -1,68 +0,0 @@
|
||||
// Copyright (c) 2023 Dominic Masters
|
||||
//
|
||||
// This software is released under the MIT License.
|
||||
// https://opensource.org/licenses/MIT
|
||||
|
||||
#include "PrefabChildParser.hpp"
|
||||
|
||||
using namespace Dawn;
|
||||
|
||||
std::vector<std::string> PrefabChildParser::getRequiredAttributes() {
|
||||
return std::vector<std::string>();
|
||||
}
|
||||
|
||||
std::map<std::string, std::string> PrefabChildParser::getOptionalAttributes() {
|
||||
return {
|
||||
{ "ref", "" },
|
||||
{ "position", "" },
|
||||
{ "scale", "" }
|
||||
};
|
||||
}
|
||||
|
||||
int32_t PrefabChildParser::onParse(
|
||||
Xml *node,
|
||||
std::map<std::string, std::string> values,
|
||||
struct PrefabChild *out,
|
||||
std::string *error
|
||||
) {
|
||||
out->ref = values["ref"];
|
||||
|
||||
if(values["position"].size() > 0) {
|
||||
out->position = vec3Parser(values["position"], error);
|
||||
if(error->size() > 0) return 1;
|
||||
}
|
||||
|
||||
if(values["scale"].size() > 0) {
|
||||
out->scale = vec3Parser(values["scale"], error);
|
||||
if(error->size() > 0) return 1;
|
||||
}
|
||||
|
||||
auto itChildren = node->children.begin();
|
||||
while(itChildren != node->children.end()) {
|
||||
// Parse child nodes, they may be components or not
|
||||
auto c = *itChildren;
|
||||
if(c->node == "child") {
|
||||
struct PrefabChild child;
|
||||
child.registry = out->registry;
|
||||
auto ret = (PrefabChildParser()).parse(c, &child, error);
|
||||
if(ret != 0) return ret;
|
||||
out->children.push_back(child);
|
||||
|
||||
} else if(c->node == "asset") {
|
||||
struct PrefabAsset asset;
|
||||
auto ret = (PrefabAssetParser()).parse(c, &asset, error);
|
||||
if(ret != 0) return ret;
|
||||
out->assets.push_back(asset);
|
||||
|
||||
} else {
|
||||
struct PrefabComponent component;
|
||||
component.registry = out->registry;
|
||||
auto ret = (PrefabComponentParser()).parse(c, &component, error);
|
||||
if(ret != 0) return ret;
|
||||
out->components.push_back(component);
|
||||
}
|
||||
++itChildren;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
@@ -1,32 +0,0 @@
|
||||
// Copyright (c) 2023 Dominic Masters
|
||||
//
|
||||
// This software is released under the MIT License.
|
||||
// https://opensource.org/licenses/MIT
|
||||
|
||||
#pragma once
|
||||
#include "PrefabComponentParser.hpp"
|
||||
#include "PrefabAssetParser.hpp"
|
||||
|
||||
namespace Dawn {
|
||||
struct PrefabChild {
|
||||
struct PrefabRegistry *registry;
|
||||
std::string ref;
|
||||
std::string position;
|
||||
std::string scale;
|
||||
std::vector<struct PrefabComponent> components;
|
||||
std::vector<struct PrefabChild> children;
|
||||
std::vector<struct PrefabAsset> assets;
|
||||
};
|
||||
|
||||
class PrefabChildParser : public XmlParser<struct PrefabChild> {
|
||||
protected:
|
||||
std::vector<std::string> getRequiredAttributes() override;
|
||||
std::map<std::string, std::string> getOptionalAttributes() override;
|
||||
int32_t onParse(
|
||||
Xml *node,
|
||||
std::map<std::string, std::string> values,
|
||||
struct PrefabChild *out,
|
||||
std::string *error
|
||||
) override;
|
||||
};
|
||||
}
|
@@ -1,89 +0,0 @@
|
||||
// Copyright (c) 2023 Dominic Masters
|
||||
//
|
||||
// This software is released under the MIT License.
|
||||
// https://opensource.org/licenses/MIT
|
||||
|
||||
#include "PrefabComponentParser.hpp"
|
||||
|
||||
using namespace Dawn;
|
||||
|
||||
std::vector<std::string> PrefabComponentParser::getRequiredAttributes() {
|
||||
return { };
|
||||
}
|
||||
|
||||
std::map<std::string, std::string> PrefabComponentParser::getOptionalAttributes() {
|
||||
return { { "ref", "" } };
|
||||
}
|
||||
|
||||
int32_t PrefabComponentParser::onParse(
|
||||
Xml *node,
|
||||
std::map<std::string, std::string> values,
|
||||
struct PrefabComponent *out,
|
||||
std::string *error
|
||||
) {
|
||||
// Check if values contains key "ref" and has a string of size more than 0
|
||||
if(values.find("ref") != values.end() && values["ref"].size() > 0) {
|
||||
out->ref = values["ref"];
|
||||
}
|
||||
|
||||
// Get the ruleset.
|
||||
auto ruleset = out->registry->getRuleset(node->node);
|
||||
if(ruleset.name.size() == 0) {
|
||||
*error = "Unknown prefab node type: " + node->node;
|
||||
return 1;
|
||||
}
|
||||
|
||||
out->include = ruleset.include;
|
||||
out->type = node->node;
|
||||
|
||||
// Define parser types here.
|
||||
|
||||
// Iterate all the optional attributes and store within the out if present
|
||||
auto itOptional = ruleset.optional.begin();
|
||||
while(itOptional != ruleset.optional.end()) {
|
||||
// Determine the parser to use
|
||||
auto name = itOptional->first;
|
||||
auto type = itOptional->second;
|
||||
|
||||
std::function<std::string(std::string, std::string*)> parser = rawParser;
|
||||
if(type.find("string") != std::string::npos) {
|
||||
parser = stringParser;
|
||||
} else if(type.find("float") != std::string::npos) {
|
||||
parser = floatParser;
|
||||
} else if(type.find("Color") != std::string::npos) {
|
||||
parser = colorParser;
|
||||
} else if(type.find("vec2") != std::string::npos) {
|
||||
parser = vec2Parser;
|
||||
} else if(type.find("vec3") != std::string::npos) {
|
||||
parser = vec3Parser;
|
||||
} else if(type.find("vec4") != std::string::npos) {
|
||||
parser = vec4Parser;
|
||||
} else if(type == "int32_t" || type == "int") {
|
||||
parser = intParser;
|
||||
} else if(type == "bool_t") {
|
||||
parser = boolParser;
|
||||
} else if(type == "flag_t") {
|
||||
parser = rawParser;
|
||||
} else if(type.starts_with("enum")) {
|
||||
parser = rawParser;
|
||||
} else if(type.find("*") == (type.size() - 1)) {
|
||||
type = type.substr(0, type.size() - 1);
|
||||
parser = rawParser;
|
||||
} else if(name[0] == '*') {
|
||||
name = name.substr(1, name.size());
|
||||
parser = rawParser;
|
||||
} else {
|
||||
*error = "Unknown parser for type: " + type + "::" + name;
|
||||
return 1;
|
||||
}
|
||||
|
||||
if(node->attributes.find(name) != node->attributes.end()) {
|
||||
auto raw = node->attributes[name];
|
||||
out->values[name] = parser(raw, error);
|
||||
if(error->size() != 0) return 1;
|
||||
}
|
||||
++itOptional;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
@@ -1,30 +0,0 @@
|
||||
// Copyright (c) 2023 Dominic Masters
|
||||
//
|
||||
// This software is released under the MIT License.
|
||||
// https://opensource.org/licenses/MIT
|
||||
|
||||
#pragma once
|
||||
#include "PrefabRegistry.hpp"
|
||||
#include "Parsers.hpp"
|
||||
|
||||
namespace Dawn {
|
||||
struct PrefabComponent {
|
||||
struct PrefabRegistry *registry;
|
||||
std::string include;
|
||||
std::string type;
|
||||
std::map<std::string, std::string> values;
|
||||
std::string ref;
|
||||
};
|
||||
|
||||
class PrefabComponentParser : public XmlParser<struct PrefabComponent> {
|
||||
protected:
|
||||
std::vector<std::string> getRequiredAttributes() override;
|
||||
std::map<std::string, std::string> getOptionalAttributes() override;
|
||||
int32_t onParse(
|
||||
Xml *node,
|
||||
std::map<std::string, std::string> values,
|
||||
struct PrefabComponent *out,
|
||||
std::string *error
|
||||
) override;
|
||||
};
|
||||
}
|
@@ -32,123 +32,25 @@ void PrefabGen::generate(
|
||||
|
||||
classInfo.includes.push_back("prefab/SceneItemPrefab.hpp");
|
||||
|
||||
// Process assets
|
||||
// Generate
|
||||
int32_t assetNumber = 0;
|
||||
std::map<std::string, std::string> assetMap;
|
||||
auto processAsset = [&](struct PrefabAsset a) {
|
||||
std::string assetType = "";
|
||||
a.usageName = "asset" + std::to_string(assetNumber++);
|
||||
switch(a.type) {
|
||||
case PREFAB_ASSET_TYPE_TEXTURE:
|
||||
assetType = "TextureAsset";
|
||||
assetMap[a.fileName] = "&" + a.usageName + "->texture";
|
||||
break;
|
||||
|
||||
case PREFAB_ASSET_TYPE_TRUETYPE_FONT:
|
||||
assetType = "TrueTypeAsset";
|
||||
assetMap[a.fileName] = "&" + a.usageName + "->font";
|
||||
break;
|
||||
|
||||
default:
|
||||
assertUnreachable();
|
||||
}
|
||||
line(&methodInit.body, "auto " + a.usageName + " = man->get<" + assetType + ">(\"" + a.fileName + "\");", "");
|
||||
line(&methodAssets.body, "assets.push_back(man->get<" + assetType + ">(\"" + a.fileName + "\"));", "");
|
||||
};
|
||||
|
||||
// Load self assets
|
||||
auto itAssets = info->root.assets.begin();
|
||||
while(itAssets != info->root.assets.end()) {
|
||||
processAsset(*itAssets);
|
||||
++itAssets;
|
||||
}
|
||||
// TODO: Load child assets?
|
||||
line(&methodInit.body, "", "");
|
||||
|
||||
// Process root and all of its children
|
||||
int32_t childNumber = 0;
|
||||
int32_t componentNumber = 0;
|
||||
|
||||
auto processComponent = [&](struct PrefabComponent c, std::string item) {
|
||||
auto componentName = "cmp" + std::to_string(componentNumber++);
|
||||
bool_t componentInit = true;
|
||||
if(c.ref.size() > 0) {
|
||||
componentInit = false;
|
||||
componentName = c.ref;
|
||||
line(&classInfo.publicProperties, c.type + " *" + c.ref + " = nullptr;", "");
|
||||
}
|
||||
|
||||
// Initialize
|
||||
line(&methodInit.body, (componentInit ? "auto " : "") + componentName + " = " + item + "->addComponent<" + c.type + ">();", "");
|
||||
|
||||
// Now set each property
|
||||
auto itValues = c.values.begin();
|
||||
while(itValues != c.values.end()) {
|
||||
auto value = itValues->second;
|
||||
if(assetMap.find(value) != assetMap.end()) {
|
||||
value = assetMap[value];
|
||||
}
|
||||
line(&methodInit.body, componentName + "->" + itValues->first + " = " + value + ";", "");
|
||||
++itValues;
|
||||
}
|
||||
|
||||
classInfo.includes.push_back(c.include);
|
||||
};
|
||||
|
||||
std::function<void(struct PrefabChild &, std::string)> processChild;
|
||||
processChild = [&](struct PrefabChild &child, std::string parent) {
|
||||
auto name = "itm" + std::to_string(childNumber++);
|
||||
bool_t init = true;
|
||||
if(child.ref.size() > 0) {
|
||||
init = false;
|
||||
name = child.ref;
|
||||
line(&classInfo.publicProperties, "SceneItemComponent *" + name + " = nullptr;", "");
|
||||
}
|
||||
line(&methodInit.body, (init ? "auto " : "") + name + " = scene->createSceneItem();", "");
|
||||
|
||||
// Process extra properties
|
||||
if(child.position.size() > 0) {
|
||||
line(&methodInit.body, name + "->transform.setLocalPosition(" + child.position + ");", "");
|
||||
}
|
||||
|
||||
if(child.scale.size() > 0) {
|
||||
line(&methodInit.body, name + "->transform.setLocalScale(" + child.scale + ");", "");
|
||||
}
|
||||
|
||||
// Add components for children
|
||||
auto itComponents = child.components.begin();
|
||||
while(itComponents != child.components.end()) {
|
||||
auto c = *itComponents;
|
||||
processComponent(c, name);
|
||||
++itComponents;
|
||||
}
|
||||
|
||||
// Process sub children
|
||||
auto itChildren = child.children.begin();
|
||||
while(itChildren != child.children.end()) {
|
||||
processChild(*itChildren, name);
|
||||
++itChildren;
|
||||
}
|
||||
|
||||
// Set parent
|
||||
line(&methodInit.body, name + "->transform.setParent(&"+parent+"->transform);", "");
|
||||
};
|
||||
|
||||
// Process each child
|
||||
auto itChildren = info->root.children.begin();
|
||||
while(itChildren != info->root.children.end()) {
|
||||
processChild(*itChildren, "this");
|
||||
line(&methodInit.body, "", "");
|
||||
++itChildren;
|
||||
}
|
||||
|
||||
// Process self components
|
||||
auto itComponents = info->root.components.begin();
|
||||
while(itComponents != info->root.components.end()) {
|
||||
auto c = *itComponents;
|
||||
processComponent(c, "this");
|
||||
++itComponents;
|
||||
}
|
||||
std::map<std::string, std::string> assetMap;
|
||||
info->root.ref = "this";
|
||||
SceneItemGenerator::generate(
|
||||
assetNumber,
|
||||
componentNumber,
|
||||
childNumber,
|
||||
assetMap,
|
||||
classInfo.includes,
|
||||
&classInfo.publicProperties,
|
||||
&methodInit.body,
|
||||
&methodAssets.body,
|
||||
"",
|
||||
&info->root,
|
||||
""
|
||||
);
|
||||
|
||||
// Seal methods
|
||||
line(&methodAssets.body, "return assets;", "");
|
||||
|
@@ -5,6 +5,7 @@
|
||||
|
||||
#pragma once
|
||||
#include "PrefabParser.hpp"
|
||||
#include "util/generator/SceneItemGenerator.hpp"
|
||||
|
||||
namespace Dawn {
|
||||
class PrefabGen : public CodeGen {
|
||||
|
@@ -24,5 +24,5 @@ int32_t PrefabParser::onParse(
|
||||
out->name = values["name"];
|
||||
out->type = values["type"];
|
||||
out->root.registry = out->registry;
|
||||
return (PrefabChildParser()).parse(node, &out->root, error);
|
||||
return (SceneItemParser()).parse(node, &out->root, error);
|
||||
}
|
@@ -4,13 +4,13 @@
|
||||
// https://opensource.org/licenses/MIT
|
||||
|
||||
#pragma once
|
||||
#include "PrefabComponentParser.hpp"
|
||||
#include "PrefabChildParser.hpp"
|
||||
#include "util/parser/SceneItemComponentParser.hpp"
|
||||
#include "util/parser/SceneItemParser.hpp"
|
||||
|
||||
namespace Dawn {
|
||||
struct Prefab {
|
||||
struct PrefabRegistry *registry;
|
||||
struct PrefabChild root;
|
||||
struct SceneItemComponentRegistry *registry;
|
||||
struct SceneItem root;
|
||||
std::string name;
|
||||
std::string type;
|
||||
};
|
||||
|
@@ -1,186 +0,0 @@
|
||||
// Copyright (c) 2023 Dominic Masters
|
||||
//
|
||||
// This software is released under the MIT License.
|
||||
// https://opensource.org/licenses/MIT
|
||||
|
||||
#include "PrefabRegistry.hpp"
|
||||
|
||||
using namespace Dawn;
|
||||
|
||||
struct PrefabComponentParserRuleset PrefabRegistry::parseFile(
|
||||
File *file,
|
||||
std::string clazz
|
||||
) {
|
||||
assertNotNull(file);
|
||||
|
||||
std::string data;
|
||||
if(!file->readString(&data)) {
|
||||
std::cout << "Failed to read ruleset file!" << std::endl;
|
||||
return { .name = "" };
|
||||
}
|
||||
|
||||
// Begin scanning contentsr
|
||||
// std::string include = this->sources;
|
||||
auto toRemove = File::normalizeSlashes(this->sources + FILE_PATH_SEP);
|
||||
auto includePath = file->filename.substr(toRemove.size(), file->filename.size() - toRemove.size());
|
||||
|
||||
// Now locate the first subdir since we don't want to include the root path (e.g. dawn, dawnrose, etc)
|
||||
auto firstSlash = includePath.find(FILE_PATH_SEP);
|
||||
if(firstSlash != std::string::npos) {
|
||||
includePath = includePath.substr(firstSlash + 1, includePath.size() - firstSlash - 1);
|
||||
}
|
||||
|
||||
struct PrefabComponentParserRuleset ruleset;
|
||||
// Replace all file seps with slashes
|
||||
size_t pos = 0;
|
||||
while ((pos = includePath.find(FILE_PATH_SEP, pos)) != std::string::npos) {
|
||||
includePath.replace(pos, 1, "/");
|
||||
pos += 1;
|
||||
}
|
||||
ruleset.include = includePath;
|
||||
ruleset.name = clazz;
|
||||
|
||||
std::regex_constants::syntax_option_type regexFlags;
|
||||
#if defined(__GNUC__)
|
||||
regexFlags = std::regex_constants::ECMAScript | std::regex_constants::multiline;
|
||||
#else
|
||||
regexFlags = std::regex_constants::ECMAScript;
|
||||
#endif
|
||||
|
||||
// First, let's look for what class(es) this class extends
|
||||
std::regex regexClassName("class\\s+\\w+\\s+:\\s+", regexFlags);
|
||||
std::smatch match;
|
||||
if(std::regex_search(data, match, regexClassName)) {
|
||||
// Now find the next "{"
|
||||
auto matchStart = match.position() + match.length();
|
||||
auto openBracePos = data.find("{", matchStart);
|
||||
if(openBracePos == std::string::npos) {
|
||||
std::cout << "Failed to find open brace for class!" << std::endl;
|
||||
return { .name = "" };
|
||||
}
|
||||
|
||||
// Match each of the class names
|
||||
std::regex regexClass("(public\\s+(\\w+))[,\\s{]+", regexFlags);
|
||||
std::sregex_iterator itClass(data.begin() + matchStart, data.begin() + openBracePos, regexClass);
|
||||
std::sregex_iterator endClass;
|
||||
while(itClass != endClass) {
|
||||
// Get the class name
|
||||
auto className = itClass->str(2);
|
||||
itClass++;
|
||||
|
||||
// We don't parse interface classes
|
||||
if(className[0] == 'I') continue;
|
||||
ruleset.extends.push_back(className);
|
||||
}
|
||||
}
|
||||
|
||||
// Find each instance of "@optional" when it's used within a comment
|
||||
// e.g. // @optional or /* @optional */ in the string data.1
|
||||
std::regex regex("^\\s*(?:\\/\\/|\\/\\*){1}\\s*\\@optional\\s*(?:\\*\\/)?\\s*$", regexFlags);
|
||||
std::sregex_iterator it(data.begin(), data.end(), regex);
|
||||
std::sregex_iterator end;
|
||||
while(it != end) {
|
||||
// Find the next ";"
|
||||
auto endPos = data.find(";", it->position() + it->length());
|
||||
if(endPos == std::string::npos) {
|
||||
std::cout << "Failed to find end of line for optional attribute!" << std::endl;
|
||||
return { .name = "" };
|
||||
}
|
||||
|
||||
// Go backwards see if there's an equals sign after the match but before endPos
|
||||
auto equalsPos = data.rfind("=", endPos);
|
||||
|
||||
// If there's an equals sign, we search backwards from there,
|
||||
// otherwise we search backwards from the ;
|
||||
auto varStart = it->position() + it->length() + 1;
|
||||
size_t lastSearchPos = (
|
||||
(equalsPos == std::string::npos || equalsPos <= varStart) ?
|
||||
endPos :
|
||||
equalsPos
|
||||
);
|
||||
|
||||
// Now we have our string
|
||||
auto varLength = lastSearchPos - varStart;
|
||||
auto variableString = data.substr(varStart, varLength);
|
||||
|
||||
// Now (should) be able to extract the type;
|
||||
std::regex regex2("^\\s*(?:[\\S]+<)?([\\w*:_\\s]+)(?:[\\S]+)? (\\**[\\w]+)\\s*$", regexFlags);
|
||||
std::smatch match;
|
||||
if(!std::regex_search(variableString, match, regex2)) {
|
||||
std::cout << "Failed to extract type and name from variable string! " << variableString << std::endl;
|
||||
return { .name = "" };
|
||||
}
|
||||
|
||||
// Now we have our type and name
|
||||
auto type = match[1].str();
|
||||
auto name = match[2].str();
|
||||
ruleset.selfOptional[name] = type;
|
||||
++it;
|
||||
}
|
||||
return ruleset;
|
||||
}
|
||||
|
||||
struct PrefabComponentParserRuleset PrefabRegistry::getRuleset(std::string type) {
|
||||
if(this->rulesets.find(type) != this->rulesets.end()) {
|
||||
return this->rulesets[type];
|
||||
}
|
||||
|
||||
std::vector<std::string> pathsToScan;
|
||||
pathsToScan.push_back(this->sources);
|
||||
|
||||
auto it = pathsToScan.begin();
|
||||
while(it != pathsToScan.end()) {
|
||||
auto str = *it;
|
||||
pathsToScan.erase(it);
|
||||
|
||||
Directory dir = Directory(str);
|
||||
auto children = dir.readDirectory();
|
||||
|
||||
auto itChildren = children.begin();
|
||||
while(itChildren != children.end()) {
|
||||
if(itChildren->second == DIRECTORY_CHILD_TYPE_DIRECTORY) {
|
||||
pathsToScan.push_back(str + "/" + itChildren->first);
|
||||
++itChildren;
|
||||
continue;
|
||||
}
|
||||
|
||||
if(itChildren->first != type+".hpp") {
|
||||
++itChildren;
|
||||
continue;
|
||||
}
|
||||
|
||||
|
||||
// Load ruleset
|
||||
File file(str + "/" + itChildren->first);
|
||||
auto parsed = PrefabRegistry::parseFile(&file, type);
|
||||
if(parsed.name == "") {
|
||||
std::cout << "Parsing error occured on " << type << std::endl;
|
||||
return parsed;
|
||||
}
|
||||
|
||||
// Update optionals
|
||||
parsed.optional.insert(parsed.selfOptional.begin(), parsed.selfOptional.end());
|
||||
|
||||
// Recursively parse children
|
||||
auto itExtends = parsed.extends.begin();
|
||||
while(itExtends != parsed.extends.end()) {
|
||||
auto ruleset = this->getRuleset(*itExtends);
|
||||
if(ruleset.name == "") {
|
||||
++itExtends;
|
||||
continue;
|
||||
}
|
||||
|
||||
// Merge ruleset
|
||||
parsed.optional.insert(ruleset.optional.begin(), ruleset.optional.end());
|
||||
++itExtends;
|
||||
}
|
||||
|
||||
this->rulesets[type] = parsed;
|
||||
return parsed;
|
||||
}
|
||||
|
||||
it = pathsToScan.begin();
|
||||
};
|
||||
|
||||
return { .name = "" };
|
||||
}
|
@@ -1,41 +0,0 @@
|
||||
// Copyright (c) 2023 Dominic Masters
|
||||
//
|
||||
// This software is released under the MIT License.
|
||||
// https://opensource.org/licenses/MIT
|
||||
|
||||
#pragma once
|
||||
#include "util/DawnTool.hpp"
|
||||
#include "util/Directory.hpp"
|
||||
#include "util/XmlParser.hpp"
|
||||
#include "util/CodeGen.hpp"
|
||||
#include "util/string.hpp"
|
||||
#include <regex>
|
||||
|
||||
namespace Dawn {
|
||||
struct PrefabComponentParserRuleset {
|
||||
std::string name;
|
||||
std::string include;
|
||||
std::map<std::string, std::string> selfOptional;
|
||||
std::map<std::string, std::string> optional;
|
||||
std::vector<std::string> extends;
|
||||
};
|
||||
|
||||
|
||||
struct PrefabRegistry {
|
||||
std::string sources;
|
||||
std::map<std::string, struct PrefabComponentParserRuleset> rulesets;
|
||||
|
||||
struct PrefabComponentParserRuleset parseFile(
|
||||
File *file,
|
||||
std::string clazz
|
||||
);
|
||||
|
||||
/**
|
||||
* Gets a prefab component ruleset for a specific scene item component type.
|
||||
*
|
||||
* @param type Scene Item Component Type to get ruleset for.
|
||||
* @return The found ruleset, or an empty ruleset if not found.
|
||||
*/
|
||||
struct PrefabComponentParserRuleset getRuleset(std::string type);
|
||||
};
|
||||
}
|
@@ -28,7 +28,7 @@ int32_t PrefabTool::start() {
|
||||
return 1;
|
||||
}
|
||||
|
||||
struct PrefabRegistry registry;
|
||||
struct SceneItemComponentRegistry registry;
|
||||
registry.sources = File::normalizeSlashes(flags["sources"]);
|
||||
|
||||
auto xml = Xml::load(data);
|
||||
@@ -41,7 +41,6 @@ int32_t PrefabTool::start() {
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
// Generate output
|
||||
std::vector<std::string> outputData;
|
||||
PrefabGen::generate(&outputData, &prefab, "");
|
||||
|
Reference in New Issue
Block a user