Skip to content

Commit

Permalink
Fix #49
Browse files Browse the repository at this point in the history
  • Loading branch information
mottosso committed Jan 22, 2021
1 parent 1ab4707 commit fdcff9b
Showing 1 changed file with 61 additions and 17 deletions.
78 changes: 61 additions & 17 deletions cmdx.py
Original file line number Diff line number Diff line change
Expand Up @@ -5784,16 +5784,19 @@ class Distance4(Compound):
# --------------------------------------------------------


# E.g. ragdoll.vendor.cmdx => ragdoll_vendor_cmdx_plugin.py
unique_plugin = "cmdx_%s_plugin.py" % __version__.replace(".", "_")

# Support for multiple co-existing versions of apiundo.
command = "__cmdxUndo"
unique_command = "cmdx_%s_command" % __version__.replace(".", "_")

# This module is both a Python module and Maya plug-in.
# Data is shared amongst the two through this "module"
name = "__cmdxShared"
if name not in sys.modules:
sys.modules[name] = types.ModuleType(name)
unique_name = "cmdx_%s_shared" % __version__.replace(".", "_")
if unique_name not in sys.modules:
sys.modules[unique_name] = types.ModuleType(unique_name)

shared = sys.modules[name]
shared = sys.modules[unique_name]
shared.undo = None
shared.redo = None
shared.undos = {}
Expand All @@ -5812,7 +5815,7 @@ def commit(undo, redo=lambda: None):
if not ENABLE_UNDO:
return

if not hasattr(cmds, command):
if not hasattr(cmds, unique_command):
install()

# Precautionary measure.
Expand All @@ -5834,18 +5837,60 @@ def commit(undo, redo=lambda: None):
shared.redos[shared.redo] = redo

# Let Maya know that something is undoable
getattr(cmds, command)()
getattr(cmds, unique_command)()


def install():
"""Load this shared as a plug-in
Call this prior to using the shared
"""Load this module as a plug-in
Inception time! :)
In order to facilitate undo, we need a custom command registered
with Maya's native plug-in system. To do that, we need a dedicated
file. We *could* register ourselves as that file, but what we need
is a unique instance of said command per distribution of cmdx.
Per distribution? Yes, because cmdx.py can be vendored with any
library, and we don't want cmdx.py from one vendor to interfere
with one from another.
Maya uses (pollutes) global memory in two ways that
matter to us here.
1. Plug-ins are referenced by name, not path. So there can only be
one "cmdx.py" for example. That's why we can't load this module
as-is but must instead write a new file somewhere, with a name
unique to this particular distribution.
2. Commands are referenced via the native `cmds` module, and there can
only be 1 command of any given name. So we can't just register e.g.
`cmdxUndo` if we want to support multiple versions of cmdx being
registered at once. Instead, we'll generate a unique name per
distribution of cmdx, like the plug-in itself.
We can't leverage things like sys.modules[__name__] or even
the __name__ variable, because the way Maya loads Python modules
as plug-ins is to copy/paste the text itself and call that. So there
*is* no __name__. Instead, we'll rely on each version being unique
and consistent.
"""

if ENABLE_UNDO:
cmds.loadPlugin(__file__, quiet=True)
import tempfile

tempdir = tempfile.gettempdir()
tempfname = os.path.join(tempdir, unique_plugin)

# Write out ourselves..
with open(__file__) as f:
thisfile = f.read()

# ..to this transient Python module
with open(tempfname, "w") as f:
f.write(thisfile)

# Now we're guaranteed to not interfere
# with other versions of cmdx. Win!
cmds.loadPlugin(tempfname, quiet=True)

self.installed = True

Expand All @@ -5863,7 +5908,7 @@ def uninstall():
shared.redos.clear()
sys.modules.pop(name, None)

cmds.unloadPlugin(os.path.basename(__file__))
cmds.unloadPlugin(plugin)

self.installed = False

Expand All @@ -5881,8 +5926,6 @@ def doIt(self, args):
shared.undo = None
shared.redo = None

print("Yeppppppppppppppp ------------")

def undoIt(self):
shared.undos[self.undo]()

Expand All @@ -5895,14 +5938,15 @@ def isUndoable(self):


def initializePlugin(plugin):
print("Registering %s @ %s" % (unique_command, _apiUndo))
om.MFnPlugin(plugin).registerCommand(
command,
unique_command,
_apiUndo
)


def uninitializePlugin(plugin):
om.MFnPlugin(plugin).deregisterCommand(command)
om.MFnPlugin(plugin).deregisterCommand(unique_command)


# --------------------------------------------------------
Expand Down

0 comments on commit fdcff9b

Please sign in to comment.