diff --git a/xml_converter/integration_tests/run_tests.py b/xml_converter/integration_tests/run_tests.py index 4d99b9df..06c50c8a 100755 --- a/xml_converter/integration_tests/run_tests.py +++ b/xml_converter/integration_tests/run_tests.py @@ -20,6 +20,7 @@ def run_xml_converter( input_proto: Optional[List[str]] = None, output_proto: Optional[List[str]] = None, split_output_proto: Optional[str] = None, + allow_duplicates: Optional[bool] = None, ) -> Tuple[str, str, int]: # Build the command to execute the C++ program with the desired function and arguments @@ -35,6 +36,8 @@ def run_xml_converter( cmd += ["--output-guildpoint-path"] + output_proto if split_output_proto: cmd += ["--output-split-guildpoint-path"] + [split_output_proto] + if allow_duplicates: + cmd += ["--allow-duplicates"] # Run the C++ program and capture its output result = subprocess.run(cmd, stdout=subprocess.PIPE, stderr=subprocess.PIPE, text=True) @@ -174,6 +177,7 @@ def main() -> bool: input_proto=testcase.proto_input_paths, output_xml=[xml_output_dir_path], output_proto=[proto_output_dir_path], + allow_duplicates=testcase.allow_duplicates ) # Sanitize and denoise the lines @@ -206,8 +210,10 @@ def main() -> bool: if testcase.expected_returncode is not None and testcase.expected_returncode != returncode: print(f"Expected a return code of {testcase.expected_returncode} for {testcase.name} but got {returncode}") - testcase_passed &= diff_dirs(xml_output_dir_path, testcase.expected_output_xml_path) - testcase_passed &= diff_dirs(proto_output_dir_path, testcase.expected_output_proto_path) + if os.path.exists(testcase.expected_output_xml_path): + testcase_passed &= diff_dirs(xml_output_dir_path, testcase.expected_output_xml_path) + if os.path.exists(testcase.expected_output_proto_path): + testcase_passed &= diff_dirs(proto_output_dir_path, testcase.expected_output_proto_path) if testcase_passed: print(f"Success: test {testcase.name}") diff --git a/xml_converter/integration_tests/src/testcase_loader.py b/xml_converter/integration_tests/src/testcase_loader.py index aa85b442..b0d4394f 100644 --- a/xml_converter/integration_tests/src/testcase_loader.py +++ b/xml_converter/integration_tests/src/testcase_loader.py @@ -21,6 +21,7 @@ class Testcase: expected_stdout: List[str] expected_stderr: List[str] expected_returncode: int + allow_duplicates: bool ################################################################################ @@ -58,6 +59,7 @@ def load_testcase(path: str) -> Optional[Testcase]: # Load all of the input paths into either xml input or proto inputs xml_input_paths: List[str] = [] proto_input_paths: List[str] = [] + allow_duplicates: bool = False for pack_name, pack_type in data["input_paths"].items(): if not isinstance(pack_name, str): print(f"Invalid pack name, expecting a string but got {pack_name}") @@ -104,6 +106,13 @@ def load_testcase(path: str) -> Optional[Testcase]: print(f"Invalid Test, expecting string value for 'expected_returncode' in {path}") return None + if "allow_duplicates" in data: + if not isinstance(data["allow_duplicates"], bool): + print(f"Invalid Test, expecting bool value for 'allow_duplicates' in {path}") + return None + else: + allow_duplicates = data["allow_duplicates"] + return Testcase( name=os.path.basename(path), xml_input_paths=xml_input_paths, @@ -112,7 +121,8 @@ def load_testcase(path: str) -> Optional[Testcase]: expected_output_proto_path=os.path.join(path, "output_proto"), expected_stdout=to_lines(data["expected_stdout"]), expected_stderr=to_lines(data["expected_stderr"]), - expected_returncode=data["expected_returncode"] + expected_returncode=data["expected_returncode"], + allow_duplicates=allow_duplicates ) diff --git a/xml_converter/integration_tests/test_cases/proto_and_xml_input_allow_duplicates/input/pack/xml_file.xml b/xml_converter/integration_tests/test_cases/proto_and_xml_input_allow_duplicates/input/pack/xml_file.xml new file mode 100644 index 00000000..5cf29494 --- /dev/null +++ b/xml_converter/integration_tests/test_cases/proto_and_xml_input_allow_duplicates/input/pack/xml_file.xml @@ -0,0 +1,8 @@ + + + + + + + + diff --git a/xml_converter/integration_tests/test_cases/proto_and_xml_input_allow_duplicates/input/pack2/markers.bin b/xml_converter/integration_tests/test_cases/proto_and_xml_input_allow_duplicates/input/pack2/markers.bin new file mode 100644 index 00000000..50078921 --- /dev/null +++ b/xml_converter/integration_tests/test_cases/proto_and_xml_input_allow_duplicates/input/pack2/markers.bin @@ -0,0 +1,4 @@ + ++ + +MyCategory 2B \Ï)Cf¦RC{ÔWCB(èÌ“^– \ No newline at end of file diff --git a/xml_converter/integration_tests/test_cases/proto_and_xml_input_allow_duplicates/input/pack3/xml_file.xml b/xml_converter/integration_tests/test_cases/proto_and_xml_input_allow_duplicates/input/pack3/xml_file.xml new file mode 100644 index 00000000..5cf29494 --- /dev/null +++ b/xml_converter/integration_tests/test_cases/proto_and_xml_input_allow_duplicates/input/pack3/xml_file.xml @@ -0,0 +1,8 @@ + + + + + + + + diff --git a/xml_converter/integration_tests/test_cases/proto_and_xml_input_allow_duplicates/output_proto/markers.bin b/xml_converter/integration_tests/test_cases/proto_and_xml_input_allow_duplicates/output_proto/markers.bin new file mode 100644 index 00000000..40148278 --- /dev/null +++ b/xml_converter/integration_tests/test_cases/proto_and_xml_input_allow_duplicates/output_proto/markers.bin @@ -0,0 +1,4 @@ + +U + +MyCategory 2B \Ï)Cf¦RC{ÔWC 2B \Ï)Cf¦RC{ÔWC 2B \Ï)Cf¦RC{ÔWCB(èÌ“^– \ No newline at end of file diff --git a/xml_converter/integration_tests/test_cases/proto_and_xml_input_allow_duplicates/output_xml/xml_file.xml b/xml_converter/integration_tests/test_cases/proto_and_xml_input_allow_duplicates/output_xml/xml_file.xml new file mode 100644 index 00000000..3638e1e3 --- /dev/null +++ b/xml_converter/integration_tests/test_cases/proto_and_xml_input_allow_duplicates/output_xml/xml_file.xml @@ -0,0 +1,10 @@ + + + + + + + + + + diff --git a/xml_converter/integration_tests/test_cases/proto_and_xml_input_allow_duplicates/testcase.yaml b/xml_converter/integration_tests/test_cases/proto_and_xml_input_allow_duplicates/testcase.yaml new file mode 100644 index 00000000..348087c5 --- /dev/null +++ b/xml_converter/integration_tests/test_cases/proto_and_xml_input_allow_duplicates/testcase.yaml @@ -0,0 +1,8 @@ +input_paths: + "pack": "xml" + "pack2": "proto" + "pack3": "xml" +expected_stdout: | +expected_stderr: | +expected_returncode: 0 +allow_duplicates: true \ No newline at end of file diff --git a/xml_converter/integration_tests/test_cases/proto_and_xml_input_no_duplicates/input/pack/xml_file.xml b/xml_converter/integration_tests/test_cases/proto_and_xml_input_no_duplicates/input/pack/xml_file.xml new file mode 100644 index 00000000..5cf29494 --- /dev/null +++ b/xml_converter/integration_tests/test_cases/proto_and_xml_input_no_duplicates/input/pack/xml_file.xml @@ -0,0 +1,8 @@ + + + + + + + + diff --git a/xml_converter/integration_tests/test_cases/proto_and_xml_input_no_duplicates/input/pack2/markers.bin b/xml_converter/integration_tests/test_cases/proto_and_xml_input_no_duplicates/input/pack2/markers.bin new file mode 100644 index 00000000..50078921 --- /dev/null +++ b/xml_converter/integration_tests/test_cases/proto_and_xml_input_no_duplicates/input/pack2/markers.bin @@ -0,0 +1,4 @@ + ++ + +MyCategory 2B \Ï)Cf¦RC{ÔWCB(èÌ“^– \ No newline at end of file diff --git a/xml_converter/integration_tests/test_cases/proto_and_xml_input_no_duplicates/input/pack3/xml_file.xml b/xml_converter/integration_tests/test_cases/proto_and_xml_input_no_duplicates/input/pack3/xml_file.xml new file mode 100644 index 00000000..5cf29494 --- /dev/null +++ b/xml_converter/integration_tests/test_cases/proto_and_xml_input_no_duplicates/input/pack3/xml_file.xml @@ -0,0 +1,8 @@ + + + + + + + + diff --git a/xml_converter/integration_tests/test_cases/proto_and_xml_input_no_duplicates/testcase.yaml b/xml_converter/integration_tests/test_cases/proto_and_xml_input_no_duplicates/testcase.yaml new file mode 100644 index 00000000..9f5d0f93 --- /dev/null +++ b/xml_converter/integration_tests/test_cases/proto_and_xml_input_no_duplicates/testcase.yaml @@ -0,0 +1,16 @@ +input_paths: + "pack": "xml" + "pack2": "proto" + "pack3": "xml" +expected_stdout: | + Did not write due to duplicates in categories. + This commonly occurs when attempting to read the same pack multiple times or when separate packs coincidentally have the same name. + Please remove one of the packs or edit the name of the packs' top level category before running the program again. + If you want to bypass this stop, use '--allow-duplicates'. + The following top level categories were found in more than one pack: + "mycategory" in files: + pack/xml_file.xml + pack2/markers.bin + pack3/xml_file.xml +expected_stderr: | +expected_returncode: 0 \ No newline at end of file diff --git a/xml_converter/src/packaging_protobin.cpp b/xml_converter/src/packaging_protobin.cpp index f4b636f5..00179a41 100644 --- a/xml_converter/src/packaging_protobin.cpp +++ b/xml_converter/src/packaging_protobin.cpp @@ -23,7 +23,7 @@ using namespace std; //////////////////////////////////////////////////////////////////////////////// // //////////////////////////////////////////////////////////////////////////////// -void parse_guildpoint_categories( +string parse_guildpoint_categories( string full_category_name, ::guildpoint::Category proto_category, map* marker_categories, @@ -57,16 +57,18 @@ void parse_guildpoint_categories( for (int i = 0; i < proto_category.children_size(); i++) { parse_guildpoint_categories(full_category_name + ".", proto_category.children(i), &(this_category->children), parsed_pois, state); } + return category_name; } //////////////////////////////////////////////////////////////////////////////// // //////////////////////////////////////////////////////////////////////////////// -void read_protobuf_file(string proto_filepath, const string marker_pack_root_directory, map* marker_categories, vector* parsed_pois) { +set read_protobuf_file(string proto_filepath, const string marker_pack_root_directory, map* marker_categories, vector* parsed_pois) { fstream infile; guildpoint::Guildpoint proto_message; ProtoReaderState state; state.marker_pack_root_directory = marker_pack_root_directory; + set category_names; infile.open(proto_filepath, ios::in | ios::binary); proto_message.ParseFromIstream(&infile); @@ -74,8 +76,9 @@ void read_protobuf_file(string proto_filepath, const string marker_pack_root_dir state.textures = proto_message.textures(); for (int i = 0; i < proto_message.category_size(); i++) { - parse_guildpoint_categories("", proto_message.category(i), marker_categories, parsed_pois, &state); + category_names.insert(parse_guildpoint_categories("", proto_message.category(i), marker_categories, parsed_pois, &state)); } + return category_names; } //////////////////////////////////////////////////////////////////////////////// diff --git a/xml_converter/src/packaging_protobin.hpp b/xml_converter/src/packaging_protobin.hpp index 9cdc27a4..6b66cfa5 100644 --- a/xml_converter/src/packaging_protobin.hpp +++ b/xml_converter/src/packaging_protobin.hpp @@ -2,6 +2,7 @@ #include #include +#include #include #include @@ -10,7 +11,7 @@ #include "parseable.hpp" #include "string_hierarchy.hpp" -void read_protobuf_file( +std::set read_protobuf_file( std::string proto_filepath, const std::string marker_pack_root_directory, std::map* marker_categories, diff --git a/xml_converter/src/packaging_xml.cpp b/xml_converter/src/packaging_xml.cpp index b2806d37..6675c2d3 100644 --- a/xml_converter/src/packaging_xml.cpp +++ b/xml_converter/src/packaging_xml.cpp @@ -1,5 +1,6 @@ #include "packaging_xml.hpp" +#include #include #include "hash_helpers.hpp" @@ -16,33 +17,44 @@ using namespace std; //////////////////////////////////////////////////////////////////////////////// unsigned int UNKNOWN_CATEGORY_COUNTER = 0; -void parse_marker_categories( +OptionalString parse_marker_categories( rapidxml::xml_node<>* node, map* marker_categories, Category* parent, vector* errors, XMLReaderState* state, int depth = 0) { + OptionalString name = { + "", // value + false, // is_null + }; if (get_node_name(node) == "MarkerCategory") { - string name; - rapidxml::xml_attribute<>* name_attribute = find_attribute(node, "name"); if (name_attribute == 0) { // TODO: This error should really be for the entire node not just the name errors->push_back(new XMLNodeNameError("Category attribute 'name' is missing so it cannot be properly referenced", node)); // TODO: Maybe fall back on display name slugification. - name = "UNKNOWN_CATEGORY_" + to_string(UNKNOWN_CATEGORY_COUNTER); + name = { + "UNKNOWN_CATEGORY_" + to_string(UNKNOWN_CATEGORY_COUNTER), + false, + }; UNKNOWN_CATEGORY_COUNTER++; } else { - name = lowercase(get_attribute_value(name_attribute)); + name = { + lowercase(get_attribute_value(name_attribute)), + false, + }; } - if (name == "") { + if (name.value == "") { errors->push_back(new XMLNodeNameError("Category attribute 'name' is an empty string so it cannot be properly referenced", node)); // TODO: Maybe fall back on display name slugification. - name = "UNKNOWN_CATEGORY_" + to_string(UNKNOWN_CATEGORY_COUNTER); + name = { + "UNKNOWN_CATEGORY_" + to_string(UNKNOWN_CATEGORY_COUNTER), + false, + }; UNKNOWN_CATEGORY_COUNTER++; } @@ -50,9 +62,9 @@ void parse_marker_categories( Category* category; // Create and initialize a new category if this one does not exist - auto existing_category_search = marker_categories->find(name); + auto existing_category_search = marker_categories->find(name.value); if (existing_category_search == marker_categories->end()) { - category = &(*marker_categories)[name]; + category = &(*marker_categories)[name.value]; category->parent = parent; } else { @@ -68,7 +80,7 @@ void parse_marker_categories( // based on the hashes of its name and its parents names. if (!category->menu_id_is_set) { Hash128 new_id; - new_id.update(name); + new_id.update(name.value); Category* next_node = parent; while (next_node != nullptr) { @@ -82,9 +94,15 @@ void parse_marker_categories( for (rapidxml::xml_node<>* child_node = node->first_node(); child_node; child_node = child_node->next_sibling()) { parse_marker_categories(child_node, &(category->children), category, errors, state, depth + 1); } + return name; } else { errors->push_back(new XMLNodeNameError("Unknown MarkerCategory Tag", node)); + name = { + "", + true, + }; + return name; } } @@ -189,12 +207,13 @@ vector parse_pois(rapidxml::xml_node<>* root_node, map* marker_categories, vector* parsed_pois) { +set parse_xml_file(string xml_filepath, const string marker_pack_root_directory, map* marker_categories, vector* parsed_pois) { vector errors; rapidxml::xml_document<> doc; rapidxml::xml_node<>* root_node; XMLReaderState state; state.marker_pack_root_directory = marker_pack_root_directory; + set category_names; rapidxml::file<> xml_file(xml_filepath.c_str()); doc.parse(xml_file.data(), xml_filepath.c_str()); @@ -210,7 +229,10 @@ void parse_xml_file(string xml_filepath, const string marker_pack_root_directory for (rapidxml::xml_node<>* node = root_node->first_node(); node; node = node->next_sibling()) { if (get_node_name(node) == "MarkerCategory") { - parse_marker_categories(node, marker_categories, nullptr, &errors, &state); + OptionalString name = parse_marker_categories(node, marker_categories, nullptr, &errors, &state); + if (name.is_null == false) { + category_names.insert(name.value); + } } else if (get_node_name(node) == "POIs") { vector temp_vector = parse_pois(node, marker_categories, &errors, &state); @@ -224,6 +246,7 @@ void parse_xml_file(string xml_filepath, const string marker_pack_root_directory for (auto error : errors) { error->print_error(); } + return category_names; } //////////////////////////////////////////////////////////////////////////////// diff --git a/xml_converter/src/packaging_xml.hpp b/xml_converter/src/packaging_xml.hpp index a099d625..6efabdfd 100644 --- a/xml_converter/src/packaging_xml.hpp +++ b/xml_converter/src/packaging_xml.hpp @@ -1,6 +1,7 @@ #pragma once #include +#include #include #include @@ -10,7 +11,7 @@ #include "rapidxml-1.13/rapidxml_utils.hpp" #include "state_structs/xml_reader_state.hpp" -void parse_xml_file( +std::set parse_xml_file( std::string xml_filepath, const std::string marker_pack_root_directory, std::map* marker_categories, diff --git a/xml_converter/src/string_helper.cpp b/xml_converter/src/string_helper.cpp index 3f0056f2..fc498b87 100644 --- a/xml_converter/src/string_helper.cpp +++ b/xml_converter/src/string_helper.cpp @@ -3,6 +3,7 @@ #include #include #include +#include #include #include diff --git a/xml_converter/src/string_helper.hpp b/xml_converter/src/string_helper.hpp index 89fc3f93..81f4d529 100644 --- a/xml_converter/src/string_helper.hpp +++ b/xml_converter/src/string_helper.hpp @@ -2,9 +2,15 @@ #include #include +#include #include #include +struct OptionalString { + std::string value; + bool is_null; +}; + bool matches_any(std::string test, std::initializer_list list); bool normalized_matches_any(std::string test, std::initializer_list list); bool normalized_matches_any(std::string test, std::vector list); diff --git a/xml_converter/src/xml_converter.cpp b/xml_converter/src/xml_converter.cpp index 1d498970..d32d25f4 100644 --- a/xml_converter/src/xml_converter.cpp +++ b/xml_converter/src/xml_converter.cpp @@ -36,6 +36,7 @@ bool filename_comp(string a, string b) { return lowercase(a) < lowercase(b); } +// Searchs for files within a directory with a suffix and returns their relative paths. vector get_files_by_suffix(string directory, string suffix) { vector files; DIR* dir = opendir(directory.c_str()); @@ -49,11 +50,11 @@ vector get_files_by_suffix(string directory, string suffix) { // Default: markerpacks have all xml files in the first directory for (string subfile : subfiles) { cout << subfile << " found in subfolder" << endl; - files.push_back(subfile); + files.push_back(join_file_paths(filename, subfile)); } } else if (has_suffix(filename, suffix)) { - files.push_back(path); + files.push_back(filename); } } } @@ -62,40 +63,62 @@ vector get_files_by_suffix(string directory, string suffix) { return files; } -void read_taco_directory( +map> read_taco_directory( string input_path, map* marker_categories, vector* parsed_pois) { + map> top_level_category_file_locations; if (!filesystem::exists(input_path)) { cout << "Error: " << input_path << " is not an existing directory or file" << endl; } else if (filesystem::is_directory(input_path)) { + string directory_name = filesystem::path(input_path).filename(); vector xml_files = get_files_by_suffix(input_path, ".xml"); for (const string& path : xml_files) { - parse_xml_file(path, input_path, marker_categories, parsed_pois); + set top_level_category_names = parse_xml_file(join_file_paths(input_path, path), input_path, marker_categories, parsed_pois); + string relative_path = join_file_paths(directory_name, path); + for (set::iterator it = top_level_category_names.begin(); it != top_level_category_names.end(); it++) { + top_level_category_file_locations[*it].push_back(relative_path); + } } } else if (filesystem::is_regular_file(input_path)) { - parse_xml_file(input_path, get_base_dir(input_path), marker_categories, parsed_pois); + set top_level_category_names = parse_xml_file(input_path, get_base_dir(input_path), marker_categories, parsed_pois); + string filename = filesystem::path(input_path).filename(); + for (set::iterator it = top_level_category_names.begin(); it != top_level_category_names.end(); it++) { + top_level_category_file_locations[*it].push_back(filename); + } } + return top_level_category_file_locations; } -void read_burrito_directory( +map> read_burrito_directory( string input_path, map* marker_categories, vector* parsed_pois) { + map> top_level_category_file_locations; if (!filesystem::exists(input_path)) { cout << "Error: " << input_path << " is not an existing directory or file" << endl; } else if (filesystem::is_directory(input_path)) { + string directory_name = filesystem::path(input_path).filename(); vector burrito_files = get_files_by_suffix(input_path, ".guildpoint"); for (const string& path : burrito_files) { - read_protobuf_file(path, input_path, marker_categories, parsed_pois); + set top_level_category_names = read_protobuf_file(join_file_paths(input_path, path), input_path, marker_categories, parsed_pois); + string relative_path = join_file_paths(directory_name, path); + for (set::iterator it = top_level_category_names.begin(); it != top_level_category_names.end(); it++) { + top_level_category_file_locations[*it].push_back(relative_path); + } } } else if (filesystem::is_regular_file(input_path)) { - read_protobuf_file(input_path, get_base_dir(input_path), marker_categories, parsed_pois); + set top_level_category_names = read_protobuf_file(input_path, get_base_dir(input_path), marker_categories, parsed_pois); + string filename = filesystem::path(input_path).filename(); + for (set::iterator it = top_level_category_names.begin(); it != top_level_category_names.end(); it++) { + top_level_category_file_locations[*it].push_back(filename); + } } + return top_level_category_file_locations; } void write_taco_directory( @@ -136,7 +159,9 @@ void write_burrito_directory( void process_data( vector input_taco_paths, vector input_guildpoint_paths, - + // If multiple inputs are found to have the same top level categories, + // The program will skip writing to output unless the below is true + bool allow_duplicates, // These will eventually have additional arguments for each output path to // allow for splitting out a single markerpack vector output_taco_paths, @@ -148,16 +173,21 @@ void process_data( // All of the loaded pois and categories vector parsed_pois; map marker_categories; + map>> top_level_category_file_locations_by_pack; + map> duplicate_categories; // Read in all the xml taco markerpacks auto begin = chrono::high_resolution_clock::now(); for (size_t i = 0; i < input_taco_paths.size(); i++) { cout << "Loading taco pack " << input_taco_paths[i] << endl; - read_taco_directory( + map> top_level_category_file_locations = read_taco_directory( input_taco_paths[i], &marker_categories, &parsed_pois); + for (map>::iterator it = top_level_category_file_locations.begin(); it != top_level_category_file_locations.end(); it++) { + top_level_category_file_locations_by_pack[it->first].push_back(it->second); + } } auto end = chrono::high_resolution_clock::now(); auto dur = end - begin; @@ -168,10 +198,39 @@ void process_data( for (size_t i = 0; i < input_guildpoint_paths.size(); i++) { cout << "Loading guildpoint pack " << input_guildpoint_paths[i] << endl; - read_burrito_directory( + map> top_level_category_file_locations = read_burrito_directory( input_guildpoint_paths[i], &marker_categories, &parsed_pois); + for (map>::iterator it = top_level_category_file_locations.begin(); it != top_level_category_file_locations.end(); it++) { + top_level_category_file_locations_by_pack[it->first].push_back(it->second); + } + } + + for (map>>::iterator it = top_level_category_file_locations_by_pack.begin(); it != top_level_category_file_locations_by_pack.end(); it++) { + if (it->second.size() != 1) { + for (size_t i = 0; i < it->second.size(); i++) { + for (size_t j = 0; j < it->second[i].size(); j++) { + duplicate_categories[it->first].insert(it->second[i][j]); + } + } + } + } + if (duplicate_categories.size() > 0 && allow_duplicates == false) { + cout << "Did not write due to duplicates in categories." << endl; + cout << "This commonly occurs when attempting to read the same pack multiple times or when separate packs coincidentally have the same name." << endl; + // TODO: This is the current advice. Further updates could allow other + // options like selective merges or changing category names to be unique + cout << "Please remove one of the packs or edit the name of the packs' top level category before running the program again." << endl; + cout << "If you want to bypass this stop, use '--allow-duplicates'." << endl; + cout << "The following top level categories were found in more than one pack:" << endl; + for (map>::iterator it = duplicate_categories.begin(); it != duplicate_categories.end(); it++) { + cout << " \"" << it->first << "\" in files:" << endl; + for (string str : it->second) { + cout << " " << str << endl; + } + } + return; } // Write all of the xml taco paths @@ -218,12 +277,13 @@ int main(int argc, char* argv[]) { vector output_taco_paths; vector input_guildpoint_paths; vector output_guildpoint_paths; + bool allow_duplicates = false; // Typically "~/.local/share/godot/app_userdata/Burrito/protobins" for // converting from xml markerpacks to internal protobuf files. vector output_split_guildpoint_paths; - vector* arg_target = &input_taco_paths; + vector* arg_target = nullptr; for (int i = 1; i < argc; i++) { if (!strcmp(argv[i], "--input-taco-path")) { @@ -244,8 +304,18 @@ int main(int argc, char* argv[]) { // CLI arg parsing later to properly capture this. arg_target = &output_split_guildpoint_paths; } + else if (!strcmp(argv[i], "--allow-duplicates")) { + allow_duplicates = true; + arg_target = nullptr; + } else { - arg_target->push_back(argv[i]); + if (arg_target != nullptr) { + arg_target->push_back(argv[i]); + } + else { + cout << "Unknown argument " << argv[i] << endl; + return -1; + } } } @@ -262,6 +332,7 @@ int main(int argc, char* argv[]) { process_data( input_taco_paths, input_guildpoint_paths, + allow_duplicates, output_taco_paths, output_guildpoint_paths, output_split_guildpoint_dir);