Prefab tool more-or-less done
This commit is contained in:
		| @@ -44,7 +44,7 @@ function(tool_prefab in) | ||||
|   endif() | ||||
|  | ||||
|   add_custom_target(prefab_${in} | ||||
|     COMMAND prefabtool --input="${DAWN_ASSETS_SOURCE_DIR}/${in}" | ||||
|     COMMAND prefabtool --input="${DAWN_ASSETS_SOURCE_DIR}/${in}" --output="${DAWN_TEMP_DIR}" | ||||
|     COMMENT "Generating prefab from ${in}" | ||||
|     DEPENDS ${DEPS} | ||||
|   ) | ||||
|   | ||||
| @@ -8,7 +8,7 @@ | ||||
| using namespace Dawn; | ||||
|  | ||||
| std::vector<std::string> PrefabTool::getRequiredFlags() { | ||||
|   return { "input" }; | ||||
|   return { "input", "output" }; | ||||
| } | ||||
|  | ||||
| std::map<std::string, std::string> PrefabTool::getOptionalFlags() { | ||||
| @@ -22,5 +22,198 @@ int32_t PrefabTool::start() { | ||||
|     return 1; | ||||
|   } | ||||
|  | ||||
|   std::string data; | ||||
|   if(!input.readString(&data)) return 1; | ||||
|  | ||||
|   auto xml = Xml::load(data); | ||||
|   std::string error; | ||||
|   struct Prefab prefab; | ||||
|   auto result = ((PrefabParser()).parse(&xml, &prefab, &error)); | ||||
|   if(result != 0) return result; | ||||
|  | ||||
|   // Generate output | ||||
|   std::vector<std::string> outputData; | ||||
|   PrefabGen::generate(&outputData, &prefab, ""); | ||||
|  | ||||
|   // Load output file from name and type | ||||
|   File outputFile = File(flags["output"] + "/prefabs/" + prefab.type + "/" + prefab.name + ".hpp"); | ||||
|   if(!outputFile.mkdirp()) { | ||||
|     std::cout << "Failed to create output directory!" << std::endl; | ||||
|     return 1; | ||||
|   } | ||||
|  | ||||
|   // Combine vector into single string | ||||
|   std::string outputDataStr = ""; | ||||
|   auto it = outputData.begin(); | ||||
|   while(it != outputData.end()) { | ||||
|     outputDataStr += *it + "\n"; | ||||
|     ++it;  | ||||
|   } | ||||
|    | ||||
|   if(!outputFile.writeString(outputDataStr)) { | ||||
|     std::cout << "Failed to write output file!" << std::endl; | ||||
|     return 1; | ||||
|   } | ||||
|  | ||||
|   return 0; | ||||
| } | ||||
|  | ||||
| // | ||||
|  | ||||
| std::vector<std::string> PrefabParser::getRequiredAttributes() { | ||||
|   return { "name", "type" }; | ||||
| } | ||||
|  | ||||
| std::map<std::string, std::string> PrefabParser::getOptionalAttributes() { | ||||
|   return { }; | ||||
| } | ||||
|  | ||||
| int32_t PrefabParser::onParse( | ||||
|   Xml *node, | ||||
|   std::map<std::string, std::string> values, | ||||
|   struct Prefab *out, | ||||
|   std::string *error | ||||
| ) { | ||||
|   out->name = values["name"]; | ||||
|   out->type = values["type"]; | ||||
|  | ||||
|   auto itChildren = node->children.begin(); | ||||
|   while(itChildren != node->children.end()) { | ||||
|     // Parse children as components | ||||
|     struct PrefabComponent component; | ||||
|     auto ret = (PrefabComponentParser()).parse(*itChildren, &component, error); | ||||
|     if(ret != 0) return ret; | ||||
|     out->components.push_back(component); | ||||
|     ++itChildren; | ||||
|   } | ||||
|  | ||||
|   return 0; | ||||
| } | ||||
|  | ||||
| // | ||||
|  | ||||
| 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"]; | ||||
|   } | ||||
|  | ||||
|   std::function<std::string(std::string)> stringParser = [&](std::string str) { | ||||
|     return "\"" + str + "\""; | ||||
|   }; | ||||
|  | ||||
|   // Handle different node types! | ||||
|   std::map<std::string, struct PrefabComponentParserRuleset> attributesForTypes = { | ||||
|     { "UILabel", { | ||||
|       .include = "scene/components/ui/UILabel.hpp", | ||||
|       .optional = { | ||||
|         { "text", stringParser } | ||||
|       } | ||||
|     } } | ||||
|   }; | ||||
|  | ||||
|   // Check if the node type is in the map | ||||
|   if(attributesForTypes.find(node->node) != attributesForTypes.end()) { | ||||
|     // Get the ruleset for this node type | ||||
|     auto ruleset = attributesForTypes[node->node]; | ||||
|     out->include = ruleset.include; | ||||
|     out->type = node->node; | ||||
|  | ||||
|     // Iterate all the optional attributes and store within the out if present | ||||
|     auto itOptional = ruleset.optional.begin(); | ||||
|     while(itOptional != ruleset.optional.end()) { | ||||
|       if(node->attributes.find(itOptional->first) != node->attributes.end()) { | ||||
|         auto raw = node->attributes[itOptional->first]; | ||||
|         auto parsed = itOptional->second(raw); | ||||
|         out->values[itOptional->first] = parsed; | ||||
|       } | ||||
|       ++itOptional; | ||||
|     } | ||||
|  | ||||
|     // TODO: Handle required attributes  | ||||
|   } else { | ||||
|     *error = "Unknown node type: " + node->node; | ||||
|     return 1; | ||||
|   } | ||||
|  | ||||
|   return 0; | ||||
| } | ||||
|  | ||||
| // | ||||
|  | ||||
| void PrefabGen::generate( | ||||
|   std::vector<std::string> *out, | ||||
|   struct Prefab *info, | ||||
|   std::string tabs | ||||
| ) { | ||||
|   struct ClassGenInfo classInfo; | ||||
|   classInfo.clazz = info->name; | ||||
|   classInfo.extend = "SceneItemPrefab<" + info->name + ">"; | ||||
|   classInfo.constructorArgs = "Scene *scene, sceneid_t id"; | ||||
|   classInfo.extendArgs = "scene, id"; | ||||
|  | ||||
|   struct MethodGenInfo methodAssets; | ||||
|   methodAssets.name = "prefabAssets"; | ||||
|   methodAssets.isStatic = true; | ||||
|   methodAssets.type = "std::vector<Asset*>"; | ||||
|   methodAssets.args = "AssetManager *man"; | ||||
|   line(&methodAssets.body, "std::vector<Asset*> assets;", ""); | ||||
|  | ||||
|   struct MethodGenInfo methodInit; | ||||
|   methodInit.name = "prefabInit"; | ||||
|   methodInit.isOverride = true; | ||||
|   methodInit.args = "AssetManager *man"; | ||||
|  | ||||
|   classInfo.includes.push_back("prefab/SceneItemPrefab.hpp"); | ||||
|  | ||||
|   // Includes | ||||
|   int32_t componentNumber = 0; | ||||
|   auto itChildren = info->components.begin(); | ||||
|   while(itChildren != info->components.end()) { | ||||
|     auto c = *itChildren; | ||||
|     std::string name = "c" + std::to_string(componentNumber++); | ||||
|     bool_t init = true; | ||||
|     if(c.ref.size() > 0) { | ||||
|       init = false; | ||||
|       name = c.ref; | ||||
|       line(&classInfo.publicProperties, c.type + " *" + c.ref + ";", ""); | ||||
|     } | ||||
|  | ||||
|     // Initialize | ||||
|     line(&methodInit.body, (init ? "auto " : "") + name + " = this->addComponent<" + c.type + ">();", ""); | ||||
|  | ||||
|     // Now set each property | ||||
|     auto itValues = c.values.begin(); | ||||
|     while(itValues != c.values.end()) { | ||||
|       line(&methodInit.body, name + "->" + itValues->first + " = " + itValues->second + ";", ""); | ||||
|       ++itValues; | ||||
|     } | ||||
|     line(&methodInit.body, "", ""); | ||||
|  | ||||
|     classInfo.includes.push_back(c.include); | ||||
|     ++itChildren; | ||||
|   } | ||||
|    | ||||
|   // Seal methods | ||||
|   line(&methodAssets.body, "return assets;", ""); | ||||
|  | ||||
|   // Add in methods | ||||
|   CodeGen::methodGen(&classInfo.publicCode, methodAssets); | ||||
|   line(&classInfo.publicCode, "", ""); | ||||
|   CodeGen::methodGen(&classInfo.publicCode, methodInit); | ||||
|  | ||||
|   CodeGen::classGen(out, classInfo); | ||||
| } | ||||
| @@ -6,8 +6,28 @@ | ||||
| #pragma once | ||||
| #include "util/DawnTool.hpp" | ||||
| #include "util/File.hpp" | ||||
| #include "util/XmlParser.hpp" | ||||
| #include "util/CodeGen.hpp" | ||||
|  | ||||
| namespace Dawn { | ||||
|   struct PrefabComponentParserRuleset { | ||||
|     std::string include; | ||||
|     std::map<std::string, std::function<std::string(std::string)>> optional; | ||||
|   }; | ||||
|  | ||||
|   struct PrefabComponent { | ||||
|     std::string include; | ||||
|     std::string type; | ||||
|     std::map<std::string, std::string> values; | ||||
|     std::string ref; | ||||
|   }; | ||||
|  | ||||
|   struct Prefab { | ||||
|     std::string name; | ||||
|     std::string type; | ||||
|     std::vector<struct PrefabComponent> components; | ||||
|   }; | ||||
|  | ||||
|   class PrefabTool : public DawnTool { | ||||
|     protected: | ||||
|       std::vector<std::string> getRequiredFlags() override; | ||||
| @@ -16,4 +36,37 @@ namespace Dawn { | ||||
|     public: | ||||
|       int32_t start(); | ||||
|   }; | ||||
|  | ||||
|   class PrefabParser : public XmlParser<struct Prefab> { | ||||
|     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 Prefab *out, | ||||
|         std::string *error | ||||
|       ) override; | ||||
|   }; | ||||
|  | ||||
|   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; | ||||
|   }; | ||||
|  | ||||
|   class PrefabGen : public CodeGen { | ||||
|     public: | ||||
|       static void generate( | ||||
|         std::vector<std::string> *out, | ||||
|         struct Prefab *prefab, | ||||
|         std::string tabs | ||||
|       ); | ||||
|   }; | ||||
| } | ||||
| @@ -35,10 +35,25 @@ void CodeGen::classGen( | ||||
|  | ||||
|   line(out, "#pragma once", ""); | ||||
|   line(out, "", ""); | ||||
|  | ||||
|   // Includes | ||||
|   if(info.includes.size() > 0) { | ||||
|     lines(out, info.includes, ""); | ||||
|     // iterate over info.includes | ||||
|     std::vector<std::string> included; | ||||
|     auto itInclude = info.includes.begin(); | ||||
|     while(itInclude != info.includes.end()) { | ||||
|       // skip if already included | ||||
|       if(std::find(included.begin(), included.end(), *itInclude) != included.end()) { | ||||
|         ++itInclude; | ||||
|         continue; | ||||
|       } | ||||
|       line(out, "#include \"" + *itInclude + "\"", ""); | ||||
|       included.push_back(*itInclude); | ||||
|       ++itInclude; | ||||
|     } | ||||
|     line(out, "", ""); | ||||
|   } | ||||
|  | ||||
|   line(out, "namespace Dawn {", ""); | ||||
|     line(out, "class " + info.clazz + (info.extend.size() == 0 ? "{" : " : public " + info.extend + " {" ), "  "); | ||||
|     if(info.protectedCode.size() > 0) { | ||||
|   | ||||
		Reference in New Issue
	
	Block a user