Skip to content

Commit

Permalink
Rebase from production
Browse files Browse the repository at this point in the history
  • Loading branch information
jackyjacky1307 authored and rebeccaLinx committed Feb 9, 2023
1 parent e1f4012 commit 9d3d3e7
Show file tree
Hide file tree
Showing 33 changed files with 2,039 additions and 75 deletions.
4 changes: 4 additions & 0 deletions avalon/api.py
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,8 @@

get_representation_context,
update_current_task,
get_session_template_data,
get_publish_path,
get_representation_path,
loaders_from_representation,

Expand Down Expand Up @@ -96,6 +98,8 @@

"get_representation_context",
"update_current_task",
"get_session_template_data",
"get_publish_path",
"get_representation_path",
"loaders_from_representation",

Expand Down
50 changes: 50 additions & 0 deletions avalon/cinema4d/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
"""Public API
Anything that isn't defined here is INTERNAL and unreliable for external use.
"""

from .lib import (
maintained_selection,
)

from .workio import (
file_extensions,
has_unsaved_changes,
save_file,
open_file,
current_file,
work_root,
)

from .pipeline import (
register_commands,
install,
uninstall,
ls,
)

__all__ = [
# Lib API.
"maintained_selection",

# Workfiles API
"file_extensions",
"has_unsaved_changes",
"save_file",
"open_file",
"current_file",
"work_root",

# Pipeline API.
"register_commands",
"install",
"uninstall",
"ls",
]

# Backwards API compatibility
open = open_file
save = save_file

host_name = 'cinema4d'
26 changes: 26 additions & 0 deletions avalon/cinema4d/lib.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
import os
import contextlib
import c4d

AVALON_TAB = "avalon"


@contextlib.contextmanager
def maintained_selection():
"""Maintain selection during context
Example:
>>> doc = c4d.documents.GetActiveDocument()
>>> with maintained_selection():
... doc.SetSelection([node])
>>> print(node in doc.GetSelection())
False
"""

doc = c4d.documents.GetActiveDocument()
previous_selection = doc.GetSelection()
try:
yield
finally:
doc.SetSelection(previous_selection)
212 changes: 212 additions & 0 deletions avalon/cinema4d/pipeline.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,212 @@
import os
import sys
import importlib

import c4d
from c4d import gui
from pyblish import api as pyblish

from ..lib import logger, find_submodule
from .. import api

self = sys.modules[__name__]
self._menu = None


class AvalonContextLabel(c4d.plugins.CommandData):
PLUGIN_ID = 999000001

def GetSubContainer(self, doc, submenu):
context_label = "{}, {}".format(
api.Session["AVALON_ASSET"],
api.Session["AVALON_TASK"]
)
submenu.InsData(1, context_label)
return True

def GetState(self, doc):
# return False to disable the command action
return False


class AvalonSwitchTask(c4d.plugins.CommandData):
PLUGIN_ID = 999000002

def Execute(self, doc):
from ..tools import workfiles
workfiles.show_switch_task()
return True


class AvalonCreate(c4d.plugins.CommandData):
PLUGIN_ID = 999000003

def Execute(self, doc):
from ..tools import creator
creator.show()
return True


class AvalonLoad(c4d.plugins.CommandData):
PLUGIN_ID = 999000004

def Execute(self, doc):
from ..tools import loader
loader.show()
return True


class AvalonPublish(c4d.plugins.CommandData):
PLUGIN_ID = 999000005

def Execute(self, doc):
from ..tools import publish
publish.show()
return True


class AvalonManage(c4d.plugins.CommandData):
PLUGIN_ID = 999000006

def Execute(self, doc):
from ..tools import sceneinventory
sceneinventory.show()
return True


class AvalonWorkfiles(c4d.plugins.CommandData):
PLUGIN_ID = 999000007

def Execute(self, doc):
from ..tools import workfiles
workfiles.show()
return True


def reload_pipeline():
"""Attempt to reload pipeline at run-time.
CAUTION: This is primarily for development and debugging purposes.
"""

api.uninstall()
_uninstall_menu()

for module in ("avalon.api",
"avalon.io",
"avalon.lib",
"avalon.pipeline",
"avalon.tools",
"avalon.cinema4d",
"avalon.cinema4d.pipeline",
"avalon.cinema4d.lib",
"avalon.cinema4d.workio"
):

logger.info("Reloading module: {}...".format(module))

module = importlib.import_module(module)
reload(module)

import avalon.cinema4d
api.install(avalon.cinema4d)


def register_commands():
c4d.plugins.RegisterCommandPlugin(AvalonContextLabel.PLUGIN_ID, "", 0, None, "", AvalonContextLabel())
c4d.plugins.RegisterCommandPlugin(AvalonSwitchTask.PLUGIN_ID, "Switch Task", 0, None, "", AvalonSwitchTask())
c4d.plugins.RegisterCommandPlugin(AvalonCreate.PLUGIN_ID, "Create...", 0, None, "", AvalonCreate())
c4d.plugins.RegisterCommandPlugin(AvalonLoad.PLUGIN_ID, "Load...", 0, None, "", AvalonLoad())
c4d.plugins.RegisterCommandPlugin(AvalonPublish.PLUGIN_ID, "Publish...", 0, None, "", AvalonPublish())
c4d.plugins.RegisterCommandPlugin(AvalonManage.PLUGIN_ID, "Manage...", 0, None, "", AvalonManage())
c4d.plugins.RegisterCommandPlugin(AvalonWorkfiles.PLUGIN_ID, "Work Files", 0, None, "", AvalonWorkfiles())


