One-click consistent Blender files for all Synty packs!
import bpy
import os
from mathutils import Matrix

def import_characters():
    # Deselect all
    bpy.ops.object.select_all(action='DESELECT')

    # Highlight the 'Characters' collection - https://blender.stackexchange.com/a/248563
    bpy.context.view_layer.active_layer_collection = \
        bpy.context.view_layer.layer_collection.children['Characters']

    # Find our character FBX's - https://blender.stackexchange.com/a/253543
    folder = bpy.path.abspath("//Character_Files/Unity_Version_Mechanim")
    fbxs = [f for f in os.listdir(folder) if f.endswith(".fbx")]

    # Import them
    for fbx in fbxs:
        bpy.ops.import_scene.fbx(
            filepath=os.path.join(folder, fbx),
            use_anim=False,
            ignore_leaf_bones=True,
            force_connect_children=True,
            automatic_bone_orientation=True,
        )

    collection = bpy.data.collections["Characters"]

    # Loop through Characters
    first_armature = None
    for obj in collection.objects:
        # Save the first armature object
        if first_armature == None and obj.type == 'ARMATURE':
            first_armature = obj
            continue

        if obj.type == 'MESH':
            # Always use non-duplicate version of material
            obj.active_material = bpy.data.materials[
                obj.active_material.name.split('.')[0]
            ]

            # Rename Meshes to be the same as their parent MeshObjects
            obj.data.name = obj.name

            if first_armature != None and obj.modifiers and obj.modifiers[0].type == 'ARMATURE':
                # Set all mesh Armature modifiers to the first armature object
                obj.modifiers[0].object = first_armature
            # Make our first armature the object parent
            obj.parent = first_armature

    # Deselect all
    bpy.ops.object.select_all(action='DESELECT')

    # Select unnecessary armatures
    first_armature = None
    for obj in collection.objects:
        if obj.type == 'ARMATURE':
            if first_armature == None:
                first_armature = obj
            else:
                obj.select_set(True)

    # Delete them
    bpy.ops.object.delete()

    first_armature.name = "Armature"

    # Apply location, rotation, scale to deltas
    for obj in collection.all_objects:
        if obj.name != 'Armature':
            mat = obj.matrix_local
            obj.data.transform(mat)
            obj.matrix_local = Matrix()
        else:
            obj.delta_rotation_euler.rotate(obj.rotation_euler)
            obj.rotation_euler = (0, 0, 0)
            obj.delta_scale = obj.scale
            obj.scale = (1, 1, 1)


def import_buildings():
    # Deselect all
    bpy.ops.object.select_all(action='DESELECT')

    # Highlight the 'Characters' collection - https://blender.stackexchange.com/a/248563
    bpy.context.view_layer.active_layer_collection = \
        bpy.context.view_layer.layer_collection.children['Buildings']

    # Find our character FBX's - https://blender.stackexchange.com/a/253543
    folder = bpy.path.abspath("//FBX/")
    fbxs = [f for f in os.listdir(folder) \
        if f.endswith(".fbx") and f.startswith("SM_Bld_")
    ]

    collection = bpy.data.collections["Buildings"]

    # Import them
    for fbx in fbxs:
        bpy.ops.import_scene.fbx(
            filepath=os.path.join(folder, fbx),
            use_anim=False,
            ignore_leaf_bones=True,
            force_connect_children=True,
            automatic_bone_orientation=True,
        )

    for obj in collection.objects:
        if obj.type == 'MESH':
            # Always use non-duplicate version of material
            obj.active_material = bpy.data.materials[
                obj.active_material.name.split('.')[0]
            ]

            # Rename Meshes to be the same as their parent MeshObjects
            obj.data.name = obj.name


def import_environments():
    # Deselect all
    bpy.ops.object.select_all(action='DESELECT')

    # Highlight the 'Characters' collection - https://blender.stackexchange.com/a/248563
    bpy.context.view_layer.active_layer_collection = \
        bpy.context.view_layer.layer_collection.children['Environments']

    # Find our character FBX's - https://blender.stackexchange.com/a/253543
    folder = bpy.path.abspath("//FBX")
    fbxs = [f for f in os.listdir(folder) \
        if f.endswith(".fbx") and f.startswith("SM_Env_")
    ]

    collection = bpy.data.collections["Environments"]

    # Import them
    for fbx in fbxs:
        bpy.ops.import_scene.fbx(
            filepath=os.path.join(folder, fbx),
            use_anim=False,
            ignore_leaf_bones=True,
            force_connect_children=True,
            automatic_bone_orientation=True,
        )

    for obj in collection.objects:
        if obj.type == 'MESH':
            for material_slot in obj.material_slots:
                # Always use non-duplicate version of material
                material_slot.material = bpy.data.materials[
                    material_slot.material.name.split('.')[0]
                ]

#                if material_slot.material.name in ['blinn283', 'blinn284', 'blinn285', 'lambert2']:
#                    material_slot.material = bpy.data.materials["lambert14"]

            # Rename Meshes to be the same as their parent MeshObjects
            obj.data.name = obj.name


def import_props():
    # Deselect all
    bpy.ops.object.select_all(action='DESELECT')

    # Highlight the 'Characters' collection - https://blender.stackexchange.com/a/248563
    bpy.context.view_layer.active_layer_collection = \
        bpy.context.view_layer.layer_collection.children['Props']

    # Find our character FBX's - https://blender.stackexchange.com/a/253543
    folder = bpy.path.abspath("//FBX")
    fbxs = [f for f in os.listdir(folder) \
        if f.endswith(".fbx") and (f.startswith("SM_Prop_") or f.startswith('SM_Item_'))
    ]

    collection = bpy.data.collections["Props"]

    # Import them
    for fbx in fbxs:
        bpy.ops.import_scene.fbx(
            filepath=os.path.join(folder, fbx),
            use_anim=False,
            ignore_leaf_bones=True,
            force_connect_children=True,
            automatic_bone_orientation=True,
        )

    for obj in collection.objects:
        if obj.type == 'MESH':
            for material_slot in obj.material_slots:
                # Always use non-duplicate version of material
                material_slot.material = bpy.data.materials[
                    material_slot.material.name.split('.')[0]
                ]

#                if material_slot.material.name in ['blinn283', 'lambert2']:
#                    material_slot.material = bpy.data.materials["lambert14"]

            # Rename Meshes to be the same as their parent MeshObjects
            obj.data.name = obj.name


def import_weapons():
    # Deselect all
    bpy.ops.object.select_all(action='DESELECT')

    # Highlight the 'Characters' collection - https://blender.stackexchange.com/a/248563
    bpy.context.view_layer.active_layer_collection = \
        bpy.context.view_layer.layer_collection.children['Weapons']

    # Find our character FBX's - https://blender.stackexchange.com/a/253543
    folder = bpy.path.abspath("//FBX")
    fbxs = [f for f in os.listdir(folder) \
        if f.endswith(".fbx") and f.startswith("SM_Wep_")
    ]

    collection = bpy.data.collections["Weapons"]

    # Import them
    for fbx in fbxs:
        bpy.ops.import_scene.fbx(
            filepath=os.path.join(folder, fbx),
            use_anim=False,
            ignore_leaf_bones=True,
            force_connect_children=True,
            automatic_bone_orientation=True,
        )

    for obj in collection.objects:
        if obj.type == 'MESH':
            for material_slot in obj.material_slots:
                # Always use non-duplicate version of material
                material_slot.material = bpy.data.materials[
                    material_slot.material.name.split('.')[0]
                ]

#                if material_slot.material.name in ['blinn283', 'lambert2']:
#                    material_slot.material = bpy.data.materials["lambert14"]

            # Rename Meshes to be the same as their parent MeshObjects
            obj.data.name = obj.name


def fix_materials():
    # Textures pointing to the wrong directory. Fix that
    # https://blender.stackexchange.com/a/280804
    for image in bpy.data.images.values():
        filename = os.path.basename(image.filepath)
        if image.source == "FILE":
            if filename in ["Characters_White.png", "Characters_Black.png"]:
                # Make absolute
                image.filepath = bpy.path.abspath(
                    "//Textures/" + filename
                )
            elif filename in ["Texture_01.psd"]:
                image.filepath = bpy.path.abspath(
                    "//Textures/PolyAdventureTexture_01.png"
                )

    for material in bpy.data.materials:
        if material.name in ['Black', 'White']:
            material.name = 'POLYGONAdventure_' + material.name

            # https://blender.stackexchange.com/a/129014
            bsdf = material.node_tree.nodes["Principled BSDF"]
            bsdf.inputs["Metallic"].default_value = 0.0
            bsdf.inputs["Specular"].default_value = 0.5
            bsdf.inputs["Roughness"].default_value = 0.5
        elif material.name in ['blinn265']:
            material.name = 'POLYGONAdventure_Base'

            # https://blender.stackexchange.com/a/129014
            bsdf = material.node_tree.nodes["Principled BSDF"]
            bsdf.inputs["Metallic"].default_value = 0.0
            bsdf.inputs["Specular"].default_value = 0.5
            bsdf.inputs["Roughness"].default_value = 0.5



def cleanup():
    bpy.ops.object.select_all(action='DESELECT')

    # Apply rotation, scale
    for obj in bpy.data.objects:
        # Skip the 'Characters' collection. Things mess up if we apply those.
        if obj.name != 'Armature' or (obj.parent and obj.parent.name != 'Armature'):
            obj.select_set(True)
    bpy.ops.object.transform_apply(scale=True, rotation=True)

    # Removed orphaned data
    for block in bpy.data.meshes:
        if block.users == 0:
            bpy.data.meshes.remove(block)

    for block in bpy.data.materials:
        if block.users == 0:
            bpy.data.materials.remove(block)

    for block in bpy.data.textures:
        if block.users == 0:
            bpy.data.textures.remove(block)

    for block in bpy.data.images:
        if block.users == 0:
            bpy.data.images.remove(block)


import_characters()
import_buildings()
import_environments()
import_props()
import_weapons()
fix_materials()
cleanup()
POLYGON_Adventure.py
Flynsarmy/synty-in-blender
import bpy
import os

def import_characters():
    # Deselect all
    bpy.ops.object.select_all(action='DESELECT')

    # Highlight the 'Characters' collection - https://blender.stackexchange.com/a/248563
    bpy.context.view_layer.active_layer_collection = \
        bpy.context.view_layer.layer_collection.children['Characters']

    # Find our character FBX's - https://blender.stackexchange.com/a/253543
    folder = bpy.path.abspath("//SourceFiles/Chr")
    fbxs = [f for f in os.listdir(folder) if f.endswith(".fbx") and f.startswith("SK_Chr_ZombieBoss_")]

    # Import them
    for fbx in fbxs:
        bpy.ops.import_scene.fbx(
            filepath=os.path.join(folder, fbx),
            use_anim=False,
            ignore_leaf_bones=True,
            force_connect_children=True,
            automatic_bone_orientation=True,
        )

    # Loop through Characters
    first_armature = None
    collection = bpy.data.collections["Characters"]
    for obj in collection.objects:
        # Save the first armature object
        if first_armature == None and obj.type == 'ARMATURE':
            first_armature = obj
            continue

        if first_armature != None and obj.type == 'MESH' and obj.modifiers[0].type == 'ARMATURE':
            # Set all mesh Armature modifiers to the first armature object
            obj.modifiers[0].object = first_armature
            # Make our first armature the object parent
            obj.parent = first_armature

            # Add missing texture node to the material
            texture_path = bpy.path.abspath("//SourceFiles\\Textures\\PolygonZombieBoss_Texture_01_A.png")
            for material_slot in obj.material_slots:
                material = material_slot.material

                # https://blender.stackexchange.com/a/129014
                bsdf = material.node_tree.nodes["Principled BSDF"]
                tex_image = material.node_tree.nodes.new('ShaderNodeTexImage')
                tex_image.image = bpy.data.images.load(texture_path)
                material.node_tree.links.new(bsdf.inputs['Base Color'], tex_image.outputs['Color'])

    # Deselect all
    bpy.ops.object.select_all(action='DESELECT')

    # Select unnecessary armatures
    first_armature = None
    for obj in collection.objects:
        if obj.type == 'ARMATURE':
            if first_armature == None:
                first_armature = obj
            else:
                obj.select_set(True)

    # Delete them
    bpy.ops.object.delete()

    bpy.context.view_layer.objects.active = first_armature

    # Remove IK bones
    bpy.ops.object.mode_set(mode='EDIT')
    # Remove the IK bones
    for bone in first_armature.data.edit_bones:
        if bone.name.startswith("ik_"):
            first_armature.data.edit_bones.remove(bone)
    bpy.ops.object.mode_set(mode='OBJECT')

    # Apply rotation, scale
    for obj in collection.objects:
        obj.select_set(True)
    bpy.ops.object.transform_apply(scale=True, rotation=True)

    first_armature.name = "Characters"


import_characters()

POLYGON_BossZombies.py
Flynsarmy/synty-in-blender
## IMPORTANT! Some files in Polygon_City_SourceFiles/SourceFiles/FBX/*.fbx are in ASCII
## format and need conversion. Use Autodesk FBX Converter 2013 to convert them.
## Put the converted files in a 'FBX 2013' subfolder like so:
## Polygon_City_SourceFiles/SourceFiles/FBX/FBX 2013/*.fbx
## Here are the files that need conversion:
## - SM_Bld_Station_01.fbx
## - SM_Env_Flower_01.fbx

import bpy
import os
import mathutils

def import_characters():
    # Deselect all
    bpy.ops.object.select_all(action='DESELECT')

    # Highlight the 'Characters' collection - https://blender.stackexchange.com/a/248563
    bpy.context.view_layer.active_layer_collection = \
        bpy.context.view_layer.layer_collection.children['Characters']

    # Find our character FBX's - https://blender.stackexchange.com/a/253543
    folder = bpy.path.abspath("//Polygon_City_SourceFiles/SourceFiles/Characters")
    fbxs = [f for f in os.listdir(folder) if f.endswith(".fbx")]

    # Import them
    for fbx in fbxs:
        bpy.ops.import_scene.fbx(
            filepath=os.path.join(folder, fbx),
            use_anim=False,
            ignore_leaf_bones=True,
            force_connect_children=True,
            automatic_bone_orientation=True,
        )

    collection = bpy.data.collections["Characters"]

    # Loop through Characters
    first_armature = None
    for obj in collection.objects:
        # Save the first armature object
        if first_armature == None and obj.type == 'ARMATURE':
            first_armature = obj
            continue

        if obj.type == 'MESH':
            # Always use non-duplicate version of material
            obj.active_material = bpy.data.materials[
                obj
                    .active_material.name
                    .split('.')[0]
            ]

            # Rename Meshes to be the same as their parent MeshObjects
            obj.data.name = obj.name

            if first_armature != None and obj.modifiers and obj.modifiers[0].type == 'ARMATURE':
                # Set all mesh Armature modifiers to the first armature object
                obj.modifiers[0].object = first_armature
                # Make our first armature the object parent
                obj.parent = first_armature

    # Deselect all
    bpy.ops.object.select_all(action='DESELECT')

    # Select unnecessary armatures
    first_armature = None
    for obj in collection.objects:
        if obj.type == 'ARMATURE':
            if first_armature == None:
                first_armature = obj
            else:
                obj.select_set(True)

    # Delete them
    bpy.ops.object.delete()

    first_armature.name = "Armature"


