โจ๐ฌ ๐๐๐ฌ ๐๐ค๐ค๐ก ๐๐ฃ๐ฉ๐ง๐ค: "AssetLocator" ๐
Hey there, fellow Maya professionals! ๐
Day 04ย of the 100-Days Challenge brings you an exciting and essential toolโAssetLocatorโdesigned to help you locate and manage assetsย across complex Maya projects. Whether you're working with multiple references, texture files, or external assets, keeping track of everything can get tricky. AssetLocatorย does the heavy lifting by automating the process of finding missing or broken file references, ensuring that your projects are always in sync.
๐๐ฉ๐ข๐ต ๐ผ๐จ๐จ๐๐ฉ๐๐ค๐๐๐ฉ๐ค๐ง Offers:
Asset Tracking:ย Quickly locate missing file references, including textures, models, and external files.
Path Fixing:ย Automatically repair broken file paths or prompt the user for correct locations.
Cross-Project Compatibility:ย Works seamlessly with multiple Maya projects and references.
๐ ๏ธ ๐ผ๐จ๐จ๐๐ฉ๐๐ค๐๐๐ฉ๐ค๐ง (maya.cmds Version):
##1 import maya.cmds as mc import os def locate_and_fix_missing_files(base_path="", fix_paths=False): """ Locates missing file textures and references in the Maya scene. Optionally attempts to fix broken paths using a base path.
Parameters: base_path (str): The base directory to search for missing assets. fix_paths (bool): If True, attempts to fix broken paths by searching in the base_path.
Returns: dict: A dictionary with 'missing_files' and 'fixed_files' lists. """ missing_files = set() fixed_files = [] # Check for missing file texture nodes file_nodes = mc.ls(type='file') for node in file_nodes: file_path = mc.getAttr(node + '.fileTextureName') if file_path and not os.path.exists(file_path): missing_files.add(file_path) if fix_paths and base_path: potential_file = os.path.join(base_path, os.path.basename(file_path)) if os.path.exists(potential_file): mc.setAttr(node + '.fileTextureName', potential_file, type='string') fixed_files.append(potential_file) # Check for missing references references = mc.file(query=True, reference=True) for ref_file in references: if not os.path.exists(ref_file): missing_files.add(ref_file) if fix_paths and base_path: potential_file = os.path.join(base_path, os.path.basename(ref_file)) if os.path.exists(potential_file): ref_node = mc.file(ref_file, query=True, referenceNode=True) mc.file(potential_file, loadReference=ref_node) fixed_files.append(potential_file) if missing_files: print("Missing Files Detected:") for file in missing_files: print("Missing: {}".format(file)) if fix_paths and base_path: if file in fixed_files: print("Fixed: {}".format(file)) else: print("Cannot locate: {}".format(file)) else: print("No missing files found.") return {'missing_files': list(missing_files), 'fixed_files': fixed_files} # Example usage: # To locate missing files without attempting to fix paths: locate_and_fix_missing_files() # To locate and attempt to fix missing files using a base path: # base_path = "/path/to/your/assets" # locate_and_fix_missing_files(base_path=base_path, fix_paths=True) |
๐ ๏ธ ๐ผ๐จ๐จ๐๐ฉ๐๐ค๐๐๐ฉ๐ค๐ง (PySide2 Version):
import maya.cmds as mc import os from PySide2 import QtWidgets, QtCore, QtGui import maya.OpenMayaUI as omui from shiboken2 import wrapInstance def maya_main_window(): """ Returns Maya's main window as a QWidget instance. """ main_window_ptr = omui.MQtUtil.mainWindow() return wrapInstance(long(main_window_ptr), QtWidgets.QWidget) class AssetLocatorUI(QtWidgets.QDialog): """ AssetLocatorUI helps locate and fix missing file references in a Maya project. This UI has a sleek, stylish look with orange highlights and a dark theme. """ instance = None # Singleton instance def __init__(self, parent=None): super(AssetLocatorUI, self).__init__(parent or maya_main_window()) # Set window properties self.setWindowTitle('Asset Locator') self.setObjectName('AssetLocatorUI') self.setWindowFlags(QtCore.Qt.Window | QtCore.Qt.WindowStaysOnTopHint) self.resize(500, 400) # Apply advanced styling self.setStyleSheet(""" QWidget#AssetLocatorUI { background-color: #2C2C2C; /* Dark background */ border: 2px solid #FF914D; /* Orange border */ border-radius: 10px; font-family: 'Agave'; color: #F5F5F5; } QLabel { font-family: 'Agave'; color: #F5F5F5; } QPushButton { font-family: 'Agave'; background-color: #4A4A4A; color: #FFFFFF; border: 2px solid #FF914D; border-radius: 8px; padding: 8px 15px; transition: all 0.3s ease; } QPushButton:hover { background-color: #FF914D; color: #2C2C2C; border: 2px solid #F5F5F5; } QPushButton:pressed { background-color: #FF7043; border: 2px solid #FF914D; } QLineEdit { background-color: #3A3A3A; border: 2px solid #FF914D; border-radius: 5px; padding: 4px; color: #F5F5F5; } QScrollArea { background-color: #2C2C2C; border: none; } """) self.fix_paths = False self.base_path = "" # Set layout self.layout = QtWidgets.QVBoxLayout() self.layout.setContentsMargins(10, 10, 10, 10) # Status label self.status_label = QtWidgets.QLabel("Click 'Locate Missing Files' to begin.") self.layout.addWidget(self.status_label) # Scroll area for missing files self.scroll_area = QtWidgets.QScrollArea() self.scroll_area.setWidgetResizable(True) self.scroll_content = QtWidgets.QWidget() self.scroll_layout = QtWidgets.QVBoxLayout(self.scroll_content) self.scroll_area.setWidget(self.scroll_content) self.layout.addWidget(self.scroll_area) # Base path input base_path_layout = QtWidgets.QHBoxLayout() self.base_path_label = QtWidgets.QLabel("Base Path:") self.base_path_input = QtWidgets.QLineEdit() self.base_path_input.setPlaceholderText("Enter base path to search for assets") base_path_layout.addWidget(self.base_path_label) base_path_layout.addWidget(self.base_path_input) self.layout.addLayout(base_path_layout) # Fix paths checkbox self.fix_paths_checkbox = QtWidgets.QCheckBox("Attempt to fix broken paths") self.layout.addWidget(self.fix_paths_checkbox) # Locate button self.locate_button = QtWidgets.QPushButton("Locate Missing Files") self.locate_button.clicked.connect(self.locate_files) self.layout.addWidget(self.locate_button) # Cancel button self.cancel_button = QtWidgets.QPushButton("Close") self.cancel_button.clicked.connect(self.close) self.layout.addWidget(self.cancel_button) # Set layout self.setLayout(self.layout) @classmethod def display(cls): """ Displays the AssetLocatorUI, ensuring only one instance exists. """ if cls.instance is None or not cls.instance.isVisible(): cls.instance = AssetLocatorUI() cls.instance.show() else: cls.instance.raise_() cls.instance.activateWindow() def locate_files(self): """ Locates missing files and updates the UI with their status. """ self.fix_paths = self.fix_paths_checkbox.isChecked() self.base_path = self.base_path_input.text() # Clear previous results for i in reversed(range(self.scroll_layout.count())): widget = self.scroll_layout.takeAt(i).widget() if widget is not None: widget.setParent(None) missing_files = set() # Check for missing file texture nodes file_nodes = mc.ls(type='file') for node in file_nodes: file_path = mc.getAttr(node + '.fileTextureName') if file_path and not os.path.exists(file_path): missing_files.add(file_path) # Check for missing references references = mc.ls(type='reference') for ref_node in references: if ref_node == 'sharedReferenceNode': continue # Skip the shared reference node try: ref_file = mc.referenceQuery(ref_node, filename=True) if ref_file and not os.path.exists(ref_file): missing_files.add(ref_file) except RuntimeError: # Handle unloaded or broken references ref_file = mc.referenceQuery(ref_node, filename=True, unresolvedName=True) if ref_file and not os.path.exists(ref_file): missing_files.add(ref_file) if missing_files: self.status_label.setText("Missing Files Detected:") for file in missing_files: label = QtWidgets.QLabel("Missing: {0}".format(file)) self.scroll_layout.addWidget(label) if self.fix_paths and self.base_path: potential_file = os.path.join(self.base_path, os.path.basename(file)) if os.path.exists(potential_file): # For file textures file_nodes_with_path = mc.ls(type='file') for node in file_nodes_with_path: node_file_path = mc.getAttr(node + '.fileTextureName') if node_file_path == file: mc.setAttr(node + '.fileTextureName', potential_file, type='string') label.setText("Fixed: {0}".format(potential_file)) # For references reference_nodes = mc.ls(type='reference') for ref_node in reference_nodes: if ref_node == 'sharedReferenceNode': continue try: ref_file = mc.referenceQuery(ref_node, filename=True) except RuntimeError: ref_file = mc.referenceQuery(ref_node, filename=True, unresolvedName=True) if ref_file == file: mc.file(potential_file, loadReference=ref_node) label.setText("Fixed Reference: {0}".format(potential_file)) else: label.setText("Cannot locate: {0}".format(file)) else: self.status_label.setText("No missing files found.") def closeEvent(self, event): """ Overrides the close event to reset the instance variable. """ AssetLocatorUI.instance = None event.accept() # Function to display the AssetLocatorUI def show_asset_locator_ui(): AssetLocatorUI.display() # Example usage show_asset_locator_ui() |
๐ ๐ผ๐จ๐จ๐๐ฉ๐๐ค๐๐๐ฉ๐ค๐ง Benefits:
Find & Fix:ย Quickly identify and resolve missing file references in large projects.
User-Friendly: The UI provides instant feedback on missing assets, guiding you through fixing broken paths.
Project Optimization:ย Maintain organized and error-free file management across different projects.
๐ง ๐๐๐ฎ ๐ฝ๐๐ฃ๐๐๐๐ฉ๐จ:
โข ๐ Locate Broken Links:ย Ensure all your projectโs file references are intact and accessible.
โข ๐ ๏ธ Auto Fix Paths:ย Automatically repair broken file paths by searching in specified directories.
โข ๐ Efficient File Management:ย Spend less time troubleshooting missing files and more time creating.
โจ Ready to Keep Your Projects in Sync?Try out AssetLocatorย and keep your Maya projects running smoothly. Comment below or reach out to see it in action! ๐ช๐
Subbu's Linksโข YouTube Channel: https://www.youtube.com/@118subbuโข Vimeo:ย https://vimeo.com/subbu118โข Creature Rigging:ย https://www.creaturerigging.comโข Python Scripting:ย https://www.pythonscripting.comโข Hyper Rig:ย https://www.hyper-rig.com
#HappyScripting #MayaUI #AssetLocator #PipelineOptimization #Maya #PythonScripting #MayaTools #VFX #3DAnimation #ScriptDevelopment #MayaDevelopment #Automation #WorkflowEnhancement #TechnicalArt #ScriptingTools
Comments