Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Max: Create/Set Project Folder when starting Max or task changed #2

Merged
merged 12 commits into from
Jul 18, 2024
34 changes: 33 additions & 1 deletion client/ayon_max/api/pipeline.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,14 +7,18 @@
import json

from ayon_core.host import HostBase, IWorkfileHost, ILoadHost, IPublishHost

from ayon_core.lib import register_event_callback
import pyblish.api
from ayon_core.pipeline import (
register_creator_plugin_path,
register_loader_plugin_path,
AVALON_CONTAINER_ID,
AYON_CONTAINER_ID,
get_current_project_name
)
from ayon_max.api.menu import AYONMenu
from ayon_core.settings import get_project_settings
from ayon_max.api import lib
from ayon_max.api.plugin import MS_CUSTOM_ATTRIB
from ayon_max import MAX_HOST_DIR
Expand Down Expand Up @@ -47,9 +51,11 @@ def install(self):
register_loader_plugin_path(LOAD_PATH)
register_creator_plugin_path(CREATE_PATH)

# self._register_callbacks()
_set_project()

self.menu = AYONMenu()

register_event_callback("workfile.open.before", on_before_open)
self._has_been_setup = True

rt.callbacks.addScript(rt.Name('systemPostNew'), on_new)
Expand Down Expand Up @@ -205,6 +211,32 @@ def containerise(name: str, nodes: list, context,
return container


def _set_project():
project_name = get_current_project_name()
project_settings = get_project_settings(project_name)
enable_project_creation = project_settings["max"].get("enabled_project_creation")
if not enable_project_creation:
log.debug("Project creation disabled. Skipping project creation.")
workdir = os.getenv("AYON_WORKDIR")

os.makedirs(workdir, exist_ok=True)
mxp_filepath = os.path.join(workdir, "workspace.mxp")
if os.path.exists(mxp_filepath):
rt.pathConfig.load(mxp_filepath)
directory_count = rt.pathConfig.getProjectSubDirectoryCount()
for count in range(directory_count):
proj_dir = rt.pathConfig.getProjectSubDirectory(count)
if proj_dir:
os.makedirs(proj_dir, exist_ok=True)
rt.pathConfig.setCurrentProjectFolder(workdir)


def on_before_open():
"""Check and set up project before opening workfile
"""
_set_project()


def load_custom_attribute_data():
"""Re-loading the AYON custom parameter built by the creator

Expand Down
32 changes: 32 additions & 0 deletions client/ayon_max/hooks/pre_copy_mxp.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
from ayon_applications import PreLaunchHook, LaunchTypes
from ayon_max.mxp import create_workspace_mxp


class PreCopyMxp(PreLaunchHook):
"""Copy workspace.mxp to workdir.

Hook `GlobalHostDataHook` must be executed before this hook.
"""
app_groups = {"3dsmax", "adsk_3dsmax"}
launch_types = {LaunchTypes.local}

def execute(self):
max_setting = self.data["project_settings"]["max"]
mxp_workspace = max_setting.get("mxp_workspace")
# Ensure the hook would not cause possible error
# when using the old addon.
if mxp_workspace is None:
self.log.warning("No mxp workspace setting found in the "
"latest Max Addon.")
return
enabled_project_creation = mxp_workspace.get("enabled_project_creation")
if not enabled_project_creation:
self.log.debug("3dsmax project creation is not enabled. "
"Skipping creating workspace.mxp to workdir.")
return
workdir = self.launch_context.env.get("AYON_WORKDIR")
if not workdir:
self.log.warning("BUG: Workdir is not filled.")
return

create_workspace_mxp(workdir, mxp_workspace=mxp_workspace)
52 changes: 52 additions & 0 deletions client/ayon_max/mxp.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
import os
from ayon_core.lib import Logger


def create_workspace_mxp(workdir, mxp_workspace=None):
dst_filepath = os.path.join(workdir, "workspace.mxp")
if os.path.exists(dst_filepath):
return

log = Logger.get_logger("create_workspace_mxp")
max_script = default_mxp_template()
if mxp_workspace:
if not mxp_workspace.get("enabled_project_creation"):
log.debug("3dsmax project creation is disabled.")
return

max_script = mxp_workspace.get("mxp_workspace_script")
# Skip if mxp script in settings is empty
if not max_script:
log.debug("File 'workspace.mxp' not created. Settings value is empty.")
return

os.makedirs(workdir, exist_ok=True)
with open(dst_filepath, "w") as mxp_file:
mxp_file.write(max_script)

return dst_filepath


def default_mxp_template():
"""Return text script for the path configuration if
users do not enable project creation in AYON project
setting
"""
mxp_template = "\n".join((
'[Directories]',
'Animations= ./',
'Archives=./',
'AutoBackup=./',
'BitmapProxies=./',
'Fluid Simulations=./',
'Images=./',
'MaxStart=./',
'Previews=./',
'RenderAssets=./',
'RenderOutput= ./renders/3dsmax',
'Scenes=./',
'Sounds=./',
'[XReferenceDirs]',
'Dir1=./'
))
return mxp_template
35 changes: 35 additions & 0 deletions server/settings/main.py
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,14 @@ def unit_scale_enum():
]


class MxpWorkspaceSettings(BaseSettingsModel):
enabled_project_creation: bool = SettingsField(
False, title="Enable Project Creation")
mxp_workspace_script: str = SettingsField(
title="Max mxp Workspace", widget="textarea"
)


class UnitScaleSettings(BaseSettingsModel):
enabled: bool = SettingsField(True, title="Enabled")
scene_unit_scale: str = SettingsField(
Expand All @@ -46,6 +54,10 @@ class MaxSettings(BaseSettingsModel):
default_factory=UnitScaleSettings,
title="Set Unit Scale"
)
mxp_workspace: MxpWorkspaceSettings = SettingsField(
default_factory=MxpWorkspaceSettings,
title="Max Workspace"
)
imageio: ImageIOSettings = SettingsField(
default_factory=ImageIOSettings,
title="Color Management (ImageIO)"
Expand All @@ -67,11 +79,34 @@ class MaxSettings(BaseSettingsModel):
title="Publish Plugins")


DEFAULT_MXP_WORKSPACE_SETTINGS = "\n".join((
'[Directories]',
'Animations= ./sceneassets/animations',
'Archives=./archives',
'AutoBackup=./autoback',
'BitmapProxies=./proxies',
'Fluid Simulations=./SimCache',
'Images=./sceneassets/images',
'MaxStart=./',
'Previews=./previews',
'RenderAssets=./sceneassets/renderassets',
'RenderOutput= ./renders/3dsmax',
'Scenes=./',
'Sounds=./sceneassets/sounds',
'[XReferenceDirs]',
'Dir1=./'
))


DEFAULT_VALUES = {
"unit_scale_settings": {
"enabled": True,
"scene_unit_scale": "Centimeters"
},
"mxp_workspace": {
"enabled_project_creation": False,
"mxp_workspace_script": DEFAULT_MXP_WORKSPACE_SETTINGS
},
"RenderSettings": DEFAULT_RENDER_SETTINGS,
"CreateReview": DEFAULT_CREATE_REVIEW_SETTINGS,
"PointCloud": {
Expand Down