def import_buildings():
    # Deselect all
    bpy.ops.object.select_all(action='DESELECT')

    # Highlight the 'Characters' collection - https://blender.stackexchange.com/a/248563
    bpy.context.view_layer.active_layer_collection = \
        bpy.context.view_layer.layer_collection.children['Buildings']

    # Find our character FBX's - https://blender.stackexchange.com/a/253543
    folder = bpy.path.abspath("//Polygon_City_SourceFiles/SourceFiles/FBX/")
    fbxs = [f for f in os.listdir(folder) \
        if f.endswith(".fbx") and f.startswith("SM_Bld_") and f not in ["SM_Bld_Station_01.fbx"]
    ]

    collection = bpy.data.collections["Buildings"]

    # Import them
    for fbx in fbxs:
        bpy.ops.import_scene.fbx(
            filepath=os.path.join(folder, fbx),
            use_anim=False,
            ignore_leaf_bones=True,
            force_connect_children=True,
            automatic_bone_orientation=True,
        )
    # Import the converted file
    bpy.ops.import_scene.fbx(
        filepath=bpy.path.abspath("//Polygon_City_SourceFiles/SourceFiles/FBX/FBX 2013/SM_Bld_Station_01.fbx"),
        use_anim=False,
        ignore_leaf_bones=True,
        force_connect_children=True,
        automatic_bone_orientation=True,
    )

    for obj in collection.objects:
        if obj.type == 'MESH':
            # Always use non-duplicate version of material
            obj.active_material = bpy.data.materials[
                obj
                    .active_material.name
                    .split('.')[0]
            ]

            # Fix scaling
            if obj.scale.x < 1.0:
                obj.scale *= 100

            # Use the same material as the characters
            for material_slot in obj.material_slots:
                if material_slot.material.name in ['blinn283', 'blinn284', 'blinn285']:
                    material_slot.material = bpy.data.materials["lambert14"]


            # Rename Meshes to be the same as their parent MeshObjects
            obj.data.name = obj.name


def import_environments():
    # Deselect all
    bpy.ops.object.select_all(action='DESELECT')

    # Highlight the 'Characters' collection - https://blender.stackexchange.com/a/248563
    bpy.context.view_layer.active_layer_collection = \
        bpy.context.view_layer.layer_collection.children['Environments']

    # Find our character FBX's - https://blender.stackexchange.com/a/253543
    folder = bpy.path.abspath("//Polygon_City_SourceFiles/SourceFiles/FBX")
    fbxs = [f for f in os.listdir(folder) \
        if f.endswith(".fbx") and f.startswith("SM_Env_") and f not in ["SM_Env_Flower_01.fbx"]
    ]

    collection = bpy.data.collections["Environments"]

    # Import them
    for fbx in fbxs:
        bpy.ops.import_scene.fbx(
            filepath=os.path.join(folder, fbx),
            use_anim=False,
            ignore_leaf_bones=True,
            force_connect_children=True,
            automatic_bone_orientation=True,
        )
    # Import the converted file
    bpy.ops.import_scene.fbx(
        filepath=bpy.path.abspath("//Polygon_City_SourceFiles/SourceFiles/FBX/FBX 2013/SM_Env_Flower_01.fbx"),
        use_anim=False,
        ignore_leaf_bones=True,
        force_connect_children=True,
        automatic_bone_orientation=True,
    )

    for obj in collection.objects:
        if obj.type == 'MESH':
            for material_slot in obj.material_slots:
                # Always use non-duplicate version of material
                material_slot.material = bpy.data.materials[
                    material_slot.material.name.split('.')[0]
                ]

                if material_slot.material.name in ['blinn283', 'blinn284', 'blinn285', 'lambert2']:
                    material_slot.material = bpy.data.materials["lambert14"]

            # Rename Meshes to be the same as their parent MeshObjects
            obj.data.name = obj.name


def import_props():
    # Deselect all
    bpy.ops.object.select_all(action='DESELECT')

    # Highlight the 'Characters' collection - https://blender.stackexchange.com/a/248563
    bpy.context.view_layer.active_layer_collection = \
        bpy.context.view_layer.layer_collection.children['Props']

    # Find our character FBX's - https://blender.stackexchange.com/a/253543
    folder = bpy.path.abspath("//Polygon_City_SourceFiles/SourceFiles/FBX")
    fbxs = [f for f in os.listdir(folder) \
        if f.endswith(".fbx") and f.startswith("SM_Prop_")
    ]

    collection = bpy.data.collections["Props"]

    # Import them
    for fbx in fbxs:
        bpy.ops.import_scene.fbx(
            filepath=os.path.join(folder, fbx),
            use_anim=False,
            ignore_leaf_bones=True,
            force_connect_children=True,
            automatic_bone_orientation=True,
        )

    for obj in collection.objects:
        if obj.type == 'MESH':
            for material_slot in obj.material_slots:
                # Always use non-duplicate version of material
                material_slot.material = bpy.data.materials[
                    material_slot.material.name.split('.')[0]
                ]

                if material_slot.material.name in ['blinn283', 'lambert2']:
                    material_slot.material = bpy.data.materials["lambert14"]

            # Rename Meshes to be the same as their parent MeshObjects
            obj.data.name = obj.name


def import_vehicles():
    # Deselect all
    bpy.ops.object.select_all(action='DESELECT')

    # Highlight the 'Characters' collection - https://blender.stackexchange.com/a/248563
    bpy.context.view_layer.active_layer_collection = \
        bpy.context.view_layer.layer_collection.children['Vehicles']

    # Find our character FBX's - https://blender.stackexchange.com/a/253543
    folder = bpy.path.abspath("//Polygon_City_SourceFiles/SourceFiles/FBX//Veh")
    fbxs = [f for f in os.listdir(folder) if f.endswith(".fbx") and f.startswith("SM_Veh_")]

    collection = bpy.data.collections["Vehicles"]

    # Import them
    for fbx in fbxs:
        bpy.ops.import_scene.fbx(
            filepath=os.path.join(folder, fbx),
            use_anim=False,
            ignore_leaf_bones=True,
            force_connect_children=True,
            automatic_bone_orientation=True,
        )

    for obj in collection.objects:
        if obj.type == 'MESH':
            for material_slot in obj.material_slots:
                # Always use non-duplicate version of material
                material_slot.material = bpy.data.materials[
                    material_slot.material.name.split('.')[0]
                ]

                if material_slot.material.name in ['Body']:
                    material_slot.material = bpy.data.materials["lambert14"]

            # Rename Meshes to be the same as their parent MeshObjects
            obj.data.name = obj.name


def fix_materials():
    # https://blender.stackexchange.com/a/280804
    for image in bpy.data.images.values():
        filename = os.path.basename(image.filepath)
        if image.source == "FILE":
            if filename in ["PolygonCity_Texture_01_C.png"]:
                # Make absolute
                image.filepath = bpy.path.abspath(
                    "//Polygon_City_SourceFiles\\SourceFiles\\Textures\\" + filename
                )
#            elif filename in ["PolygonCity_Texture_Normal.png", "PolygonCity_Texture_Metallic.tga"]:
#                image.colorspace_settings.name = 'Non-Color'

    for material in bpy.data.materials:
        if material.name == 'lambert14':
            material.name = 'POLYGONCity_Base'

            # https://blender.stackexchange.com/a/129014
            bsdf = material.node_tree.nodes["Principled BSDF"]
            bsdf.inputs["Specular"].default_value = 0.5

            # Set up metallic map
            uv_map = material.node_tree.nodes.new('ShaderNodeUVMap')
            mapping = material.node_tree.nodes.new('ShaderNodeMapping')
            tex_metallic = material.node_tree.nodes.new('ShaderNodeTexImage')
            tex_metallic.image = bpy.data.images.load(bpy.path.abspath(
                "//Polygon_City_SourceFiles/SourceFiles/Textures/PolygonCity_Texture_Metallic.tga"
            ))
            tex_metallic.image.colorspace_settings.name = 'Non-Color'
            tex_metallic_mp = material.node_tree.nodes.new('ShaderNodeMath')
            tex_metallic_mp.operation = 'MULTIPLY'
            tex_metallic_mp.inputs[1].default_value = 1.5
            material.node_tree.links.new(mapping.inputs['Vector'], uv_map.outputs['UV'])
            material.node_tree.links.new(tex_metallic.inputs['Vector'], mapping.outputs['Vector'])
            material.node_tree.links.new(tex_metallic_mp.inputs[0], tex_metallic.outputs['Color'])
            material.node_tree.links.new(bsdf.inputs['Metallic'], tex_metallic_mp.outputs[0])

            # Set up normal map
            uv_map = material.node_tree.nodes.new('ShaderNodeUVMap')
            mapping = material.node_tree.nodes.new('ShaderNodeMapping')
            tex_normal = material.node_tree.nodes.new('ShaderNodeTexImage')
            tex_normal.image = bpy.data.images.load(bpy.path.abspath(
                "//Polygon_City_SourceFiles/SourceFiles/Textures/PolygonCity_Texture_Normal.png"
            ))
            tex_normal.image.colorspace_settings.name = 'Non-Color'
            normal = material.node_tree.nodes["Normal Map"]
            material.node_tree.links.new(mapping.inputs['Vector'], uv_map.outputs['UV'])
            material.node_tree.links.new(tex_normal.inputs['Vector'], mapping.outputs['Vector'])
            material.node_tree.links.new(normal.inputs['Color'], tex_normal.outputs['Color'])
            material.node_tree.links.new(bsdf.inputs['Normal'], normal.outputs['Normal'])

        elif material.name == 'Glass':
            material.name = 'POLYGONCity_Glass'

            # https://blender.stackexchange.com/a/129014
            bsdf = material.node_tree.nodes["Principled BSDF"]

            bsdf.inputs["Base Color"].default_value = (0.054, 0.8, 0.627, 0)
            bsdf.inputs["Metallic"].default_value = 0.5
            bsdf.inputs["Specular"].default_value = 0.9
            bsdf.inputs["Roughness"].default_value = 0.2
            bsdf.inputs["Alpha"].default_value = 0.5


def cleanup():
    # Apply rotation, scale
    for obj in bpy.data.objects:
        obj.select_set(True)
    bpy.ops.object.transform_apply(scale=True, rotation=True)

    # Removed orphaned data
    for block in bpy.data.meshes:
        if block.users == 0:
            bpy.data.meshes.remove(block)

    for block in bpy.data.materials:
        if block.users == 0:
            bpy.data.materials.remove(block)

    for block in bpy.data.textures:
        if block.users == 0:
            bpy.data.textures.remove(block)

    for block in bpy.data.images:
        if block.users == 0:
            bpy.data.images.remove(block)


import_characters()
import_buildings()
import_environments()
import_props()
import_vehicles()
fix_materials()
cleanup()
POLYGON_City.py
Flynsarmy/synty-in-blender
import bpy
import os

def import_characters():
    # Deselect all
    bpy.ops.object.select_all(action='DESELECT')

    # Highlight the 'Characters' collection - https://blender.stackexchange.com/a/248563
    bpy.context.view_layer.active_layer_collection = \
        bpy.context.view_layer.layer_collection.children['Characters']

    # Import characters
    bpy.ops.import_scene.fbx(
        filepath=bpy.path.abspath("//Source_Files/FBX/Character.fbx"),
        use_anim=False,
        ignore_leaf_bones=True,
        force_connect_children=True,
        automatic_bone_orientation=True,
    )

def fix_materials():
    # Textures pointing to the wrong directory. Fix that
    # https://blender.stackexchange.com/a/280804
    for image in bpy.data.images.values():
        if image.source == "FILE":
            # Make absolute
            image.filepath = bpy.path.abspath(
                "//Source_Files/Textures/" + os.path.basename(image.filepath)
            )

    for material in bpy.data.materials:
        if material.name == 'lambert2':
            material.name = 'POLYGONCityCharacters_Base'

            # https://blender.stackexchange.com/a/129014
            bsdf = material.node_tree.nodes["Principled BSDF"]

            bsdf.inputs["Specular"].default_value = 0.5
            bsdf.inputs["Roughness"].default_value = 0.6


def cleanup():
    # Apply rotation, scale
    for obj in bpy.data.objects:
        obj.select_set(True)
    bpy.ops.object.transform_apply(scale=True, rotation=True)

    # Removed orphaned data
    for block in bpy.data.meshes:
        if block.users == 0:
            bpy.data.meshes.remove(block)

    for block in bpy.data.materials:
        if block.users == 0:
            bpy.data.materials.remove(block)

    for block in bpy.data.textures:
        if block.users == 0:
            bpy.data.textures.remove(block)

    for block in bpy.data.images:
        if block.users == 0:
            bpy.data.images.remove(block)


import_characters()
fix_materials()
cleanup()
POLYGON_CityCharacters.py
Flynsarmy/synty-in-blender
import bpy
import os

def import_characters():
    # Deselect all
    bpy.ops.object.select_all(action='DESELECT')

    # Highlight the 'Characters' collection - https://blender.stackexchange.com/a/248563
    bpy.context.view_layer.active_layer_collection = \
        bpy.context.view_layer.layer_collection.children['Characters']

    # Find our character FBX's - https://blender.stackexchange.com/a/253543
    folder = bpy.path.abspath("//SourceFiles\\Characters")
    fbxs = [f for f in os.listdir(folder) if f.endswith(".fbx")]

    # Import them
    for fbx in fbxs:
        bpy.ops.import_scene.fbx(
            filepath=os.path.join(folder, fbx),
            use_anim=False,
            ignore_leaf_bones=True,
            force_connect_children=True,
            automatic_bone_orientation=True,
        )

    collection = bpy.data.collections["Characters"]

    # Loop through Characters
    first_armature = None
    for obj in collection.objects:
        # Save the first armature object
        if first_armature == None and obj.type == 'ARMATURE':
            first_armature = obj
            continue

        if first_armature != None and obj.type == 'MESH':
            if obj.modifiers and obj.modifiers[0].type == 'ARMATURE':
                # Set all mesh Armature modifiers to the first armature object
                obj.modifiers[0].object = first_armature
            # Make our first armature the object parent
            obj.parent = first_armature

    # Deselect all
    bpy.ops.object.select_all(action='DESELECT')

    # Select unnecessary armatures
    first_armature = None
    for obj in collection.objects:
        if obj.type == 'ARMATURE':
            if first_armature == None:
                first_armature = obj
            else:
                obj.select_set(True)

    # Delete them
    bpy.ops.object.delete()

    # Remove IK bones
    bpy.context.view_layer.objects.active = first_armature
    bpy.ops.object.mode_set(mode='EDIT')
    # Remove the IK bones
    for bone in first_armature.data.edit_bones:
        if bone.name.startswith("_ik_"):
            first_armature.data.edit_bones.remove(bone)
    bpy.ops.object.mode_set(mode='OBJECT')

    first_armature.name = "Characters"

    # Textures pointing to the wrong directory. Fix that
    # https://blender.stackexchange.com/a/280804
    for image in bpy.data.images.values():
        if image.source == "FILE":
            filename = os.path.basename(image.filepath)
            if filename == "PolygonExplorers_Texture_01.psd":
                image.filepath = bpy.path.abspath(
                    "//SourceFiles\\Textures\\PolygonExplorers_Texture_01_A.png"
                )
            else:
                # Make absolute
                image.filepath = bpy.path.abspath(
                    "//SourceFiles\\Textures\\" + filename
                )

