Merge pull request #93 from ynput/enhancement/OP-8297_Remove-maya-shader-definition

Maya: Remove shader definition
This commit is contained in:
Kayla Man 2024-02-20 18:48:34 +08:00 committed by GitHub
commit 7199c97ee3
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
3 changed files with 0 additions and 356 deletions

View file

@ -38,25 +38,6 @@ class ToolWindows:
cls._windows[tool] = window
def edit_shader_definitions():
from qtpy import QtWidgets
from ayon_core.hosts.maya.api.shader_definition_editor import (
ShaderDefinitionsEditor
)
from ayon_core.tools.utils import qt_app_context
top_level_widgets = QtWidgets.QApplication.topLevelWidgets()
main_window = next(widget for widget in top_level_widgets
if widget.objectName() == "MayaWindow")
with qt_app_context():
window = ToolWindows.get_window("shader_definition_editor")
if not window:
window = ShaderDefinitionsEditor(parent=main_window)
ToolWindows.set_window("shader_definition_editor", window)
window.show()
def _resolution_from_document(doc):
if not doc or "data" not in doc:
print("Entered document is not valid. \"{}\"".format(str(doc)))

View file

@ -1,176 +0,0 @@
# -*- coding: utf-8 -*-
"""Editor for shader definitions.
Shader names are stored as simple text file over GridFS in mongodb.
"""
import os
from qtpy import QtWidgets, QtCore, QtGui
from ayon_core.client.mongo import OpenPypeMongoConnection
from ayon_core import resources
import gridfs
DEFINITION_FILENAME = "{}/maya/shader_definition.txt".format(
os.getenv("AYON_PROJECT_NAME"))
class ShaderDefinitionsEditor(QtWidgets.QWidget):
"""Widget serving as simple editor for shader name definitions."""
# name of the file used to store definitions
def __init__(self, parent=None):
super(ShaderDefinitionsEditor, self).__init__(parent)
self._mongo = OpenPypeMongoConnection.get_mongo_client()
self._gridfs = gridfs.GridFS(
self._mongo[os.getenv("OPENPYPE_DATABASE_NAME")])
self._editor = None
self._original_content = self._read_definition_file()
self.setObjectName("shaderDefinitionEditor")
self.setWindowTitle("OpenPype shader name definition editor")
icon = QtGui.QIcon(resources.get_ayon_icon_filepath())
self.setWindowIcon(icon)
self.setWindowFlags(QtCore.Qt.Window)
self.setParent(parent)
self.setAttribute(QtCore.Qt.WA_DeleteOnClose)
self.resize(750, 500)
self._setup_ui()
self._reload()
def _setup_ui(self):
"""Setup UI of Widget."""
layout = QtWidgets.QVBoxLayout(self)
label = QtWidgets.QLabel()
label.setText("Put shader names here - one name per line:")
layout.addWidget(label)
self._editor = QtWidgets.QPlainTextEdit()
self._editor.setStyleSheet("border: none;")
layout.addWidget(self._editor)
btn_layout = QtWidgets.QHBoxLayout()
save_btn = QtWidgets.QPushButton("Save")
save_btn.clicked.connect(self._save)
reload_btn = QtWidgets.QPushButton("Reload")
reload_btn.clicked.connect(self._reload)
exit_btn = QtWidgets.QPushButton("Exit")
exit_btn.clicked.connect(self._close)
btn_layout.addWidget(reload_btn)
btn_layout.addWidget(save_btn)
btn_layout.addWidget(exit_btn)
layout.addLayout(btn_layout)
def _read_definition_file(self, file=None):
"""Read definition file from database.
Args:
file (gridfs.grid_file.GridOut, Optional): File to read. If not
set, new query will be issued to find it.
Returns:
str: Content of the file or empty string if file doesn't exist.
"""
content = ""
if not file:
file = self._gridfs.find_one(
{"filename": DEFINITION_FILENAME})
if not file:
print(">>> [SNDE]: nothing in database yet")
return content
content = file.read()
file.close()
return content
def _write_definition_file(self, content, force=False):
"""Write content as definition to file in database.
Before file is written, check is made if its content has not
changed. If is changed, warning is issued to user if he wants
it to overwrite. Note: GridFs doesn't allow changing file content.
You need to delete existing file and create new one.
Args:
content (str): Content to write.
Raises:
ContentException: If file is changed in database while
editor is running.
"""
file = self._gridfs.find_one(
{"filename": DEFINITION_FILENAME})
if file:
content_check = self._read_definition_file(file)
if content == content_check:
print(">>> [SNDE]: content not changed")
return
if self._original_content != content_check:
if not force:
raise ContentException("Content changed")
print(">>> [SNDE]: overwriting data")
file.close()
self._gridfs.delete(file._id)
file = self._gridfs.new_file(
filename=DEFINITION_FILENAME,
content_type='text/plain',
encoding='utf-8')
file.write(content)
file.close()
QtCore.QTimer.singleShot(200, self._reset_style)
self._editor.setStyleSheet("border: 1px solid #33AF65;")
self._original_content = content
def _reset_style(self):
"""Reset editor style back.
Used to visually indicate save.
"""
self._editor.setStyleSheet("border: none;")
def _close(self):
self.hide()
def closeEvent(self, event):
event.ignore()
self.hide()
def _reload(self):
print(">>> [SNDE]: reloading")
self._set_content(self._read_definition_file())
def _save(self):
try:
self._write_definition_file(content=self._editor.toPlainText())
except ContentException:
# content has changed meanwhile
print(">>> [SNDE]: content has changed")
self._show_overwrite_warning()
def _set_content(self, content):
self._editor.setPlainText(content)
def _show_overwrite_warning(self):
reply = QtWidgets.QMessageBox.question(
self,
"Warning",
("Content you are editing was changed meanwhile in database.\n"
"Please, reload and solve the conflict."),
QtWidgets.QMessageBox.OK)
if reply == QtWidgets.QMessageBox.OK:
# do nothing
pass
class ContentException(Exception):
"""This is risen during save if file is changed in database."""
pass

