Source code for cgl.plugins.unreal.utils.setup

import logging
import os
import stat
from pathlib import Path

from cgl.core.config.query import AlchemyConfigManager
from cgl.core.utils.general import cgl_copy, load_json, save_json
from cgl.core.utils.general import cgl_execute
from cgl.core.utils.read_write import unzip
from cgl.plugins.perforce.utils.workspace import get_workspace_path
from cgl.plugins.unreal.utils.engine import (
    get_unreal_config_path,
    get_unreal_exe_path,
    get_unreal_python_path,
)
from cgl.plugins.unreal.utils.uproject import get_uproject_path
from cgl.plugins.unreal.utils.world import are_plugins_enabled

CFG = AlchemyConfigManager()


[docs] def configure_unreal_python_env(company=None, project=None, world=None): """ Sets up unreal python env to run alchemy tools and see cookbook If called with no parameters we set this up in the engine settings, not in the project settings ex: C:\\Program Files\\Epic Games\\UE_5.3\\Engine\\Config\\BaseEngine.ini Args: company (str): company name project (str): Project name world (str): World name """ alc_code_root = CFG.code_root.replace("\\", "/") # cgl_root = os.path.join(alc_code_root, "cgl").replace("\\", "/") cookbook_root = CFG.cookbook_root menu_creation_script_path = os.path.join( alc_code_root, "cgl", "plugins", "unreal", "userSetup.py" ).replace("\\", "/") print(f"MENU CREATION PATH: {menu_creation_script_path}") if not company and not project and not world: unreal_config_path = get_unreal_config_path() settings_file_path = os.path.join(unreal_config_path, "BaseEngine.ini") else: workspace_path = get_workspace_path(company, project, world) settings_file_path = os.path.join(workspace_path, "Config", "DefaultEngine.ini") if os.path.exists(settings_file_path): remove_read_only_attribute(settings_file_path) lines = open(settings_file_path, "r").readlines() if has_python_settings_string(lines): line_num = 0 for line in lines: if "StartupScripts" in line: lines[line_num] = "+StartupScripts={}\n".format( menu_creation_script_path ) lines[line_num + 1] = '+AdditionalPaths=(Path="{}")\n'.format( alc_code_root ) lines[line_num + 2] = '+AdditionalPaths=(Path="{}")\n'.format( cookbook_root ) lines[line_num + 3] = ( "+bIsolateInterpreterEnvironment=False\n".format() ) break line_num += 1 out = open(settings_file_path, "w") out.writelines(lines) out.close() else: python_env_string = ( "\n\n[/Script/PythonScriptPlugin.PythonScriptPluginSettings]" "\n+StartupScripts={}" '\n+AdditionalPaths=(Path="{}")' '\n+AdditionalPaths=(Path="{}")' "\nbIsolateInterpreterEnvironment=False\n".format( menu_creation_script_path, alc_code_root, cookbook_root ) ) with open(settings_file_path, "a+") as f: f.write(python_env_string) f.close()
[docs] def unreal_pip_install(): unreal_python = get_unreal_python_path() code_root = CFG.get_code_root() requirements_path = os.path.join(code_root, "requirements.txt") if not os.path.exists(requirements_path): requirements_path = os.path.join(code_root, "requirements", "requirements.txt") os.chdir(code_root) command = f'"{unreal_python}" -m pip install -r {requirements_path}' os.system(command)
[docs] def remove_read_only_attribute(file_path): """ Removes read only attribute from file Args: file_path (str): Absolute file path to file """ os.chmod(file_path, stat.S_IWRITE)
[docs] def has_python_settings_string(file_lines): """ Checks to see if the project config file has registered python settings already Args: file_lines (str): Lines from the config txt file Returns: True if there already are python settings, False if no python settings """ for line in file_lines: if line.strip() == "[/Script/PythonScriptPlugin.PythonScriptPluginSettings]": return True return False
[docs] def get_enabled_plugins(json_obj): """ Get list of plugins Args: json_obj (arr): json object from uproject file Returns: List of enabled plugins """ enabled_list = [] try: for plugin_obj in json_obj["Plugins"]: plugin_name = plugin_obj["Name"] enabled_list.append(plugin_name) except KeyError: print("Plugins Not Found in .uproject File") return None return enabled_list
[docs] def enable_plugins(project, world): """ Enables the python plugins for the uproject asset being opened Args: project (str): Project name world (str): World name """ unzip_storyboard_plugin() installed_plugins = install_marketplace_plugins() uproject_path = get_uproject_path(project=project, world=world) remove_read_only_attribute(uproject_path) plugins_to_enable = ( CFG.project_config["unreal_info"]["built_in_plugins"] + installed_plugins ) json_obj = load_json(uproject_path) enabled_plugins = get_enabled_plugins(json_obj) if are_plugins_enabled(json_obj): plugins_list = json_obj["Plugins"] else: plugins_list = [] for plugin_name in plugins_to_enable: if plugin_name not in enabled_plugins: plugin_dict = {"Name": plugin_name, "Enabled": True} plugins_list.append(plugin_dict) json_obj["Plugins"] = plugins_list save_json(uproject_path, json_obj)
[docs] def install_marketplace_plugins(): cfg = CFG storyboard_zip_path = "" market_place_plugin_list = cfg.project_config["unreal_info"]["marketplace_plugins"] installed_plugins = [] for json_dict in market_place_plugin_list: plugin_name = json_dict["name"] plugin_path = json_dict["network_path"] if not os.path.exists(plugin_path): logging.info( f"Could Not Load Plugin: {plugin_name}\nPath Does not Exist: {plugin_path}" ) continue epic_games_dir = os.path.join(os.getenv("ProgramFiles"), "Epic Games") for dir_name in os.listdir(epic_games_dir): if "5.1" or "5.0" in dir_name: marketplace_plugin_path = os.path.join( epic_games_dir, dir_name, "Engine", "Plugins", "Marketplace" ) if not os.path.exists(marketplace_plugin_path): os.mkdir(marketplace_plugin_path) dest_path = os.path.join(marketplace_plugin_path, plugin_name) if not os.path.exists(dest_path): if os.path.isfile(plugin_path): if os.path.splitext(marketplace_plugin_path)[1] == ".zip": unzip( zipped_file=storyboard_zip_path, destination=plugin_path ) installed_plugins.append(plugin_name) else: cgl_copy( source=plugin_path, destination=dest_path, dest_is_folder=True, ) installed_plugins.append(plugin_name) else: installed_plugins.append(plugin_name) return installed_plugins
[docs] def unzip_storyboard_plugin(): alc_code_root = CFG.get_code_root() if not alc_code_root: logging.error("ALC ROOT not set as environment variable") return False else: storyboard_zip_path = os.path.join( alc_code_root, "cgl", "plugins", "unreal_engine", "resources", "StoryBoardHelpers-1.0-windows.zip", ) epic_games_dir = os.path.join(os.getenv("ProgramFiles"), "Epic Games") for dir_name in os.listdir(epic_games_dir): if "5.1" or "5.0" in dir_name: plugin_path = os.path.join( epic_games_dir, dir_name, "Engine", "Plugins" ) if not os.path.exists(os.path.join(plugin_path, "StoryBoardHelpers")): unzip(zipped_file=storyboard_zip_path, destination=plugin_path)
[docs] def set_engine_settings(company, project, world): workspace_path = get_workspace_path(company, project, world) settings_file_path = os.path.join(workspace_path, "Config", "DefaultEngine.ini") if os.path.exists(settings_file_path): remove_read_only_attribute(settings_file_path) lines = open(settings_file_path, "r").readlines() if not has_engine_settings_string(lines): engine_string = ( "\n[/Script/Engine.PhysicsSettings]\nbSupportUVFromHitResults=True" ) with open(settings_file_path, "a+") as f: f.write(engine_string) f.close()
[docs] def has_engine_settings_string(file_lines): for line in file_lines: if line.strip() == "[/Script/Engine.PhysicsSettings]": return True return False
[docs] def engine_setup(): unreal_pip_install()
[docs] def location_setup(company, project, world): configure_unreal_python_env(company, project, world)
[docs] def open_project_in_unreal( company: str, project: str, world: str, *, new_console: bool = False ): """ Launch Unreal Editor for the given .uproject in a *detached* process. - Detaches from the current (Alchemy) process group so closing Alchemy won't kill UE. - Avoids shell=True (safer + faster quoting). - On Windows: choose between a new visible console window (new_console=True) or no console. Returns (pid) on success; raises RuntimeError on failure. """ uproject_path = Path(get_uproject_path(company, project, world=world)) unreal_exe = Path(get_unreal_exe_path()) if not unreal_exe or not unreal_exe.exists(): raise RuntimeError(f"Unreal executable not found: {unreal_exe!s}") if not uproject_path or not uproject_path.exists(): raise RuntimeError(f".uproject not found: {uproject_path!s}") cmd = [str(unreal_exe), str(uproject_path)] proc_info = cgl_execute( command=cmd, return_output=False, # <- non-blocking! new_window=new_console, detach=True, working_directory=uproject_path.parent, ) return proc_info
if __name__ == "__main__": open_project_in_unreal("jhcs", "ttas", "test")