import_characters()
POLYGON_Explorers.py
Flynsarmy/synty-in-blender
import bpy
import os

def import_characters():
    # Deselect all
    bpy.ops.object.select_all(action='DESELECT')

    # Highlight the 'Characters' collection - https://blender.stackexchange.com/a/248563
    bpy.context.view_layer.active_layer_collection = \
        bpy.context.view_layer.layer_collection.children['Characters']

    # Find our character FBX's - https://blender.stackexchange.com/a/253543
    folder = bpy.path.abspath("//Source_Files\\Characters")
    fbxs = [f for f in os.listdir(folder) if f.endswith(".fbx")]

    # Import them
    for fbx in fbxs:
        bpy.ops.import_scene.fbx(
            filepath=os.path.join(folder, fbx),
            use_anim=False,
            ignore_leaf_bones=True,
            force_connect_children=True,
            automatic_bone_orientation=True,
        )

    collection = bpy.data.collections["Characters"]

    # Loop through Characters
    first_armature = None
    for obj in collection.objects:
        # Save the first armature object
        if first_armature == None and obj.type == 'ARMATURE':
            first_armature = obj
            continue

        if first_armature != None and obj.type == 'MESH':
            if obj.modifiers and obj.modifiers[0].type == 'ARMATURE':
                # Set all mesh Armature modifiers to the first armature object
                obj.modifiers[0].object = first_armature
            # Make our first armature the object parent
            obj.parent = first_armature

    # Deselect all
    bpy.ops.object.select_all(action='DESELECT')


    # Remove IK bones
    bpy.context.view_layer.objects.active = first_armature
    bpy.ops.object.mode_set(mode='EDIT')
    # Remove the IK bones
    for bone in first_armature.data.edit_bones:
        if bone.name.startswith("ik_"):
            first_armature.data.edit_bones.remove(bone)
    bpy.ops.object.mode_set(mode='OBJECT')

    # Select unnecessary armatures
    first_armature = None
    for obj in collection.objects:
        if obj.type == 'ARMATURE':
            if first_armature == None:
                first_armature = obj
            else:
                obj.select_set(True)

    # Delete them
    bpy.ops.object.delete()

    first_armature.name = "Characters"

    # Textures pointing to the wrong directory. Fix that
    # https://blender.stackexchange.com/a/280804
    for image in bpy.data.images.values():
        # Textures are pointing towards PolygonCity. Fix that
        filename = os.path.basename(image.filepath).replace("PolygonCity", "Polygon_Fantasy_Characters")
        if image.source == "FILE":
            # Make absolute
            image.filepath = bpy.path.abspath(
                "//Source_Files\\Textures\\" + filename
            )

import_characters()
POLYGON_FantasyCharacters.py
Flynsarmy/synty-in-blender
import bpy
import os

def import_characters():
    # Deselect all
    bpy.ops.object.select_all(action='DESELECT')

    # Highlight the 'Characters' collection - https://blender.stackexchange.com/a/248563
    bpy.context.view_layer.active_layer_collection = \
        bpy.context.view_layer.layer_collection.children['Characters']

    # Find our character FBX's - https://blender.stackexchange.com/a/253543
    folder = bpy.path.abspath("//Source_Files\\Characters")
    fbxs = [f for f in os.listdir(folder) if f.endswith(".fbx") and "_Cape_" not in f and "_Fairy_Wing_" not in f]

    # Import them
    for fbx in fbxs:
        bpy.ops.import_scene.fbx(
            filepath=os.path.join(folder, fbx),
            use_anim=False,
            ignore_leaf_bones=True,
            force_connect_children=True,
            automatic_bone_orientation=True,
        )

    collection = bpy.data.collections["Characters"]

    # Loop through Characters
    first_armature = None
    for obj in collection.objects:
        # Save the first armature object
        if first_armature == None and obj.type == 'ARMATURE':
            first_armature = obj
            continue

        if first_armature != None and obj.type == 'MESH':
            if obj.modifiers and obj.modifiers[0].type == 'ARMATURE':
                # Set all mesh Armature modifiers to the first armature object
                obj.modifiers[0].object = first_armature
            # Make our first armature the object parent
            obj.parent = first_armature

    # Deselect all
    bpy.ops.object.select_all(action='DESELECT')


    # Remove IK bones
    bpy.context.view_layer.objects.active = first_armature
    bpy.ops.object.mode_set(mode='EDIT')
    # Remove the IK bones
    for bone in first_armature.data.edit_bones:
        if bone.name.startswith("ik_"):
            first_armature.data.edit_bones.remove(bone)
    bpy.ops.object.mode_set(mode='OBJECT')

    # Select unnecessary armatures
    first_armature = None
    for obj in collection.objects:
        if obj.type == 'ARMATURE':
            if first_armature == None:
                first_armature = obj
            else:
                obj.select_set(True)

    # Delete them
    bpy.ops.object.delete()

    # Apply location, rotation, scale to deltas
    for obj in collection.all_objects:
        obj.delta_location += obj.location
        obj.location = (0, 0, 0)
        obj.delta_rotation_euler.rotate(obj.rotation_euler)
        obj.rotation_euler = (0, 0, 0)
        obj.delta_scale = obj.scale
        obj.scale = (1, 1, 1)

    first_armature.name = "Characters"

    # Textures pointing to the wrong directory. Fix that
    # https://blender.stackexchange.com/a/280804
    for image in bpy.data.images.values():
        # Textures are pointing towards PolygonCity. Fix that
        filename = os.path.basename(image.filepath)
        if image.source == "FILE":
            # Make absolute
            image.filepath = bpy.path.abspath(
                "//Source_Files\\Textures\\" + filename
            )

import_characters()
POLYGON_FantasyKingdom.py
Flynsarmy/synty-in-blender
import bpy
import os

def import_characters():
    # Deselect all
    bpy.ops.object.select_all(action='DESELECT')

    # Highlight the 'Characters' collection - https://blender.stackexchange.com/a/248563
    bpy.context.view_layer.active_layer_collection = \
        bpy.context.view_layer.layer_collection.children['Characters']

    # Find our character FBX's - https://blender.stackexchange.com/a/253543
    folder = bpy.path.abspath("//Source_Files\\Characters")
    fbxs = [f for f in os.listdir(folder) if f.endswith(".fbx") and (f.startswith("SK_BR_Char") or f.startswith("SK_Char"))]

    # Import them
    for fbx in fbxs:
        bpy.ops.import_scene.fbx(
            filepath=os.path.join(folder, fbx),
            use_anim=False,
            ignore_leaf_bones=True,
            force_connect_children=True,
            automatic_bone_orientation=True,
        )

    collection = bpy.data.collections["Characters"]

    # Loop through Characters
    first_armature = None
    for obj in collection.objects:
        # Save the first armature object
        if first_armature == None and obj.type == 'ARMATURE':
            first_armature = obj
            continue

        if first_armature != None and obj.type == 'MESH':
            if obj.modifiers and obj.modifiers[0].type == 'ARMATURE':
                # Set all mesh Armature modifiers to the first armature object
                obj.modifiers[0].object = first_armature
            # Make our first armature the object parent
            obj.parent = first_armature

    # Deselect all
    bpy.ops.object.select_all(action='DESELECT')


    # Remove IK bones
    bpy.context.view_layer.objects.active = first_armature
    bpy.ops.object.mode_set(mode='EDIT')
    # Remove the IK bones
    for bone in first_armature.data.edit_bones:
        if bone.name.startswith("ik_"):
            first_armature.data.edit_bones.remove(bone)
    bpy.ops.object.mode_set(mode='OBJECT')

    # Select unnecessary armatures
    first_armature = None
    for obj in collection.objects:
        if obj.type == 'ARMATURE':
            if first_armature == None:
                first_armature = obj
            else:
                obj.select_set(True)

    # Delete them
    bpy.ops.object.delete()

    # Apply location, rotation, scale to deltas
    for obj in collection.all_objects:
        obj.delta_location += obj.location
        obj.location = (0, 0, 0)
        obj.delta_rotation_euler.rotate(obj.rotation_euler)
        obj.rotation_euler = (0, 0, 0)
        obj.delta_scale = obj.scale
        obj.scale = (1, 1, 1)

    first_armature.name = "Characters"

    # Textures pointing to the wrong directory. Fix that
    # https://blender.stackexchange.com/a/280804
    for image in bpy.data.images.values():
        # Textures are pointing towards PolygonCity. Fix that
        filename = os.path.basename(image.filepath)
        if image.source == "FILE":
            if filename == "Texture_A1.png" or filename == "FantasyRivals_Justin_Main_01.psd":
                # Make absolute
                image.filepath = bpy.path.abspath(
                    "//Source_Files\\Textures\\FantasyRivals_Texture_01_A.png"
                )
            else:
                # Make absolute
                image.filepath = bpy.path.abspath(
                    "//Source_Files\\Textures\\" + filename
                )

import_characters()
POLYGON_FantasyRivals.py
Flynsarmy/synty-in-blender
import bpy
import os

## IMPORTANT! Convert the SourceFiles/Characters/*.fbx from ASCII to FBX 2013.
## Put the converted files in a 'FBX 2013' subfolder like so:
## SourceFiles/Characters/FBX 2013/*.fbx
## Do the same for the following files in SourceFiles/FBX/ :
## - SM_Chr_Attach_ScarecrowHat_01.fbx
## - SM_Veh_Pickup_01.fbx


def import_characters():
    # Deselect all
    bpy.ops.object.select_all(action='DESELECT')

    # Highlight the 'Characters' collection - https://blender.stackexchange.com/a/248563
    bpy.context.view_layer.active_layer_collection = \
        bpy.context.view_layer.layer_collection.children['Characters']

    # Find our character FBX's - https://blender.stackexchange.com/a/253543
    folder = bpy.path.abspath("//SourceFiles/Characters/FBX 2013")
    fbxs = [f for f in os.listdir(folder) \
        if f.endswith(".fbx") \
        and f.startswith("SK_Chr_")
    ]

    # Import them
    for fbx in fbxs:
        bpy.ops.import_scene.fbx(
            filepath=os.path.join(folder, fbx),
            use_anim=False,
            ignore_leaf_bones=True,
            force_connect_children=True,
            automatic_bone_orientation=True,
        )

    # Loop through Characters
    first_armature = None
    collection = bpy.data.collections["Characters"]
    for obj in collection.objects:
        # Save the first armature object
        if first_armature == None and obj.type == 'ARMATURE':
            first_armature = obj
            continue

        if obj.type == 'MESH':
            # Always use non-duplicate version of material
            obj.active_material = bpy.data.materials[
                obj
                    .active_material.name
                    .split('.')[0]
            ]

            # Rename Meshes to be the same as their parent MeshObjects
            obj.data.name = obj.name


            if first_armature != None and obj.modifiers[0].type == 'ARMATURE':
                # Set all mesh Armature modifiers to the first armature object
                obj.modifiers[0].object = first_armature

                # Make our first armature the object parent
                obj.parent = first_armature

    # Deselect all
    bpy.ops.object.select_all(action='DESELECT')

    # Select unnecessary armatures
    first_armature = None
    for obj in collection.objects:
        if obj.type == 'ARMATURE':
            if first_armature == None:
                first_armature = obj
            else:
                obj.select_set(True)

    # Delete them
    bpy.ops.object.delete()

    first_armature.name = "Armature"


def import_attachments():
    # Deselect all
    bpy.ops.object.select_all(action='DESELECT')

    # Highlight the 'Characters' collection - https://blender.stackexchange.com/a/248563
    bpy.context.view_layer.active_layer_collection = \
        bpy.context.view_layer.layer_collection.children['Character_Attachments']

    # Find our character FBX's - https://blender.stackexchange.com/a/253543
    folder = bpy.path.abspath("//SourceFiles/FBX")
    fbxs = [f for f in os.listdir(folder) \
        if f.endswith(".fbx") \
        and f.startswith("SM_Chr_Attach_") \
        and f not in ["SM_Chr_Attach_ScarecrowHat_01.fbx"]
    ]

    collection = bpy.data.collections["Character_Attachments"]

    # Import them
    for fbx in fbxs:
        bpy.ops.import_scene.fbx(
            filepath=os.path.join(folder, fbx),
            use_anim=False,
            ignore_leaf_bones=True,
            force_connect_children=True,
            automatic_bone_orientation=True,
        )
    # And the converted one
    bpy.ops.import_scene.fbx(
        filepath=bpy.path.abspath("//SourceFiles/FBX/FBX 2013/SM_Chr_Attach_ScarecrowHat_01.fbx"),
        use_anim=False,
        ignore_leaf_bones=True,
        force_connect_children=True,
        automatic_bone_orientation=True,
    )

    for obj in collection.objects:
        if obj.type == 'MESH':
            # Use the same material as the characters
            obj.active_material = bpy.data.materials["lambert2"]

            # Rename Meshes to be the same as their parent MeshObjects
            obj.data.name = obj.name

def import_weapons():
    # Deselect all
    bpy.ops.object.select_all(action='DESELECT')

    # Highlight the 'Characters' collection - https://blender.stackexchange.com/a/248563
    bpy.context.view_layer.active_layer_collection = \
        bpy.context.view_layer.layer_collection.children['Weapons']

    # Find our character FBX's - https://blender.stackexchange.com/a/253543
    folder = bpy.path.abspath("//SourceFiles/FBX")
    fbxs = [f for f in os.listdir(folder) \
        if f.endswith(".fbx") and f.startswith("SM_Wep_")
    ]

    collection = bpy.data.collections["Weapons"]

    # Import them
    for fbx in fbxs:
        bpy.ops.import_scene.fbx(
            filepath=os.path.join(folder, fbx),
            use_anim=False,
            ignore_leaf_bones=True,
            force_connect_children=True,
            automatic_bone_orientation=True,
        )

    for obj in collection.objects:
        if obj.type == 'MESH':
            # Use the same material as the characters
            obj.active_material = bpy.data.materials["lambert2"]

            # Rename Meshes to be the same as their parent MeshObjects
            obj.data.name = obj.name

