MetaBox/Scripts/Animation/aTools/animTools/animationCrashRecovery.py
2025-01-14 03:08:55 +08:00

975 lines
40 KiB
Python

'''
========================================================================================================================
Author: Alan Camilo
www.alancamilo.com
Modified: Michael Klimenko
Requirements: aTools Package
------------------------------------------------------------------------------------------------------------------------
To install aTools, please follow the instructions in the file how_to_install.txt
------------------------------------------------------------------------------------------------------------------------
To unistall aTools, go to menu (the last button on the right), Uninstall
========================================================================================================================
'''
from maya import cmds
from maya import OpenMaya
from maya import OpenMayaAnim
from aTools.generalTools.aToolsGlobals import aToolsGlobals as G
from aTools.commonMods import uiMod
from aTools.commonMods import utilMod
from aTools.commonMods import animMod
from aTools.commonMods import aToolsMod
import os
import time
import datetime
import math
class AnimationCrashRecovery(object):
def __init__(self):
G.animationCrashRecovery = self
self.deferredQueue = []
self.animCurvesNames = []
self.animCurvesInfo = {}
self.nonKeyedAttrInfo = {}
self.baseFolderName = "animationCrashRecovery"
self.baseLatestFolderName = "latest"
self.baseBackupFolderName = "backup"
self.infoDataFileName = "infoData"
self.selectedObjs = []
self.ignoreAttrs = ["visibility"]
self.curveExt = "curve"
self.attrExt = "attr"
self.curvesInFile = []
self.nonKeyedAttrsInFile = []
self.mayaFileName = None
self.pause = False
self.mayaFileName = utilMod.getMayaFileName()
self.mayaFilePath = utilMod.getMayaFileName("path")
G.ACR_messages = G.ACR_messages or {"anim":[], "node":[], "scene":[], "mdg":[]}
self.blinkingLedState = False
self.saveRecommended = True
self.checkNodeCreated = True
G.lastSaveWarning = G.lastSaveWarning or None
self.redBlinkingSecs = 300#300 = 5 minutes
self.daysToKeepOldFiles = 5*86400#5days
self.nodesCreated = []
#self.daysToKeepOldFiles = 10#TMP
self.checkForCrashLog()
self.checkAndClearOldFiles()
#G.deferredManager.removeFromQueue("ACR")#TMP
def switch(self, onOff):
self.removeMessages()
utilMod.killScriptJobs("G.animationCrashRecoveryScriptJobs")
if onOff:
#self.saveAllAnimationData(update=True)
self.addAnimSceneMessages()
self.addNodeMessages()
self.addMdgMessages()
G.animationCrashRecoveryScriptJobs.append(cmds.scriptJob(runOnce = False, killWithScene = False, event =('SelectionChanged', self.addNodeMessages )))
self.recommendSaving(True)
#self.recommendSaving(False)#TMP
else:
G.deferredManager.removeFromQueue("ACR")
self.setLed("off")
def setLed(self, state):
if not cmds.image("animationCrashRecoveryLed", query=True, exists=True): return
self.blinkingRed(False)
if state == "on":
if self.saveRecommended:
image = "ACR_red"
ann = "Animation Crash Recovery recommends you to save"
G.lastSaveWarning = time.time() if not G.lastSaveWarning else G.lastSaveWarning
if time.time() - G.lastSaveWarning >= self.redBlinkingSecs: self.blinkingRed(True)
else:
image = "ACR_green"
ann = "Animation Crash Recovery is ON"
G.lastSaveWarning = None
cmds.image("animationCrashRecoveryLed", edit=True, image= uiMod.getImagePath(image), ann=ann)
elif state == "off":
cmds.image("animationCrashRecoveryLed", edit=True, image= uiMod.getImagePath("ACR_off"), ann="Animation Crash Recovery is OFF")
elif state == "blinking":
self.blinkingLedState = not self.blinkingLedState
image = "ACR_white_half" if self.blinkingLedState else "ACR_white_bright"
cmds.image("animationCrashRecoveryLed", edit=True, image= uiMod.getImagePath(image), ann="Animation Crash Recovery is saving animation")
elif state == "blinking_red":
self.blinkingLedState = not self.blinkingLedState
image = "ACR_red_half" if self.blinkingLedState else "ACR_red_bright"
cmds.image("animationCrashRecoveryLed", edit=True, image= uiMod.getImagePath(image), ann="Animation Crash Recovery HIGHLY recommends you to save")
def blinkingRed(self, onOff):
if onOff: G.aToolsBar.timeoutInterval.setInterval(self.toggleRed, .3, id="ACR_red_blinking")
else: G.aToolsBar.timeoutInterval.stopInterval("ACR_red_blinking")
def toggleRed(self):
self.setLed("blinking_red")
def optionBoxWindow(self, *args):
sceneId = aToolsMod.getSceneId()
idFolder = "%s%s%s"%(self.baseFolderName, os.sep, sceneId)
bkpFolder = "%s%s%s"%(idFolder, os.sep, self.baseBackupFolderName)
infoData = aToolsMod.loadFileWithUser(bkpFolder, self.infoDataFileName, ext="info")
infoDataFile = "%s%s%s%s%s.info"%(G.USER_FOLDER, os.sep, bkpFolder, os.sep, self.infoDataFileName)
modDate = os.path.getmtime(infoDataFile) if os.path.isfile(infoDataFile) else None
if not infoData or not modDate:
cmds.warning("There is no crash file to restore.")
return
def loadWindow():
mayaFileName = infoData["mayaFileName"]
message = "%s\n%s\n\nWarning: Loading crash files after editing your Maya file can lead to unpredictable results."%(mayaFileName, time.ctime(modDate))
formLayout = cmds.setParent(query=True)
icon = cmds.image(image= uiMod.getImagePath("ACR_white_bright"))
titleText = cmds.text(label="Do you want to load?", font="boldLabelFont", align="left")
messageText = cmds.text(label=message, align="left")
buttonLoad = cmds.button(label='Load', command='cmds.layoutDialog(dismiss="load")')
buttonLoadSel = cmds.button(label='Load On Selection', command='cmds.layoutDialog(dismiss="load_selection")', w=110)
cmds.formLayout (formLayout, edit=True, width=300, height=170,
attachPosition = [
(icon, 'left', 10, 0),
(icon, 'top', 10, 0),
(titleText, 'top', 10, 0),
(messageText, 'left', 10, 0),
(messageText, 'top', 0, 30),
(buttonLoad, 'left', 10, 0),
(buttonLoad, 'bottom', 10, 100),
(buttonLoadSel, 'bottom', 10, 100)
],
attachForm = [
(buttonLoad, 'left', 10),
(buttonLoadSel, 'right', 10)
],
attachControl = [
(titleText, 'left', 10, icon),
(buttonLoad, 'right', 5, buttonLoadSel)
])
def window(dismiss):
if dismiss == "dismiss": return
onlySelectedNodes = True if dismiss == "load_selection" else False
self.loadData(onlySelectedNodes, self.baseBackupFolderName)
window(cmds.layoutDialog(title="aTools Animation Crash Recovery", ui=loadWindow))
def checkForAnimationSaved(self, clearDeferredQueue=False, *args):
if clearDeferredQueue: self.deferredQueue = []
sceneId = aToolsMod.getSceneId()
idFolder = "%s%s%s"%(self.baseFolderName, os.sep, sceneId)
latestFolder = "%s%s%s"%(idFolder, os.sep, self.baseLatestFolderName)
infoFile = "%s%s%s%s%s.info"%(G.USER_FOLDER, os.sep, latestFolder, os.sep, self.infoDataFileName)
mayaFile = cmds.file(query=True, sceneName=True)
if not os.path.isfile(infoFile) or not os.path.isfile(mayaFile): return
mayaFileModTime = os.path.getmtime(mayaFile)
infoFileModTime = os.path.getmtime(infoFile)
if mayaFileModTime < infoFileModTime:
infoData = aToolsMod.loadFileWithUser(latestFolder, self.infoDataFileName, ext="info")
if not infoData: return
height = 170
completed = infoData["completed"]
mayaFileModTimeStr = time.ctime(mayaFileModTime)
infoFileModTimeStr = time.ctime(infoFileModTime)
message = "This Maya file:\n%s\n\n"%(mayaFileModTimeStr)
message += "Latest Animation Crash Recovery file:\n%s"%(infoFileModTimeStr)
if not completed:
message += "\n\n*Some animation may not be loaded.\nAnimation Crash Recovery did not finish saving before Maya crashed."
height += 40
self.warningForLoading(message, height)
def warningForLoading(self, message, height):
def warningWindow():
formLayout = cmds.setParent(query=True)
icon = cmds.image(image= uiMod.getImagePath("ACR_white_bright"))
titleText = cmds.text(label="You have newer animation. Do you want to load?", font="boldLabelFont", align="left")
messageText = cmds.text(label=message, align="left")
buttonLoad = cmds.button(label='Load', command='cmds.layoutDialog(dismiss="load")')
buttonMaybe = cmds.button(label='Maybe Later', command='cmds.layoutDialog(dismiss="maybe")', w=100)
cmds.formLayout (formLayout, edit=True, width=300, height=height,
attachPosition = [
(icon, 'left', 10, 0),
(icon, 'top', 10, 0),
(titleText, 'top', 10, 0),
(messageText, 'left', 10, 0),
(messageText, 'top', 0, 30),
(buttonLoad, 'left', 10, 0),
(buttonLoad, 'bottom', 10, 100),
(buttonMaybe, 'bottom', 10, 100)
],
attachForm = [
(buttonLoad, 'left', 10),
(buttonMaybe, 'right', 10)
],
attachControl = [
(titleText, 'left', 10, icon),
(buttonLoad, 'right', 5, buttonMaybe)
])
def window(dismiss):
if dismiss == "load":
self.loadData()
else:
cmds.warning("If you want to load later, go to aTools menu/Animation Crash Recovery option box")
self.saveBackup()
window(cmds.layoutDialog(title="aTools Animation Crash Recovery", ui=warningWindow))
def saveBackup(self):
sceneId = aToolsMod.getSceneId()
idFolder = "%s%s%s"%(self.baseFolderName, os.sep, sceneId)
latestFolder = "%s%s%s"%(idFolder, os.sep, self.baseLatestFolderName)
bkpFolder = "%s%s%s"%(idFolder, os.sep, self.baseBackupFolderName)
print("henlo")
print(f"backup: {bkpFolder}")
aToolsMod.deleteFolderWithUser(bkpFolder)
aToolsMod.renameFolderWithUser(latestFolder, bkpFolder)
aToolsMod.deleteFolderWithUser(latestFolder)
def getSavedData(self, crashFolder=None, onlySelectedNodes=False, *args):
idFolder = aToolsMod.getSceneId()
crashFolder = self.baseLatestFolderName if not crashFolder else crashFolder
folder = "%s%s%s%s%s"%(self.baseFolderName, os.sep, idFolder, os.sep, crashFolder)
filePath = cmds.file(query=True, sceneName=True)
fileModTime = None
if os.path.isfile(filePath):
fileModTime = os.path.getmtime(filePath)
curveFiles = aToolsMod.readFilesWithUser(folder, ext=self.curveExt)
attrFiles = aToolsMod.readFilesWithUser(folder, ext=self.attrExt)
status = "aTools Animation Crash Recovery - Step 1/3 - Loading crash files..."
utilMod.startProgressBar(status)
totalSteps = len(curveFiles + attrFiles)
firstStep = 0
thisStep = 0
estimatedTime = None
startChrono = None
progressInfo = [startChrono, firstStep, thisStep, totalSteps, estimatedTime, status]
data = self.getDataFromFiles("anim", folder, curveFiles, fileModTime, self.curveExt, progressInfo, onlySelectedNodes)
if not data: return
animData = data[0]
progressInfo = data[1]
data = self.getDataFromFiles("attr", folder, attrFiles, fileModTime, self.attrExt, progressInfo, onlySelectedNodes)
attrData = data[0]
if not data: return
utilMod.setProgressBar(endProgress=True)
return {"fileModTime":fileModTime, "animData":animData, "attrData":attrData}
def getDataFromFiles(self, animAttr, folder, infoFiles, fileModTime, ext, progressInfo, onlySelectedNodes):
currSel = animMod.getObjsSel()
data = {"data":[], "modTime":None}
infoFileModTimeList = []
startChrono, firstStep, thisStep, totalSteps, estimatedTime, status = progressInfo
initialStep = thisStep
for n, loopFile in enumerate(infoFiles):
if cmds.progressBar(G.progBar, query=True, isCancelled=True ):
utilMod.setProgressBar(endProgress=True)
return
thisStep = n+initialStep
startChrono = utilMod.chronoStart(startChrono, firstStep, thisStep, totalSteps, estimatedTime, status)
infoFileStr = loopFile.replace(":", "_aTools_")[0:-(len(ext)+1)]
infoFilePath = aToolsMod.getSaveFilePath("%s%s%s"%(folder, os.sep, infoFileStr), ext=ext)
infoFileModTimeList.append(os.path.getmtime(infoFilePath))
if infoFileModTimeList[-1] > fileModTime: #load only what is newer
object = loopFile.replace("_aTools_", ":")[0:-(len(ext)+1)]
value = aToolsMod.loadFileWithUser(folder, infoFileStr, ext=ext)
if onlySelectedNodes:
if animAttr == "anim":
obj = value["objects"][0]
else:
obj = object.split(".")[0]
if obj not in currSel: continue
data["data"].append({"_modTime":infoFileModTimeList[-1],"object":object, "value":value})
estimatedTime = utilMod.chronoEnd(startChrono, firstStep, thisStep, totalSteps)
#file mod date
data["data"].sort() #sort newer files last
if len(infoFileModTimeList) > 0:
data["modTime"] = max(infoFileModTimeList)
progressInfo = [startChrono, firstStep, thisStep, totalSteps, estimatedTime, status]
#blend animation data=================
return [data, progressInfo]
def loadData(self, onlySelectedNodes=False, crashFolder=None, *args):
cmds.waitCursor(state=True)
cmds.refresh(suspend=True)
cmds.undoInfo(openChunk=True)
utilMod.startProgressBar("aTools Animation Crash Recovery - Loading data...")
self.pause = True
savedData = self.getSavedData(crashFolder, onlySelectedNodes)
if savedData:
animData = savedData["animData"]["data"]
attrData = savedData["attrData"]["data"]
self.applyAttrData(attrData)
self.applyAnimData(animData)
if not crashFolder: self.loadInfoData()
utilMod.setProgressBar(endProgress=True)
self.pause = False
cmds.undoInfo(closeChunk=True)
cmds.refresh(suspend=False)
cmds.waitCursor(state=False)
def blendAnimData(self, acrAnimData):
blendedAnimData = {"objects":[], "animData":[]}
for loopData in acrAnimData:
data = loopData["value"]
objects = data["objects"]
animData = data["animData"]
blendedAnimData["objects"].extend(objects)
blendedAnimData["animData"].extend(animData)
return blendedAnimData
def applyAnimData(self, animData):
if len(animData) == 0 : return
animData = self.blendAnimData(animData)
animMod.applyAnimData(animData, pasteInPlace=False, showProgress=True, status="aTools Animation Crash Recovery - Step 3/3 - Applying animation data...")
def applyAttrData(self, attrData):
firstStep = 0
totalSteps = len(attrData)
estimatedTime = None
status = "aTools Animation Crash Recovery - Step 2/3 - Applying attributes data..."
startChrono = None
for thisStep, loopData in enumerate(attrData):
if cmds.progressBar(G.progBar, query=True, isCancelled=True ): return
startChrono = utilMod.chronoStart(startChrono, firstStep, thisStep, totalSteps, estimatedTime, status)
objAttr = loopData["object"]
value = loopData["value"]["value"]
if not cmds.objExists(objAttr): continue
if not cmds.getAttr(objAttr, settable=True): continue
if cmds.getAttr(objAttr, lock=True): continue
if cmds.getAttr(objAttr, type=True) == "string": continue
cmds.cutKey(objAttr)
if type(value) is list: #translate, rotate, scale
value = value[0]
cmds.setAttr(objAttr, value[0],value[1],value[2], clamp=True)
else: #translatex, translatey, etc
cmds.setAttr(objAttr, value, clamp=True)
estimatedTime = utilMod.chronoEnd(startChrono, firstStep, thisStep, totalSteps)
def getAllAnimCurves(self):
return cmds.ls(type=["animCurveTA","animCurveTL","animCurveTT","animCurveTU"])
def getAllNonKeyedAttrs(self):
return self.getNonKeyedAttrs(cmds.ls(transforms=True, visible=True))
#return self.getNonKeyedAttrs([loopObj for loopObj in cmds.ls() if "transform" in cmds.nodeType(loopObj, inherited=True)])
def saveSelectedCurve(self, *args):
if self.pause: return
curveMsg = args[0]
curves = [OpenMaya.MFnDependencyNode(curveMsg[n]).name() for n in range(curveMsg.length())]
function = lambda *args:self.sendDataToSaveDeferred(curves, [])
G.deferredManager.sendToQueue(function, 50, "ACR")
def saveSelectedAttr(self, msg, mplug, otherMplug, clientData):
if self.pause: return
if OpenMaya.MNodeMessage.kAttributeSet == (OpenMaya.MNodeMessage.kAttributeSet & msg):
#nodeName, attrName = mplug.name().split('.')
nonKeyedAttr = mplug.name()
#if cmds.keyframe(nonKeyedAttr, query=True): return
function = lambda *args:self.sendDataToSaveDeferred([], [nonKeyedAttr])
G.deferredManager.sendToQueue(function, 50, "ACR")
def getNonKeyedAttrs(self, animObjects):
objAttrs = animMod.getAllChannels(animObjects, changed=True, withAnimation=False)
nonKeyedObjAttrs = []
for n, loopObj in enumerate(animObjects):
loopObjAttrs = objAttrs[n]
if not loopObjAttrs: continue
for loopAttr in loopObjAttrs:
if loopAttr in self.ignoreAttrs: continue
objAttr = "%s.%s"%(loopObj, loopAttr)
if not cmds.objExists(objAttr): continue
frameCount = cmds.keyframe(objAttr, query=True, keyframeCount=True)
if frameCount <= 0:
nonKeyedObjAttrs.append(objAttr)
return nonKeyedObjAttrs
def saveAllAnimationData(self, update=False, *args):#nao precisa???
#print "saveAllAnimationData"
if update:
self.curvesInFile = self.getAllAnimCurves()
self.nonKeyedAttrsInFile = self.getAllNonKeyedAttrs()
self.sendDataToSaveDeferred(self.curvesInFile, self.nonKeyedAttrsInFile)
def sendDataToSaveDeferred(self, curves, nonKeyedAttrs):
if not len(curves) > 0 and not len(nonKeyedAttrs) > 0:
return
for loopCurve in curves:
curveStr = loopCurve.replace(":", "_aTools_")
if not cmds.objExists(loopCurve):
if curveStr in self.deferredQueue: self.deferredQueue.remove(curveStr)
continue
if curveStr in self.deferredQueue: continue
self.deferredQueue.append(curveStr)
function = lambda function=self.saveCurve, mayaFileName=self.mayaFileName, attrStr=curveStr, *args: self.sendToDeferredManager(function, mayaFileName, attrStr)
G.deferredManager.sendToQueue(function, 50, "ACR")
for loopNonKeyedAttr in nonKeyedAttrs:
nonKeyedAttrsStr = loopNonKeyedAttr.replace(":", "_aTools_")
if not cmds.objExists(loopNonKeyedAttr):
if nonKeyedAttrsStr in self.deferredQueue: self.deferredQueue.remove(nonKeyedAttrsStr)
continue
if cmds.keyframe(loopNonKeyedAttr, query=True): continue
if nonKeyedAttrsStr in self.deferredQueue: continue
self.deferredQueue.append(nonKeyedAttrsStr)
function = lambda function=self.saveNonKeyedAttrs, mayaFileName=self.mayaFileName, attrStr=nonKeyedAttrsStr, *args: self.sendToDeferredManager(function, mayaFileName, attrStr)
G.deferredManager.sendToQueue(function, 50, "ACR")
G.deferredManager.sendToQueue(lambda *args:self.stopBlinking(self.mayaFileName), 50, "ACR")
def stopBlinking(self, mayaFileName):
if G.deferredManager.inQueue("ACR") <= 1:
self.setLed("on")
self.saveInfoData(mayaFileName, completed=True)
self.checkDeletedNodesCreated()
def checkDeletedNodesCreated(self):
if len(G.ACR_messages["mdg"]) == 0: return
toRemove = []
for loopNode in self.nodesCreated:
if not cmds.objExists(loopNode): toRemove.append(loopNode)
for loopNode in toRemove: self.nodesCreated.remove(loopNode)
if len(self.nodesCreated) == 0: self.recommendSaving(False)
def sendToDeferredManager(self, function, mayaFileName, attrStr):
function(mayaFileName, attrStr)
def saveCurve(self, mayaFileName, curveStr):
self.setLed("blinking")
sceneId = aToolsMod.getSceneId()
curve = curveStr.replace("_aTools_", ":")
animData = animMod.getAnimData([curve])
if curveStr in self.deferredQueue: self.deferredQueue.remove(curveStr)
if animData is None: return
if sceneId not in self.animCurvesInfo: self.animCurvesInfo[sceneId] = {}
if curveStr in self.animCurvesInfo[sceneId]:
if self.animCurvesInfo[sceneId][curveStr] == animData: return
self.animCurvesInfo[sceneId][curveStr] = animData
#save curve to disk
aToolsMod.saveFileWithUser("%s%s%s%s%s"%(self.baseFolderName, os.sep, sceneId, os.sep, self.baseLatestFolderName), curveStr, animData, ext=self.curveExt)
self.saveInfoData(mayaFileName)
def saveInfoData(self, mayaFileName, completed=False):
sceneId = aToolsMod.getSceneId()
currFrame = cmds.currentTime(query=True)
currSel = cmds.ls(selection=True)
infoData = {"mayaFileName":mayaFileName, "currFrame":currFrame, "currSel":currSel, "completed":completed}
aToolsMod.saveFileWithUser("%s%s%s%s%s"%(self.baseFolderName, os.sep, sceneId, os.sep, self.baseLatestFolderName), self.infoDataFileName, infoData, ext="info")
def loadInfoData(self):
sceneId = aToolsMod.getSceneId()
infoData = aToolsMod.loadFileWithUser("%s%s%s%s%s"%(self.baseFolderName, os.sep, sceneId, os.sep, self.baseLatestFolderName), self.infoDataFileName, ext="info")
if not infoData: return
currFrame = infoData["currFrame"]
currSel = infoData["currSel"]
if currFrame: cmds.currentTime(currFrame)
if len(currSel) > 0: cmds.select(currSel, replace=True)
def saveNonKeyedAttrs(self, mayaFileName, nonKeyedAttrsStr):
self.setLed("blinking")
sceneId = aToolsMod.getSceneId()
nonKeyedAttr = nonKeyedAttrsStr.replace("_aTools_", ":")
attrData = self.getNonKeyedAttrData(nonKeyedAttr)
if nonKeyedAttrsStr in self.deferredQueue: self.deferredQueue.remove(nonKeyedAttrsStr)
if attrData is None: return
if sceneId not in self.nonKeyedAttrInfo: self.nonKeyedAttrInfo[sceneId] = {}
if nonKeyedAttrsStr in self.nonKeyedAttrInfo[sceneId]:
if self.nonKeyedAttrInfo[sceneId][nonKeyedAttrsStr] == attrData: return
self.nonKeyedAttrInfo[sceneId][nonKeyedAttrsStr] = attrData
#save curve to disk
aToolsMod.saveFileWithUser("%s%s%s%s%s"%(self.baseFolderName, os.sep, sceneId, os.sep, self.baseLatestFolderName), nonKeyedAttrsStr, attrData, ext=self.attrExt)
self.saveInfoData(mayaFileName)
def checkAndClearOldFiles(self):
allIdFolders = aToolsMod.readFoldersWithUser(self.baseFolderName)
timeNow = time.time()
for loopIdFolder in allIdFolders:
idFolder = "%s%s%s"%(self.baseFolderName, os.sep, loopIdFolder)
modDate = None
for loopInfoFile in [self.baseLatestFolderName, self.baseBackupFolderName]:
infoDataFile = "%s%s%s%s%s%s%s.info"%(G.USER_FOLDER, os.sep, idFolder, os.sep, loopInfoFile, os.sep, self.infoDataFileName)
if os.path.isfile(infoDataFile):
modDate = os.path.getmtime(infoDataFile)
break
if not modDate: return
if timeNow - modDate >= self.daysToKeepOldFiles:
aToolsMod.deleteFolderWithUser(idFolder)
def clearLatestFolder(self):
self.deferredQueue = []
G.deferredManager.removeFromQueue("ACR")
sceneId = aToolsMod.getSceneId()
idFolder = "%s%s%s"%(self.baseFolderName, os.sep, sceneId)
latestFolder = "%s%s%s"%(idFolder, os.sep, self.baseLatestFolderName)
aToolsMod.deleteFolderWithUser(latestFolder)
def getNonKeyedAttrData(self, nonKeyedAttr):
value = None
if cmds.objExists(nonKeyedAttr): value = cmds.getAttr(nonKeyedAttr)
return {"value":value}
def recommendSaving(self, trueFalse):
self.saveRecommended = trueFalse
if not trueFalse: self.addMdgMessages()
self.setLed("on")
def isCrashSaving(self):
t = datetime.date.today()
todaySt = ".%s%s%s."%(str(t.year).zfill(4),str(t.month).zfill(2),str(t.day).zfill(2))
return (todaySt in utilMod.getMayaFileName())
def beforeSave(self, *args):
pass
def afterSave(self, *args):
if self.isCrashSaving():
self.saveCrashLog(cmds.file(query=True, sceneName=True), self.mayaFilePath, self.mayaFileName)
return
self.mayaFileName = utilMod.getMayaFileName()
self.mayaFilePath = utilMod.getMayaFileName("path")
self.recommendSaving(False)
self.addMdgMessages()
self.clearLatestFolder()
def afterNew(self, *args):
#print "afterOpen"
self.mayaFileName = utilMod.getMayaFileName()
self.mayaFilePath = utilMod.getMayaFileName("path")
self.recommendSaving(False)
def beforeOpen(self, *args):
self.pause = True
def afterOpen(self, *args):
self.pause = False
#print "afterOpen"
self.mayaFileName = utilMod.getMayaFileName()
self.mayaFilePath = utilMod.getMayaFileName("path")
self.recommendSaving(False)
function = lambda *args: self.checkForAnimationSaved(clearDeferredQueue=True)
G.deferredManager.sendToQueue(function, 80, "ACR")
#self.checkForAnimationSaved(clearDeferredQueue=True)
def checkForCrashLog(self):
crashLog = self.loadCrashLog()
if crashLog and "crashFilePath" in crashLog: self.warnCrashLog(crashLog)
def saveCrashLog(self, crashFilePath, beforeCrashPath, beforeCrashName):
crashData = {"crashFilePath":crashFilePath, "beforeCrashPath":beforeCrashPath, "beforeCrashName":beforeCrashName}
aToolsMod.saveFileWithUser("%s"%(self.baseFolderName), "crashLog", crashData, ext="info")
def loadCrashLog(self):
return aToolsMod.loadFileWithUser("%s"%(self.baseFolderName), "crashLog", ext="info")
def warnCrashLog(self, crashLog):
crashFilePath = crashLog["crashFilePath"]
beforeCrashPath = crashLog["beforeCrashPath"]
beforeCrashName = crashLog["beforeCrashName"]
if not os.path.isfile(crashFilePath) or not os.path.isfile(beforeCrashPath): return
crashFileModTime = time.ctime(os.path.getmtime(crashFilePath))
beforeCrashModTime = time.ctime(os.path.getmtime(beforeCrashPath))
message = "Looks like last Maya session crashed and saved a crash file.\n\nOriginal file:\n%s\n%s\n\nCrash saved file:\n%s\n%s\n\nDo you want to open the crash saved file?"%(beforeCrashName, beforeCrashModTime, crashFilePath, crashFileModTime)
confirm = cmds.confirmDialog( title='aTools Animation Crash Recovery', message=message, button=['Yes','No'], defaultButton='Yes', cancelButton='No', dismissString='No' )
if confirm == 'Yes':
if cmds.file(query=True, sceneName=True):
message = "Save current file first? If you click NO, changes will be lost."
confirm = cmds.confirmDialog( title='aTools Animation Crash Recovery', message=message, button=['Yes','No'], defaultButton='Yes', cancelButton='No', dismissString='No' )
if confirm == 'Yes': cmds.file(save=True)
cmds.file(new=True, force=True)
cmds.file(crashFilePath, open=True, prompt=True)
aToolsMod.deleteFileWithUser("%s"%(self.baseFolderName), "crashLog", ext="info")
"""
def sceneUpdate(self, *args):
self.clearOldFiles()
self.mayaFileName = utilMod.getMayaFileName()
#print "sceneUpdate", args, self.mayaFileName
def beforeSaveCheck(self, retCode, *args):
self.clearOldFiles()
OpenMaya.MScriptUtil.setBool(retCode, True)
print "beforeSaveCheck", args, self.mayaFileName
"""
def afterNodeCreated(self, *args):
if not self.checkNodeCreated: return
nodeCreated = OpenMaya.MFnDependencyNode(args[0]).name()
nodeType = cmds.nodeType(nodeCreated)
if nodeType in ["animCurveTA","animCurveTL","animCurveTT","animCurveTU"]:
return
print(("nodeCreated", nodeCreated, nodeType))
if nodeCreated not in self.nodesCreated: self.nodesCreated.append(nodeCreated)
self.recommendSaving(True)
#self.removeMdgMessages()
def afterNodeParent(self, *args):
if not self.checkNodeCreated: return
dag = args[0]
firstObj = dag.partialPathName()
#print "firstObj",firstObj
if not firstObj: return
dag = args[1]
secondObj = dag.partialPathName()
#print "secondObj",secondObj
if not firstObj: return
#if firstObj not in self.nodesCreated: self.nodesCreated.append(firstObj)
print(("parented", firstObj, secondObj))
self.recommendSaving(True)
self.removeMdgMessages()
def addAnimSceneMessages(self):
self.removeMessages()
#ANIM MESSAGES
G.ACR_messages["anim"].append(OpenMayaAnim.MAnimMessage.addAnimCurveEditedCallback(self.saveSelectedCurve))
#SCENE MESSAGES
G.ACR_messages["scene"].append(OpenMaya.MSceneMessage.addCallback( OpenMaya.MSceneMessage.kBeforeSave, self.beforeSave))
G.ACR_messages["scene"].append(OpenMaya.MSceneMessage.addCallback( OpenMaya.MSceneMessage.kAfterSave, self.afterSave))
G.ACR_messages["scene"].append(OpenMaya.MSceneMessage.addCallback( OpenMaya.MSceneMessage.kBeforeOpen, self.beforeOpen))
G.ACR_messages["scene"].append(OpenMaya.MSceneMessage.addCallback( OpenMaya.MSceneMessage.kAfterOpen, self.afterOpen))
G.ACR_messages["scene"].append(OpenMaya.MSceneMessage.addCallback( OpenMaya.MSceneMessage.kAfterNew, self.afterNew))
#G.ACR_messages["scene"].append(OpenMaya.MSceneMessage.addCallback( OpenMaya.MSceneMessage.kSceneUpdate, self.sceneUpdate))
#G.ACR_messages["scene"].append(OpenMaya.MSceneMessage.addCheckCallback( OpenMaya.MSceneMessage.kBeforeSaveCheck, self.beforeSaveCheck))
def addMdgMessages(self):
self.removeMdgMessages()
#MDG MESSAGES
G.ACR_messages["mdg"].append(OpenMaya.MDGMessage.addNodeAddedCallback(self.afterNodeCreated))
G.ACR_messages["mdg"].append(OpenMaya.MDagMessage.addParentAddedCallback(self.afterNodeParent, "_noData_"))
def addNodeMessages(self):
self.removeNodeMessages()
#NODE MESSAGES
currSel = cmds.ls(selection=True)
MSelectionList = OpenMaya.MSelectionList()
OpenMaya.MGlobal.getActiveSelectionList(MSelectionList)
node = OpenMaya.MObject()
for n, loopSel in enumerate(currSel):
MSelectionList.getDependNode(n, node)
G.ACR_messages["node"].append(OpenMaya.MNodeMessage.addAttributeChangedCallback(node, self.saveSelectedAttr, None))
def removeMessages(self):
try:
for loopId in G.ACR_messages["anim"]:
OpenMayaAnim.MAnimMessage.removeCallback(loopId)
except: pass
self.removeNodeMessages()
try:
for loopId in G.ACR_messages["scene"]:
OpenMaya.MSceneMessage.removeCallback(loopId)
except: pass
self.removeMdgMessages()
G.ACR_messages["anim"] = []
G.ACR_messages["scene"] = []
def removeMdgMessages(self):
try:
for loopId in G.ACR_messages["mdg"]:
OpenMaya.MDGMessage.removeCallback(loopId)
except: pass
G.ACR_messages["mdg"] = []
def removeNodeMessages(self):
try:
for loopId in G.ACR_messages["node"]:
OpenMaya.MNodeMessage.removeCallback(loopId)
except: pass
G.ACR_messages["node"] = []
"""
import maya.OpenMaya as om
import maya.OpenMayaAnim as oma
def undoTest(*args):
print 'Checking Undo callback'
def undoRedoCallback(arg):
global callbackIDs
Null = om.MObject()
objs = cmds.ls(sl=1)
if arg == 'add':
undoID = oma.MAnimMessage.addAnimCurveEditedCallback(undoTest)
#undoID = oma.MAnimMessage.addAnimKeyframeEditedCallback(undoTest)
#undoID = oma.MAnimMessage.addNodeAnimKeyframeEditedCallback(undoTest)
#undoID = oma.MAnimMessage.addAnimKeyframeEditCheckCallback(undoTest)
#undoID = oma.MAnimMessage.addAnimKeyframeEditedCallback(undoTest)
callbackIDs = [undoID]
elif arg == 'remove':
try:
for i in callbackIDs:
oma.MAnimMessage.removeCallback(i)
except:
print 'There is no ID to delete'
undoRedoCallback("add")
undoRedoCallback("remove")
MNodeMessage.addAttributeChangedCallback
"""