From 8eb997fe252ec22c074e76e175036d30e117c236 Mon Sep 17 00:00:00 2001 From: Stanislas Daniel Claude Dolcini Date: Sun, 4 Aug 2024 10:57:47 +0200 Subject: [PATCH] ruff format pass --- build.py | 11 +- .../ImportPyrogenesisActor.py | 529 ++++++++++++------ io_scene_pyrogenesis/MaxColladaFixer.py | 49 +- io_scene_pyrogenesis/__init__.py | 10 +- 4 files changed, 395 insertions(+), 204 deletions(-) diff --git a/build.py b/build.py index 8db140b..03605fa 100644 --- a/build.py +++ b/build.py @@ -3,9 +3,10 @@ # SPDX-License-Identifier: GPL-2.0-or-later import os -try: + +try: import tomllib -except ModuleNotFoundError: +except ModuleNotFoundError: import pip._vendor.tomli as tomllib import zipfile @@ -19,11 +20,13 @@ def get_version(): def build_archive(): os.makedirs("dist", exist_ok=True) - with zipfile.ZipFile(os.path.join("dist", "io_scene_pyrogenesis-" + get_version() + ".zip"), mode="w") as archive: + with zipfile.ZipFile( + os.path.join("dist", "io_scene_pyrogenesis-" + get_version() + ".zip"), mode="w" + ) as archive: archive.write("io_scene_pyrogenesis/__init__.py") archive.write("io_scene_pyrogenesis/blender_manifest.toml") archive.write("LICENSE", arcname="io_scene_pyrogenesis/LICENSE") -if __name__ == '__main__': +if __name__ == "__main__": build_archive() diff --git a/io_scene_pyrogenesis/ImportPyrogenesisActor.py b/io_scene_pyrogenesis/ImportPyrogenesisActor.py index c079a6c..2f869a0 100644 --- a/io_scene_pyrogenesis/ImportPyrogenesisActor.py +++ b/io_scene_pyrogenesis/ImportPyrogenesisActor.py @@ -7,40 +7,39 @@ import os from . import MaxColladaFixer + class ImportPyrogenesisActor(bpy.types.Operator, bpy_extras.io_utils.ImportHelper): """Load a Pyrogenesis actor file""" + bl_label = "Import Pyrogenesis Actor" - bl_idname = 'import_pyrogenesis_scene.xml' + bl_idname = "import_pyrogenesis_scene.xml" currentPath = "" - filter_glob: bpy.props.StringProperty( - default="*.xml", - options={'HIDDEN'} - ) # type: ignore + filter_glob: bpy.props.StringProperty(default="*.xml", options={"HIDDEN"}) # type: ignore import_props: bpy.props.BoolProperty( - name='Import props', - description='Whether to include props in the importation.', - default=True - ) # type: ignore + name="Import props", + description="Whether to include props in the importation.", + default=True, + ) # type: ignore import_textures: bpy.props.BoolProperty( - name='Import textures', - description='Whether to include textures in the importation.', - default=True - ) # type: ignore + name="Import textures", + description="Whether to include textures in the importation.", + default=True, + ) # type: ignore import_depth: bpy.props.IntProperty( - name='Import Depth', - description='How much prop depth there should be', - default=-1 - ) # type: ignore + name="Import Depth", + description="How much prop depth there should be", + default=-1, + ) # type: ignore def draw(self, context): layout = self.layout - layout.prop(self, 'import_props') - layout.prop(self, 'import_textures') - layout.prop(self, 'import_depth') + layout.prop(self, "import_props") + layout.prop(self, "import_textures") + layout.prop(self, "import_depth") def execute(self, context): return self.import_pyrogenesis_actor(context) @@ -50,23 +49,27 @@ def find_parent_armature(self, bone): for armature_bone in armature.bones: if bone.name == armature_bone.name: for obj in bpy.data.objects: - if hasattr(obj, 'data') and hasattr(obj.data, 'name') and obj.data.name == armature.name: - return obj + if ( + hasattr(obj, "data") + and hasattr(obj.data, "name") + and obj.data.name == armature.name + ): + return obj return None def set_copy_transform_constraint(self, obj, parent): """Set constraints for props so that they fit their prop point.""" - if(str(type(parent)) == ''): + if str(type(parent)) == "": armature = self.find_parent_armature(parent) - print(obj.name + " -> " + armature.name + " -> " + parent.name) - constraint = obj.constraints.new('COPY_LOCATION') + print(obj.name + " -> " + armature.name + " -> " + parent.name) + constraint = obj.constraints.new("COPY_LOCATION") constraint.show_expanded = False constraint.mute = False constraint.target = armature constraint.subtarget = parent.name - constraint2 = obj.constraints.new('COPY_ROTATION') + constraint2 = obj.constraints.new("COPY_ROTATION") constraint2.show_expanded = False constraint2.mute = False constraint2.target = armature @@ -74,11 +77,11 @@ def set_copy_transform_constraint(self, obj, parent): return print(obj.name + " -> " + parent.name) - constraint = obj.constraints.new('COPY_LOCATION') + constraint = obj.constraints.new("COPY_LOCATION") constraint.show_expanded = False constraint.mute = False constraint.target = parent - constraint2 = obj.constraints.new('COPY_ROTATION') + constraint2 = obj.constraints.new("COPY_ROTATION") constraint2.show_expanded = False constraint2.mute = False constraint2.target = parent @@ -87,77 +90,114 @@ def set_copy_transform_constraint(self, obj, parent): def create_new_material(self, textures, material): mname = None for texture in textures: - if texture.split('|')[0] == 'baseTex': - mname = os.path.basename(texture.split('|')[1]) + if texture.split("|")[0] == "baseTex": + mname = os.path.basename(texture.split("|")[1]) break if mname is None: - mname = os.path.basename(textures[0].split('|')[1]) + mname = os.path.basename(textures[0].split("|")[1]) - if (bpy.data.materials.get(mname) is not None): + if bpy.data.materials.get(mname) is not None: return mname - mat = bpy.data.materials.new(name= mname) + mat = bpy.data.materials.new(name=mname) mat.use_nodes = True bsdf = mat.node_tree.nodes["Principled BSDF"] for texture in textures: - fname = os.path.basename(texture.split('|')[1]) + fname = os.path.basename(texture.split("|")[1]) print(fname) if fname not in bpy.data.images: continue - texImage = mat.node_tree.nodes.new('ShaderNodeTexImage') + texImage = mat.node_tree.nodes.new("ShaderNodeTexImage") texImage.image = bpy.data.images[fname] - if texture.split('|')[0] == 'baseTex': - mat.node_tree.links.new(bsdf.inputs['Base Color'], texImage.outputs['Color']) + if texture.split("|")[0] == "baseTex": + mat.node_tree.links.new( + bsdf.inputs["Base Color"], texImage.outputs["Color"] + ) - if 'player_trans' in material: - color_node = mat.node_tree.nodes.new('ShaderNodeRGB') + if "player_trans" in material: + color_node = mat.node_tree.nodes.new("ShaderNodeRGB") color_node.outputs[0].default_value = (1, 0.213477, 0.0543914, 1) - multiply_node = mat.node_tree.nodes.new('ShaderNodeMixRGB') - multiply_node.blend_type = 'MULTIPLY' - invert_node = mat.node_tree.nodes.new('ShaderNodeInvert') - mat.node_tree.links.new(invert_node.inputs['Color'], texImage.outputs['Alpha']) - mat.node_tree.links.new(multiply_node.inputs[1], texImage.outputs['Color']) - mat.node_tree.links.new(multiply_node.inputs[2], color_node.outputs['Color']) - mat.node_tree.links.new(multiply_node.inputs[0], invert_node.outputs['Color']) - mat.node_tree.links.new(bsdf.inputs['Base Color'], multiply_node.outputs['Color']) - - elif 'basic_trans' in material: - mix_shader_node = mat.node_tree.nodes.new('ShaderNodeMixShader') - transparent_node = mat.node_tree.nodes.new('ShaderNodeBsdfTransparent') - mat.node_tree.links.new(mix_shader_node.inputs[0], texImage.outputs['Alpha']) - mat.node_tree.links.new(mix_shader_node.inputs[2], bsdf.outputs['BSDF']) - mat.node_tree.links.new(mix_shader_node.inputs[1], transparent_node.outputs['BSDF']) + multiply_node = mat.node_tree.nodes.new("ShaderNodeMixRGB") + multiply_node.blend_type = "MULTIPLY" + invert_node = mat.node_tree.nodes.new("ShaderNodeInvert") + mat.node_tree.links.new( + invert_node.inputs["Color"], texImage.outputs["Alpha"] + ) + mat.node_tree.links.new( + multiply_node.inputs[1], texImage.outputs["Color"] + ) + mat.node_tree.links.new( + multiply_node.inputs[2], color_node.outputs["Color"] + ) + mat.node_tree.links.new( + multiply_node.inputs[0], invert_node.outputs["Color"] + ) + mat.node_tree.links.new( + bsdf.inputs["Base Color"], multiply_node.outputs["Color"] + ) + + elif "basic_trans" in material: + mix_shader_node = mat.node_tree.nodes.new("ShaderNodeMixShader") + transparent_node = mat.node_tree.nodes.new( + "ShaderNodeBsdfTransparent" + ) + mat.node_tree.links.new( + mix_shader_node.inputs[0], texImage.outputs["Alpha"] + ) + mat.node_tree.links.new( + mix_shader_node.inputs[2], bsdf.outputs["BSDF"] + ) + mat.node_tree.links.new( + mix_shader_node.inputs[1], transparent_node.outputs["BSDF"] + ) output_node = mat.node_tree.nodes.get("Material Output") - mat.node_tree.links.new(output_node.inputs['Surface'], mix_shader_node.outputs['Shader']) - mat.blend_method = 'CLIP' + mat.node_tree.links.new( + output_node.inputs["Surface"], mix_shader_node.outputs["Shader"] + ) + mat.blend_method = "CLIP" continue - if texture.split('|')[0] == 'normTex': - texImage.image.colorspace_settings.name='Non-Color' - normal_node = mat.node_tree.nodes.new('ShaderNodeNormalMap') - separate_node = mat.node_tree.nodes.new('ShaderNodeSeparateXYZ') - invert_node = mat.node_tree.nodes.new('ShaderNodeInvert') - join_node = mat.node_tree.nodes.new('ShaderNodeCombineXYZ') - - mat.node_tree.links.new(separate_node.inputs['Vector'], texImage.outputs['Color']) - #Direct X normals need to have their Y channel inverted for OpenGL - mat.node_tree.links.new(invert_node.inputs['Color'], separate_node.outputs['Y']) - mat.node_tree.links.new(join_node.inputs['X'], separate_node.outputs['X']) - mat.node_tree.links.new(join_node.inputs['Z'], separate_node.outputs['Z']) - mat.node_tree.links.new(join_node.inputs['Y'], invert_node.outputs['Color']) - mat.node_tree.links.new(normal_node.inputs['Color'], join_node.outputs['Vector']) - mat.node_tree.links.new(bsdf.inputs['Normal'], normal_node.outputs['Normal']) + if texture.split("|")[0] == "normTex": + texImage.image.colorspace_settings.name = "Non-Color" + normal_node = mat.node_tree.nodes.new("ShaderNodeNormalMap") + separate_node = mat.node_tree.nodes.new("ShaderNodeSeparateXYZ") + invert_node = mat.node_tree.nodes.new("ShaderNodeInvert") + join_node = mat.node_tree.nodes.new("ShaderNodeCombineXYZ") + + mat.node_tree.links.new( + separate_node.inputs["Vector"], texImage.outputs["Color"] + ) + # Direct X normals need to have their Y channel inverted for OpenGL + mat.node_tree.links.new( + invert_node.inputs["Color"], separate_node.outputs["Y"] + ) + mat.node_tree.links.new( + join_node.inputs["X"], separate_node.outputs["X"] + ) + mat.node_tree.links.new( + join_node.inputs["Z"], separate_node.outputs["Z"] + ) + mat.node_tree.links.new( + join_node.inputs["Y"], invert_node.outputs["Color"] + ) + mat.node_tree.links.new( + normal_node.inputs["Color"], join_node.outputs["Vector"] + ) + mat.node_tree.links.new( + bsdf.inputs["Normal"], normal_node.outputs["Normal"] + ) continue - - if texture.split('|')[0] == 'specTex': - texImage.image.colorspace_settings.name='Non-Color' - mat.node_tree.links.new(bsdf.inputs['Specular IOR Level'], texImage.outputs['Color']) + if texture.split("|")[0] == "specTex": + texImage.image.colorspace_settings.name = "Non-Color" + mat.node_tree.links.new( + bsdf.inputs["Specular IOR Level"], texImage.outputs["Color"] + ) return mat.name @@ -178,13 +218,17 @@ def assign_material_to_object(self, ob, material_name): def import_pyrogenesis_actor(self, context): import xml.etree.ElementTree as ET - print('loading ' + self.filepath + '...') - self.currentPath = (self.filepath[0:self.filepath.find('actors')]).replace("\\", "/") + print("loading " + self.filepath + "...") + + self.currentPath = (self.filepath[0 : self.filepath.find("actors")]).replace( + "\\", "/" + ) root = ET.parse(self.filepath).getroot() self.parse_actor(root) - return {'FINISHED'} + return {"FINISHED"} + def create_custom_mesh(self, objname, px, py, pz, width, depth): # Define arrays for holding data myvertex = [] @@ -193,19 +237,19 @@ def create_custom_mesh(self, objname, px, py, pz, width, depth): # Create all Vertices # vertex 0 - mypoint = [(-width/2, -depth/2, 0.01)] + mypoint = [(-width / 2, -depth / 2, 0.01)] myvertex.extend(mypoint) # vertex 1 - mypoint = [(width/2, -depth/2, 0.01)] + mypoint = [(width / 2, -depth / 2, 0.01)] myvertex.extend(mypoint) # vertex 2 - mypoint = [(-width/2, depth/2, 0.01)] + mypoint = [(-width / 2, depth / 2, 0.01)] myvertex.extend(mypoint) # vertex 3 - mypoint = [(width/2, depth/2, 0.01)] + mypoint = [(width / 2, depth / 2, 0.01)] myvertex.extend(mypoint) # ------------------------------------- @@ -231,29 +275,35 @@ def create_custom_mesh(self, objname, px, py, pz, width, depth): def get_element_from_variant(self, root, name): import xml.etree.ElementTree as ET + for child in root: if child.tag == name: return child # No mesh was found in this variant. - if 'file' in root.attrib is not None: - variantParent = ET.parse(self.currentPath + 'variants/' + root.attrib['file']).getroot() + if "file" in root.attrib is not None: + variantParent = ET.parse( + self.currentPath + "variants/" + root.attrib["file"] + ).getroot() return self.get_element_from_variant(variantParent, name) return None def get_mesh_from_variant(self, root): - return self.get_element_from_variant(root, 'mesh') + return self.get_element_from_variant(root, "mesh") def get_textures_from_variant(self, root): import xml.etree.ElementTree as ET + child_textures = None for child in root: - if child.tag == 'textures': + if child.tag == "textures": child_textures = child - if 'file' in root.attrib is not None: - variantParent = ET.parse(self.currentPath + 'variants/' + root.attrib['file']).getroot() + if "file" in root.attrib is not None: + variantParent = ET.parse( + self.currentPath + "variants/" + root.attrib["file"] + ).getroot() parent_textures = self.get_textures_from_variant(variantParent) if parent_textures is not None and child_textures is not None: for texture in child_textures: @@ -262,7 +312,6 @@ def get_textures_from_variant(self, root): else: return child_textures - return child_textures def get_props_from_variant(self, root): @@ -270,13 +319,14 @@ def get_props_from_variant(self, root): childProps = None for child in root: - if child.tag == 'props': + if child.tag == "props": childProps = child break - - if 'file' in root.attrib is not None: - variantParent = ET.parse(self.currentPath + 'variants/' + root.attrib['file']).getroot() + if "file" in root.attrib is not None: + variantParent = ET.parse( + self.currentPath + "variants/" + root.attrib["file"] + ).getroot() parentProps = self.get_props_from_variant(variantParent) if parentProps is not None and childProps is not None: for prop in childProps: @@ -287,27 +337,30 @@ def get_props_from_variant(self, root): return childProps - def parse_actor(self, root, proppoint="root", parentprops=[], rootObj=None, propDepth=0): + def parse_actor( + self, root, proppoint="root", parentprops=[], rootObj=None, propDepth=0 + ): import xml.etree.ElementTree as ET import bpy import random import math + meshprops = [] imported_props = [] imported_textures = [] imported_objects = [] material_object = None rootObject = rootObj - material_type = 'default.xml' + material_type = "default.xml" for group in root: - if group.tag == 'material': + if group.tag == "material": material_type = group.text if rootObj is not None: print("Root object is:" + rootObj.name) for group in root: - if group.tag == 'material': + if group.tag == "material": continue if len(group) == 0: @@ -317,40 +370,55 @@ def parse_actor(self, root, proppoint="root", parentprops=[], rootObj=None, prop # If there is more than one group pick one randomly. if len(group) > 1: retries = 0 - while (('frequency' not in variant.attrib or variant.attrib['frequency'] == "0") and retries < len(group)): - variant = group[random.randint(0,len(group) - 1)] + while ( + "frequency" not in variant.attrib + or variant.attrib["frequency"] == "0" + ) and retries < len(group): + variant = group[random.randint(0, len(group) - 1)] retries = retries + 1 - if 'file' in variant.attrib: + if "file" in variant.attrib: present_tags = [child.tag for child in variant] - variantParent = ET.parse(self.currentPath + 'variants/' + variant.attrib['file']).getroot() - if 'mesh' not in present_tags: + variantParent = ET.parse( + self.currentPath + "variants/" + variant.attrib["file"] + ).getroot() + if "mesh" not in present_tags: mesh_child = self.get_mesh_from_variant(variantParent) if mesh_child is not None: variant.append(mesh_child) variant_parent_textures = self.get_textures_from_variant(variantParent) - if 'textures' not in present_tags: + if "textures" not in present_tags: if variant_parent_textures is not None: variant.append(variant_parent_textures) elif variant_parent_textures is not None: - variant_tags = [texture.attrib['name'] for texture in variant.find('textures')] + variant_tags = [ + texture.attrib["name"] for texture in variant.find("textures") + ] for texture in variant_parent_textures: - if texture is not None and texture.attrib['name'] not in variant_tags: - variant.find('textures').append(texture) + if ( + texture is not None + and texture.attrib["name"] not in variant_tags + ): + variant.find("textures").append(texture) variant_parent_props = self.get_props_from_variant(variant) - if 'props' not in present_tags and variant_parent_props is not None: + if "props" not in present_tags and variant_parent_props is not None: variant.append(variant_parent_props) elif variant_parent_props is not None: - variant_tags = [prop.attrib['attachpoint'] for prop in variant.find('props')] + variant_tags = [ + prop.attrib["attachpoint"] for prop in variant.find("props") + ] for prop in variant_parent_props: - if prop is not None and prop.attrib['attachpoint'] not in variant_tags: - variant.find('props').append(prop) + if ( + prop is not None + and prop.attrib["attachpoint"] not in variant_tags + ): + variant.find("props").append(prop) for child in variant: - if(child.tag == 'mesh' or child.tag == 'decal'): + if child.tag == "mesh" or child.tag == "decal": print("=======================================================") print("============== Gathering Mesh =========================") print("=======================================================") @@ -363,68 +431,109 @@ def parse_actor(self, root, proppoint="root", parentprops=[], rootObj=None, prop obj.select_set(False) # Import the new objects if child.tag == "mesh": - mesh_path = self.currentPath + 'meshes/' + child.text + mesh_path = self.currentPath + "meshes/" + child.text try: - fixer = MaxColladaFixer(mesh_path) fixer.execute() - bpy.ops.wm.collada_import(filepath=mesh_path, import_units=True) + bpy.ops.wm.collada_import( + filepath=mesh_path, import_units=True + ) except Exception: - print('Could not load' + mesh_path) + print("Could not load" + mesh_path) else: - bpy.ops.object.select_all(action='DESELECT') - if material_type == 'default.xml' or 'terrain' in material_type: - material_type = 'basic_trans.xml' - - decal = self.create_custom_mesh("Decal", float(child.attrib['offsetx']), float(child.attrib['offsetz']), 0, float(child.attrib['width']), float(child.attrib['depth'])) + bpy.ops.object.select_all(action="DESELECT") + if material_type == "default.xml" or "terrain" in material_type: + material_type = "basic_trans.xml" + + decal = self.create_custom_mesh( + "Decal", + float(child.attrib["offsetx"]), + float(child.attrib["offsetz"]), + 0, + float(child.attrib["width"]), + float(child.attrib["depth"]), + ) decal.select_set(True) bpy.context.view_layer.objects.active = decal - bpy.ops.object.mode_set(mode='EDIT') + bpy.ops.object.mode_set(mode="EDIT") bpy.ops.uv.reset() - bpy.ops.object.mode_set(mode='OBJECT') - decal.rotation_euler = (0,0, math.radians(float(child.attrib['angle']))) - - new_current_objects = [object for object in bpy.context.scene.objects] + bpy.ops.object.mode_set(mode="OBJECT") + decal.rotation_euler = ( + 0, + 0, + math.radians(float(child.attrib["angle"])), + ) + + new_current_objects = [ + object for object in bpy.context.scene.objects + ] # Select those objects - for obj in (set(new_current_objects) - set(prior_objects)): + for obj in set(new_current_objects) - set(prior_objects): obj.select_set(True) - backup = bpy.context.selected_objects.copy() - for b in backup : - if b.data is None or b.data.uv_layers is None or not len(b.data.uv_layers): + backup = bpy.context.selected_objects.copy() + for b in backup: + if ( + b.data is None + or b.data.uv_layers is None + or not len(b.data.uv_layers) + ): continue if len(b.data.uv_layers) > 0: - print("Renaming" + b.data.uv_layers[0].name + " to " + "UVMap") + print( + "Renaming" + b.data.uv_layers[0].name + " to " + "UVMap" + ) b.data.uv_layers[0].name = "UVMap" if len(b.data.uv_layers) > 1: - print("Renaming" + b.data.uv_layers[1].name + " to " + "AOMap") + print( + "Renaming" + b.data.uv_layers[1].name + " to " + "AOMap" + ) b.data.uv_layers[1].name = "AOMap" - # Get those objects imported_objects = bpy.context.selected_objects.copy() - for imported_object in imported_objects: - if imported_object is not None and 'prop.' in imported_object.name: - imported_object.name = imported_object.name.replace("prop.","prop_") - if imported_object.data is not None and 'prop.' in imported_object.data.name: - imported_object.data.name = imported_object.data.name.replace("prop.","prop_") + if ( + imported_object is not None + and "prop." in imported_object.name + ): + imported_object.name = imported_object.name.replace( + "prop.", "prop_" + ) + if ( + imported_object.data is not None + and "prop." in imported_object.data.name + ): + imported_object.data.name = ( + imported_object.data.name.replace("prop.", "prop_") + ) # props are parented so they should follow their root object. if "prop-" in imported_object.name: - imported_object.name = imported_object.name.replace("prop-","prop_") - if imported_object.data is not None and 'prop-' in imported_object.data.name: - imported_object.data.name = imported_object.data.name.replace("prop-","prop_") + imported_object.name = imported_object.name.replace( + "prop-", "prop_" + ) + if ( + imported_object.data is not None + and "prop-" in imported_object.data.name + ): + imported_object.data.name = ( + imported_object.data.name.replace("prop-", "prop_") + ) if "prop_" in imported_object.name: meshprops.append(imported_object) imported_object.select_set(False) - bpy.ops.object.transform_apply(location=True, rotation=True, scale=True) + bpy.ops.object.transform_apply( + location=True, rotation=True, scale=True + ) for obj in backup: obj.select_set(True) - bpy.ops.object.transform_apply(location=False, rotation=False, scale=True) + bpy.ops.object.transform_apply( + location=False, rotation=False, scale=True + ) # Clear old materials for ob in bpy.context.selected_editable_objects: @@ -432,8 +541,10 @@ def parse_actor(self, root, proppoint="root", parentprops=[], rootObj=None, prop for i in range(len(ob.material_slots)): bpy.ops.object.material_slot_remove() - new_current_materials = [material for material in bpy.data.materials] - for material in (set(new_current_materials) - set(prior_materials)): + new_current_materials = [ + material for material in bpy.data.materials + ] + for material in set(new_current_materials) - set(prior_materials): bpy.data.materials.remove(material) print("=======================================================") print("============== Setting Constraints ====================") @@ -441,10 +552,17 @@ def parse_actor(self, root, proppoint="root", parentprops=[], rootObj=None, prop for imported_object in imported_objects: # props are parented so they should follow their root object. - if ('prop-' in imported_object.name or 'prop_' in imported_object.name) and hasattr(imported_object, 'type') and imported_object.type == 'EMPTY': + if ( + ( + "prop-" in imported_object.name + or "prop_" in imported_object.name + ) + and hasattr(imported_object, "type") + and imported_object.type == "EMPTY" + ): continue - if proppoint == 'root' and rootObj is not None: + if proppoint == "root" and rootObj is not None: self.set_copy_transform_constraint(imported_object, rootObj) continue @@ -452,24 +570,40 @@ def parse_actor(self, root, proppoint="root", parentprops=[], rootObj=None, prop for prop in parentprops: if proppoint in prop.name: found = True - self.set_copy_transform_constraint(imported_object, prop) + self.set_copy_transform_constraint( + imported_object, prop + ) break if found: continue - print('' + imported_object.name + ' has no parent prop point named prop_' + proppoint + '. Root object name: ' + (rootObj.name if rootObj is not None else 'Undefined') + '') - - if(child.tag == 'textures' and self.import_textures): + print( + "" + + imported_object.name + + " has no parent prop point named prop_" + + proppoint + + ". Root object name: " + + (rootObj.name if rootObj is not None else "Undefined") + + "" + ) + + if child.tag == "textures" and self.import_textures: print("=======================================================") print("============== Gathering Textures =====================") print("=======================================================") - if(len(child) > 0): + if len(child) > 0: for texture in child: imported_textures.append(texture) - if(child.tag == 'props' and self.import_props and (self.import_depth == -1 or (self.import_depth > propDepth and self.import_depth > 0))): - + if ( + child.tag == "props" + and self.import_props + and ( + self.import_depth == -1 + or (self.import_depth > propDepth and self.import_depth > 0) + ) + ): print("=======================================================") print("============== Gathering Parent Props =================") print("=======================================================") @@ -478,25 +612,31 @@ def parse_actor(self, root, proppoint="root", parentprops=[], rootObj=None, prop if len(finalprops) > 0: rootObject = None for obj in finalprops: - if ('prop-' in obj.name or 'prop_' in obj.name): + if "prop-" in obj.name or "prop_" in obj.name: continue - if hasattr(obj, 'type') and obj.type == 'ARMATURE': - print("=======================================================") - print("============== Gathering Armature Props ===============") - print("=======================================================") + if hasattr(obj, "type") and obj.type == "ARMATURE": + print( + "=======================================================" + ) + print( + "============== Gathering Armature Props ===============" + ) + print( + "=======================================================" + ) for bone in obj.data.bones: - if 'prop.' in bone.name: - bone.name = bone.name.replace('prop.','prop_') - if 'prop-' in bone.name: - bone.name = bone.name.replace('prop-','prop_') - if 'prop_' in bone.name: + if "prop." in bone.name: + bone.name = bone.name.replace("prop.", "prop_") + if "prop-" in bone.name: + bone.name = bone.name.replace("prop-", "prop_") + if "prop_" in bone.name: print(bone.name) finalprops.append(bone) continue - if hasattr(obj, 'type'): + if hasattr(obj, "type"): rootObject = bpy.data.objects[obj.name] finalprops.remove(obj) @@ -508,19 +648,37 @@ def parse_actor(self, root, proppoint="root", parentprops=[], rootObj=None, prop mat_textures = [] for texture in imported_textures: - print("Loading " + texture.attrib['name'] + ": " + self.currentPath + 'textures/skins/' + texture.attrib['file']) - bpy.data.images.load(self.currentPath + 'textures/skins/' + texture.attrib['file'], check_existing=True) - mat_textures.append(texture.attrib['name'] + '|' + self.currentPath + 'textures/skins/' + texture.attrib['file']) + print( + "Loading " + + texture.attrib["name"] + + ": " + + self.currentPath + + "textures/skins/" + + texture.attrib["file"] + ) + bpy.data.images.load( + self.currentPath + "textures/skins/" + texture.attrib["file"], + check_existing=True, + ) + mat_textures.append( + texture.attrib["name"] + + "|" + + self.currentPath + + "textures/skins/" + + texture.attrib["file"] + ) if len(mat_textures): material_object = self.create_new_material(mat_textures, material_type) for obj in imported_objects: - if ('prop-' in obj.name or 'prop_' in obj.name) and not hasattr(obj, 'type'): + if ("prop-" in obj.name or "prop_" in obj.name) and not hasattr( + obj, "type" + ): continue - if hasattr(obj, 'type') and obj.type == 'EMPTY': + if hasattr(obj, "type") and obj.type == "EMPTY": continue - if hasattr(obj, 'type') and obj.type == 'ARMATURE': + if hasattr(obj, "type") and obj.type == "ARMATURE": continue self.assign_material_to_object(obj, material_object) @@ -529,26 +687,39 @@ def parse_actor(self, root, proppoint="root", parentprops=[], rootObj=None, prop print("=======================================================") print("============== Gathering Props ========================") print("=======================================================") - if prop.attrib['actor'] == "": + if prop.attrib["actor"] == "": continue try: - prop_path = self.currentPath + 'actors/' + prop.attrib['actor'] - print('Loading ' + prop_path + '.') + prop_path = self.currentPath + "actors/" + prop.attrib["actor"] + print("Loading " + prop_path + ".") proproot = ET.parse(prop_path).getroot() - propRootObj = self.find_prop_root_object(finalprops, prop.attrib['attachpoint']) - if propRootObj is not None and prop.attrib['attachpoint'] != 'root' and rootObject is None: + propRootObj = self.find_prop_root_object( + finalprops, prop.attrib["attachpoint"] + ) + if ( + propRootObj is not None + and prop.attrib["attachpoint"] != "root" + and rootObject is None + ): rootObject = propRootObj - self.parse_actor(proproot, prop.attrib['attachpoint'], meshprops if finalprops is None or len(finalprops) <= 0 else finalprops, rootObject, propDepth + 1) + self.parse_actor( + proproot, + prop.attrib["attachpoint"], + meshprops + if finalprops is None or len(finalprops) <= 0 + else finalprops, + rootObject, + propDepth + 1, + ) except Exception: - print('Could not load' + mesh_path) - + print("Could not load" + mesh_path) def find_prop_root_object(self, imported_objects, proppoint): for imported_object in imported_objects: - if 'prop_' + proppoint in imported_object.name: + if "prop_" + proppoint in imported_object.name: return imported_object return None diff --git a/io_scene_pyrogenesis/MaxColladaFixer.py b/io_scene_pyrogenesis/MaxColladaFixer.py index e4bbeb7..2721ae9 100644 --- a/io_scene_pyrogenesis/MaxColladaFixer.py +++ b/io_scene_pyrogenesis/MaxColladaFixer.py @@ -2,23 +2,23 @@ # This file is part of 0 A.D. # SPDX-License-Identifier: GPL-2.0-or-later + class MaxColladaFixer: file_path = None - collada_prefix = '{http://www.collada.org/2005/11/COLLADASchema}' + collada_prefix = "{http://www.collada.org/2005/11/COLLADASchema}" def sortchildrenby(self, parent): parent[:] = sorted(parent, key=lambda child: child.tag) - def indent(self, elem, level=0): - i = "\n" + level*" " + i = "\n" + level * " " if len(elem): if not elem.text or not elem.text.strip(): elem.text = i + " " if not elem.tail or not elem.tail.strip(): elem.tail = i for elem in elem: - self.indent(elem, level+1) + self.indent(elem, level + 1) if not elem.tail or not elem.tail.strip(): elem.tail = i else: @@ -39,53 +39,64 @@ def execute(self): for child in root: print("Fixing Collada..." + child.tag) for child in root[:]: - if child.tag == self.collada_prefix + 'library_images': + if child.tag == self.collada_prefix + "library_images": root.remove(child) - element = ET.Element(self.collada_prefix + 'library_images') + element = ET.Element(self.collada_prefix + "library_images") new_elements.append(element) continue - if child.tag == self.collada_prefix + 'library_materials': + if child.tag == self.collada_prefix + "library_materials": root.remove(child) # If there is no material no need to append it. continue - if child.tag == self.collada_prefix + 'library_effects': + if child.tag == self.collada_prefix + "library_effects": root.remove(child) - element = ET.Element(self.collada_prefix + 'library_effects') + element = ET.Element(self.collada_prefix + "library_effects") new_elements.append(element) continue - if child.tag == self.collada_prefix + 'library_visual_scenes': + if child.tag == self.collada_prefix + "library_visual_scenes": for visual_scene in child: for node in visual_scene: for subchild in node: - if subchild.tag == self.collada_prefix + 'instance_geometry': + if ( + subchild.tag + == self.collada_prefix + "instance_geometry" + ): for binding in subchild: - if binding.tag == self.collada_prefix + 'bind_material': + if ( + binding.tag + == self.collada_prefix + "bind_material" + ): subchild.remove(binding) break - if subchild.tag == self.collada_prefix + 'instance_controller': + if ( + subchild.tag + == self.collada_prefix + "instance_controller" + ): for binding in subchild: - if binding.tag == self.collada_prefix + 'bind_material': + if ( + binding.tag + == self.collada_prefix + "bind_material" + ): subchild.remove(binding) break continue - if child.tag == self.collada_prefix + 'asset': + if child.tag == self.collada_prefix + "asset": for property in child: - if property.tag == self.collada_prefix + 'modified': + if property.tag == self.collada_prefix + "modified": property.text = str(date.today()) for element in new_elements: root.append(element) - self.sortchildrenby(root) for child in root: self.sortchildrenby(child) self.indent(root) - tree.write(open(self.file_path, 'wb'), encoding='utf-8') - tree.write(open(self.file_path, 'wb'),encoding='utf-8') + tree.write(open(self.file_path, "wb"), encoding="utf-8") + tree.write(open(self.file_path, "wb"), encoding="utf-8") diff --git a/io_scene_pyrogenesis/__init__.py b/io_scene_pyrogenesis/__init__.py index a04a2cc..90fb5f2 100644 --- a/io_scene_pyrogenesis/__init__.py +++ b/io_scene_pyrogenesis/__init__.py @@ -10,6 +10,7 @@ # Script reloading (if the user calls 'Reload Scripts' from Blender) # + def reload_package(module_dict_main): import importlib from pathlib import Path @@ -26,11 +27,16 @@ def reload_package_recursive(current_dir, module_dict): reload_package_recursive(Path(__file__).parent, module_dict_main) + if "bpy" in locals(): reload_package(locals()) + def menu_func_import(self, context): - self.layout.operator(ImportPyrogenesisActor.bl_idname, text='Pyrogenesis Actor (.xml)') + self.layout.operator( + ImportPyrogenesisActor.bl_idname, text="Pyrogenesis Actor (.xml)" + ) + def register(): # bpy.utils.register_module(__name__) @@ -46,5 +52,5 @@ def unregister(): bpy.types.TOPBAR_MT_file_import.remove(menu_func_import) -if __name__ == '__main__': +if __name__ == "__main__": register()