Files
Nexus/2023/scripts/animation_tools/dwpicker/scenedata.py
2025-11-23 23:31:18 +08:00

103 lines
3.2 KiB
Python

import base64
import json
import re
import sys
from maya import cmds
from .compatibility import ensure_retro_compatibility
from .namespace import maya_namespace, node_full_namespace
from .optionvar import USE_BASE64_DATA_ENCODING
PICKER_HOLDER_NODE = '_dwpicker_data'
PICKER_HOLDER_ATTRIBUTE = '_dwpicker_data'
LS_EXP = ["*." + PICKER_HOLDER_ATTRIBUTE, "*:*." + PICKER_HOLDER_ATTRIBUTE]
def get_picker_holder_node():
if cmds.objExists(PICKER_HOLDER_NODE):
return PICKER_HOLDER_NODE
return create_picker_holder_node()
def create_picker_holder_node():
with maya_namespace(":"):
selection = cmds.ls(selection=True)
node = cmds.createNode('script', name=PICKER_HOLDER_NODE)
cmds.select(selection)
cmds.setAttr(node + '.nodeState', 1)
cmds.addAttr(node, longName=PICKER_HOLDER_ATTRIBUTE, dataType='string')
return node
def store_local_picker_data(pickers):
data = encode_data(pickers)
node = get_picker_holder_node()
cmds.setAttr(node + '.' + PICKER_HOLDER_ATTRIBUTE, data, type='string')
clean_stray_picker_holder_nodes()
def load_local_picker_data():
nodes = list_picker_holder_nodes()
pickers = []
for node in nodes:
data = cmds.getAttr(node + '.' + PICKER_HOLDER_ATTRIBUTE)
if not data:
continue
data = [ensure_retro_compatibility(p) for p in decode_data(data)]
namespace = node_full_namespace(node)
if namespace:
# holder node would have namespace when it is referenced
# and we should add it's namespace for items to be selectable
for p in data:
for s in p['shapes']:
s['action.targets'] = [
re.sub(r'([^|]+)', r'{}:\1'.format(namespace), n)
for n in s['action.targets']]
pickers.extend(data)
return pickers
def encode_data(pickers):
data = json.dumps(pickers)
if not cmds.optionVar(query=USE_BASE64_DATA_ENCODING):
return data
# Ensure backward compatibility.
if sys.version_info[0] == 2:
return base64.b64encode(bytes(data))
return base64.b64encode(bytes(data, "utf-8"))
def decode_data(data):
try:
return json.loads(data)
except ValueError: # Happe if data encoded is encoded as base 64 string.
return json.loads(base64.b64decode(data))
def list_picker_holder_nodes():
"""
Look up in the scene all the nodes holding an attribute named
"_dwpicker_holder" which are not set on the "_dwpicker_holder" node.
This mignt happed if a node node is imported (creating a namespace or a
incrementation).
"""
return [node.split(".")[0] for node in cmds.ls(LS_EXP)]
def clean_stray_picker_holder_nodes():
"""
If the scene contains multiple picker holder nodes, we remove them
automatically to avoid repeated pickers.
"""
for node in list_picker_holder_nodes():
if node == PICKER_HOLDER_NODE:
continue
cmds.delete(node)
if cmds.objExists(node):
# Node is locked or in reference and cannot be removed.
# As we cant remove it, we reset his data to avoid double pickers.
cmds.setAttr(
node + "." + PICKER_HOLDER_ATTRIBUTE, "", type="string")