def install():
"""Install Cinema 4D-specific functionality of avalon-core.
This is where you install menus and register families, data
and loaders into Cinema 4D.
It is called automatically when installing via `api.install(cinema4d)`.
See the Maya equivalent for inspiration on how to implement this.
"""

_install_menu()
_register_events()

pyblish.register_host("cinema4d")

logger.info("config.cinema4d installed")


def uninstall():
"""Uninstall all that was previously installed
This is where you undo everything that was done in `install()`.
That means, removing menus, deregistering families and data
and everything. It should be as though `install()` was never run,
because odds are calling this function means the user is interested
in re-installing shortly afterwards. If, for example, he has been
modifying the menu or registered families.
"""

_uninstall_menu()

pyblish.deregister_host("cinema4d")


def _install_menu():
"""Installing Avalon menu to Cinema 4D
"""

mainMenu = gui.GetMenuResource("M_EDITOR")

self._menu = c4d.BaseContainer()
self._menu.InsData(c4d.MENURESOURCE_SUBTITLE, api.Session["AVALON_LABEL"])

# Create context menu
self._menu.InsData(c4d.MENURESOURCE_COMMAND, "PLUGIN_CMD_%s" % AvalonContextLabel.PLUGIN_ID)
self._menu.InsData(c4d.MENURESOURCE_COMMAND, "PLUGIN_CMD_%s" % AvalonSwitchTask.PLUGIN_ID)

self._menu.InsData(c4d.MENURESOURCE_SEPERATOR, True)
self._menu.InsData(c4d.MENURESOURCE_COMMAND, "PLUGIN_CMD_%s" % AvalonCreate.PLUGIN_ID)
self._menu.InsData(c4d.MENURESOURCE_COMMAND, "PLUGIN_CMD_%s" % AvalonLoad.PLUGIN_ID)
self._menu.InsData(c4d.MENURESOURCE_COMMAND, "PLUGIN_CMD_%s" % AvalonPublish.PLUGIN_ID)
self._menu.InsData(c4d.MENURESOURCE_COMMAND, "PLUGIN_CMD_%s" % AvalonManage.PLUGIN_ID)

self._menu.InsData(c4d.MENURESOURCE_SEPERATOR, True)

self._menu.InsData(c4d.MENURESOURCE_COMMAND, "PLUGIN_CMD_%s" % AvalonWorkfiles.PLUGIN_ID)

pluginsMenu = gui.SearchPluginMenuResource()
if pluginsMenu:
# Insert menu after 'Plugins' menu
mainMenu.InsDataAfter(c4d.MENURESOURCE_STRING, self._menu, pluginsMenu)
else:
# Insert menu after the last existing menu ('Plugins' menu was not found)
mainMenu.InsData(c4d.MENURESOURCE_STRING, self._menu)


def _uninstall_menu():
"""Uninstalling Avalon menu to Cinema 4D
"""


def ls():
"""Yields containers from active Cinema 4D scene
"""


def _register_events():

api.on("taskChanged", _on_task_changed)
logger.info("Installed event callback for 'taskChanged'..")


def _on_task_changed(*args):
pass
54 changes: 54 additions & 0 deletions avalon/cinema4d/workio.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
import os
import c4d


def file_extensions():
return [".c4d"]


def has_unsaved_changes():
doc = c4d.documents.GetActiveDocument()
return doc.GetChanged()


def save_file(filepath):
dirname, basename = os.path.split(filepath)

doc = c4d.documents.GetActiveDocument()
doc.SetDocumentPath(dirname)
doc.SetDocumentName(basename)

flags = c4d.SAVEDOCUMENTFLAGS_NONE
file_format = c4d.FORMAT_C4DEXPORT

c4d.documents.SaveDocument(doc, filepath, flags, file_format)


def open_file(filepath):
filepath = filepath.replace("\\", "/")

c4d.documents.LoadFile(filepath)


def current_file():
doc = c4d.documents.GetActiveDocument()

dirname = doc.GetDocumentPath()
basename = doc.GetDocumentName()
if not dirname:
return None

current_filepath = os.path.join(dirname, basename)

return os.path.normpath(current_filepath).replace("\\", "/")

def work_root(session):

work_dir = session["AVALON_WORKDIR"]
scene_dir = session.get("AVALON_SCENEDIR")
if scene_dir:
path = os.path.join(work_dir, scene_dir)
else:
path = work_dir

return os.path.normpath(path).replace("\\", "/")
10 changes: 8 additions & 2 deletions avalon/inventory.py
Original file line number Diff line number Diff line change
Expand Up @@ -107,7 +107,7 @@ def create_project(name):
}).inserted_id


def create_asset(name, silo, data, parent):
def create_asset(name, silo, data, parent, episode, sequence, asset_type):
assert isinstance(parent, io.ObjectId)
if io.find_one({"type": "asset", "name": name}):
raise RuntimeError("%s already exists" % name)
Expand All @@ -116,6 +116,9 @@ def create_asset(name, silo, data, parent):
"schema": "avalon-core:asset-2.0",
"name": name,
"silo": silo,
"episode": episode,
"sequence": sequence,
"asset_type": asset_type,
"parent": parent,
"type": "asset",
"data": data
Expand Down Expand Up @@ -313,7 +316,10 @@ def _save_inventory_1_0(project_name, data):
name=data.pop("name"),
silo=data.pop("silo"),
data=data,
parent=document["_id"]
parent=document["_id"],
episode=data.pop("episode"),
sequence=data.pop("sequence"),
asset_type=data.pop("asset_type")
)

else:
Expand Down
Loading

0 comments on commit 9d3d3e7

Please sign in to comment.