def import_buildings():
    # Deselect all
    bpy.ops.object.select_all(action='DESELECT')

    # Highlight the 'Characters' collection - https://blender.stackexchange.com/a/248563
    bpy.context.view_layer.active_layer_collection = \
        bpy.context.view_layer.layer_collection.children['Buildings']

    # Find our character FBX's - https://blender.stackexchange.com/a/253543
    folder = bpy.path.abspath("//SourceFiles/FBX")
    fbxs = [f for f in os.listdir(folder) \
        if f.endswith(".fbx") and f.startswith("SM_Bld_")
    ]

    collection = bpy.data.collections["Buildings"]

    # Import them
    for fbx in fbxs:
        bpy.ops.import_scene.fbx(
            filepath=os.path.join(folder, fbx),
            use_anim=False,
            ignore_leaf_bones=True,
            force_connect_children=True,
            automatic_bone_orientation=True,
        )

    for obj in collection.objects:
        if obj.type == 'MESH':
            # Use the same material as the characters
            obj.active_material = bpy.data.materials["lambert2"]

            # Rename Meshes to be the same as their parent MeshObjects
            obj.data.name = obj.name

def import_environments():
    # Deselect all
    bpy.ops.object.select_all(action='DESELECT')

    # Highlight the 'Characters' collection - https://blender.stackexchange.com/a/248563
    bpy.context.view_layer.active_layer_collection = \
        bpy.context.view_layer.layer_collection.children['Environments']

    # Find our character FBX's - https://blender.stackexchange.com/a/253543
    folder = bpy.path.abspath("//SourceFiles/FBX")
    fbxs = [f for f in os.listdir(folder) \
        if f.endswith(".fbx") and (f.startswith("SM_Env_") or f.startswith("SM_Generic_"))
    ]

    collection = bpy.data.collections["Environments"]

    # Import them
    for fbx in fbxs:
        bpy.ops.import_scene.fbx(
            filepath=os.path.join(folder, fbx),
            use_anim=False,
            ignore_leaf_bones=True,
            force_connect_children=True,
            automatic_bone_orientation=True,
        )

    for obj in collection.objects:
        if obj.type == 'MESH':
            # Use the same material as the characters
            obj.active_material = bpy.data.materials["lambert2"]

            # Rename Meshes to be the same as their parent MeshObjects
            obj.data.name = obj.name

def import_props():
    # Deselect all
    bpy.ops.object.select_all(action='DESELECT')

    # Highlight the 'Characters' collection - https://blender.stackexchange.com/a/248563
    bpy.context.view_layer.active_layer_collection = \
        bpy.context.view_layer.layer_collection.children['Props']

    # Find our character FBX's - https://blender.stackexchange.com/a/253543
    folder = bpy.path.abspath("//SourceFiles/FBX")
    fbxs = [f for f in os.listdir(folder) \
        if f.endswith(".fbx") and f.startswith("SM_Prop_")
    ]

    collection = bpy.data.collections["Props"]

    # Import them
    for fbx in fbxs:
        bpy.ops.import_scene.fbx(
            filepath=os.path.join(folder, fbx),
            use_anim=False,
            ignore_leaf_bones=True,
            force_connect_children=True,
            automatic_bone_orientation=True,
        )

    for obj in collection.objects:
        if obj.type == 'MESH':
            for material_slot in obj.material_slots:
                # Always use non-duplicate version of material
                material_slot.material = bpy.data.materials[
                    material_slot.material.name.split('.')[0]
                ]
                # Use the same material as the characters
                if (material_slot.material.name in [
                        "Farm", "lambert1", "lambert23", "Vehicles", "Blade",
                        "lambert861"
                    ]) \
                    or material_slot.material.name.startswith("Farm"):
                    material_slot.material = bpy.data.materials["lambert2"]
                elif material_slot.material.name in ["Leaves"]:
                    material_slot.material = bpy.data.materials["lambert863"]

            # Rename Meshes to be the same as their parent MeshObjects
            obj.data.name = obj.name

def import_vehicles():
    # Deselect all
    bpy.ops.object.select_all(action='DESELECT')

    # Highlight the 'Characters' collection - https://blender.stackexchange.com/a/248563
    bpy.context.view_layer.active_layer_collection = \
        bpy.context.view_layer.layer_collection.children['Vehicles']

    # Find our character FBX's - https://blender.stackexchange.com/a/253543
    folder = bpy.path.abspath("//SourceFiles/FBX")
    fbxs = [f for f in os.listdir(folder) \
        if f.endswith(".fbx") \
        and f.startswith("SM_Veh_") \
        and f not in ["SM_Veh_Pickup_01.fbx"]
    ]

    collection = bpy.data.collections["Vehicles"]

    # Import them
    for fbx in fbxs:
        bpy.ops.import_scene.fbx(
            filepath=os.path.join(folder, fbx),
            use_anim=False,
            ignore_leaf_bones=True,
            force_connect_children=True,
            automatic_bone_orientation=True,
        )
    # And the converted one
    bpy.ops.import_scene.fbx(
        filepath=bpy.path.abspath("//SourceFiles/FBX/FBX 2013/SM_Veh_Pickup_01.fbx"),
        use_anim=False,
        ignore_leaf_bones=True,
        force_connect_children=True,
        automatic_bone_orientation=True,
    )


    for obj in collection.objects:
        if obj.type == 'MESH':
            # Always use non-duplicate version of material
            obj.active_material = bpy.data.materials[
                obj
                    .active_material.name
                    .split('.')[0]
            ]
            # Use the same material as the characters
            if obj.active_material.name in ["lambert1", "lambert2"]:
                obj.active_material = bpy.data.materials["lambert2"]

            # Rename Meshes to be the same as their parent MeshObjects
            obj.data.name = obj.name


def fix_materials():
    # https://blender.stackexchange.com/a/280804
    for image in bpy.data.images.values():
        filename = os.path.basename(image.filepath)
        if image.source == "FILE":
            if filename in ['Fence_Alpha.tga', 'PolygonFarm_Texture_01_A.png', 'PolygonFarm_Signs.png']:
                image.filepath = bpy.path.abspath(
                    "//SourceFiles\\Textures\\" + filename
                )
            elif filename == 'leavessheet_cavity.png':
                image.filepath = bpy.path.abspath(
                    "//SourceFiles\\Textures\\Leaves_Diff.tga"
                )

    for material in bpy.data.materials:
        # Leaves material
        if material.name == 'lambert863':
            material.name = "POLYGONFarm_Leaves"

            # https://blender.stackexchange.com/a/129014
            bsdf = material.node_tree.nodes["Principled BSDF"]

            tex_image = material.node_tree.nodes.new('ShaderNodeTexImage')
            tex_image.image = bpy.data.images.load(bpy.path.abspath(
                "//SourceFiles\\Textures\\Leaves_Diff.tga"
            ))

            norm_image = material.node_tree.nodes.new('ShaderNodeTexImage')
            norm_image.image = bpy.data.images.load(bpy.path.abspath(
                "//SourceFiles\\Textures\\Leaves_Normals.png"
            ))

            normal_map = material.node_tree.nodes["Normal Map"]
            material.node_tree.links.new(bsdf.inputs['Alpha'], tex_image.outputs['Alpha'])
            material.node_tree.links.new(normal_map.inputs['Color'], norm_image.outputs['Color'])

            bsdf.inputs["Metallic"].default_value = 0.0
            bsdf.inputs["Specular"].default_value = 0.2
            bsdf.inputs["Roughness"].default_value = 0.8

        # Glass material
        elif material.name == 'lambert3':
            material.name = "POLYGONFarm_Glass"

            bsdf = material.node_tree.nodes["Principled BSDF"]

            tex_image = material.node_tree.nodes.new('ShaderNodeTexImage')
            tex_image.image = bpy.data.images.load(bpy.path.abspath(
                "//SourceFiles\\Textures\\PolygonFarm_Texture_01_A.png"
            ))
            material.node_tree.links.new(bsdf.inputs['Base Color'], tex_image.outputs['Color'])

            bsdf.inputs["Metallic"].default_value = 0.0
            bsdf.inputs["Specular"].default_value = 0.8
            bsdf.inputs["Roughness"].default_value = 0.2
            bsdf.inputs["Alpha"].default_value = 0.5

        elif material.name == 'fence':
            material.name = "POLYGONFarm_Fence"
        elif material.name == 'lambert864':
            material.name = "POLYGONFarm_Signs"

            bsdf = material.node_tree.nodes["Principled BSDF"]
            bsdf.inputs["Metallic"].default_value = 0.0
            bsdf.inputs["Specular"].default_value = 0.2
            bsdf.inputs["Roughness"].default_value = 0.8
        elif material.name == 'lambert9':
            material.name = "POLYGONFarm_Wire"

            # https://blender.stackexchange.com/a/129014
            bsdf = material.node_tree.nodes["Principled BSDF"]

            alpha_tex = material.node_tree.nodes['Image Texture.001']
            material.node_tree.links.new(bsdf.inputs['Alpha'], alpha_tex.outputs['Alpha'])

            bsdf.inputs["Metallic"].default_value = 0.0
            bsdf.inputs["Specular"].default_value = 0.2
            bsdf.inputs["Roughness"].default_value = 0.8
        elif material.name == 'lambert2':
            material.name = "POLYGONFarm_Base"

            bsdf = material.node_tree.nodes["Principled BSDF"]
            bsdf.inputs["Metallic"].default_value = 0.0
            bsdf.inputs["Specular"].default_value = 0.2
            bsdf.inputs["Roughness"].default_value = 0.8


def cleanup():
    # Apply rotation, scale
    for obj in bpy.data.objects:
        obj.select_set(True)
    bpy.ops.object.transform_apply(scale=True, rotation=True)

    # Removed orphaned data
    for block in bpy.data.meshes:
        if block.users == 0:
            bpy.data.meshes.remove(block)

    for block in bpy.data.materials:
        if block.users == 0:
            bpy.data.materials.remove(block)

    for block in bpy.data.textures:
        if block.users == 0:
            bpy.data.textures.remove(block)

    for block in bpy.data.images:
        if block.users == 0:
            bpy.data.images.remove(block)

import_characters()
import_attachments()
import_weapons()
import_buildings()
import_environments()
import_props()
import_vehicles()
fix_materials()
cleanup()
POLYGON_Farm.py
Flynsarmy/synty-in-blender
import bpy
import os

def import_characters():
    # Deselect all
    bpy.ops.object.select_all(action='DESELECT')

    # Highlight the 'Characters' collection - https://blender.stackexchange.com/a/248563
    bpy.context.view_layer.active_layer_collection = \
        bpy.context.view_layer.layer_collection.children['Characters']

    # Find our character FBX's - https://blender.stackexchange.com/a/253543
    folder = bpy.path.abspath("//CHR")
    fbxs = [f for f in os.listdir(folder) if f.endswith(".fbx")]

    # Import them
    for fbx in fbxs:
        bpy.ops.import_scene.fbx(
            filepath=os.path.join(folder, fbx),
            use_anim=False,
            ignore_leaf_bones=True,
            force_connect_children=True,
            automatic_bone_orientation=True,
        )

    collection = bpy.data.collections["Characters"]

    # Loop through Characters
    first_armature = None
    for obj in collection.objects:
        # Save the first armature object
        if first_armature == None and obj.type == 'ARMATURE':
            first_armature = obj
            continue

        if first_armature != None and obj.type == 'MESH':
            if obj.modifiers and obj.modifiers[0].type == 'ARMATURE':
                # Set all mesh Armature modifiers to the first armature object
                obj.modifiers[0].object = first_armature
            # Make our first armature the object parent
            obj.parent = first_armature

    # Deselect all
    bpy.ops.object.select_all(action='DESELECT')


    # Remove IK bones
    bpy.context.view_layer.objects.active = first_armature
    bpy.ops.object.mode_set(mode='EDIT')
    # Remove the IK bones
    for bone in first_armature.data.edit_bones:
        if bone.name.startswith("ik_"):
            first_armature.data.edit_bones.remove(bone)
    bpy.ops.object.mode_set(mode='OBJECT')

    # Select unnecessary armatures
    first_armature = None
    for obj in collection.objects:
        if obj.type == 'ARMATURE':
            if first_armature == None:
                first_armature = obj
            else:
                obj.select_set(True)

    # Delete them
    bpy.ops.object.delete()

    # Apply location, rotation, scale to deltas
    for obj in collection.all_objects:
        obj.delta_location += obj.location
        obj.location = (0, 0, 0)
        obj.delta_rotation_euler.rotate(obj.rotation_euler)
        obj.rotation_euler = (0, 0, 0)
        obj.delta_scale = obj.scale
        obj.scale = (1, 1, 1)

    first_armature.name = "Characters"

    # Textures pointing to the wrong directory. Fix that
    # https://blender.stackexchange.com/a/280804
    for image in bpy.data.images.values():
        # Textures are pointing towards PolygonCity. Fix that
        filename = os.path.basename(image.filepath)
        if image.source == "FILE":
            if filename == "PolygonGangWars_Texture_01_A.psd":
                # Make absolute
                image.filepath = bpy.path.abspath(
                    "//UnrealFBXs\\tex\\PolygonGangWarfare_Texture_01_A.png"
                )
            else:
                # Make absolute
                image.filepath = bpy.path.abspath(
                    "//UnrealFBXs\\tex\\" + filename
                )

import_characters()
POLYGON_GangWarfare.py
Flynsarmy/synty-in-blender
import bpy
import os

