diff --git a/xml_converter/doc/position/position.md b/xml_converter/doc/position/position.md index 719d8d44..6ddc7514 100644 --- a/xml_converter/doc/position/position.md +++ b/xml_converter/doc/position/position.md @@ -5,29 +5,26 @@ applies_to: ["Icon"] xml_fields: ["Position"] compatability: [TacO, Burrito, BlishHUD] protobuf_field: position +xml_bundled_components: [] +xml_separate_components: ["X Position", "Y Position", "Z Position"] components: - - - name: X Position - type: Float32 - xml_fields: [XPos, PositionX] - protobuf_field: "x" - compatability: [TacO, Burrito, BlishHUD] - - - - name: Y Position - type: Float32 - xml_fields: [YPos, PositionY] - protobuf_field: "y" - compatability: [TacO, Burrito, BlishHUD] - - - - name: Z Position - type: Float32 - xml_fields: [ZPos, PositionZ] - protobuf_field: "z" - compatability: [TacO, Burrito, BlishHUD] - -xml_export: "Children" +- name: X Position + type: Float32 + xml_fields: [XPos, PositionX] + protobuf_field: "x" + compatability: [TacO, Burrito, BlishHUD] + +- name: Y Position + type: Float32 + xml_fields: [YPos, PositionY] + protobuf_field: "y" + compatability: [TacO, Burrito, BlishHUD] + +- name: Z Position + type: Float32 + xml_fields: [ZPos, PositionZ] + protobuf_field: "z" + compatability: [TacO, Burrito, BlishHUD] --- An XYZ location of a point in the game world. diff --git a/xml_converter/doc/rotation/euler_rotation.md b/xml_converter/doc/rotation/euler_rotation.md index 90ea3ff1..e628fd67 100644 --- a/xml_converter/doc/rotation/euler_rotation.md +++ b/xml_converter/doc/rotation/euler_rotation.md @@ -5,28 +5,27 @@ applies_to: ["Icon"] xml_fields: ["Rotate"] compatability: [TacO, Burrito, BlishHUD] protobuf_field: euler_rotation +xml_bundled_components: ['X Rotation', 'Y Rotation', 'Z Rotation'] +xml_separate_components: [] components: - name: X Rotation type: Float32 xml_fields: [RotateX] protobuf_field: "x" compatability: [TacO, Burrito, BlishHUD] - - name: Y Rotation type: Float32 xml_fields: [RotateY] protobuf_field: "y" compatability: [TacO, Burrito, BlishHUD] - - name: Z Rotation type: Float32 xml_fields: [RotateZ] protobuf_field: "z" compatability: [TacO, Burrito, BlishHUD] - -xml_export: "Parent" + --- Euler X Y Z rotation. diff --git a/xml_converter/doc/texture/color.md b/xml_converter/doc/texture/color.md index 8dd31278..eff7724e 100644 --- a/xml_converter/doc/texture/color.md +++ b/xml_converter/doc/texture/color.md @@ -1,11 +1,39 @@ --- name: Color -type: Custom +type: CompoundCustomClass class: Color applies_to: [Icon, Trail] xml_fields: [Color, BHColor] protobuf_field: rgba_color compatability: [TacO, BlishHUD, Burrito] +xml_bundled_components: ['Red', 'Green', 'Blue'] +xml_separate_components: ['Alpha'] +components: +- name: Red + type: Float32 + xml_fields: [Red] + protobuf_field: rgba_color + compatability: [TacO, Burrito, BlishHUD] + +- name: Green + type: Float32 + xml_fields: [Green] + protobuf_field: rgba_color + compatability: [TacO, Burrito, BlishHUD] + +- name: Blue + type: Float32 + xml_fields: [Blue] + protobuf_field: rgba_color + compatability: [TacO, Burrito, BlishHUD] + +- name: Alpha + type: Float32 + xml_fields: [Alpha] + protobuf_field: rgba_color + compatability: [TacO, Burrito, BlishHUD] + + --- A multiplier color to tint the raw albedo texture of a marker of trail texture. (Unclear) Solid white will result in no change, solid black will result in a black texture. diff --git a/xml_converter/generators/code_generator.py b/xml_converter/generators/code_generator.py index 8359d919..c35fc1d1 100644 --- a/xml_converter/generators/code_generator.py +++ b/xml_converter/generators/code_generator.py @@ -15,7 +15,7 @@ properties: type: type: string - enum: [Int32, Fixed32, Float32, String, Boolean, MultiflagValue, Enum, CompoundValue, Custom] + enum: [Int32, Fixed32, Float32, String, Boolean, MultiflagValue, Enum, CompoundValue, Custom, CompoundCustomClass] allOf: ############################# # Int32 Type @@ -131,15 +131,64 @@ const: CompoundValue then: additionalProperties: false - required: [{shared_fields}, xml_export, components] + required: [{shared_fields}, xml_bundled_components, xml_separate_components, components] properties: {shared_field_properties} - xml_export: + xml_bundled_components: + type: array + items: + type: string + xml_separate_components: + type: array + items: + type: string + components: + type: array + items: + type: object + additionalProperties: false + required: [name, type, xml_fields, protobuf_field, compatability] + properties: + name: + type: string + type: + type: string + enum: [Int32, Fixed32, Float32] + xml_fields: + type: array + items: + type: string + pattern: "^[A-Za-z]+$" + protobuf_field: + type: string + pattern: "^[a-z_.]+$" + compatability: + type: array + items: + type: string + enum: [BlishHUD, Burrito, TacO] + ############################# + # CompoundCustomClass Type + ############################# + - if: + properties: + type: + const: CompoundCustomClass + then: + additionalProperties: false + required: [{shared_fields}, xml_bundled_components, xml_separate_components, class] + properties: + {shared_field_properties} + class: type: string - enum: - - Parent - - Parent and Children - - Children + xml_bundled_components: + type: array + items: + type: string + xml_separate_components: + type: array + items: + type: string components: type: array items: @@ -166,7 +215,6 @@ type: string enum: [BlishHUD, Burrito, TacO] - ############################# # Custom Type ############################# @@ -289,12 +337,14 @@ class AttributeVariable: xml_fields: List[str] protobuf_field: str args: List[str] = field(default_factory=list) - default_xml_fields: List[str] = field(default_factory=list) - xml_export: str = "" + default_xml_field: str = "" side_effects: List[str] = field(default_factory=list) - compound_name: Optional[str] = None + xml_bundled_components: List[str] = field(default_factory=list) + attribute_flag_name: Optional[str] = "" + write_to_xml: bool = True is_trigger: bool = False uses_file_path: bool = False + is_component: bool = False XML_ATTRIBUTE_PARSER_DEFAULT_ARGUMENTS: Final[List[str]] = ["attribute", "errors"] @@ -433,16 +483,9 @@ def generate_cpp_variable_data( doc_type: str, ) -> Tuple[List[AttributeVariable], CPPInclude]: - cpp_includes: CPPInclude = CPPInclude() - attribute_name: str = "" + # Type defining the outputs attribute_variables: List[AttributeVariable] = [] - xml_fields: List[str] = [] - default_xml_fields: List[str] = [] - side_effects: List[str] = [] - xml_export: str = "" - args: List[str] = [] - protobuf_field: str = "" - is_trigger: bool = False + cpp_includes: CPPInclude = CPPInclude() cpp_includes.hpp_absolute_includes.add("string") cpp_includes.hpp_absolute_includes.add("vector") @@ -467,21 +510,24 @@ def generate_cpp_variable_data( for filepath, document in sorted(self.data.items()): fieldval = document.metadata - attribute_name = attribute_name_from_markdown_data(fieldval['name']) + attribute_name: str = attribute_name_from_markdown_data(fieldval['name']) if doc_type in fieldval['applies_to']: - xml_fields = [] - default_xml_fields = [] - side_effects = [] - xml_export = "" - args = XML_ATTRIBUTE_PARSER_DEFAULT_ARGUMENTS.copy() + xml_fields: List[str] = [] + side_effects: List[str] = [] + write_to_xml: bool = True + protobuf_field: str = "" + is_trigger: bool = False + default_xml_field: str = "" + + args: List[str] = XML_ATTRIBUTE_PARSER_DEFAULT_ARGUMENTS.copy() if fieldval['type'] in documentation_type_data: cpp_type = documentation_type_data[fieldval['type']]["cpp_type"] class_name = documentation_type_data[fieldval['type']]["class_name"] cpp_includes.cpp_relative_includes.add("attribute/{}.hpp".format(class_name)) - elif fieldval['type'] == "Custom": + elif fieldval['type'] in ["Custom", "CompoundCustomClass"]: cpp_type = fieldval['class'] class_name = insert_delimiter(fieldval['class'], delimiter="_") cpp_includes.hpp_relative_includes.add("attribute/{}.hpp".format(class_name)) @@ -500,7 +546,7 @@ def generate_cpp_variable_data( for x in fieldval['xml_fields']: xml_fields.append(lowercase(x, delimiter="")) - default_xml_fields.append(fieldval['xml_fields'][0]) + default_xml_field = fieldval['xml_fields'][0] if fieldval["protobuf_field"].startswith("trigger"): is_trigger = True @@ -517,30 +563,37 @@ def generate_cpp_variable_data( side_effects.append(attribute_name_from_markdown_data(side_effect)) # Compound Values are unique in that the components have xml fields in addition to the compound variable - if fieldval['type'] == "CompoundValue": - xml_export = fieldval['xml_export'] + if fieldval['type'] in ["CompoundValue", "CompoundCustomClass"]: for component in fieldval['components']: - component_xml_fields = [] - component_default_xml_fields = [] - for item in component['xml_fields']: - if xml_export == "Children": - component_default_xml_fields.append(item) - if xml_export == "Parent": - component_default_xml_fields.append(fieldval["xml_fields"][0]) - component_xml_fields.append(lowercase(item, delimiter="")) + component_xml_fields: List[str] = [] + component_name: str = attribute_name_from_markdown_data(component['name']) + component_default_xml_field: str = "" + for x in component['xml_fields']: + component_xml_fields.append(lowercase(x, delimiter="")) + component_class_name = documentation_type_data[component['type']]["class_name"] + if component['name'] in fieldval['xml_separate_components']: + component_default_xml_field = component['xml_fields'][0] + write_to_xml = True + if component['name'] in fieldval['xml_bundled_components']: + component_default_xml_field = fieldval['xml_fields'][0] + write_to_xml = False component_attribute_variable = AttributeVariable( - attribute_name=lowercase(component['name'], delimiter="_"), + attribute_name=attribute_name + "." + component_name, attribute_type="CompoundValue", cpp_type=doc_type_to_cpp_type[component['type']], - class_name=class_name, + class_name=component_class_name, xml_fields=component_xml_fields, - default_xml_fields=component_default_xml_fields, - xml_export=xml_export, + default_xml_field=component_default_xml_field, protobuf_field=component["protobuf_field"], - compound_name=lowercase(fieldval['name'], delimiter="_"), + attribute_flag_name=attribute_name + "_is_set", + write_to_xml=write_to_xml, + is_component=True, args=args, ) attribute_variables.append(component_attribute_variable) + # If there aren't any components to bundle, we don't want to render the attribute + if fieldval['xml_bundled_components'] == []: + write_to_xml = False attribute_variable = AttributeVariable( attribute_name=attribute_name, @@ -548,11 +601,12 @@ def generate_cpp_variable_data( cpp_type=cpp_type, class_name=class_name, xml_fields=xml_fields, - default_xml_fields=default_xml_fields, - xml_export=xml_export, + default_xml_field=default_xml_field, protobuf_field=protobuf_field, is_trigger=is_trigger, args=args, + write_to_xml=write_to_xml, + attribute_flag_name=attribute_name + "_is_set", side_effects=side_effects, ) attribute_variables.append(attribute_variable) @@ -594,8 +648,9 @@ def write_attribute(self, output_directory: str) -> None: for filepath in attribute_names: attribute_variables = [] - attribute_name = attribute_names[filepath] + xml_bundled_components: List[str] = [] metadata[filepath] = self.data[filepath].metadata + attribute_name = attribute_name_from_markdown_data(metadata[filepath]['name']) if metadata[filepath]["protobuf_field"].startswith("trigger"): is_trigger = True @@ -628,15 +683,17 @@ def write_attribute(self, output_directory: str) -> None: raise ValueError("Unexpected type for component. Look at markdown file {attribute_name}".format( attribute_name=attribute_name )) + component_attribute_name: str = attribute_name_from_markdown_data(component['name']) for item in component['xml_fields']: xml_fields.append(normalize(item)) + if component['name'] in metadata[filepath]['xml_bundled_components']: + xml_bundled_components.append(component_attribute_name) attribute_variable = AttributeVariable( - attribute_name=lowercase(component['name'], delimiter="_"), + attribute_name=component_attribute_name, attribute_type=metadata[filepath]['type'], cpp_type=doc_type_to_cpp_type[component['type']], class_name=attribute_name, xml_fields=xml_fields, - xml_export=metadata[filepath]["xml_export"], protobuf_field=component["protobuf_field"], is_trigger=is_trigger, ) @@ -675,6 +732,7 @@ def write_attribute(self, output_directory: str) -> None: attribute_variables=attribute_variables, class_name=capitalize(attribute_name, delimiter=""), enumerate=enumerate, + xml_bundled_components=xml_bundled_components )) ############################################################################ diff --git a/xml_converter/generators/cpp_templates/class_template.cpp b/xml_converter/generators/cpp_templates/class_template.cpp index b9fa7839..51932b58 100644 --- a/xml_converter/generators/cpp_templates/class_template.cpp +++ b/xml_converter/generators/cpp_templates/class_template.cpp @@ -39,26 +39,14 @@ bool {{cpp_class}}::init_xml_attribute(rapidxml::xml_attribute<>* attribute, vec attributename = normalize(get_attribute_name(attribute)); {% for n, attribute_variable in enumerate(attribute_variables) %} {% for i, value in enumerate(attribute_variable.xml_fields) %} - {% if i == 0 and n == 0: %} - if (attributename == "{{value}}") { - this->{{attribute_variable.attribute_name}} = parse_{{attribute_variable.class_name}}({{", ".join(attribute_variable.args)}}); - this->{{attribute_variable.attribute_name}}_is_set = true; - } - {% elif (attribute_variable.attribute_type == "CompoundValue" and attribute_variable.compound_name != None) %} - else if (attributename == "{{value}}") { - this->{{attribute_variable.compound_name}}.{{attribute_variable.attribute_name}} = parse_float(attribute, errors); - this->{{attribute_variable.compound_name}}_is_set = true; - } - {% else: %} - else if (attributename == "{{value}}") { - this->{{attribute_variable.attribute_name}} = parse_{{attribute_variable.class_name}}({{", ".join(attribute_variable.args)}}); - this->{{attribute_variable.attribute_name}}_is_set = true; - {% for side_effect in attribute_variable.side_effects %} - this->{{side_effect}} = this->{{attribute_variable.class_name}}.side_effect_{{side_effect}}; - this->{{side_effect}}_is_set = true; - {% endfor %} - } - {% endif %} + {{ "if" if i == n == 0 else "else if" }} (attributename == "{{value}}") { + this->{{attribute_variable.attribute_name}} = parse_{{attribute_variable.class_name}}({{", ".join(attribute_variable.args)}}); + this->{{attribute_variable.attribute_flag_name}} = true; + {% for side_effect in attribute_variable.side_effects %} + this->{{side_effect}} = this->{{attribute_variable.class_name}}.side_effect_{{side_effect}}; + this->{{side_effect}}_is_set = true; + {% endfor %} + } {% endfor %} {% endfor %} else { @@ -66,8 +54,7 @@ bool {{cpp_class}}::init_xml_attribute(rapidxml::xml_attribute<>* attribute, vec } return true; } - -{%- if attributes_of_type_marker_category %} +{% if attributes_of_type_marker_category %} bool {{cpp_class}}::validate_attributes_of_type_marker_category() { {% for attribute in attributes_of_type_marker_category %} @@ -81,25 +68,9 @@ vector {{cpp_class}}::as_xml() const { vector xml_node_contents; xml_node_contents.push_back("<{{xml_class_name}} "); {% for attribute_variable in attribute_variables %} - {% if (attribute_variable.attribute_type == "CompoundValue") %} - {% if (attribute_variable.xml_export == "Children" and attribute_variable.compound_name != None) %} - if (this->{{attribute_variable.compound_name}}_is_set) { - xml_node_contents.push_back(" {{attribute_variable.default_xml_fields[0]}}=\"" + to_string(this->{{attribute_variable.compound_name}}.{{attribute_variable.attribute_name}}) + "\""); - } - {% elif (attribute_variable.xml_export == "Parent" and attribute_variable.compound_name == None)%} - if (this->{{attribute_variable.attribute_name}}_is_set) { - xml_node_contents.push_back(" {{attribute_variable.default_xml_fields[0]}}=\"" + stringify_{{attribute_variable.class_name}}(this->{{attribute_variable.attribute_name}}) + "\""); - } - {% elif (attribute_variable.xml_export == "Parent and Children")%} - {% for value in attribute_variable.xml_fields %} - if (this->{{attribute_variable.attribute_name}}_is_set) { - xml_node_contents.push_back(" {{value}}=\"" + stringify_{{attribute_variable.class_name}}(this->{{attribute_variable.attribute_name}}) + "\""); - {% endfor %} - } - {% endif %} - {% else: %} - if (this->{{attribute_variable.attribute_name}}_is_set) { - xml_node_contents.push_back(" {{attribute_variable.default_xml_fields[0]}}=\"" + stringify_{{attribute_variable.class_name}}(this->{{attribute_variable.attribute_name}}) + "\""); + {% if attribute_variable.write_to_xml == true %} + if (this->{{attribute_variable.attribute_flag_name}}) { + xml_node_contents.push_back(" {{attribute_variable.default_xml_field}}=\"" + stringify_{{attribute_variable.class_name}}(this->{{attribute_variable.attribute_name}}) + "\""); } {% endif %} {% endfor %} @@ -116,7 +87,7 @@ vector {{cpp_class}}::as_xml() const { } xml_node_contents.push_back("\n"); - {% else: %} + {% else %} xml_node_contents.push_back("/>"); {% endif %} return xml_node_contents; @@ -128,43 +99,44 @@ waypoint::{{cpp_class}} {{cpp_class}}::as_protobuf() const { waypoint::Trigger* trigger = nullptr; {% endif %} {% for attribute_variable in attribute_variables %} - {% if (attribute_variable.is_trigger == true)%} - {% if (attribute_variable.attribute_type == "Custom")%} - if (this->{{attribute_variable.attribute_name}}_is_set) { - if (trigger == nullptr) { - trigger = new waypoint::Trigger(); + {% if attribute_variable.is_component == false %} + {% if (attribute_variable.is_trigger == true)%} + {% if (attribute_variable.attribute_type == "Custom")%} + if (this->{{attribute_variable.attribute_flag_name}}) { + if (trigger == nullptr) { + trigger = new waypoint::Trigger(); + } + trigger->set_allocated_{{attribute_variable.protobuf_field}}(to_proto_{{attribute_variable.class_name}}(this->{{attribute_variable.attribute_name}})); } - trigger->set_allocated_{{attribute_variable.protobuf_field}}(to_proto_{{attribute_variable.class_name}}(this->{{attribute_variable.attribute_name}})); - } - {% elif (attribute_variable.attribute_type == "Enum")%} - if (this->{{attribute_variable.attribute_name}}_is_set) { - if (trigger == nullptr) { - trigger = new waypoint::Trigger(); + {% elif (attribute_variable.attribute_type == "Enum")%} + if (this->{{attribute_variable.attribute_flag_name}}) { + if (trigger == nullptr) { + trigger = new waypoint::Trigger(); + } + trigger->set_{{attribute_variable.protobuf_field}}(to_proto_{{attribute_variable.class_name}}(this->{{attribute_variable.attribute_name}})); } - trigger->set_{{attribute_variable.protobuf_field}}(to_proto_{{attribute_variable.class_name}}(this->{{attribute_variable.attribute_name}})); - } - {% else: %} - if (this->{{attribute_variable.attribute_name}}_is_set) { - if (trigger == nullptr) { - trigger = new waypoint::Trigger(); + {% else: %} + if (this->{{attribute_variable.attribute_flag_name}}) { + if (trigger == nullptr) { + trigger = new waypoint::Trigger(); + } + trigger->set_{{attribute_variable.protobuf_field}}(this->{{attribute_variable.attribute_name}}); } - trigger->set_{{attribute_variable.protobuf_field}}(this->{{attribute_variable.attribute_name}}); - } - {% endif %} - {% else: %} - {% if (attribute_variable.attribute_type == "Enum")%} - if (this->{{attribute_variable.attribute_name}}_is_set) { - proto_{{cpp_class_header}}.set_{{attribute_variable.protobuf_field}}(to_proto_{{attribute_variable.class_name}}(this->{{attribute_variable.attribute_name}})); - } - {% elif (attribute_variable.attribute_type in ["MultiflagValue", "CompoundValue", "Custom"]) and attribute_variable.compound_name == None%} - if (this->{{attribute_variable.attribute_name}}_is_set) { - proto_{{cpp_class_header}}.set_allocated_{{attribute_variable.protobuf_field}}(to_proto_{{attribute_variable.class_name}}(this->{{attribute_variable.attribute_name}})); - } - {% elif (attribute_variable.compound_name != None)%} + {% endif %} {% else: %} - if (this->{{attribute_variable.attribute_name}}_is_set) { - proto_{{cpp_class_header}}.set_{{attribute_variable.protobuf_field}}(this->{{attribute_variable.attribute_name}}); - } + {% if (attribute_variable.attribute_type == "Enum")%} + if (this->{{attribute_variable.attribute_flag_name}}) { + proto_{{cpp_class_header}}.set_{{attribute_variable.protobuf_field}}(to_proto_{{attribute_variable.class_name}}(this->{{attribute_variable.attribute_name}})); + } + {% elif (attribute_variable.attribute_type in ["MultiflagValue", "CompoundValue", "Custom", "CompoundCustomClass"])%} + if (this->{{attribute_variable.attribute_flag_name}}) { + proto_{{cpp_class_header}}.set_allocated_{{attribute_variable.protobuf_field}}(to_proto_{{attribute_variable.class_name}}(this->{{attribute_variable.attribute_name}})); + } + {% else: %} + if (this->{{attribute_variable.attribute_flag_name}}) { + proto_{{cpp_class_header}}.set_{{attribute_variable.protobuf_field}}(this->{{attribute_variable.attribute_name}}); + } + {% endif %} {% endif %} {% endif %} {% endfor %} @@ -187,50 +159,51 @@ void {{cpp_class}}::parse_protobuf(waypoint::{{cpp_class}} proto_{{cpp_class_hea waypoint::Trigger trigger = proto_{{cpp_class_header}}.trigger(); {% endif %} {% for attribute_variable in attribute_variables %} - {% if (attribute_variable.is_trigger == true) %} - {% if (attribute_variable.attribute_type == "Custom") %} - if (trigger.has_{{attribute_variable.protobuf_field}}()) { - this->{{attribute_variable.attribute_name}} = from_proto_{{attribute_variable.class_name}}(trigger.{{attribute_variable.protobuf_field}}()); - this->{{attribute_variable.attribute_name}}_is_set = true; - } - {% elif attribute_variable.class_name == "string" %} - if (trigger.{{attribute_variable.protobuf_field}}() != "") { - this->{{attribute_variable.attribute_name}} = trigger.{{attribute_variable.protobuf_field}}(); - this->{{attribute_variable.attribute_name}}_is_set = true; - } - {% elif (attribute_variable.attribute_type == "Enum") %} - if (trigger.{{attribute_variable.protobuf_field}}() != 0) { - this->{{attribute_variable.attribute_name}} = from_proto_{{attribute_variable.class_name}}(trigger.{{attribute_variable.protobuf_field}}()); - this->{{attribute_variable.attribute_name}}_is_set = true; - } - {% else: %} - if (trigger.{{attribute_variable.protobuf_field}}() != 0) { - this->{{attribute_variable.attribute_name}} = trigger.{{attribute_variable.protobuf_field}}(); - this->{{attribute_variable.attribute_name}}_is_set = true; - } - {% endif %} - {% else: %} - {% if (attribute_variable.attribute_type == "Enum") %} - if (proto_{{cpp_class_header}}.{{attribute_variable.protobuf_field}}() != 0) { - this->{{attribute_variable.attribute_name}} = from_proto_{{attribute_variable.class_name}}(proto_{{cpp_class_header}}.{{attribute_variable.protobuf_field}}()); - this->{{attribute_variable.attribute_name}}_is_set = true; - } - {% elif (attribute_variable.attribute_type in ["MultiflagValue", "CompoundValue", "Custom"]) and attribute_variable.compound_name == None%} - if (proto_{{cpp_class_header}}.has_{{attribute_variable.protobuf_field}}()) { - this->{{attribute_variable.attribute_name}} = from_proto_{{attribute_variable.class_name}}(proto_{{cpp_class_header}}.{{attribute_variable.protobuf_field}}()); - this->{{attribute_variable.attribute_name}}_is_set = true; - } - {% elif (attribute_variable.compound_name != None) %} - {% elif (attribute_variable.class_name == "string") %} - if (proto_{{cpp_class_header}}.{{attribute_variable.protobuf_field}}() != "") { - this->{{attribute_variable.attribute_name}} = proto_{{cpp_class_header}}.{{attribute_variable.protobuf_field}}(); - this->{{attribute_variable.attribute_name}}_is_set = true; - } + {% if attribute_variable.is_component == false %} + {% if (attribute_variable.is_trigger == true) %} + {% if (attribute_variable.attribute_type == "Custom") %} + if (trigger.has_{{attribute_variable.protobuf_field}}()) { + this->{{attribute_variable.attribute_name}} = from_proto_{{attribute_variable.class_name}}(trigger.{{attribute_variable.protobuf_field}}()); + this->{{attribute_variable.attribute_flag_name}} = true; + } + {% elif attribute_variable.class_name == "string" %} + if (trigger.{{attribute_variable.protobuf_field}}() != "") { + this->{{attribute_variable.attribute_name}} = trigger.{{attribute_variable.protobuf_field}}(); + this->{{attribute_variable.attribute_flag_name}} = true; + } + {% elif (attribute_variable.attribute_type == "Enum") %} + if (trigger.{{attribute_variable.protobuf_field}}() != 0) { + this->{{attribute_variable.attribute_name}} = from_proto_{{attribute_variable.class_name}}(trigger.{{attribute_variable.protobuf_field}}()); + this->{{attribute_variable.attribute_flag_name}} = true; + } + {% else: %} + if (trigger.{{attribute_variable.protobuf_field}}() != 0) { + this->{{attribute_variable.attribute_name}} = trigger.{{attribute_variable.protobuf_field}}(); + this->{{attribute_variable.attribute_flag_name}} = true; + } + {% endif %} {% else: %} - if (proto_{{cpp_class_header}}.{{attribute_variable.protobuf_field}}() != 0) { - this->{{attribute_variable.attribute_name}} = proto_{{cpp_class_header}}.{{attribute_variable.protobuf_field}}(); - this->{{attribute_variable.attribute_name}}_is_set = true; - } + {% if (attribute_variable.attribute_type == "Enum") %} + if (proto_{{cpp_class_header}}.{{attribute_variable.protobuf_field}}() != 0) { + this->{{attribute_variable.attribute_name}} = from_proto_{{attribute_variable.class_name}}(proto_{{cpp_class_header}}.{{attribute_variable.protobuf_field}}()); + this->{{attribute_variable.attribute_flag_name}} = true; + } + {% elif (attribute_variable.attribute_type in ["MultiflagValue", "CompoundValue", "Custom", "CompoundCustomClass"])%} + if (proto_{{cpp_class_header}}.has_{{attribute_variable.protobuf_field}}()) { + this->{{attribute_variable.attribute_name}} = from_proto_{{attribute_variable.class_name}}(proto_{{cpp_class_header}}.{{attribute_variable.protobuf_field}}()); + this->{{attribute_variable.attribute_flag_name}} = true; + } + {% elif (attribute_variable.class_name == "string") %} + if (proto_{{cpp_class_header}}.{{attribute_variable.protobuf_field}}() != "") { + this->{{attribute_variable.attribute_name}} = proto_{{cpp_class_header}}.{{attribute_variable.protobuf_field}}(); + this->{{attribute_variable.attribute_flag_name}} = true; + } + {% else: %} + if (proto_{{cpp_class_header}}.{{attribute_variable.protobuf_field}}() != 0) { + this->{{attribute_variable.attribute_name}} = proto_{{cpp_class_header}}.{{attribute_variable.protobuf_field}}(); + this->{{attribute_variable.attribute_flag_name}} = true; + } + {% endif %} {% endif %} {% endif %} {% endfor %} diff --git a/xml_converter/generators/cpp_templates/class_template.hpp b/xml_converter/generators/cpp_templates/class_template.hpp index 7574f46a..19d7aa26 100644 --- a/xml_converter/generators/cpp_templates/class_template.hpp +++ b/xml_converter/generators/cpp_templates/class_template.hpp @@ -15,13 +15,13 @@ class {{cpp_class}} : public Parseable { public: {% for attribute_variable in attribute_variables: %} - {% if attribute_variable.compound_name == None: %} + {% if attribute_variable.is_component == false: %} {{attribute_variable.cpp_type}} {{attribute_variable.attribute_name}}; {% endif %} {% endfor %} {% for attribute_variable in attribute_variables: %} - {% if attribute_variable.compound_name == None: %} - bool {{attribute_variable.attribute_name}}_is_set = false; + {% if attribute_variable.is_component == false: %} + bool {{attribute_variable.attribute_flag_name}} = false; {% endif %} {% endfor %} {% if cpp_class == "Category": %} diff --git a/xml_converter/generators/cpp_templates/compoundvalue.cpp b/xml_converter/generators/cpp_templates/compoundvalue.cpp index eb5ab4c6..3480fe65 100644 --- a/xml_converter/generators/cpp_templates/compoundvalue.cpp +++ b/xml_converter/generators/cpp_templates/compoundvalue.cpp @@ -22,19 +22,22 @@ using namespace std; compound_values = split(get_attribute_value(input), ","); if (compound_values.size() == {{ attribute_variables|length }}) { {% for n, attribute_variable in enumerate(attribute_variables) %} - {{attribute_name}}.{{attribute_variables[n].attribute_name}} = std::stof(compound_values[{{n}}]); + {{attribute_name}}.{{attribute_variable.attribute_name}} = std::stof(compound_values[{{n}}]); {% endfor %} } return {{attribute_name}}; } -{% if attribute_variables[0].xml_export == "Parent" %} +{% if xml_bundled_components != [] %} + string stringify_{{attribute_name}}({{class_name}} attribute_value) { string output; {% for n, attribute_variable in enumerate(attribute_variables) %} - {% if n == 0: %} - output = to_string(attribute_value.{{attribute_variables[n].attribute_name}}); - {% else %} - output = output + "," + to_string(attribute_value.{{attribute_variables[n].attribute_name}}); + {% if attribute_variable.attribute_name in xml_bundled_components %} + {% if n == 0: %} + output = to_string(attribute_value.{{attribute_variable.attribute_name}}); + {% else %} + output = output + "," + to_string(attribute_value.{{attribute_variable.attribute_name}}); + {% endif %} {% endif %} {% endfor %} return output; diff --git a/xml_converter/proto/waypoint.proto b/xml_converter/proto/waypoint.proto index 1e62199e..33545ca2 100644 --- a/xml_converter/proto/waypoint.proto +++ b/xml_converter/proto/waypoint.proto @@ -122,7 +122,7 @@ message Trigger { Category action_hide_category = 12; Category action_show_category = 13; Category action_toggle_category = 14; - ResetBehavior reset_behavior= 15; + ResetBehavior reset_behavior = 15; } message GUID { diff --git a/xml_converter/src/attribute/color.cpp b/xml_converter/src/attribute/color.cpp index 5b93d9b2..24636522 100644 --- a/xml_converter/src/attribute/color.cpp +++ b/xml_converter/src/attribute/color.cpp @@ -2,8 +2,10 @@ #include +#include #include -#include +#include +#include #include #include @@ -13,16 +15,73 @@ using namespace std; +//////////////////////////////////////////////////////////////////////////////// +// int_to_float // float_to_int +// +// Helper functions to convert the value of colors from one type to another. +// Also serves to make sure the values stay within the bounds. +//////////////////////////////////////////////////////////////////////////////// +float convert_color_channel_int_to_float(int input) { + if (input > 255) { + input = 255; + } + if (input < 0) { + input = 0; + } + float output = static_cast(input) / 255.0f; + return output; +} + +int convert_color_channel_float_to_int(float input) { + if (input > 1.0) { + input = 1.0; + } + if (input < 0) { + input = 0; + } + int output = static_cast(input * 255); + return output; +} + //////////////////////////////////////////////////////////////////////////////// // parse_color // // Parses a Color from the value of a rapidxml::xml_attribute. -// TODO(#98): Color should be saved in a better format then the raw hex string. -// TODO(#129): Compound Value XML Export //////////////////////////////////////////////////////////////////////////////// -Color parse_color(rapidxml::xml_attribute<>* input, vector*) { +Color parse_color(rapidxml::xml_attribute<>* input, vector* errors) { Color color; - color.hex = get_attribute_value(input); + std::string input_string = get_attribute_value(input); + std::string hex_string; + + if (input_string.size() > 0 && input_string[0] == '#') { + hex_string = input_string.substr(1); + } + else { + hex_string = input_string; + } + + std::regex hex_pattern("^([A-Fa-f0-9]+)"); + + if (std::regex_match(hex_string, hex_pattern)) { + // Extract the R, G, B, and A values from the Hex string + if (hex_string.size() == 6 || hex_string.size() == 8) { + color.red = convert_color_channel_int_to_float(std::stoi(hex_string.substr(0, 2), nullptr, 16)); + color.green = convert_color_channel_int_to_float(std::stoi(hex_string.substr(2, 2), nullptr, 16)); + color.blue = convert_color_channel_int_to_float(std::stoi(hex_string.substr(4, 2), nullptr, 16)); + if (hex_string.size() == 8) { + color.alpha = convert_color_channel_int_to_float(std::stoi(hex_string.substr(6, 2), nullptr, 16)); + } + else { + color.alpha = 1.0; + } + } + else { + errors->push_back(new XMLAttributeValueError("Found a hex color value that was not 6 or 8 characters", input)); + } + } + else { + errors->push_back(new XMLAttributeValueError("Found a color value not in hex format", input)); + } return color; } @@ -32,7 +91,20 @@ Color parse_color(rapidxml::xml_attribute<>* input, vector*) { // Converts a Color into a stringy value so it can be saved to xml. //////////////////////////////////////////////////////////////////////////////// string stringify_color(Color attribute_value) { - return attribute_value.hex; + std::stringstream stream; + std::string hex_string = "#"; + + stream << std::hex << convert_color_channel_float_to_int(attribute_value.red); + hex_string += stream.str(); + + stream << std::hex << convert_color_channel_float_to_int(attribute_value.green); + hex_string += stream.str(); + + stream << std::hex << convert_color_channel_float_to_int(attribute_value.blue); + hex_string += stream.str(); + + std::string rgb = hex_string; + return rgb; } //////////////////////////////////////////////////////////////////////////////// @@ -41,14 +113,16 @@ string stringify_color(Color attribute_value) { // Converts a Color into a proto message //////////////////////////////////////////////////////////////////////////////// waypoint::RGBAColor* to_proto_color(Color attribute_value) { - string hex = attribute_value.hex; - waypoint::RGBAColor* color = new waypoint::RGBAColor; - // Adding default values until TODO #98 - int r = 255; - int g = 255; - int b = 255; - int a = 255; - uint32_t rgba = ((r & 0xff) << 24) + ((g & 0xff) << 16) + ((b & 0xff) << 8) + (a & 0xff); + waypoint::RGBAColor* color = new waypoint::RGBAColor(); + // The default RGB in burrito will be 000000 (i.e. black) + // Default value of alpha in Burrito is 1.0 (i.e. 255) + int int_alpha = 255; + // If alpha (float) is not the default value, convert to int + if (attribute_value.alpha != 0) { + int_alpha = convert_color_channel_float_to_int(attribute_value.alpha); + } + + uint32_t rgba = ((convert_color_channel_float_to_int(attribute_value.red) & 0xff) << 24) + ((convert_color_channel_float_to_int(attribute_value.green) & 0xff) << 16) + ((convert_color_channel_float_to_int(attribute_value.blue) & 0xff) << 8) + (int_alpha & 0xff); color->set_rgba_color(rgba); return color; } @@ -61,11 +135,12 @@ waypoint::RGBAColor* to_proto_color(Color attribute_value) { Color from_proto_color(waypoint::RGBAColor attribute_value) { Color color; std::stringstream stream; - stream << std::hex << attribute_value.rgba_color(); - std::string rgba = stream.str(); + uint32_t rgba = attribute_value.rgba_color(); + + color.red = convert_color_channel_int_to_float((rgba >> 24) & 0xff); + color.green = convert_color_channel_int_to_float((rgba >> 16) & 0xff); + color.blue = convert_color_channel_int_to_float((rgba >> 8) & 0xff); + color.alpha = convert_color_channel_int_to_float(rgba & 0xff); - color.hex = rgba.substr(0, 6); - // Adding default values until TODO #98 - color.alpha = 1.0; return color; } diff --git a/xml_converter/src/attribute/color.hpp b/xml_converter/src/attribute/color.hpp index 7f5f4fab..564e7307 100644 --- a/xml_converter/src/attribute/color.hpp +++ b/xml_converter/src/attribute/color.hpp @@ -12,7 +12,9 @@ class RGBAColor; class Color { public: - std::string hex; + float red; + float green; + float blue; float alpha; }; diff --git a/xml_converter/src/attribute/euler_rotation_gen.cpp b/xml_converter/src/attribute/euler_rotation_gen.cpp index f960aee7..fcc17686 100644 --- a/xml_converter/src/attribute/euler_rotation_gen.cpp +++ b/xml_converter/src/attribute/euler_rotation_gen.cpp @@ -27,6 +27,7 @@ EulerRotation parse_euler_rotation(rapidxml::xml_attribute<>* input, vector* attribute, vector Category::as_xml() const { vector xml_node_contents; xml_node_contents.push_back("* attribute, vectorcolor = parse_color(attribute, errors); this->color_is_set = true; } + else if (attributename == "alpha") { + this->color.alpha = parse_float(attribute, errors); + this->color_is_set = true; + } + else if (attributename == "blue") { + this->color.blue = parse_float(attribute, errors); + this->color_is_set = true; + } + else if (attributename == "green") { + this->color.green = parse_float(attribute, errors); + this->color_is_set = true; + } + else if (attributename == "red") { + this->color.red = parse_float(attribute, errors); + this->color_is_set = true; + } else if (attributename == "copy") { this->copy_clipboard = parse_string(attribute, errors); this->copy_clipboard_is_set = true; @@ -102,6 +118,18 @@ bool Icon::init_xml_attribute(rapidxml::xml_attribute<>* attribute, vectoreuler_rotation = parse_euler_rotation(attribute, errors); this->euler_rotation_is_set = true; } + else if (attributename == "rotatex") { + this->euler_rotation.x_rotation = parse_float(attribute, errors); + this->euler_rotation_is_set = true; + } + else if (attributename == "rotatey") { + this->euler_rotation.y_rotation = parse_float(attribute, errors); + this->euler_rotation_is_set = true; + } + else if (attributename == "rotatez") { + this->euler_rotation.z_rotation = parse_float(attribute, errors); + this->euler_rotation_is_set = true; + } else if (attributename == "festival") { this->festival_filter = parse_festival_filter(attribute, errors); this->festival_filter_is_set = true; @@ -170,6 +198,30 @@ bool Icon::init_xml_attribute(rapidxml::xml_attribute<>* attribute, vectorposition = parse_position(attribute, errors); this->position_is_set = true; } + else if (attributename == "xpos") { + this->position.x_position = parse_float(attribute, errors); + this->position_is_set = true; + } + else if (attributename == "positionx") { + this->position.x_position = parse_float(attribute, errors); + this->position_is_set = true; + } + else if (attributename == "ypos") { + this->position.y_position = parse_float(attribute, errors); + this->position_is_set = true; + } + else if (attributename == "positiony") { + this->position.y_position = parse_float(attribute, errors); + this->position_is_set = true; + } + else if (attributename == "zpos") { + this->position.z_position = parse_float(attribute, errors); + this->position_is_set = true; + } + else if (attributename == "positionz") { + this->position.z_position = parse_float(attribute, errors); + this->position_is_set = true; + } else if (attributename == "profession") { this->profession_filter = parse_profession_filter(attribute, errors); this->profession_filter_is_set = true; @@ -258,47 +310,12 @@ bool Icon::init_xml_attribute(rapidxml::xml_attribute<>* attribute, vectortrigger_range = parse_float(attribute, errors); this->trigger_range_is_set = true; } - else if (attributename == "xpos") { - this->position.x_position = parse_float(attribute, errors); - this->position_is_set = true; - } - else if (attributename == "positionx") { - this->position.x_position = parse_float(attribute, errors); - this->position_is_set = true; - } - else if (attributename == "rotatex") { - this->euler_rotation.x_rotation = parse_float(attribute, errors); - this->euler_rotation_is_set = true; - } - else if (attributename == "ypos") { - this->position.y_position = parse_float(attribute, errors); - this->position_is_set = true; - } - else if (attributename == "positiony") { - this->position.y_position = parse_float(attribute, errors); - this->position_is_set = true; - } - else if (attributename == "rotatey") { - this->euler_rotation.y_rotation = parse_float(attribute, errors); - this->euler_rotation_is_set = true; - } - else if (attributename == "zpos") { - this->position.z_position = parse_float(attribute, errors); - this->position_is_set = true; - } - else if (attributename == "positionz") { - this->position.z_position = parse_float(attribute, errors); - this->position_is_set = true; - } - else if (attributename == "rotatez") { - this->euler_rotation.z_rotation = parse_float(attribute, errors); - this->euler_rotation_is_set = true; - } else { return false; } return true; } + bool Icon::validate_attributes_of_type_marker_category() { // TODO: validate "category" // TODO: validate "hide_category" @@ -337,6 +354,9 @@ vector Icon::as_xml() const { if (this->color_is_set) { xml_node_contents.push_back(" Color=\"" + stringify_color(this->color) + "\""); } + if (this->color_is_set) { + xml_node_contents.push_back(" Alpha=\"" + stringify_float(this->color.alpha) + "\""); + } if (this->copy_clipboard_is_set) { xml_node_contents.push_back(" Copy=\"" + stringify_string(this->copy_clipboard) + "\""); } @@ -352,9 +372,6 @@ vector Icon::as_xml() const { if (this->distance_fade_start_is_set) { xml_node_contents.push_back(" FadeNear=\"" + stringify_float(this->distance_fade_start) + "\""); } - if (this->euler_rotation_is_set) { - xml_node_contents.push_back(" Rotate=\"" + stringify_euler_rotation(this->euler_rotation) + "\""); - } if (this->festival_filter_is_set) { xml_node_contents.push_back(" Festival=\"" + stringify_festival_filter(this->festival_filter) + "\""); } @@ -400,6 +417,15 @@ vector Icon::as_xml() const { if (this->mount_filter_is_set) { xml_node_contents.push_back(" Mount=\"" + stringify_mount_filter(this->mount_filter) + "\""); } + if (this->position_is_set) { + xml_node_contents.push_back(" XPos=\"" + stringify_float(this->position.x_position) + "\""); + } + if (this->position_is_set) { + xml_node_contents.push_back(" YPos=\"" + stringify_float(this->position.y_position) + "\""); + } + if (this->position_is_set) { + xml_node_contents.push_back(" ZPos=\"" + stringify_float(this->position.z_position) + "\""); + } if (this->profession_filter_is_set) { xml_node_contents.push_back(" Profession=\"" + stringify_profession_filter(this->profession_filter) + "\""); } @@ -448,15 +474,6 @@ vector Icon::as_xml() const { if (this->trigger_range_is_set) { xml_node_contents.push_back(" TriggerRange=\"" + stringify_float(this->trigger_range) + "\""); } - if (this->position_is_set) { - xml_node_contents.push_back(" XPos=\"" + to_string(this->position.x_position) + "\""); - } - if (this->position_is_set) { - xml_node_contents.push_back(" YPos=\"" + to_string(this->position.y_position) + "\""); - } - if (this->position_is_set) { - xml_node_contents.push_back(" ZPos=\"" + to_string(this->position.z_position) + "\""); - } xml_node_contents.push_back("/>"); return xml_node_contents; } diff --git a/xml_converter/src/trail_gen.cpp b/xml_converter/src/trail_gen.cpp index 57676fb4..e2491b5d 100644 --- a/xml_converter/src/trail_gen.cpp +++ b/xml_converter/src/trail_gen.cpp @@ -58,6 +58,22 @@ bool Trail::init_xml_attribute(rapidxml::xml_attribute<>* attribute, vectorcolor = parse_color(attribute, errors); this->color_is_set = true; } + else if (attributename == "alpha") { + this->color.alpha = parse_float(attribute, errors); + this->color_is_set = true; + } + else if (attributename == "blue") { + this->color.blue = parse_float(attribute, errors); + this->color_is_set = true; + } + else if (attributename == "green") { + this->color.green = parse_float(attribute, errors); + this->color_is_set = true; + } + else if (attributename == "red") { + this->color.red = parse_float(attribute, errors); + this->color_is_set = true; + } else if (attributename == "cull") { this->cull_chirality = parse_cull_chirality(attribute, errors); this->cull_chirality_is_set = true; @@ -173,6 +189,7 @@ bool Trail::init_xml_attribute(rapidxml::xml_attribute<>* attribute, vector Trail::as_xml() const { if (this->color_is_set) { xml_node_contents.push_back(" Color=\"" + stringify_color(this->color) + "\""); } + if (this->color_is_set) { + xml_node_contents.push_back(" Alpha=\"" + stringify_float(this->color.alpha) + "\""); + } if (this->cull_chirality_is_set) { xml_node_contents.push_back(" Cull=\"" + stringify_cull_chirality(this->cull_chirality) + "\""); }