View file

@ -1,161 +0,0 @@
# -*- coding: utf-8 -*-
"""Validate model nodes names."""
import os
import platform
import re
import gridfs
import pyblish.api
from maya import cmds
import ayon_core.hosts.maya.api.action
from ayon_core.client.mongo import OpenPypeMongoConnection
from ayon_core.hosts.maya.api.shader_definition_editor import (
DEFINITION_FILENAME)
from ayon_core.pipeline.publish import (
OptionalPyblishPluginMixin, PublishValidationError, ValidateContentsOrder)
class ValidateModelName(pyblish.api.InstancePlugin,
OptionalPyblishPluginMixin):
"""Validate name of model
starts with (somename)_###_(materialID)_GEO
materialID must be present in list
padding number doesn't have limit
"""
optional = True
order = ValidateContentsOrder
hosts = ["maya"]
families = ["model"]
label = "Model Name"
actions = [ayon_core.hosts.maya.api.action.SelectInvalidAction]
material_file = None
database_file = DEFINITION_FILENAME
@classmethod
def get_invalid(cls, instance):
"""Get invalid nodes."""
use_db = cls.database
def is_group(group_name):
"""Find out if supplied transform is group or not."""
try:
children = cmds.listRelatives(group_name, children=True)
for child in children:
if not cmds.ls(child, transforms=True):
return False
return True
except Exception:
return False
invalid = []
content_instance = instance.data.get("setMembers", None)
if not content_instance:
cls.log.error("Instance has no nodes!")
return True
pass
# validate top level group name
assemblies = cmds.ls(content_instance, assemblies=True, long=True)
if len(assemblies) != 1:
cls.log.error("Must have exactly one top group")
return assemblies or True
top_group = assemblies[0]
regex = cls.top_level_regex
r = re.compile(regex)
m = r.match(top_group)
project_name = instance.context.data["projectName"]
current_asset_name = instance.context.data["asset"]
if m is None:
cls.log.error("invalid name on: {}".format(top_group))
cls.log.error("name doesn't match regex {}".format(regex))
invalid.append(top_group)
else:
if "asset" in r.groupindex:
if m.group("asset") != current_asset_name:
cls.log.error("Invalid asset name in top level group.")
return top_group
if "subset" in r.groupindex:
if m.group("subset") != instance.data.get("subset"):
cls.log.error("Invalid subset name in top level group.")
return top_group
if "project" in r.groupindex:
if m.group("project") != project_name:
cls.log.error("Invalid project name in top level group.")
return top_group
descendants = cmds.listRelatives(content_instance,
allDescendents=True,
fullPath=True) or []
descendants = cmds.ls(descendants, noIntermediate=True, long=True)
trns = cmds.ls(descendants, long=False, type='transform')
# filter out groups
filtered = [node for node in trns if not is_group(node)]
# load shader list file as utf-8
shaders = []
if not use_db:
material_file = cls.material_file[platform.system().lower()]
if material_file:
if os.path.isfile(material_file):
shader_file = open(material_file, "r")
shaders = shader_file.readlines()
shader_file.close()
else:
cls.log.error("Missing shader name definition file.")
return True
else:
client = OpenPypeMongoConnection.get_mongo_client()
fs = gridfs.GridFS(client[os.getenv("OPENPYPE_DATABASE_NAME")])
shader_file = fs.find_one({"filename": cls.database_file})
if not shader_file:
cls.log.error("Missing shader name definition in database.")
return True
shaders = shader_file.read().splitlines()
shader_file.close()
# strip line endings from list
shaders = [s.rstrip() for s in shaders if s.rstrip()]
# compile regex for testing names
regex = cls.regex
r = re.compile(regex)
for obj in filtered:
cls.log.debug("testing: {}".format(obj))
m = r.match(obj)
if m is None:
cls.log.error("invalid name on: {}".format(obj))
invalid.append(obj)
else:
# if we have shader files and shader named group is in
# regex, test this group against names in shader file
if "shader" in r.groupindex and shaders:
try:
if not m.group('shader') in shaders:
cls.log.error(
"invalid materialID on: {0} ({1})".format(
obj, m.group('shader')))
invalid.append(obj)
except IndexError:
# shader named group doesn't match
cls.log.error(
"shader group doesn't match: {}".format(obj))
invalid.append(obj)
return invalid
def process(self, instance):
"""Plugin entry point."""
if not self.is_active(instance.data):
return
invalid = self.get_invalid(instance)
if invalid:
raise PublishValidationError(
"Model naming is invalid. See the log.")