def import_characters():
    # Deselect all
    bpy.ops.object.select_all(action='DESELECT')

    # Highlight the 'Characters' collection - https://blender.stackexchange.com/a/248563
    bpy.context.view_layer.active_layer_collection = \
        bpy.context.view_layer.layer_collection.children['Characters']

    # Find our character FBX's - https://blender.stackexchange.com/a/253543
    folder = bpy.path.abspath("//_SourceFiles\\Characters")
    fbxs = [f for f in os.listdir(folder) if f.endswith(".fbx")]

    # Import them
    for fbx in fbxs:
        bpy.ops.import_scene.fbx(
            filepath=os.path.join(folder, fbx),
            use_anim=False,
            ignore_leaf_bones=True,
            force_connect_children=True,
            automatic_bone_orientation=True,
        )

    collection = bpy.data.collections["Characters"]

    # Loop through Characters
    first_armature = None
    for obj in collection.objects:
        # Save the first armature object
        if first_armature == None and obj.type == 'ARMATURE':
            first_armature = obj
            continue

        if first_armature != None and obj.type == 'MESH':
            if obj.modifiers and obj.modifiers[0].type == 'ARMATURE':
                # Set all mesh Armature modifiers to the first armature object
                obj.modifiers[0].object = first_armature
            # Make our first armature the object parent
            obj.parent = first_armature

    # Deselect all
    bpy.ops.object.select_all(action='DESELECT')


    # Remove IK bones
    bpy.context.view_layer.objects.active = first_armature
    bpy.ops.object.mode_set(mode='EDIT')
    # Remove the IK bones
    for bone in first_armature.data.edit_bones:
        if bone.name.startswith("ik_"):
            first_armature.data.edit_bones.remove(bone)
    bpy.ops.object.mode_set(mode='OBJECT')

    # Select unnecessary armatures
    first_armature = None
    for obj in collection.objects:
        if obj.type == 'ARMATURE':
            if first_armature == None:
                first_armature = obj
            else:
                obj.select_set(True)

    # Delete them
    bpy.ops.object.delete()

    # Apply location, rotation, scale to deltas
    for obj in collection.all_objects:
        obj.delta_location += obj.location
        obj.location = (0, 0, 0)
        obj.delta_rotation_euler.rotate(obj.rotation_euler)
        obj.rotation_euler = (0, 0, 0)
        obj.delta_scale = obj.scale
        obj.scale = (1, 1, 1)

    first_armature.name = "Characters"

    # Textures pointing to the wrong directory. Fix that
    # https://blender.stackexchange.com/a/280804
    for image in bpy.data.images.values():
        # Textures are pointing towards PolygonCity. Fix that
        filename = os.path.basename(image.filepath)
        if image.source == "FILE":
            if filename == "PolygonHeist_Texture.psd":
                # Make absolute
                image.filepath = bpy.path.abspath(
                    "//_SourceFiles\\Textures\\PolygonHeist_Texture_01_A.png"
                )
            else:
                # Make absolute
                image.filepath = bpy.path.abspath(
                    "//_SourceFiles\\Textures\\" + filename
                )

import_characters()
POLYGON_Heist.py
Flynsarmy/synty-in-blender
import bpy
import os

def import_characters():
    # Deselect all
    bpy.ops.object.select_all(action='DESELECT')

    # Highlight the 'Characters' collection - https://blender.stackexchange.com/a/248563
    bpy.context.view_layer.active_layer_collection = \
        bpy.context.view_layer.layer_collection.children['Characters']

    # Import the characters
    bpy.ops.import_scene.fbx(
        filepath=bpy.path.abspath("//SourceFiles\\FBX\\Characters.fbx"),
        use_anim=False,
        ignore_leaf_bones=True,
        force_connect_children=True,
        automatic_bone_orientation=True,
    )

    collection = bpy.data.collections["Characters"]

    # Apply location, rotation, scale to deltas
    for obj in collection.all_objects:
        obj.delta_location += obj.location
        obj.location = (0, 0, 0)
        obj.delta_rotation_euler.rotate(obj.rotation_euler)
        obj.rotation_euler = (0, 0, 0)
        obj.delta_scale = obj.scale
        obj.scale = (1, 1, 1)

    # Textures pointing to the wrong directory. Fix that
    # https://blender.stackexchange.com/a/280804
    for image in bpy.data.images.values():
        # Textures are pointing towards PolygonCity. Fix that
        filename = os.path.basename(image.filepath)
        if image.source == "FILE":
            if filename == "PolygonHorror_Texture_01.psd":
                # Make absolute
                image.filepath = bpy.path.abspath(
                    "//SourceFiles\\Textures\\Alts\\PolygonHorror_Texture_01_A.png"
                )
            else:
                # Make absolute
                image.filepath = bpy.path.abspath(
                    "//SourceFiles\\Textures\\Alts\\" + filename
                )

import_characters()
POLYGON_HorrorMansion.py
Flynsarmy/synty-in-blender
import bpy
import os

def import_characters():
    # Deselect all
    bpy.ops.object.select_all(action='DESELECT')

    # Highlight the 'Characters' collection - https://blender.stackexchange.com/a/248563
    bpy.context.view_layer.active_layer_collection = \
        bpy.context.view_layer.layer_collection.children['Characters']

    # Find our character FBX's - https://blender.stackexchange.com/a/253543
    folder = bpy.path.abspath("//SourceFiles/Chr")
    fbxs = [f for f in os.listdir(folder) \
        if f.endswith(".fbx") \
        and f.startswith("SK_Chr_") \
        and not f.startswith("SK_Chr_Baby")
        # These ones have 's' versions whatever that means
        and f not in ["SK_Chr_Eyebrows_01.fbx", "SK_Chr_Eyes_Female_01.fbx", "SK_Chr_Eyes_Male_01.fbx"]
    ]

    # Import them
    for fbx in fbxs:
        bpy.ops.import_scene.fbx(
            filepath=os.path.join(folder, fbx),
            use_anim=False,
            ignore_leaf_bones=True,
            force_connect_children=True,
            automatic_bone_orientation=True,
        )

    # Loop through Characters
    first_armature = None
    collection = bpy.data.collections["Characters"]
    for obj in collection.objects:
        # Save the first armature object
        if first_armature == None and obj.type == 'ARMATURE':
            first_armature = obj
            continue

        if obj.type == 'MESH':
            # Always use non-duplicate version of material
            obj.active_material = bpy.data.materials[
                obj
                    .active_material.name
                    # SK_Chr_Kid_Schoolboy_01 has a broken 'lambert3' material. Set it to
                    # the same as all the others
                    .replace("lambert3", "lambert2")
                    # The eyes/eyebrows should also be on lambert2
                    .replace("KIds", "lambert2")
                    .split('.')[0]
            ]

            # Rename Meshes to be the same as their parent MeshObjects
            obj.data.name = obj.name


            if first_armature != None and obj.modifiers[0].type == 'ARMATURE':
                # Set all mesh Armature modifiers to the first armature object
                obj.modifiers[0].object = first_armature

                # Make our first armature the object parent
                obj.parent = first_armature

    # Deselect all
    bpy.ops.object.select_all(action='DESELECT')

    # Select unnecessary armatures
    first_armature = None
    for obj in collection.objects:
        if obj.type == 'ARMATURE':
            if first_armature == None:
                first_armature = obj
            else:
                obj.select_set(True)

    # Delete them
    bpy.ops.object.delete()

    first_armature.name = "Armature"


def import_attachments():
    # Deselect all
    bpy.ops.object.select_all(action='DESELECT')

    # Highlight the 'Characters' collection - https://blender.stackexchange.com/a/248563
    bpy.context.view_layer.active_layer_collection = \
        bpy.context.view_layer.layer_collection.children['Character_Attachments']

    # Find our character FBX's - https://blender.stackexchange.com/a/253543
    folder = bpy.path.abspath("//SourceFiles/FBX")
    fbxs = [f for f in os.listdir(folder) \
        if f.endswith(".fbx") \
        and (f.startswith("SM_Chr_Attach_") or f.startswith("SM_Chr_Hair"))
    ]

    collection = bpy.data.collections["Character_Attachments"]

    # Import them
    for fbx in fbxs:
        bpy.ops.import_scene.fbx(
            filepath=os.path.join(folder, fbx),
            use_anim=False,
            ignore_leaf_bones=True,
            force_connect_children=True,
            automatic_bone_orientation=True,
        )

    for obj in collection.objects:
        for material_slot in obj.material_slots:
            # Always use non-duplicate version of material
            material_slot.material = bpy.data.materials[
                material_slot.material.name.split('.')[0]
            ]

            # Remove duplicate glass materials
            if material_slot.material.name in [
                "lambert1431", "lambert1440", "paintballMask_GlassSHD", "_Glass_kids"
            ]:
                material_slot.material = bpy.data.materials["lambert1431"]
            else:
                # Use the base material for everything else
                material_slot.material = bpy.data.materials["lambert2"]

            # Rename Meshes to be the same as their parent MeshObjects
            obj.data.name = obj.name


def import_environments():
    # Deselect all
    bpy.ops.object.select_all(action='DESELECT')

    # Highlight the 'Characters' collection - https://blender.stackexchange.com/a/248563
    bpy.context.view_layer.active_layer_collection = \
        bpy.context.view_layer.layer_collection.children['Environments']

    # Find our character FBX's - https://blender.stackexchange.com/a/253543
    folder = bpy.path.abspath("//SourceFiles/FBX")
    fbxs = [f for f in os.listdir(folder) \
        if f.endswith(".fbx") and (f.startswith("SM_Env_") or f.startswith("SM_Generic_"))
    ]

    collection = bpy.data.collections["Environments"]

    # Import them
    for fbx in fbxs:
        bpy.ops.import_scene.fbx(
            filepath=os.path.join(folder, fbx),
            use_anim=False,
            ignore_leaf_bones=True,
            force_connect_children=True,
            automatic_bone_orientation=True,
        )

    for obj in collection.objects:
        if obj.type == 'MESH':
            for material_slot in obj.material_slots:
                # Always use non-duplicate version of material
                material_slot.material = bpy.data.materials[
                    material_slot.material.name.split('.')[0]
                ]

                if material_slot.material.name == "GlassSHD":
                    material_slot.material = bpy.data.materials["lambert1431"]
                else:
                    material_slot.material = bpy.data.materials["lambert2"]

            # Rename Meshes to be the same as their parent MeshObjects
            obj.data.name = obj.name


def import_props():
    # Deselect all
    bpy.ops.object.select_all(action='DESELECT')

    # Highlight the 'Characters' collection - https://blender.stackexchange.com/a/248563
    bpy.context.view_layer.active_layer_collection = \
        bpy.context.view_layer.layer_collection.children['Props']

    # Find our character FBX's - https://blender.stackexchange.com/a/253543
    folder = bpy.path.abspath("//SourceFiles/FBX")
    fbxs = [f for f in os.listdir(folder) \
        if f.endswith(".fbx") \
        and (f.startswith("SM_Prop_") or f.startswith("SK_Prop_"))
    ]

    collection = bpy.data.collections["Props"]

    # Import them
    for fbx in fbxs:
        bpy.ops.import_scene.fbx(
            filepath=os.path.join(folder, fbx),
            use_anim=False,
            ignore_leaf_bones=True,
            force_connect_children=True,
            automatic_bone_orientation=True,
        )

    for obj in collection.objects:
        if obj.type == 'MESH':
            for material_slot in obj.material_slots:
                # Always use non-duplicate version of material
                material_slot.material = bpy.data.materials[
                    material_slot.material.name.split('.')[0]
                ]

                if material_slot.material.name.startswith("Glass"):
                    material_slot.material = bpy.data.materials["lambert1431"]
                else:
                    material_slot.material = bpy.data.materials["lambert2"]

            # Rename Meshes to be the same as their parent MeshObjects
            obj.data.name = obj.name


def import_vehicles():
    # Deselect all
    bpy.ops.object.select_all(action='DESELECT')

    # Highlight the 'Characters' collection - https://blender.stackexchange.com/a/248563
    bpy.context.view_layer.active_layer_collection = \
        bpy.context.view_layer.layer_collection.children['Vehicles']

    # Find our character FBX's - https://blender.stackexchange.com/a/253543
    folder = bpy.path.abspath("//SourceFiles/FBX")
    fbxs = [f for f in os.listdir(folder) \
        if f.endswith(".fbx") \
        and (f.startswith("SM_Veh_") or f.startswith("SK_Veh_"))
    ]

    collection = bpy.data.collections["Vehicles"]

    # Import them
    for fbx in fbxs:
        bpy.ops.import_scene.fbx(
            filepath=os.path.join(folder, fbx),
            use_anim=False,
            ignore_leaf_bones=True,
            force_connect_children=True,
            automatic_bone_orientation=True,
        )

    for obj in collection.objects:
        if obj.type == 'MESH':
            for material_slot in obj.material_slots:
                # Always use non-duplicate version of material
                material_slot.material = bpy.data.materials[
                    material_slot.material.name.split('.')[0]
                ]

                if material_slot.material.name.startswith("Glass"):
                    material_slot.material = bpy.data.materials["lambert1431"]
                else:
                    material_slot.material = bpy.data.materials["lambert2"]

            # Rename Meshes to be the same as their parent MeshObjects
            obj.data.name = obj.name


def import_weapons():
    # Deselect all
    bpy.ops.object.select_all(action='DESELECT')

    # Highlight the 'Characters' collection - https://blender.stackexchange.com/a/248563
    bpy.context.view_layer.active_layer_collection = \
        bpy.context.view_layer.layer_collection.children['Weapons']

    # Find our character FBX's - https://blender.stackexchange.com/a/253543
    folder = bpy.path.abspath("//SourceFiles/FBX")
    fbxs = [f for f in os.listdir(folder) \
        if f.endswith(".fbx") \
        and (f.startswith("SK_Wep_") or f.startswith("SM_Wep_"))
    ]

    collection = bpy.data.collections["Weapons"]

    # Import them
    for fbx in fbxs:
        bpy.ops.import_scene.fbx(
            filepath=os.path.join(folder, fbx),
            use_anim=False,
            ignore_leaf_bones=True,
            force_connect_children=True,
            automatic_bone_orientation=True,
        )

    for obj in collection.objects:
        # Rename any armatures to their first mesh object name
        # So they're not just 'Armature'.
        if obj.type == 'ARMATURE':
            for obj2 in collection.objects:
                if obj2.type == 'MESH' and obj2.parent == obj:
                    obj.name = obj2.name
                    break


        if obj.type == 'MESH':
            # The static mesh assets are sitting inside EMPTYs. Pull them out.
            if obj.parent and obj.parent.type == 'EMPTY':
                obj.parent = None

            # Some objects are scaled 100x too large.
            if obj.scale.x == 1.0:
                obj.scale /= 100.0

            for material_slot in obj.material_slots:
                # Always use non-duplicate version of material
                material_slot.material = bpy.data.materials[
                    material_slot.material.name.split('.')[0]
                ]
                # Use the same material as the characters
                material_slot.material = bpy.data.materials["lambert2"]

            # Rename Meshes to be the same as their parent MeshObjects
            obj.data.name = obj.name

    # Delete all EMPTYs
    bpy.ops.object.select_all(action='DESELECT')
    for obj in collection.objects:
        if obj.type == 'EMPTY':
            obj.select_set(True)
    bpy.ops.object.delete()


