From 10337d6a1ba82b860a4938884352b59442f8ea23 Mon Sep 17 00:00:00 2001 From: "Patrick W. Crawford" Date: Sat, 11 Mar 2023 15:17:09 -0500 Subject: [PATCH] Edit sync file button and using json lookup for sync mats. This greatly improves the usability of the sync materials function, as users can now easily open to edit the sync file (matching their resource pack), as well as use the MCprep built in generate materials function and still have the material lookups match from their imported OBJs. Before this change, materials had to be exact matches, and there was no easy way to get to the sync material file or to create your own sync file for a custom resource pack without very manual steps. --- MCprep_addon/materials/sync.py | 89 ++++++++++++++++++++++++++-------- MCprep_addon/mcprep_ui.py | 5 +- 2 files changed, 74 insertions(+), 20 deletions(-) diff --git a/MCprep_addon/materials/sync.py b/MCprep_addon/materials/sync.py index 99cd772c..86169b22 100644 --- a/MCprep_addon/materials/sync.py +++ b/MCprep_addon/materials/sync.py @@ -22,6 +22,7 @@ import bpy from bpy.app.handlers import persistent +from . import generate from .. import conf from .. import tracking from .. import util @@ -55,28 +56,35 @@ def reload_material_sync_library(context): conf.log("Updated sync cache", vv_only=True) -def material_in_sync_library(material, context): +def material_in_sync_library(mat_name, context): """Returns true if the material is in the sync mat library blend file""" if conf.material_sync_cache is None: reload_material_sync_library(context) - if util.nameGeneralize(material.name) in conf.material_sync_cache: + if util.nameGeneralize(mat_name) in conf.material_sync_cache: return True - elif material.name in conf.material_sync_cache: + elif mat_name in conf.material_sync_cache: return True return False -def sync_material(context, material, link, replace): +def sync_material(context, source_mat, sync_mat_name, link, replace): """If found, load and apply the material found in a library. + Args: + context: Current bpy context. + source_mat: bpy.Types.Material in the current open blend file + sync_mat_name: str of the mat to try to replace in. + link: Bool, if true then new material is linkd instead of appended. + replace: If true, the old material in this file is immediately rm'd. + Returns: 0 if nothing modified, 1 if modified None if no error or string if error """ - if material.name in conf.material_sync_cache: - import_name = material.name - elif util.nameGeneralize(material.name) in conf.material_sync_cache: - import_name = util.nameGeneralize(material.name) + if sync_mat_name in conf.material_sync_cache: + import_name = sync_mat_name + elif util.nameGeneralize(sync_mat_name) in conf.material_sync_cache: + import_name = util.nameGeneralize(sync_mat_name) # if link is true, check library material not already linked sync_file = get_sync_blend(context) @@ -85,16 +93,16 @@ def sync_material(context, material, link, replace): imported = set(bpy.data.materials[:]) - set(init_mats) if not imported: - return 0, "Could not import " + str(material.name) + return 0, "Could not import {}".format(import_name) new_material = list(imported)[0] # 2.78+ only, else silent failure - res = util.remap_users(material, new_material) + res = util.remap_users(source_mat, new_material) if res != 0: # try a fallback where we at least go over the selected objects return 0, res if replace is True: - bpy.data.materials.remove(material) + bpy.data.materials.remove(source_mat) return 1, None @@ -156,22 +164,33 @@ def execute(self, context): # gets the list of materials (without repetition) from selected mat_list = util.materialsFromObj(obj_list) - if not mat_list: - if not self.skipUsage: - self.report({'ERROR'}, "No materials found on selected objects") - return {'CANCELLED'} else: mat_list = list(bpy.data.materials) + if not mat_list: + if not self.skipUsage: + self.report({'ERROR'}, "No materials to sync") + return {'CANCELLED'} + # consider force reloading the material library blend eligible = 0 modified = 0 last_err = None for mat in mat_list: - if not material_in_sync_library(mat, context): + # Match either exact name, or translated name. + lookup_match, _ = generate.get_mc_canonical_name(mat.name) + if material_in_sync_library(mat.name, context) is True: + sync_mat_name = mat.name + elif material_in_sync_library(lookup_match, context) is True: + sync_mat_name = lookup_match + else: continue affected, err = sync_material( - context, mat, self.link, self.replace_materials) + context, + source_mat=mat, + sync_mat_name=sync_mat_name, + link=self.link, + replace=self.replace_materials) eligible += 1 modified += affected if err: @@ -202,6 +221,37 @@ def execute(self, context): return {'FINISHED'} +class MCPREP_OT_edit_sync_materials_file(bpy.types.Operator): + """Open the the file used fo syncrhonization.""" + bl_idname = "mcprep.edit_sync_materials_file" + bl_label = "Edit sync file" + bl_options = {'REGISTER', 'UNDO'} + + track_function = "edit_sync_materials" + track_param = None + @tracking.report_error + def execute(self, context): + file = get_sync_blend(context) + if not bpy.data.is_saved: + self.report({'ERROR'}, "Save your blend file first") + return {'CANCELLED'} + + # Will open without saving or prompting! + # TODO: Perform action more similar to the asset browser, which opens + # a new instance of blender. + if os.path.isfile(file): + bpy.ops.wm.open_mainfile(filepath=file) + else: + # Open and save a new sync file instead. + bpy.ops.wm.read_homefile(use_empty=True) + + # Set the local resource pack to match this generated file. + bpy.context.scene.mcprep_texturepack_path = "//" + + bpy.ops.wm.save_as_mainfile(filepath=file) + return {'FINISHED'} + + # ----------------------------------------------------------------------------- # Registration # ----------------------------------------------------------------------------- @@ -209,6 +259,7 @@ def execute(self, context): classes = ( MCPREP_OT_sync_materials, + MCPREP_OT_edit_sync_materials_file, ) @@ -224,5 +275,5 @@ def unregister(): bpy.utils.unregister_class(cls) try: bpy.app.handlers.load_post.remove(clear_sync_cache) - except: - pass + except Exception as e: + print("Unregister post handler error: ", e) diff --git a/MCprep_addon/mcprep_ui.py b/MCprep_addon/mcprep_ui.py index 9f084068..f69493ac 100644 --- a/MCprep_addon/mcprep_ui.py +++ b/MCprep_addon/mcprep_ui.py @@ -805,7 +805,10 @@ def draw(self, context): b_row = box.row() b_col = b_row.column(align=True) - b_col.operator("mcprep.sync_materials") + sync_row = b_col.row(align=True) + sync_row.operator("mcprep.sync_materials") + sync_row.operator( + "mcprep.edit_sync_materials_file", text="", icon="FILE_TICK") # or TOOL_SETTINGS. b_col.operator("mcprep.replace_missing_textures") b_col.operator("mcprep.animate_textures") # TODO: operator to make all local, all packed, or set to other location