diff --git a/pype/hooks/unreal/pre_workfile_preparation.py b/pype/hooks/unreal/pre_workfile_preparation.py new file mode 100644 index 0000000000..f0e09669dc --- /dev/null +++ b/pype/hooks/unreal/pre_workfile_preparation.py @@ -0,0 +1,95 @@ +import os + +from pype.lib import ( + PreLaunchHook, + ApplicationLaunchFailed +) +from pype.hosts.unreal import lib as unreal_lib + + +class UnrealPrelaunchHook(PreLaunchHook): + """ + This hook will check if current workfile path has Unreal + project inside. IF not, it initialize it and finally it pass + path to the project by environment variable to Unreal launcher + shell script. + """ + + def __init__(self, *args, **kwargs): + super().__init__(*args, **kwargs) + + self.signature = "( {} )".format(self.__class__.__name__) + + def execute(self): + asset_name = self.data["asset_name"] + task_name = self.data["task_name"] + workdir = self.env["AVALON_WORKDIR"] + engine_version = self.app_name.split("_")[-1] + unreal_project_name = f"{asset_name}_{task_name}" + + # Unreal is sensitive about project names longer then 20 chars + if len(unreal_project_name) > 20: + self.log.warning(( + f"Project name exceed 20 characters ({unreal_project_name})!" + )) + + # Unreal doesn't accept non alphabet characters at the start + # of the project name. This is because project name is then used + # in various places inside c++ code and there variable names cannot + # start with non-alpha. We append 'P' before project name to solve it. + # 😱 + if not unreal_project_name[:1].isalpha(): + self.log.warning(( + "Project name doesn't start with alphabet " + f"character ({unreal_project_name}). Appending 'P'" + )) + unreal_project_name = f"P{unreal_project_name}" + + project_path = os.path.join(workdir, unreal_project_name) + + self.log.info(( + f"{self.signature} requested UE4 version: " + f"[ {engine_version} ]" + )) + + detected = unreal_lib.get_engine_versions() + detected_str = ', '.join(detected.keys()) or 'none' + self.log.info(( + f"{self.signature} detected UE4 versions: " + f"[ {detected_str} ]" + )) + + engine_version = ".".join(engine_version.split(".")[:2]) + if engine_version not in detected.keys(): + raise ApplicationLaunchFailed(( + f"{self.signature} requested version not " + f"detected [ {engine_version} ]" + )) + + os.makedirs(project_path, exist_ok=True) + + project_file = os.path.join( + project_path, + f"{unreal_project_name}.uproject" + ) + if not os.path.isfile(project_file): + engine_path = detected[engine_version] + self.log.info(( + f"{self.signature} creating unreal " + f"project [ {unreal_project_name} ]" + )) + # Set "AVALON_UNREAL_PLUGIN" to current process environment for + # execution of `create_unreal_project` + env_key = "AVALON_UNREAL_PLUGIN" + if self.env.get(env_key): + os.environ[env_key] = self.env[env_key] + + unreal_lib.create_unreal_project( + unreal_project_name, + engine_version, + project_path, + engine_path=engine_path + ) + + # Append project file to launch arguments + self.launch_context.launch_args.append(f"\"{project_file}\"")