def fix_materials():
    # https://blender.stackexchange.com/a/280804
    for image in bpy.data.images.values():
        filename = os.path.basename(image.filepath)
        if image.source == "FILE":
            # Eye/Eyebrow pointing to wrong file in wrong directory. Fix that
            if filename == "Polygon_Kids_Texture_Facial_Expression_Frown_Freckles_01.png":
                # Make absolute
                image.filepath = bpy.path.abspath(
                    "//SourceFiles/Textures/Faces_Human/Normal/Expression/Polygon_Kids_Texture_Facial_Expression_Frown_01.png"
                )
            elif filename == "Polygon_Kids_Texture_A _Justin.psd":
                image.filepath = bpy.path.abspath(
                    "//SourceFiles/Textures/PolygonKids_Texture_01_A.png"
                )

    for material in bpy.data.materials:
        if material.name == 'lambert2':
            material.name = 'POLYGONKids_Base'

            # https://blender.stackexchange.com/a/129014
            bsdf = material.node_tree.nodes["Principled BSDF"]
            bsdf.inputs["Metallic"].default_value = 0.0
            bsdf.inputs["Specular"].default_value = 0.2
            bsdf.inputs["Roughness"].default_value = 0.8
        elif material.name == 'lambert1431':
            material.name = 'POLYGONKids_Glass'

            # https://blender.stackexchange.com/a/129014
            bsdf = material.node_tree.nodes["Principled BSDF"]
            bsdf.inputs["Metallic"].default_value = 0.0
            bsdf.inputs["Specular"].default_value = 0.2
            bsdf.inputs["Roughness"].default_value = 0.8
            bsdf.inputs["Alpha"].default_value = 0.5

def cleanup():
    # Apply rotation, scale
    for obj in bpy.data.objects:
        obj.select_set(True)
    bpy.ops.object.transform_apply(scale=True, rotation=True)

    # Removed orphaned data
    for block in bpy.data.meshes:
        if block.users == 0:
            bpy.data.meshes.remove(block)

    for block in bpy.data.materials:
        if block.users == 0:
            bpy.data.materials.remove(block)

    for block in bpy.data.textures:
        if block.users == 0:
            bpy.data.textures.remove(block)

    for block in bpy.data.images:
        if block.users == 0:
            bpy.data.images.remove(block)

import_characters()
import_attachments()
import_environments()
import_props()
import_vehicles()
import_weapons()
fix_materials()
cleanup()
POLYGON_Kids.py
Flynsarmy/synty-in-blender
import bpy
import os

def import_characters():
    # Deselect all
    bpy.ops.object.select_all(action='DESELECT')

    # Highlight the 'Characters' collection - https://blender.stackexchange.com/a/248563
    bpy.context.view_layer.active_layer_collection = \
        bpy.context.view_layer.layer_collection.children['Characters']

    # Find our character FBX's - https://blender.stackexchange.com/a/253543
    folder = bpy.path.abspath("//Source_Files\\Character_Files\\FBX_Characters\\Updated_Unreal_Rig")
    fbxs = [f for f in os.listdir(folder) if f.endswith(".fbx")]

    # Import them
    for fbx in fbxs:
        bpy.ops.import_scene.fbx(
            filepath=os.path.join(folder, fbx),
            use_anim=False,
            ignore_leaf_bones=True,
            force_connect_children=True,
            automatic_bone_orientation=True,
        )

    collection = bpy.data.collections["Characters"]

    # Loop through Characters
    first_armature = None
    for obj in collection.objects:
        # Save the first armature object
        if first_armature == None and obj.type == 'ARMATURE':
            first_armature = obj
            continue

        if first_armature != None and obj.type == 'MESH':
            if obj.modifiers and obj.modifiers[0].type == 'ARMATURE':
                # Set all mesh Armature modifiers to the first armature object
                obj.modifiers[0].object = first_armature
            # Make our first armature the object parent
            obj.parent = first_armature

    # Deselect all
    bpy.ops.object.select_all(action='DESELECT')


    # Remove IK bones
    bpy.context.view_layer.objects.active = first_armature
    bpy.ops.object.mode_set(mode='EDIT')
    # Remove the IK bones
    for bone in first_armature.data.edit_bones:
        if bone.name.startswith("ik_"):
            first_armature.data.edit_bones.remove(bone)
    bpy.ops.object.mode_set(mode='OBJECT')

    # Select unnecessary armatures
    first_armature = None
    for obj in collection.objects:
        if obj.type == 'ARMATURE':
            if first_armature == None:
                first_armature = obj
            else:
                obj.select_set(True)

    # Delete them
    bpy.ops.object.delete()

    # Apply location, rotation, scale to deltas
    for obj in collection.all_objects:
        obj.delta_location += obj.location
        obj.location = (0, 0, 0)
        obj.delta_rotation_euler.rotate(obj.rotation_euler)
        obj.rotation_euler = (0, 0, 0)
        obj.delta_scale = obj.scale
        obj.scale = (1, 1, 1)

    first_armature.name = "Characters"

    # Textures pointing to the wrong directory. Fix that
    # https://blender.stackexchange.com/a/280804
    for image in bpy.data.images.values():
        filename = os.path.basename(image.filepath)
        if image.source == "FILE":
            if filename == "Characters_Texture_03.psd":
                # Make absolute
                image.filepath = bpy.path.abspath(
                    "//Source_Files\\Textures\\Characters_Texture_Black.png"
                )
            else:
                # Make absolute
                image.filepath = bpy.path.abspath(
                    "//Source_Files\\Textures\\" + filename
                )

import_characters()
POLYGON_Knights.py
Flynsarmy/synty-in-blender
import bpy
import os

def import_characters():
    # Deselect all
    bpy.ops.object.select_all(action='DESELECT')

    # Highlight the 'Characters' collection - https://blender.stackexchange.com/a/248563
    bpy.context.view_layer.active_layer_collection = \
        bpy.context.view_layer.layer_collection.children['Characters']

    # Import the characters
    bpy.ops.import_scene.fbx(
        filepath=bpy.path.abspath("//SourceFiles/FBX/Character.fbx"),
        use_anim=False,
        ignore_leaf_bones=True,
        force_connect_children=True,
        automatic_bone_orientation=True,
    )

    collection = bpy.data.collections["Characters"]

    for obj in collection.objects:
        if obj.type == 'MESH':
            # All these characters share the same material
            obj.active_material = bpy.data.materials['lambert295']


def import_character_attachments():
    # Deselect all
    bpy.ops.object.select_all(action='DESELECT')

    # Highlight the 'Buildings' collection - https://blender.stackexchange.com/a/248563
    bpy.context.view_layer.active_layer_collection = \
        bpy.context.view_layer.layer_collection.children['Character_Attachments']

    # Find our FBX's - https://blender.stackexchange.com/a/253543
    folder = bpy.path.abspath("//SourceFiles/FBX/")
    fbxs = [f for f in os.listdir(folder) \
        if f.endswith(".fbx") and f.startswith("SM_Chr_Attachment_")
    ]

    collection = bpy.data.collections["Character_Attachments"]

    # Import them
    for fbx in fbxs:
        bpy.ops.import_scene.fbx(
            filepath=os.path.join(folder, fbx),
            use_anim=False,
            ignore_leaf_bones=True,
            force_connect_children=True,
            automatic_bone_orientation=True,
        )

    for obj in collection.objects:
        if obj.type == 'MESH':
            # All char attachments in this pack use a single texture and it's always
            # the base one.
            obj.active_material = bpy.data.materials['lambert295']


            # Rename Meshes to be the same as their parent MeshObjects
            obj.data.name = obj.name


def import_buildings():
    # Deselect all
    bpy.ops.object.select_all(action='DESELECT')

    # Highlight the 'Buildings' collection - https://blender.stackexchange.com/a/248563
    bpy.context.view_layer.active_layer_collection = \
        bpy.context.view_layer.layer_collection.children['Buildings']

    # Find our FBX's - https://blender.stackexchange.com/a/253543
    folder = bpy.path.abspath("//SourceFiles/FBX/")
    fbxs = [f for f in os.listdir(folder) \
        if f.endswith(".fbx") and f.startswith("SM_Bld_")
    ]

    collection = bpy.data.collections["Buildings"]

    # Import them
    for fbx in fbxs:
        bpy.ops.import_scene.fbx(
            filepath=os.path.join(folder, fbx),
            use_anim=False,
            ignore_leaf_bones=True,
            force_connect_children=True,
            automatic_bone_orientation=True,
        )

    for obj in collection.objects:
        if obj.type == 'MESH':
            for material_slot in obj.material_slots:
                # Always use non-duplicate version of material
                material_slot.material = bpy.data.materials[
                    material_slot.material.name.split('.')[0]
                ]

                for material_slot in obj.material_slots:
                    if material_slot.material.name.startswith("A_Glass") \
                        or material_slot.material.name.startswith("Glass"):
                        material_slot.material = bpy.data.materials["A_Glass"]
                    elif material_slot.material.name.startswith('lambert') \
                        or material_slot.material.name.startswith('OfficeSHD'):
                        material_slot.material = bpy.data.materials['lambert295']


            # Rename Meshes to be the same as their parent MeshObjects
            obj.data.name = obj.name


def import_props():
    # Deselect all
    bpy.ops.object.select_all(action='DESELECT')

    # Highlight the 'Buildings' collection - https://blender.stackexchange.com/a/248563
    bpy.context.view_layer.active_layer_collection = \
        bpy.context.view_layer.layer_collection.children['Props']

    # Find our FBX's - https://blender.stackexchange.com/a/253543
    folder = bpy.path.abspath("//SourceFiles/FBX/")
    fbxs = [f for f in os.listdir(folder) \
        if f.endswith(".fbx") and f.startswith("SM_Prop_")
    ]

    collection = bpy.data.collections["Props"]

    # Import them
    for fbx in fbxs:
        bpy.ops.import_scene.fbx(
            filepath=os.path.join(folder, fbx),
            use_anim=False,
            ignore_leaf_bones=True,
            force_connect_children=True,
            automatic_bone_orientation=True,
        )

    for obj in collection.objects:
        if obj.type == 'MESH':
            # A couple of meshes have incorrect materials
            if obj.name in ['SM_Prop_Sculpture_02', 'SM_Prop_Sculpture_Base_01']:
                obj.active_material = bpy.data.materials['lambert295']
            # This one has a material named 'lambert12' and it's the only
            # one that needs to be set to Chrome so do that here to avoid
            # name clashes in other meshes.
            elif obj.name == 'SM_Prop_Sculpture_01':
                obj.active_material.name = 'POLYGONOffice_Chrome'

            for material_slot in obj.material_slots:
                # Always use non-duplicate version of material
                material_slot.material = bpy.data.materials[
                    material_slot.material.name.split('.')[0]
                ]

                if obj.name == 'SM_Prop_Clock_02' and material_slot.material.name == 'lambert2':
                    material_slot.material = bpy.data.materials["Screen"]
                elif obj.name == 'SM_Prop_Laptop_02' and material_slot.material.name == 'OfficeSHD18':
                    material_slot.material = bpy.data.materials["Screen"]
                elif obj.name == 'SM_Prop_Laptop_01' and material_slot.material.name == 'OfficeSHD16':
                    material_slot.material = bpy.data.materials["Screen"]
                elif obj.name == 'SM_Prop_GraphicsTablet_02' and material_slot.material.name == 'OfficeSHD1':
                    material_slot.material = bpy.data.materials["Screen"]
                elif obj.name == 'SM_Prop_GraphicsTablet_03' and material_slot.material.name == 'OfficeSHD1':
                    material_slot.material = bpy.data.materials["Screen3"]
                elif obj.name == 'SM_Prop_GraphicsTablet_04' and material_slot.material.name == 'OfficeSHD1':
                    material_slot.material = bpy.data.materials["Screen2"]
                elif obj.name == 'SM_Prop_TV_Wall_01' and material_slot.material.name == '_lambert2':
                    material_slot.material = bpy.data.materials["Screen2"]
                elif obj.name in ['SM_Prop_Photocopier_01', 'SM_Prop_Photocopier_02'] and material_slot.material.name == 'Screen':
                    material_slot.material = bpy.data.materials["Screen2"]
                elif obj.name == 'SM_Prop_Laptop_Folding_Screen_01' and material_slot.material.name == 'OfficeSHD16':
                    material_slot.material = bpy.data.materials["Screen"]
                elif obj.name == 'SM_Prop_Laptop_Folding_Screen_02' and material_slot.material.name == 'OfficeSHD16':
                    material_slot.material = bpy.data.materials["Screen2"]
                elif obj.name == 'SM_Prop_Monitor_Crt_01' and material_slot.material.name == 'OfficeSHD7':
                    material_slot.material = bpy.data.materials["Screen"]
                elif obj.name == 'SM_Prop_ArcadeMachine_01' and material_slot.material.name == 'OfficeSHD1':
                    material_slot.material = bpy.data.materials.new(name="POLYGONOffice_Arcade")
                elif obj.name == 'SM_Prop_Bottle_01' and material_slot.material.name == 'lambert8':
                    material_slot.material = bpy.data.materials["A_Glass"]
                elif material_slot.material.name == 'glassSHD':
                    material_slot.material = bpy.data.materials["A_Glass"]
                # Everything else goes to default mat
                elif material_slot.material.name.startswith("lambert") \
                    or material_slot.material.name.startswith("Office") \
                    or material_slot.material.name.startswith("gang"):
                    material_slot.material = bpy.data.materials["lambert295"]

            # Rename Meshes to be the same as their parent MeshObjects
            obj.data.name = obj.name


def import_weapons():
    # Deselect all
    bpy.ops.object.select_all(action='DESELECT')

    # Highlight the 'Buildings' collection - https://blender.stackexchange.com/a/248563
    bpy.context.view_layer.active_layer_collection = \
        bpy.context.view_layer.layer_collection.children['Weapons']

    # Find our FBX's - https://blender.stackexchange.com/a/253543
    folder = bpy.path.abspath("//SourceFiles/FBX/")
    fbxs = [f for f in os.listdir(folder) \
        if f.endswith(".fbx") and f.startswith("SM_Wep_")
    ]

    collection = bpy.data.collections["Weapons"]

    # Import them
    for fbx in fbxs:
        bpy.ops.import_scene.fbx(
            filepath=os.path.join(folder, fbx),
            use_anim=False,
            ignore_leaf_bones=True,
            force_connect_children=True,
            automatic_bone_orientation=True,
        )

    for obj in collection.objects:
        if obj.type == 'MESH':
            for material_slot in obj.material_slots:
                # Always use non-duplicate version of material
                material_slot.material = bpy.data.materials[
                    material_slot.material.name.split('.')[0]
                ]

                # All weapons in this pack use a single texture and it's always
                # the base one.
                obj.active_material = bpy.data.materials['lambert295']

            # Rename Meshes to be the same as their parent MeshObjects
            obj.data.name = obj.name


def fix_materials():
    # https://blender.stackexchange.com/a/280804
    for image in bpy.data.images.values():
        filename = os.path.basename(image.filepath)
        if image.source == "FILE":
            # Eye/Eyebrow pointing to wrong file in wrong directory. Fix that
            if filename == "PolygonOffice_Texture_01_A_New.psd":
                # Make absolute
                image.filepath = bpy.path.abspath(
                    "//SourceFiles/Textures/PolygonOffice_Texture_01_A.png"
                )
            else:
                # Make absolute
                image.filepath = bpy.path.abspath(
                    "//SourceFiles/Textures/" + filename
                )


    for material in bpy.data.materials:
        if material.name == 'lambert295':
            material.name = 'POLYGONOffice_Base'

            # https://blender.stackexchange.com/a/129014
            bsdf = material.node_tree.nodes["Principled BSDF"]
            bsdf.inputs["Metallic"].default_value = 0.0
            bsdf.inputs["Specular"].default_value = 0.2
            bsdf.inputs["Roughness"].default_value = 0.8

            tex_emissive = material.node_tree.nodes.new('ShaderNodeTexImage')
            tex_emissive.image = bpy.data.images.load(bpy.path.abspath(
                "//SourceFiles/Textures/Emissive_01.png"
            ))
            tex_emissive_mp = material.node_tree.nodes.new('ShaderNodeMath')
            tex_emissive_mp.operation = 'MULTIPLY'
            tex_emissive_mp.inputs[1].default_value = 2
            material.node_tree.links.new(tex_emissive_mp.inputs[0], tex_emissive.outputs['Color'])
            material.node_tree.links.new(bsdf.inputs['Emission Strength'], tex_emissive_mp.outputs[0])
        elif material.name == 'A_Glass':
            material.name = 'POLYGONOffice_Glass'

            # https://blender.stackexchange.com/a/129014
            bsdf = material.node_tree.nodes["Principled BSDF"]
            bsdf.inputs["Alpha"].default_value = 0.5
        elif material.name == 'Net1':
            material.name = 'POLYGONOffice_Net'

            bsdf = material.node_tree.nodes["Principled BSDF"]
            tex_emissive = material.node_tree.nodes["Image Texture.001"]

            material.node_tree.links.new(bsdf.inputs['Alpha'], tex_emissive.outputs['Alpha'])
        elif material.name == 'POLYGONOffice_Arcade':
            material.use_nodes = True
            bsdf = material.node_tree.nodes.new("ShaderNodeBsdfPrincipled")
            tex_albedo = material.node_tree.nodes.new('ShaderNodeTexImage')
            tex_albedo.image = bpy.data.images.load(bpy.path.abspath(
                "//SourceFiles/Textures/PolygonOffice_Texture_Sceen_Arcade_01.png"
            ))
            material.node_tree.links.new(bsdf.inputs['Base Color'], tex_albedo.outputs['Color'])
            material.node_tree.links.new(bsdf.inputs['Emission'], tex_albedo.outputs['Color'])

        # Set up the 5 Screen materials
        for i in range(1, 4):
            if material.name == 'Screen' + str(i).replace('1', ''):
                material.name = 'POLYGONOffice_Screen' + str(i)

                bsdf = material.node_tree.nodes["Principled BSDF"]
                tex_albedo = material.node_tree.nodes.new('ShaderNodeTexImage')
                tex_albedo.image = bpy.data.images.load(bpy.path.abspath(
                    "//SourceFiles/Textures/PolygonOffice_Texture_Sceen_0" + str(i) + ".png"
                ))
                material.node_tree.links.new(bsdf.inputs['Base Color'], tex_albedo.outputs['Color'])
                material.node_tree.links.new(bsdf.inputs['Emission'], tex_albedo.outputs['Color'])




def cleanup():
    # Apply rotation, scale
    for obj in bpy.data.objects:
        obj.select_set(True)
    bpy.ops.object.transform_apply(scale=True, rotation=True)

    # Removed orphaned data
    for block in bpy.data.meshes:
        if block.users == 0:
            bpy.data.meshes.remove(block)

    for block in bpy.data.materials:
        if block.users == 0:
            bpy.data.materials.remove(block)

    for block in bpy.data.textures:
        if block.users == 0:
            bpy.data.textures.remove(block)

    for block in bpy.data.images:
        if block.users == 0:
            bpy.data.images.remove(block)


import_characters()
import_character_attachments()
import_buildings()
import_props()
import_weapons()
fix_materials()
cleanup()
POLYGON_Office.py
Flynsarmy/synty-in-blender
import bpy
import os

def import_characters():
    # Deselect all
    bpy.ops.object.select_all(action='DESELECT')

    # Highlight the 'Characters' collection - https://blender.stackexchange.com/a/248563
    bpy.context.view_layer.active_layer_collection = \
        bpy.context.view_layer.layer_collection.children['Characters']

    # Find our character FBX's - https://blender.stackexchange.com/a/253543
    folder = bpy.path.abspath("//SourceFiles\\Characters")
    fbxs = [f for f in os.listdir(folder) if f.endswith(".fbx") and f.startswith("Character_")]

    # Import them
    for fbx in fbxs:
        bpy.ops.import_scene.fbx(
            filepath=os.path.join(folder, fbx),
            use_anim=False,
            ignore_leaf_bones=True,
            force_connect_children=True,
            automatic_bone_orientation=True,
        )

    collection = bpy.data.collections["Characters"]

    # Loop through Characters
    first_armature = None
    for obj in collection.objects:
        # Save the first armature object
        if first_armature == None and obj.type == 'ARMATURE':
            first_armature = obj
            continue

        if first_armature != None and obj.type == 'MESH':
            if obj.modifiers and obj.modifiers[0].type == 'ARMATURE':
                # Set all mesh Armature modifiers to the first armature object
                obj.modifiers[0].object = first_armature
            # Make our first armature the object parent
            obj.parent = first_armature

    # Deselect all
    bpy.ops.object.select_all(action='DESELECT')

    # Select unnecessary armatures
    first_armature = None
    for obj in collection.objects:
        if obj.type == 'ARMATURE':
            if first_armature == None:
                first_armature = obj
            else:
                obj.select_set(True)

    # Delete them
    bpy.ops.object.delete()

    # Apply location, rotation, scale to deltas
    for obj in collection.all_objects:
        obj.delta_location += obj.location
        obj.location = (0, 0, 0)
        obj.delta_rotation_euler.rotate(obj.rotation_euler)
        obj.rotation_euler = (0, 0, 0)
        obj.delta_scale = obj.scale
        obj.scale = (1, 1, 1)

    first_armature.name = "Characters"

    # Textures pointing to the wrong directory. Fix that
    # https://blender.stackexchange.com/a/280804
    for image in bpy.data.images.values():
        if image.source == "FILE":
            # Textures are pointing towards PolygonCity. Fix that
            filename = os.path.basename(image.filepath)

            if filename == "Texture_01.psd":
                image.filepath = bpy.path.abspath(
                    "//SourceFiles\\Textures\\Texture_01_A.png"
                )
            else:
                # Make absolute
                image.filepath = bpy.path.abspath(
                    "//SourceFiles\\Textures\\" + filename
                )

import_characters()
POLYGON_Pirates.py
Flynsarmy/synty-in-blender
import bpy
import os

def import_characters():
    # Deselect all
    bpy.ops.object.select_all(action='DESELECT')

    # Highlight the 'Characters' collection - https://blender.stackexchange.com/a/248563
    bpy.context.view_layer.active_layer_collection = \
        bpy.context.view_layer.layer_collection.children['Characters']

    # Find our character FBX's - https://blender.stackexchange.com/a/253543
    folder = bpy.path.abspath("//SourceFiles\\Characters")
    fbxs = [f for f in os.listdir(folder) if f.endswith(".fbx")]

    # Import them
    for fbx in fbxs:
        bpy.ops.import_scene.fbx(
            filepath=os.path.join(folder, fbx),
            use_anim=False,
            ignore_leaf_bones=True,
            force_connect_children=True,
            automatic_bone_orientation=True,
        )

    collection = bpy.data.collections["Characters"]

    # Loop through Characters
    first_armature = None
    for obj in collection.objects:
        # Save the first armature object
        if first_armature == None and obj.type == 'ARMATURE':
            first_armature = obj
            continue

        if first_armature != None and obj.type == 'MESH':
            if obj.modifiers and obj.modifiers[0].type == 'ARMATURE':
                # Set all mesh Armature modifiers to the first armature object
                obj.modifiers[0].object = first_armature
            # Make our first armature the object parent
            obj.parent = first_armature

    # Deselect all
    bpy.ops.object.select_all(action='DESELECT')

    # Select unnecessary armatures
    first_armature = None
    for obj in collection.objects:
        if obj.type == 'ARMATURE':
            if first_armature == None:
                first_armature = obj
            else:
                obj.select_set(True)

    # Delete them
    bpy.ops.object.delete()

    # Apply location, rotation, scale to deltas
    for obj in collection.all_objects:
        obj.delta_location += obj.location
        obj.location = (0, 0, 0)
        obj.delta_rotation_euler.rotate(obj.rotation_euler)
        obj.rotation_euler = (0, 0, 0)
        obj.delta_scale = obj.scale
        obj.scale = (1, 1, 1)

    first_armature.name = "Characters"

    # Textures pointing to the wrong directory. Fix that
    # https://blender.stackexchange.com/a/280804
    for image in bpy.data.images.values():
        if image.source == "FILE":
            # Textures are pointing towards PolygonCity. Fix that
            filename = os.path.basename(image.filepath)

            # Make absolute
            image.filepath = bpy.path.abspath(
                "//SourceFiles\\Textures\\" + filename
            )

import_characters()
POLYGON_Samurai.py
Flynsarmy/synty-in-blender
import bpy
import os

def import_characters():
    # Deselect all
    bpy.ops.object.select_all(action='DESELECT')

    # Highlight the 'Characters' collection - https://blender.stackexchange.com/a/248563
    bpy.context.view_layer.active_layer_collection = \
        bpy.context.view_layer.layer_collection.children['Characters']

    # Import the characters
    bpy.ops.import_scene.fbx(
        filepath=bpy.path.abspath("//Source_Files\\FBX\\Characters.fbx"),
        use_anim=False,
        ignore_leaf_bones=True,
        force_connect_children=True,
        automatic_bone_orientation=True,
    )

    collection = bpy.data.collections["Characters"]

    # Apply location, rotation, scale to deltas
    for obj in collection.all_objects:
        obj.delta_location += obj.location
        obj.location = (0, 0, 0)
        obj.delta_rotation_euler.rotate(obj.rotation_euler)
        obj.rotation_euler = (0, 0, 0)
        obj.delta_scale = obj.scale
        obj.scale = (1, 1, 1)

    # Textures pointing to the wrong directory. Fix that
    # https://blender.stackexchange.com/a/280804
    for image in bpy.data.images.values():
        # Textures are pointing towards wrong file. Fix that
        filename = os.path.basename(image.filepath).replace("PolygonSciFiCity_Texture_", "PolygonSciFi_")
        if image.source == "FILE":
            # Make absolute
            image.filepath = bpy.path.abspath(
                "//Source_Files\\Textures\\" + filename
            )

import_characters()
POLYGON_SciFiCity.py
Flynsarmy/synty-in-blender
import bpy
import os

def import_characters():
    # Deselect all
    bpy.ops.object.select_all(action='DESELECT')

    # Highlight the 'Characters' collection - https://blender.stackexchange.com/a/248563
    bpy.context.view_layer.active_layer_collection = \
        bpy.context.view_layer.layer_collection.children['Characters']

    # Find our character FBX's - https://blender.stackexchange.com/a/253543
    folder = bpy.path.abspath("//_SourceFiles\\Characters")
    fbxs = [f for f in os.listdir(folder) if \
        f.endswith(".fbx") \
        and not "_Suit_" in f \
        and not "_Head_" in f \
        and not f.startswith("SK_Chr_Attach_") \
        # The SpaceSoldier's not ending in 01.fbx are ASCII. Skip them
        and not (f.startswith("SK_Chr_SpaceSoldier_") and not f.endswith("01.fbx"))
    ]

    # Import them
    for fbx in fbxs:
        bpy.ops.import_scene.fbx(
            filepath=os.path.join(folder, fbx),
            use_anim=False,
            ignore_leaf_bones=True,
            force_connect_children=True,
            automatic_bone_orientation=True,
        )

    collection = bpy.data.collections["Characters"]

    # Loop through Characters
    first_armature = None
    for obj in collection.objects:
        # Save the first armature object
        if first_armature == None and obj.type == 'ARMATURE':
            first_armature = obj
            continue

        if first_armature != None and obj.type == 'MESH':
            if obj.modifiers and obj.modifiers[0].type == 'ARMATURE':
                # Set all mesh Armature modifiers to the first armature object
                obj.modifiers[0].object = first_armature

            # Add missing texture node to the material
            texture_path = bpy.path.abspath("//_SourceFiles\\Textures\\PolygonSciFiSpace_Texture_01_A.png")
            for material_slot in obj.material_slots:
                material = material_slot.material

                # https://blender.stackexchange.com/a/129014
                bsdf = material.node_tree.nodes["Principled BSDF"]
                tex_image = material.node_tree.nodes.new('ShaderNodeTexImage')
                tex_image.image = bpy.data.images.load(texture_path)
                material.node_tree.links.new(bsdf.inputs['Base Color'], tex_image.outputs['Color'])

            # Make our first armature the object parent
            obj.parent = first_armature

    # Deselect all
    bpy.ops.object.select_all(action='DESELECT')

    # Remove IK bones
    bpy.context.view_layer.objects.active = first_armature
    bpy.ops.object.mode_set(mode='EDIT')
    # Remove the IK bones
    for bone in first_armature.data.edit_bones:
        if bone.name.startswith("ik_"):
            first_armature.data.edit_bones.remove(bone)
    bpy.ops.object.mode_set(mode='OBJECT')

    # Select unnecessary armatures
    first_armature = None
    for obj in collection.objects:
        if obj.type == 'ARMATURE':
            if first_armature == None:
                first_armature = obj
            else:
                obj.select_set(True)

    # Delete them
    bpy.ops.object.delete()

    # Apply location, rotation, scale to deltas
    for obj in collection.all_objects:
        obj.delta_location += obj.location
        obj.location = (0, 0, 0)
        obj.delta_rotation_euler.rotate(obj.rotation_euler)
        obj.rotation_euler = (0, 0, 0)
        obj.delta_scale = obj.scale
        obj.scale = (1, 1, 1)

    first_armature.name = "Characters"

    # Textures pointing to the wrong directory. Fix that
    # https://blender.stackexchange.com/a/280804
    for image in bpy.data.images.values():
        if image.source == "FILE":
            # Textures are pointing towards PolygonCity. Fix that
            filename = os.path.basename(image.filepath)

            # Make absolute
            image.filepath = bpy.path.abspath(
                "//_SourceFiles\\Textures\\" + filename
            )

import_characters()
POLYGON_SciFiSpace.py
Flynsarmy/synty-in-blender
import bpy
import os

def import_characters():
    # Deselect all
    bpy.ops.object.select_all(action='DESELECT')

    # Highlight the 'Characters' collection - https://blender.stackexchange.com/a/248563
    bpy.context.view_layer.active_layer_collection = \
        bpy.context.view_layer.layer_collection.children['Characters']

    # Import the characters
    bpy.ops.import_scene.fbx(
        filepath=bpy.path.abspath("//SourceFiles\\FBX\\Characters.fbx"),
        use_anim=False,
        ignore_leaf_bones=True,
        force_connect_children=True,
        automatic_bone_orientation=True,
    )

    collection = bpy.data.collections["Characters"]

    # Apply location, rotation, scale to deltas
    for obj in collection.all_objects:
        obj.delta_location += obj.location
        obj.location = (0, 0, 0)
        obj.delta_rotation_euler.rotate(obj.rotation_euler)
        obj.rotation_euler = (0, 0, 0)
        obj.delta_scale = obj.scale
        obj.scale = (1, 1, 1)

    # Textures pointing to the wrong directory. Fix that
    # https://blender.stackexchange.com/a/280804
    for image in bpy.data.images.values():
        # Textures are pointing towards PolygonCity. Fix that
        filename = os.path.basename(image.filepath)
        if image.source == "FILE":
            if filename == "Polygonstarter_Texture_01_A_2k.psd":
                # Make absolute
                image.filepath = bpy.path.abspath(
                    "//SourceFiles\\Textures\\PolygonStarter_Texture_01.png"
                )
            else:
                # Make absolute
                image.filepath = bpy.path.abspath(
                    "//SourceFiles\\Textures\\" + filename
                )

import_characters()
POLYGON_Starter.py
Flynsarmy/synty-in-blender
import bpy
import os

def import_characters():
    # Deselect all
    bpy.ops.object.select_all(action='DESELECT')

    # Highlight the 'Characters' collection - https://blender.stackexchange.com/a/248563
    bpy.context.view_layer.active_layer_collection = \
        bpy.context.view_layer.layer_collection.children['Characters']

    # Import the characters
    bpy.ops.import_scene.fbx(
        filepath=bpy.path.abspath("//PolygonStreetRacer_SourceFiles\\FBX\\Characters.fbx"),
        use_anim=False,
        ignore_leaf_bones=True,
        force_connect_children=True,
        automatic_bone_orientation=True,
    )

    collection = bpy.data.collections["Characters"]

    # Apply location, rotation, scale to deltas
    for obj in collection.all_objects:
        obj.delta_location += obj.location
        obj.location = (0, 0, 0)
        obj.delta_rotation_euler.rotate(obj.rotation_euler)
        obj.rotation_euler = (0, 0, 0)
        obj.delta_scale = obj.scale
        obj.scale = (1, 1, 1)

    # Textures pointing to the wrong directory. Fix that
    # https://blender.stackexchange.com/a/280804
    for image in bpy.data.images.values():
        # Textures are pointing towards PolygonCity. Fix that
        filename = os.path.basename(image.filepath)
        if image.source == "FILE":
            if filename == "PolygonStreetRacer_Texture_Master.psd":
                # Make absolute
                image.filepath = bpy.path.abspath(
                    "//PolygonStreetRacer_SourceFiles\\Textures\\PolygonStreetRacer_Texture_01_A.png"
                )
            else:
                # Make absolute
                image.filepath = bpy.path.abspath(
                    "//PolygonStreetRacer_SourceFiles\\Textures\\" + filename
                )

import_characters()
POLYGON_StreetRacer.py
Flynsarmy/synty-in-blender
import bpy
import os

def import_characters():
    # Deselect all
    bpy.ops.object.select_all(action='DESELECT')

    # Highlight the 'Characters' collection - https://blender.stackexchange.com/a/248563
    bpy.context.view_layer.active_layer_collection = \
        bpy.context.view_layer.layer_collection.children['Characters']

    # Find our character FBX's - https://blender.stackexchange.com/a/253543
    folder = bpy.path.abspath("//Source_Files\\Character_Files\\FBX_Characters")
    fbxs = [f for f in os.listdir(folder) if f.endswith(".fbx")]

    # Import them
    for fbx in fbxs:
        bpy.ops.import_scene.fbx(
            filepath=os.path.join(folder, fbx),
            use_anim=False,
            ignore_leaf_bones=True,
            force_connect_children=True,
            automatic_bone_orientation=True,
        )

    collection = bpy.data.collections["Characters"]

    # Loop through Characters
    first_armature = None
    for obj in collection.objects:
        # Save the first armature object
        if first_armature == None and obj.type == 'ARMATURE':
            first_armature = obj
            continue

        if first_armature != None and obj.type == 'MESH':
            if obj.modifiers and obj.modifiers[0].type == 'ARMATURE':
                # Set all mesh Armature modifiers to the first armature object
                obj.modifiers[0].object = first_armature
            # Make our first armature the object parent
            obj.parent = first_armature

    # Deselect all
    bpy.ops.object.select_all(action='DESELECT')

    # Select unnecessary armatures
    first_armature = None
    for obj in collection.objects:
        if obj.type == 'ARMATURE':
            if first_armature == None:
                first_armature = obj
            else:
                obj.select_set(True)

    # Delete them
    bpy.ops.object.delete()

    # Apply location, rotation, scale to deltas
    for obj in collection.all_objects:
        obj.delta_location += obj.location
        obj.location = (0, 0, 0)
        obj.delta_rotation_euler.rotate(obj.rotation_euler)
        obj.rotation_euler = (0, 0, 0)
        obj.delta_scale = obj.scale
        obj.scale = (1, 1, 1)

    first_armature.name = "Characters"

    # Textures pointing to the wrong directory. Fix that
    # https://blender.stackexchange.com/a/280804
    for image in bpy.data.images.values():
        if image.source == "FILE":
            # Textures are pointing towards PolygonCity. Fix that
            filename = os.path.basename(image.filepath)

            # Make absolute
            image.filepath = bpy.path.abspath(
                "//Source_Files\\Textures\\" + filename
            )

import_characters()
POLYGON_Vikings.py
Flynsarmy/synty-in-blender
import bpy
import os

def import_characters():
    # Deselect all
    bpy.ops.object.select_all(action='DESELECT')

    # Highlight the 'Characters' collection - https://blender.stackexchange.com/a/248563
    bpy.context.view_layer.active_layer_collection = \
        bpy.context.view_layer.layer_collection.children['Characters']

    # Find our character FBX's - https://blender.stackexchange.com/a/253543
    folder = bpy.path.abspath("//Source Files\\Characters")
    fbxs = [f for f in os.listdir(folder) if \
        f.endswith(".fbx") \
        # Unsupported FBX version
        and f not in [
            "Character_German_Leader_01.fbx",
            "Character_Gernman_Officer_02.fbx",
            "Character_Pilot_01.fbx"
        ]
    ]

    # Import them
    for fbx in fbxs:
        bpy.ops.import_scene.fbx(
            filepath=os.path.join(folder, fbx),
            use_anim=False,
            ignore_leaf_bones=True,
            force_connect_children=True,
            automatic_bone_orientation=True,
        )

    collection = bpy.data.collections["Characters"]

    # Loop through Characters
    first_armature = None
    for obj in collection.objects:
        # Save the first armature object
        if first_armature == None and obj.type == 'ARMATURE':
            first_armature = obj
            continue

        if first_armature != None and obj.type == 'MESH':
            if obj.modifiers and obj.modifiers[0].type == 'ARMATURE':
                # Set all mesh Armature modifiers to the first armature object
                obj.modifiers[0].object = first_armature
            # Make our first armature the object parent
            obj.parent = first_armature

    # Deselect all
    bpy.ops.object.select_all(action='DESELECT')

    # Select unnecessary armatures
    first_armature = None
    for obj in collection.objects:
        if obj.type == 'ARMATURE':
            if first_armature == None:
                first_armature = obj
            else:
                obj.select_set(True)

    # Delete them
    bpy.ops.object.delete()

    # Apply location, rotation, scale to deltas
    for obj in collection.all_objects:
        obj.delta_location += obj.location
        obj.location = (0, 0, 0)
        obj.delta_rotation_euler.rotate(obj.rotation_euler)
        obj.rotation_euler = (0, 0, 0)

        # Armature is 100x too large
        if obj.type == "ARMATURE":
            obj.delta_scale = obj.scale / 100
            obj.scale = (1, 1, 1)
        elif obj.type == "MESH":
            obj.delta_scale = obj.scale * 100
            obj.scale = (1, 1, 1)


    first_armature.name = "Characters"

    # Textures pointing to the wrong directory. Fix that
    # https://blender.stackexchange.com/a/280804
    for image in bpy.data.images.values():
        if image.source == "FILE":
            # Textures are pointing towards wrong file. Fix that
            filename = os.path.basename(image.filepath)

            if filename == "PolygonWar_Texture_01.png":
                filename = "PolygonWar_Texture_01_A.png"

            # Make absolute
            image.filepath = bpy.path.abspath(
                "//Source Files\\Textures\\" + filename
            )

import_characters()
POLYGON_War.py
Flynsarmy/synty-in-blender
import bpy
import os

def import_characters():
    # Deselect all
    bpy.ops.object.select_all(action='DESELECT')

    # Highlight the 'Characters' collection - https://blender.stackexchange.com/a/248563
    bpy.context.view_layer.active_layer_collection = \
        bpy.context.view_layer.layer_collection.children['Characters']

    # Find our character FBX's - https://blender.stackexchange.com/a/253543
    folder = bpy.path.abspath("//SourceFiles\\FBX")
    fbxs = [f for f in os.listdir(folder) if f.endswith(".fbx") and f.startswith("SK_Character_")]

    # Import them
    for fbx in fbxs:
        bpy.ops.import_scene.fbx(
            filepath=os.path.join(folder, fbx),
            use_anim=False,
            ignore_leaf_bones=True,
            force_connect_children=True,
            automatic_bone_orientation=True,
        )

    collection = bpy.data.collections["Characters"]

    # Loop through Characters
    first_armature = None
    for obj in collection.objects:
        # Save the first armature object
        if first_armature == None and obj.type == 'ARMATURE':
            first_armature = obj
            continue

        if first_armature != None and obj.type == 'MESH':
            if obj.modifiers and obj.modifiers[0].type == 'ARMATURE':
                # Set all mesh Armature modifiers to the first armature object
                obj.modifiers[0].object = first_armature
            # Make our first armature the object parent
            obj.parent = first_armature

    # Deselect all
    bpy.ops.object.select_all(action='DESELECT')

    # Remove IK bones
    bpy.context.view_layer.objects.active = first_armature
    bpy.ops.object.mode_set(mode='EDIT')
    # Remove the IK bones
    for bone in first_armature.data.edit_bones:
        if bone.name.startswith("ik_"):
            first_armature.data.edit_bones.remove(bone)
    bpy.ops.object.mode_set(mode='OBJECT')

    # Select unnecessary armatures
    first_armature = None
    for obj in collection.objects:
        if obj.type == 'ARMATURE':
            if first_armature == None:
                first_armature = obj
            else:
                obj.select_set(True)

    # Delete them
    bpy.ops.object.delete()

    # Apply location, rotation, scale to deltas
    for obj in collection.all_objects:
        obj.delta_location += obj.location
        obj.location = (0, 0, 0)
        obj.delta_rotation_euler.rotate(obj.rotation_euler)
        obj.rotation_euler = (0, 0, 0)
        obj.delta_scale = obj.scale
        obj.scale = (1, 1, 1)

    first_armature.name = "Characters"

    # Textures pointing to the wrong directory. Fix that
    # https://blender.stackexchange.com/a/280804
    for image in bpy.data.images.values():
        if image.source == "FILE":
            # Textures are pointing towards wrong file. Fix that
            filename = os.path.basename(image.filepath)

            if filename == "PolygonWar_Map_Texture_Mike.psd":
                filename = "PolygonWar_Map_Texture_01_A.png"

            # Make absolute
            image.filepath = bpy.path.abspath(
                "//SourceFiles\\Textures\\" + filename
            )

import_characters()
POLYGON_WarMap.py
Flynsarmy/synty-in-blender
import bpy
import os

def import_characters():
    # Deselect all
    bpy.ops.object.select_all(action='DESELECT')

    # Highlight the 'Characters' collection - https://blender.stackexchange.com/a/248563
    bpy.context.view_layer.active_layer_collection = \
        bpy.context.view_layer.layer_collection.children['Characters']

    # Find our character FBX's - https://blender.stackexchange.com/a/253543
    folder = bpy.path.abspath("//Characters")
    fbxs = [f for f in os.listdir(folder) if f.endswith(".fbx")]

    # Import them
    for fbx in fbxs:
        bpy.ops.import_scene.fbx(
            filepath=os.path.join(folder, fbx),
            use_anim=False,
            ignore_leaf_bones=True,
            force_connect_children=True,
            automatic_bone_orientation=True,
        )

    collection = bpy.data.collections["Characters"]

    # Loop through Characters
    first_armature = None
    for obj in collection.objects:
        # Save the first armature object
        if first_armature == None and obj.type == 'ARMATURE':
            first_armature = obj
            continue

        if first_armature != None and obj.type == 'MESH':
            if obj.modifiers and obj.modifiers[0].type == 'ARMATURE':
                # Set all mesh Armature modifiers to the first armature object
                obj.modifiers[0].object = first_armature
            # Make our first armature the object parent
            obj.parent = first_armature

    # Deselect all
    bpy.ops.object.select_all(action='DESELECT')


    # Remove IK bones
    bpy.context.view_layer.objects.active = first_armature
    bpy.ops.object.mode_set(mode='EDIT')
    # Remove the IK bones
    for bone in first_armature.data.edit_bones:
        if bone.name.startswith("ik_"):
            first_armature.data.edit_bones.remove(bone)
    bpy.ops.object.mode_set(mode='OBJECT')

    # Select unnecessary armatures
    first_armature = None
    for obj in collection.objects:
        if obj.type == 'ARMATURE':
            if first_armature == None:
                first_armature = obj
            else:
                obj.select_set(True)

    # Delete them
    bpy.ops.object.delete()

    # Apply location, rotation, scale to deltas
    for obj in collection.all_objects:
        obj.delta_location += obj.location
        obj.location = (0, 0, 0)
        obj.delta_rotation_euler.rotate(obj.rotation_euler)
        obj.rotation_euler = (0, 0, 0)
        obj.delta_scale = obj.scale
        obj.scale = (1, 1, 1)

    first_armature.name = "Characters"

    # Textures pointing to the wrong directory. Fix that
    # https://blender.stackexchange.com/a/280804
    for image in bpy.data.images.values():
        filename = os.path.basename(image.filepath)
        if image.source == "FILE":
            if filename == "PolygonWestern_Texture.psd":
                # Make absolute
                image.filepath = bpy.path.abspath(
                    "//Textures\\PolygonWestern_Texture_01.png"
                )
            else:
                # Make absolute
                image.filepath = bpy.path.abspath(
                    "//Textures\\" + filename
                )

import_characters()
POLYGON_Western.py
Flynsarmy/synty-in-blender