From 90955e577900ad86072468f33cbf26af3b2a5116 Mon Sep 17 00:00:00 2001 From: Joseff Date: Wed, 25 Jan 2023 11:31:27 +0100 Subject: [PATCH] Refactored the generation of UE projects, plugin is now being installed in the engine. --- openpype/hosts/unreal/addon.py | 2 +- .../unreal/hooks/pre_workfile_preparation.py | 28 ++- .../UE_4.7/CommandletProject/.gitignore | 6 + .../CommandletProject.uproject | 12 + .../Config/DefaultEditor.ini | 0 .../Config/DefaultEngine.ini | 16 ++ .../CommandletProject/Config/DefaultGame.ini | 4 + .../UE_4.7/{ => OpenPype}/.gitignore | 0 .../Config/DefaultOpenPypeSettings.ini | 0 .../UE_4.7/OpenPype/Config/FilterPlugin.ini | 8 + .../Content/Python/init_unreal.py | 0 .../OpenPype}/OpenPype.uplugin | 4 +- .../UE_4.7/{ => OpenPype}/README.md | 0 .../{ => OpenPype}/Resources/openpype128.png | Bin .../{ => OpenPype}/Resources/openpype40.png | Bin .../{ => OpenPype}/Resources/openpype512.png | Bin .../Source/OpenPype/OpenPype.Build.cs | 5 +- .../OPGenerateProjectCommandlet.cpp | 140 +++++++++++ .../Private/Commandlets/OPActionResult.cpp | 41 ++++ .../OpenPype/Private/Logging/OP_Log.cpp | 1 + .../Source/OpenPype/Private/OpenPype.cpp | 42 ++-- .../Source/OpenPype/Private/OpenPypeLib.cpp | 0 .../Private/OpenPypePublishInstance.cpp | 4 +- .../OpenPypePublishInstanceFactory.cpp | 0 .../OpenPype/Private/OpenPypePythonBridge.cpp | 0 .../OpenPype/Private/OpenPypeSettings.cpp | 3 +- .../Source/OpenPype/Private/OpenPypeStyle.cpp | 3 +- .../OPGenerateProjectCommandlet.h | 60 +++++ .../Public/Commandlets/OPActionResult.h | 83 +++++++ .../Source/OpenPype/Public/Logging/OP_Log.h | 3 + .../Source/OpenPype/Public/OPConstants.h | 12 + .../Source/OpenPype/Public/OpenPype.h | 0 .../Source/OpenPype/Public/OpenPypeLib.h | 0 .../OpenPype/Public/OpenPypePublishInstance.h | 6 +- .../Public/OpenPypePublishInstanceFactory.h | 0 .../OpenPype/Public/OpenPypePythonBridge.h | 0 .../Source/OpenPype/Public/OpenPypeSettings.h | 1 - .../Source/OpenPype/Public/OpenPypeStyle.h | 0 .../OpenPype/Private/AssetContainer.cpp | 115 --------- .../Private/AssetContainerFactory.cpp | 20 -- .../Source/OpenPype/Public/AssetContainer.h | 39 --- .../OpenPype/Public/AssetContainerFactory.h | 21 -- .../UE_5.0/CommandletProject/.gitignore | 6 + .../CommandletProject.uproject | 20 ++ .../Config/DefaultEditor.ini | 0 .../Config/DefaultEngine.ini | 42 ++++ .../CommandletProject/Config/DefaultGame.ini | 4 + .../UE_5.0/{ => OpenPype}/.gitignore | 0 .../Config/DefaultOpenPypeSettings.ini | 0 .../UE_5.0/OpenPype/Config/FilterPlugin.ini | 8 + .../Content/Python/init_unreal.py | 0 .../OpenPype}/OpenPype.uplugin | 1 + .../UE_5.0/{ => OpenPype}/README.md | 0 .../{ => OpenPype}/Resources/openpype128.png | Bin .../{ => OpenPype}/Resources/openpype40.png | Bin .../{ => OpenPype}/Resources/openpype512.png | Bin .../Source/OpenPype/OpenPype.Build.cs | 5 +- .../OPGenerateProjectCommandlet.cpp | 140 +++++++++++ .../Private/Commandlets/OPActionResult.cpp | 41 ++++ .../OpenPype/Private/Logging/OP_Log.cpp | 1 + .../Source/OpenPype/Private/OpenPype.cpp | 0 .../OpenPype/Private/OpenPypeCommands.cpp | 0 .../Source/OpenPype/Private/OpenPypeLib.cpp | 0 .../Private/OpenPypePublishInstance.cpp | 2 +- .../OpenPypePublishInstanceFactory.cpp | 0 .../OpenPype/Private/OpenPypePythonBridge.cpp | 0 .../OpenPype/Private/OpenPypeSettings.cpp | 0 .../Source/OpenPype/Private/OpenPypeStyle.cpp | 0 .../OPGenerateProjectCommandlet.h | 60 +++++ .../Public/Commandlets/OPActionResult.h | 83 +++++++ .../Source/OpenPype/Public/Logging/OP_Log.h | 3 + .../Source/OpenPype/Public/OPConstants.h | 12 + .../Source/OpenPype/Public/OpenPype.h | 0 .../Source/OpenPype/Public/OpenPypeCommands.h | 0 .../Source/OpenPype/Public/OpenPypeLib.h | 0 .../OpenPype/Public/OpenPypePublishInstance.h | 6 +- .../Public/OpenPypePublishInstanceFactory.h | 0 .../OpenPype/Public/OpenPypePythonBridge.h | 0 .../Source/OpenPype/Public/OpenPypeSettings.h | 0 .../Source/OpenPype/Public/OpenPypeStyle.h | 0 .../OpenPype/Private/AssetContainer.cpp | 115 --------- .../Private/AssetContainerFactory.cpp | 20 -- .../Source/OpenPype/Public/AssetContainer.h | 39 --- .../OpenPype/Public/AssetContainerFactory.h | 21 -- openpype/hosts/unreal/lib.py | 230 +++++++++++++----- 85 files changed, 1029 insertions(+), 509 deletions(-) create mode 100644 openpype/hosts/unreal/integration/UE_4.7/CommandletProject/.gitignore create mode 100644 openpype/hosts/unreal/integration/UE_4.7/CommandletProject/CommandletProject.uproject create mode 100644 openpype/hosts/unreal/integration/UE_4.7/CommandletProject/Config/DefaultEditor.ini create mode 100644 openpype/hosts/unreal/integration/UE_4.7/CommandletProject/Config/DefaultEngine.ini create mode 100644 openpype/hosts/unreal/integration/UE_4.7/CommandletProject/Config/DefaultGame.ini rename openpype/hosts/unreal/integration/UE_4.7/{ => OpenPype}/.gitignore (100%) rename openpype/hosts/unreal/integration/UE_4.7/{ => OpenPype}/Config/DefaultOpenPypeSettings.ini (100%) create mode 100644 openpype/hosts/unreal/integration/UE_4.7/OpenPype/Config/FilterPlugin.ini rename openpype/hosts/unreal/integration/UE_4.7/{ => OpenPype}/Content/Python/init_unreal.py (100%) rename openpype/hosts/unreal/integration/{UE_5.0 => UE_4.7/OpenPype}/OpenPype.uplugin (90%) rename openpype/hosts/unreal/integration/UE_4.7/{ => OpenPype}/README.md (100%) rename openpype/hosts/unreal/integration/UE_4.7/{ => OpenPype}/Resources/openpype128.png (100%) rename openpype/hosts/unreal/integration/UE_4.7/{ => OpenPype}/Resources/openpype40.png (100%) rename openpype/hosts/unreal/integration/UE_4.7/{ => OpenPype}/Resources/openpype512.png (100%) rename openpype/hosts/unreal/integration/UE_4.7/{ => OpenPype}/Source/OpenPype/OpenPype.Build.cs (92%) create mode 100644 openpype/hosts/unreal/integration/UE_4.7/OpenPype/Source/OpenPype/Private/Commandlets/Implementations/OPGenerateProjectCommandlet.cpp create mode 100644 openpype/hosts/unreal/integration/UE_4.7/OpenPype/Source/OpenPype/Private/Commandlets/OPActionResult.cpp create mode 100644 openpype/hosts/unreal/integration/UE_4.7/OpenPype/Source/OpenPype/Private/Logging/OP_Log.cpp rename openpype/hosts/unreal/integration/UE_4.7/{ => OpenPype}/Source/OpenPype/Private/OpenPype.cpp (79%) rename openpype/hosts/unreal/integration/UE_4.7/{ => OpenPype}/Source/OpenPype/Private/OpenPypeLib.cpp (100%) rename openpype/hosts/unreal/integration/UE_4.7/{ => OpenPype}/Source/OpenPype/Private/OpenPypePublishInstance.cpp (98%) rename openpype/hosts/unreal/integration/UE_4.7/{ => OpenPype}/Source/OpenPype/Private/OpenPypePublishInstanceFactory.cpp (100%) rename openpype/hosts/unreal/integration/UE_4.7/{ => OpenPype}/Source/OpenPype/Private/OpenPypePythonBridge.cpp (100%) rename openpype/hosts/unreal/integration/UE_4.7/{ => OpenPype}/Source/OpenPype/Private/OpenPypeSettings.cpp (91%) rename openpype/hosts/unreal/integration/UE_4.7/{ => OpenPype}/Source/OpenPype/Private/OpenPypeStyle.cpp (93%) create mode 100644 openpype/hosts/unreal/integration/UE_4.7/OpenPype/Source/OpenPype/Public/Commandlets/Implementations/OPGenerateProjectCommandlet.h create mode 100644 openpype/hosts/unreal/integration/UE_4.7/OpenPype/Source/OpenPype/Public/Commandlets/OPActionResult.h create mode 100644 openpype/hosts/unreal/integration/UE_4.7/OpenPype/Source/OpenPype/Public/Logging/OP_Log.h create mode 100644 openpype/hosts/unreal/integration/UE_4.7/OpenPype/Source/OpenPype/Public/OPConstants.h rename openpype/hosts/unreal/integration/UE_4.7/{ => OpenPype}/Source/OpenPype/Public/OpenPype.h (100%) rename openpype/hosts/unreal/integration/UE_4.7/{ => OpenPype}/Source/OpenPype/Public/OpenPypeLib.h (100%) rename openpype/hosts/unreal/integration/UE_4.7/{ => OpenPype}/Source/OpenPype/Public/OpenPypePublishInstance.h (94%) rename openpype/hosts/unreal/integration/UE_4.7/{ => OpenPype}/Source/OpenPype/Public/OpenPypePublishInstanceFactory.h (100%) rename openpype/hosts/unreal/integration/UE_4.7/{ => OpenPype}/Source/OpenPype/Public/OpenPypePythonBridge.h (100%) rename openpype/hosts/unreal/integration/UE_4.7/{ => OpenPype}/Source/OpenPype/Public/OpenPypeSettings.h (97%) rename openpype/hosts/unreal/integration/UE_4.7/{ => OpenPype}/Source/OpenPype/Public/OpenPypeStyle.h (100%) delete mode 100644 openpype/hosts/unreal/integration/UE_4.7/Source/OpenPype/Private/AssetContainer.cpp delete mode 100644 openpype/hosts/unreal/integration/UE_4.7/Source/OpenPype/Private/AssetContainerFactory.cpp delete mode 100644 openpype/hosts/unreal/integration/UE_4.7/Source/OpenPype/Public/AssetContainer.h delete mode 100644 openpype/hosts/unreal/integration/UE_4.7/Source/OpenPype/Public/AssetContainerFactory.h create mode 100644 openpype/hosts/unreal/integration/UE_5.0/CommandletProject/.gitignore create mode 100644 openpype/hosts/unreal/integration/UE_5.0/CommandletProject/CommandletProject.uproject create mode 100644 openpype/hosts/unreal/integration/UE_5.0/CommandletProject/Config/DefaultEditor.ini create mode 100644 openpype/hosts/unreal/integration/UE_5.0/CommandletProject/Config/DefaultEngine.ini create mode 100644 openpype/hosts/unreal/integration/UE_5.0/CommandletProject/Config/DefaultGame.ini rename openpype/hosts/unreal/integration/UE_5.0/{ => OpenPype}/.gitignore (100%) rename openpype/hosts/unreal/integration/UE_5.0/{ => OpenPype}/Config/DefaultOpenPypeSettings.ini (100%) create mode 100644 openpype/hosts/unreal/integration/UE_5.0/OpenPype/Config/FilterPlugin.ini rename openpype/hosts/unreal/integration/UE_5.0/{ => OpenPype}/Content/Python/init_unreal.py (100%) rename openpype/hosts/unreal/integration/{UE_4.7 => UE_5.0/OpenPype}/OpenPype.uplugin (95%) rename openpype/hosts/unreal/integration/UE_5.0/{ => OpenPype}/README.md (100%) rename openpype/hosts/unreal/integration/UE_5.0/{ => OpenPype}/Resources/openpype128.png (100%) rename openpype/hosts/unreal/integration/UE_5.0/{ => OpenPype}/Resources/openpype40.png (100%) rename openpype/hosts/unreal/integration/UE_5.0/{ => OpenPype}/Resources/openpype512.png (100%) rename openpype/hosts/unreal/integration/UE_5.0/{ => OpenPype}/Source/OpenPype/OpenPype.Build.cs (92%) create mode 100644 openpype/hosts/unreal/integration/UE_5.0/OpenPype/Source/OpenPype/Private/Commandlets/Implementations/OPGenerateProjectCommandlet.cpp create mode 100644 openpype/hosts/unreal/integration/UE_5.0/OpenPype/Source/OpenPype/Private/Commandlets/OPActionResult.cpp create mode 100644 openpype/hosts/unreal/integration/UE_5.0/OpenPype/Source/OpenPype/Private/Logging/OP_Log.cpp rename openpype/hosts/unreal/integration/UE_5.0/{ => OpenPype}/Source/OpenPype/Private/OpenPype.cpp (100%) rename openpype/hosts/unreal/integration/UE_5.0/{ => OpenPype}/Source/OpenPype/Private/OpenPypeCommands.cpp (100%) rename openpype/hosts/unreal/integration/UE_5.0/{ => OpenPype}/Source/OpenPype/Private/OpenPypeLib.cpp (100%) rename openpype/hosts/unreal/integration/UE_5.0/{ => OpenPype}/Source/OpenPype/Private/OpenPypePublishInstance.cpp (99%) rename openpype/hosts/unreal/integration/UE_5.0/{ => OpenPype}/Source/OpenPype/Private/OpenPypePublishInstanceFactory.cpp (100%) rename openpype/hosts/unreal/integration/UE_5.0/{ => OpenPype}/Source/OpenPype/Private/OpenPypePythonBridge.cpp (100%) rename openpype/hosts/unreal/integration/UE_5.0/{ => OpenPype}/Source/OpenPype/Private/OpenPypeSettings.cpp (100%) rename openpype/hosts/unreal/integration/UE_5.0/{ => OpenPype}/Source/OpenPype/Private/OpenPypeStyle.cpp (100%) create mode 100644 openpype/hosts/unreal/integration/UE_5.0/OpenPype/Source/OpenPype/Public/Commandlets/Implementations/OPGenerateProjectCommandlet.h create mode 100644 openpype/hosts/unreal/integration/UE_5.0/OpenPype/Source/OpenPype/Public/Commandlets/OPActionResult.h create mode 100644 openpype/hosts/unreal/integration/UE_5.0/OpenPype/Source/OpenPype/Public/Logging/OP_Log.h create mode 100644 openpype/hosts/unreal/integration/UE_5.0/OpenPype/Source/OpenPype/Public/OPConstants.h rename openpype/hosts/unreal/integration/UE_5.0/{ => OpenPype}/Source/OpenPype/Public/OpenPype.h (100%) rename openpype/hosts/unreal/integration/UE_5.0/{ => OpenPype}/Source/OpenPype/Public/OpenPypeCommands.h (100%) rename openpype/hosts/unreal/integration/UE_5.0/{ => OpenPype}/Source/OpenPype/Public/OpenPypeLib.h (100%) rename openpype/hosts/unreal/integration/UE_5.0/{ => OpenPype}/Source/OpenPype/Public/OpenPypePublishInstance.h (94%) rename openpype/hosts/unreal/integration/UE_5.0/{ => OpenPype}/Source/OpenPype/Public/OpenPypePublishInstanceFactory.h (100%) rename openpype/hosts/unreal/integration/UE_5.0/{ => OpenPype}/Source/OpenPype/Public/OpenPypePythonBridge.h (100%) rename openpype/hosts/unreal/integration/UE_5.0/{ => OpenPype}/Source/OpenPype/Public/OpenPypeSettings.h (100%) rename openpype/hosts/unreal/integration/UE_5.0/{ => OpenPype}/Source/OpenPype/Public/OpenPypeStyle.h (100%) delete mode 100644 openpype/hosts/unreal/integration/UE_5.0/Source/OpenPype/Private/AssetContainer.cpp delete mode 100644 openpype/hosts/unreal/integration/UE_5.0/Source/OpenPype/Private/AssetContainerFactory.cpp delete mode 100644 openpype/hosts/unreal/integration/UE_5.0/Source/OpenPype/Public/AssetContainer.h delete mode 100644 openpype/hosts/unreal/integration/UE_5.0/Source/OpenPype/Public/AssetContainerFactory.h diff --git a/openpype/hosts/unreal/addon.py b/openpype/hosts/unreal/addon.py index e2c8484651..c92a44870f 100644 --- a/openpype/hosts/unreal/addon.py +++ b/openpype/hosts/unreal/addon.py @@ -17,7 +17,7 @@ class UnrealAddon(OpenPypeModule, IHostAddon): ue_plugin = "UE_5.0" if app.name[:1] == "5" else "UE_4.7" unreal_plugin_path = os.path.join( - UNREAL_ROOT_DIR, "integration", ue_plugin + UNREAL_ROOT_DIR, "integration", ue_plugin, "OpenPype" ) if not env.get("OPENPYPE_UNREAL_PLUGIN"): env["OPENPYPE_UNREAL_PLUGIN"] = unreal_plugin_path diff --git a/openpype/hosts/unreal/hooks/pre_workfile_preparation.py b/openpype/hosts/unreal/hooks/pre_workfile_preparation.py index 2dc6fb9f42..821018ba9d 100644 --- a/openpype/hosts/unreal/hooks/pre_workfile_preparation.py +++ b/openpype/hosts/unreal/hooks/pre_workfile_preparation.py @@ -119,29 +119,33 @@ class UnrealPrelaunchHook(PreLaunchHook): f"detected [ {engine_version} ]" )) - ue_path = unreal_lib.get_editor_executable_path( + ue_path = unreal_lib.get_editor_exe_path( Path(detected[engine_version]), engine_version) self.launch_context.launch_args = [ue_path.as_posix()] project_path.mkdir(parents=True, exist_ok=True) + # Set "OPENPYPE_UNREAL_PLUGIN" to current process environment for + # execution of `create_unreal_project` + if self.launch_context.env.get("OPENPYPE_UNREAL_PLUGIN"): + self.log.info(( + f"{self.signature} using OpenPype plugin from " + f"{self.launch_context.env.get('OPENPYPE_UNREAL_PLUGIN')}" + )) + env_key = "OPENPYPE_UNREAL_PLUGIN" + if self.launch_context.env.get(env_key): + os.environ[env_key] = self.launch_context.env[env_key] + + engine_path = detected[engine_version] + + unreal_lib.try_installing_plugin(Path(engine_path), engine_version) + project_file = project_path / unreal_project_filename if not project_file.is_file(): - engine_path = detected[engine_version] self.log.info(( f"{self.signature} creating unreal " f"project [ {unreal_project_name} ]" )) - # Set "OPENPYPE_UNREAL_PLUGIN" to current process environment for - # execution of `create_unreal_project` - if self.launch_context.env.get("OPENPYPE_UNREAL_PLUGIN"): - self.log.info(( - f"{self.signature} using OpenPype plugin from " - f"{self.launch_context.env.get('OPENPYPE_UNREAL_PLUGIN')}" - )) - env_key = "OPENPYPE_UNREAL_PLUGIN" - if self.launch_context.env.get(env_key): - os.environ[env_key] = self.launch_context.env[env_key] unreal_lib.create_unreal_project( unreal_project_name, diff --git a/openpype/hosts/unreal/integration/UE_4.7/CommandletProject/.gitignore b/openpype/hosts/unreal/integration/UE_4.7/CommandletProject/.gitignore new file mode 100644 index 0000000000..1004610e4f --- /dev/null +++ b/openpype/hosts/unreal/integration/UE_4.7/CommandletProject/.gitignore @@ -0,0 +1,6 @@ +/Saved +/DerivedDataCache +/Intermediate +/Binaries +/.idea +/.vs \ No newline at end of file diff --git a/openpype/hosts/unreal/integration/UE_4.7/CommandletProject/CommandletProject.uproject b/openpype/hosts/unreal/integration/UE_4.7/CommandletProject/CommandletProject.uproject new file mode 100644 index 0000000000..4d75e03bf3 --- /dev/null +++ b/openpype/hosts/unreal/integration/UE_4.7/CommandletProject/CommandletProject.uproject @@ -0,0 +1,12 @@ +{ + "FileVersion": 3, + "EngineAssociation": "4.27", + "Category": "", + "Description": "", + "Plugins": [ + { + "Name": "OpenPype", + "Enabled": true + } + ] +} \ No newline at end of file diff --git a/openpype/hosts/unreal/integration/UE_4.7/CommandletProject/Config/DefaultEditor.ini b/openpype/hosts/unreal/integration/UE_4.7/CommandletProject/Config/DefaultEditor.ini new file mode 100644 index 0000000000..e69de29bb2 diff --git a/openpype/hosts/unreal/integration/UE_4.7/CommandletProject/Config/DefaultEngine.ini b/openpype/hosts/unreal/integration/UE_4.7/CommandletProject/Config/DefaultEngine.ini new file mode 100644 index 0000000000..2845baccca --- /dev/null +++ b/openpype/hosts/unreal/integration/UE_4.7/CommandletProject/Config/DefaultEngine.ini @@ -0,0 +1,16 @@ + + +[/Script/EngineSettings.GameMapsSettings] +GameDefaultMap=/Engine/Maps/Templates/Template_Default.Template_Default + + +[/Script/HardwareTargeting.HardwareTargetingSettings] +TargetedHardwareClass=Desktop +AppliedTargetedHardwareClass=Desktop +DefaultGraphicsPerformance=Maximum +AppliedDefaultGraphicsPerformance=Maximum + +[/Script/Engine.Engine] ++ActiveGameNameRedirects=(OldGameName="TP_BlankBP",NewGameName="/Script/CommandletProject") ++ActiveGameNameRedirects=(OldGameName="/Script/TP_BlankBP",NewGameName="/Script/CommandletProject") + diff --git a/openpype/hosts/unreal/integration/UE_4.7/CommandletProject/Config/DefaultGame.ini b/openpype/hosts/unreal/integration/UE_4.7/CommandletProject/Config/DefaultGame.ini new file mode 100644 index 0000000000..40956de961 --- /dev/null +++ b/openpype/hosts/unreal/integration/UE_4.7/CommandletProject/Config/DefaultGame.ini @@ -0,0 +1,4 @@ + + +[/Script/EngineSettings.GeneralProjectSettings] +ProjectID=95AED0BF45A918DF73ABB3BB27D25356 diff --git a/openpype/hosts/unreal/integration/UE_4.7/.gitignore b/openpype/hosts/unreal/integration/UE_4.7/OpenPype/.gitignore similarity index 100% rename from openpype/hosts/unreal/integration/UE_4.7/.gitignore rename to openpype/hosts/unreal/integration/UE_4.7/OpenPype/.gitignore diff --git a/openpype/hosts/unreal/integration/UE_4.7/Config/DefaultOpenPypeSettings.ini b/openpype/hosts/unreal/integration/UE_4.7/OpenPype/Config/DefaultOpenPypeSettings.ini similarity index 100% rename from openpype/hosts/unreal/integration/UE_4.7/Config/DefaultOpenPypeSettings.ini rename to openpype/hosts/unreal/integration/UE_4.7/OpenPype/Config/DefaultOpenPypeSettings.ini diff --git a/openpype/hosts/unreal/integration/UE_4.7/OpenPype/Config/FilterPlugin.ini b/openpype/hosts/unreal/integration/UE_4.7/OpenPype/Config/FilterPlugin.ini new file mode 100644 index 0000000000..ccebca2f32 --- /dev/null +++ b/openpype/hosts/unreal/integration/UE_4.7/OpenPype/Config/FilterPlugin.ini @@ -0,0 +1,8 @@ +[FilterPlugin] +; This section lists additional files which will be packaged along with your plugin. Paths should be listed relative to the root plugin directory, and +; may include "...", "*", and "?" wildcards to match directories, files, and individual characters respectively. +; +; Examples: +; /README.txt +; /Extras/... +; /Binaries/ThirdParty/*.dll diff --git a/openpype/hosts/unreal/integration/UE_4.7/Content/Python/init_unreal.py b/openpype/hosts/unreal/integration/UE_4.7/OpenPype/Content/Python/init_unreal.py similarity index 100% rename from openpype/hosts/unreal/integration/UE_4.7/Content/Python/init_unreal.py rename to openpype/hosts/unreal/integration/UE_4.7/OpenPype/Content/Python/init_unreal.py diff --git a/openpype/hosts/unreal/integration/UE_5.0/OpenPype.uplugin b/openpype/hosts/unreal/integration/UE_4.7/OpenPype/OpenPype.uplugin similarity index 90% rename from openpype/hosts/unreal/integration/UE_5.0/OpenPype.uplugin rename to openpype/hosts/unreal/integration/UE_4.7/OpenPype/OpenPype.uplugin index 4c7a74403c..23155cb74d 100644 --- a/openpype/hosts/unreal/integration/UE_5.0/OpenPype.uplugin +++ b/openpype/hosts/unreal/integration/UE_4.7/OpenPype/OpenPype.uplugin @@ -10,10 +10,10 @@ "DocsURL": "https://openpype.io/docs/artist_hosts_unreal", "MarketplaceURL": "", "SupportURL": "https://pype.club/", + "EngineVersion": "4.27", "CanContainContent": true, "IsBetaVersion": true, - "IsExperimentalVersion": false, - "Installed": false, + "Installed": true, "Modules": [ { "Name": "OpenPype", diff --git a/openpype/hosts/unreal/integration/UE_4.7/README.md b/openpype/hosts/unreal/integration/UE_4.7/OpenPype/README.md similarity index 100% rename from openpype/hosts/unreal/integration/UE_4.7/README.md rename to openpype/hosts/unreal/integration/UE_4.7/OpenPype/README.md diff --git a/openpype/hosts/unreal/integration/UE_4.7/Resources/openpype128.png b/openpype/hosts/unreal/integration/UE_4.7/OpenPype/Resources/openpype128.png similarity index 100% rename from openpype/hosts/unreal/integration/UE_4.7/Resources/openpype128.png rename to openpype/hosts/unreal/integration/UE_4.7/OpenPype/Resources/openpype128.png diff --git a/openpype/hosts/unreal/integration/UE_4.7/Resources/openpype40.png b/openpype/hosts/unreal/integration/UE_4.7/OpenPype/Resources/openpype40.png similarity index 100% rename from openpype/hosts/unreal/integration/UE_4.7/Resources/openpype40.png rename to openpype/hosts/unreal/integration/UE_4.7/OpenPype/Resources/openpype40.png diff --git a/openpype/hosts/unreal/integration/UE_4.7/Resources/openpype512.png b/openpype/hosts/unreal/integration/UE_4.7/OpenPype/Resources/openpype512.png similarity index 100% rename from openpype/hosts/unreal/integration/UE_4.7/Resources/openpype512.png rename to openpype/hosts/unreal/integration/UE_4.7/OpenPype/Resources/openpype512.png diff --git a/openpype/hosts/unreal/integration/UE_4.7/Source/OpenPype/OpenPype.Build.cs b/openpype/hosts/unreal/integration/UE_4.7/OpenPype/Source/OpenPype/OpenPype.Build.cs similarity index 92% rename from openpype/hosts/unreal/integration/UE_4.7/Source/OpenPype/OpenPype.Build.cs rename to openpype/hosts/unreal/integration/UE_4.7/OpenPype/Source/OpenPype/OpenPype.Build.cs index 46e5dcb2df..13afb11003 100644 --- a/openpype/hosts/unreal/integration/UE_4.7/Source/OpenPype/OpenPype.Build.cs +++ b/openpype/hosts/unreal/integration/UE_4.7/OpenPype/Source/OpenPype/OpenPype.Build.cs @@ -6,8 +6,8 @@ public class OpenPype : ModuleRules { public OpenPype(ReadOnlyTargetRules Target) : base(Target) { - PCHUsage = ModuleRules.PCHUsageMode.UseExplicitOrSharedPCHs; - + PCHUsage = PCHUsageMode.UseExplicitOrSharedPCHs; + PublicIncludePaths.AddRange( new string[] { // ... add public include paths required here ... @@ -34,6 +34,7 @@ public class OpenPype : ModuleRules PrivateDependencyModuleNames.AddRange( new string[] { + "GameProjectGeneration", "Projects", "InputCore", "UnrealEd", diff --git a/openpype/hosts/unreal/integration/UE_4.7/OpenPype/Source/OpenPype/Private/Commandlets/Implementations/OPGenerateProjectCommandlet.cpp b/openpype/hosts/unreal/integration/UE_4.7/OpenPype/Source/OpenPype/Private/Commandlets/Implementations/OPGenerateProjectCommandlet.cpp new file mode 100644 index 0000000000..024a6097b3 --- /dev/null +++ b/openpype/hosts/unreal/integration/UE_4.7/OpenPype/Source/OpenPype/Private/Commandlets/Implementations/OPGenerateProjectCommandlet.cpp @@ -0,0 +1,140 @@ +#include "Commandlets/Implementations/OPGenerateProjectCommandlet.h" + +#include "Editor.h" +#include "GameProjectUtils.h" +#include "OPConstants.h" +#include "Commandlets/OPActionResult.h" +#include "ProjectDescriptor.h" + +int32 UOPGenerateProjectCommandlet::Main(const FString& CommandLineParams) +{ + //Parses command line parameters & creates structure FProjectInformation + const FOPGenerateProjectParams ParsedParams = FOPGenerateProjectParams(CommandLineParams); + ProjectInformation = ParsedParams.GenerateUEProjectInformation(); + + //Creates .uproject & other UE files + EVALUATE_OP_ACTION_RESULT(TryCreateProject()); + + //Loads created .uproject + EVALUATE_OP_ACTION_RESULT(TryLoadProjectDescriptor()); + + //Adds needed plugin to .uproject + AttachPluginsToProjectDescriptor(); + + //Saves .uproject + EVALUATE_OP_ACTION_RESULT(TrySave()); + + //When we are here, there should not be problems in generating Unreal Project for OpenPype + return 0; +} + + +FOPGenerateProjectParams::FOPGenerateProjectParams(): FOPGenerateProjectParams("") +{ +} + +FOPGenerateProjectParams::FOPGenerateProjectParams(const FString& CommandLineParams): CommandLineParams( + CommandLineParams) +{ + UCommandlet::ParseCommandLine(*CommandLineParams, Tokens, Switches); +} + +FProjectInformation FOPGenerateProjectParams::GenerateUEProjectInformation() const +{ + FProjectInformation ProjectInformation = FProjectInformation(); + ProjectInformation.ProjectFilename = GetProjectFileName(); + + ProjectInformation.bShouldGenerateCode = IsSwitchPresent("GenerateCode"); + + return ProjectInformation; +} + +FString FOPGenerateProjectParams::TryGetToken(const int32 Index) const +{ + return Tokens.IsValidIndex(Index) ? Tokens[Index] : ""; +} + +FString FOPGenerateProjectParams::GetProjectFileName() const +{ + return TryGetToken(0); +} + +bool FOPGenerateProjectParams::IsSwitchPresent(const FString& Switch) const +{ + return INDEX_NONE != Switches.IndexOfByPredicate([&Switch](const FString& Item) -> bool + { + return Item.Equals(Switch); + } + ); +} + + +UOPGenerateProjectCommandlet::UOPGenerateProjectCommandlet() +{ + LogToConsole = true; +} + +FOP_ActionResult UOPGenerateProjectCommandlet::TryCreateProject() const +{ + FText FailReason; + FText FailLog; + TArray OutCreatedFiles; + + if (!GameProjectUtils::CreateProject(ProjectInformation, FailReason, FailLog, &OutCreatedFiles)) + return FOP_ActionResult(EOP_ActionResult::ProjectNotCreated, FailReason); + return FOP_ActionResult(); +} + +FOP_ActionResult UOPGenerateProjectCommandlet::TryLoadProjectDescriptor() +{ + FText FailReason; + const bool bLoaded = ProjectDescriptor.Load(ProjectInformation.ProjectFilename, FailReason); + + return FOP_ActionResult(bLoaded ? EOP_ActionResult::Ok : EOP_ActionResult::ProjectNotLoaded, FailReason); +} + +void UOPGenerateProjectCommandlet::AttachPluginsToProjectDescriptor() +{ + FPluginReferenceDescriptor OPPluginDescriptor; + OPPluginDescriptor.bEnabled = true; + OPPluginDescriptor.Name = OPConstants::OP_PluginName; + ProjectDescriptor.Plugins.Add(OPPluginDescriptor); + + FPluginReferenceDescriptor PythonPluginDescriptor; + PythonPluginDescriptor.bEnabled = true; + PythonPluginDescriptor.Name = OPConstants::PythonScript_PluginName; + ProjectDescriptor.Plugins.Add(PythonPluginDescriptor); + + FPluginReferenceDescriptor SequencerScriptingPluginDescriptor; + SequencerScriptingPluginDescriptor.bEnabled = true; + SequencerScriptingPluginDescriptor.Name = OPConstants::SequencerScripting_PluginName; + ProjectDescriptor.Plugins.Add(SequencerScriptingPluginDescriptor); + + FPluginReferenceDescriptor MovieRenderPipelinePluginDescriptor; + MovieRenderPipelinePluginDescriptor.bEnabled = true; + MovieRenderPipelinePluginDescriptor.Name = OPConstants::MovieRenderPipeline_PluginName; + ProjectDescriptor.Plugins.Add(MovieRenderPipelinePluginDescriptor); + + FPluginReferenceDescriptor EditorScriptingPluginDescriptor; + EditorScriptingPluginDescriptor.bEnabled = true; + EditorScriptingPluginDescriptor.Name = OPConstants::EditorScriptingUtils_PluginName; + ProjectDescriptor.Plugins.Add(EditorScriptingPluginDescriptor); +} + +FOP_ActionResult UOPGenerateProjectCommandlet::TrySave() +{ + FText FailReason; + const bool bSaved = ProjectDescriptor.Save(ProjectInformation.ProjectFilename, FailReason); + + return FOP_ActionResult(bSaved ? EOP_ActionResult::Ok : EOP_ActionResult::ProjectNotSaved, FailReason); +} + +FOPGenerateProjectParams UOPGenerateProjectCommandlet::ParseParameters(const FString& Params) const +{ + FOPGenerateProjectParams ParamsResult; + + TArray Tokens, Switches; + ParseCommandLine(*Params, Tokens, Switches); + + return ParamsResult; +} diff --git a/openpype/hosts/unreal/integration/UE_4.7/OpenPype/Source/OpenPype/Private/Commandlets/OPActionResult.cpp b/openpype/hosts/unreal/integration/UE_4.7/OpenPype/Source/OpenPype/Private/Commandlets/OPActionResult.cpp new file mode 100644 index 0000000000..9236fbb057 --- /dev/null +++ b/openpype/hosts/unreal/integration/UE_4.7/OpenPype/Source/OpenPype/Private/Commandlets/OPActionResult.cpp @@ -0,0 +1,41 @@ +// Fill out your copyright notice in the Description page of Project Settings. + + +#include "Commandlets/OPActionResult.h" +#include "Logging/OP_Log.h" + +EOP_ActionResult::Type& FOP_ActionResult::GetStatus() +{ + return Status; +} + +FText& FOP_ActionResult::GetReason() +{ + return Reason; +} + +FOP_ActionResult::FOP_ActionResult():Status(EOP_ActionResult::Type::Ok) +{ + +} + +FOP_ActionResult::FOP_ActionResult(const EOP_ActionResult::Type& InEnum):Status(InEnum) +{ + TryLog(); +} + +FOP_ActionResult::FOP_ActionResult(const EOP_ActionResult::Type& InEnum, const FText& InReason):Status(InEnum), Reason(InReason) +{ + TryLog(); +}; + +bool FOP_ActionResult::IsProblem() const +{ + return Status != EOP_ActionResult::Ok; +} + +void FOP_ActionResult::TryLog() const +{ + if(IsProblem()) + UE_LOG(LogCommandletOPGenerateProject, Error, TEXT("%s"), *Reason.ToString()); +} diff --git a/openpype/hosts/unreal/integration/UE_4.7/OpenPype/Source/OpenPype/Private/Logging/OP_Log.cpp b/openpype/hosts/unreal/integration/UE_4.7/OpenPype/Source/OpenPype/Private/Logging/OP_Log.cpp new file mode 100644 index 0000000000..29b1068c21 --- /dev/null +++ b/openpype/hosts/unreal/integration/UE_4.7/OpenPype/Source/OpenPype/Private/Logging/OP_Log.cpp @@ -0,0 +1 @@ +#include "Logging/OP_Log.h" diff --git a/openpype/hosts/unreal/integration/UE_4.7/Source/OpenPype/Private/OpenPype.cpp b/openpype/hosts/unreal/integration/UE_4.7/OpenPype/Source/OpenPype/Private/OpenPype.cpp similarity index 79% rename from openpype/hosts/unreal/integration/UE_4.7/Source/OpenPype/Private/OpenPype.cpp rename to openpype/hosts/unreal/integration/UE_4.7/OpenPype/Source/OpenPype/Private/OpenPype.cpp index d06a08eb43..a510a5e3bf 100644 --- a/openpype/hosts/unreal/integration/UE_4.7/Source/OpenPype/Private/OpenPype.cpp +++ b/openpype/hosts/unreal/integration/UE_4.7/OpenPype/Source/OpenPype/Private/OpenPype.cpp @@ -16,32 +16,34 @@ static const FName OpenPypeTabName("OpenPype"); // This function is triggered when the plugin is staring up void FOpenPypeModule::StartupModule() { - FOpenPypeStyle::Initialize(); - FOpenPypeStyle::SetIcon("Logo", "openpype40"); + if (!IsRunningCommandlet()) { + FOpenPypeStyle::Initialize(); + FOpenPypeStyle::SetIcon("Logo", "openpype40"); - // Create the Extender that will add content to the menu - FLevelEditorModule& LevelEditorModule = FModuleManager::LoadModuleChecked("LevelEditor"); + // Create the Extender that will add content to the menu + FLevelEditorModule& LevelEditorModule = FModuleManager::LoadModuleChecked("LevelEditor"); - TSharedPtr MenuExtender = MakeShareable(new FExtender()); - TSharedPtr ToolbarExtender = MakeShareable(new FExtender()); + TSharedPtr MenuExtender = MakeShareable(new FExtender()); + TSharedPtr ToolbarExtender = MakeShareable(new FExtender()); - MenuExtender->AddMenuExtension( - "LevelEditor", - EExtensionHook::After, - NULL, - FMenuExtensionDelegate::CreateRaw(this, &FOpenPypeModule::AddMenuEntry) - ); - ToolbarExtender->AddToolBarExtension( - "Settings", - EExtensionHook::After, - NULL, - FToolBarExtensionDelegate::CreateRaw(this, &FOpenPypeModule::AddToobarEntry)); + MenuExtender->AddMenuExtension( + "LevelEditor", + EExtensionHook::After, + NULL, + FMenuExtensionDelegate::CreateRaw(this, &FOpenPypeModule::AddMenuEntry) + ); + ToolbarExtender->AddToolBarExtension( + "Settings", + EExtensionHook::After, + NULL, + FToolBarExtensionDelegate::CreateRaw(this, &FOpenPypeModule::AddToobarEntry)); - LevelEditorModule.GetMenuExtensibilityManager()->AddExtender(MenuExtender); - LevelEditorModule.GetToolBarExtensibilityManager()->AddExtender(ToolbarExtender); + LevelEditorModule.GetMenuExtensibilityManager()->AddExtender(MenuExtender); + LevelEditorModule.GetToolBarExtensibilityManager()->AddExtender(ToolbarExtender); - RegisterSettings(); + RegisterSettings(); + } } void FOpenPypeModule::ShutdownModule() diff --git a/openpype/hosts/unreal/integration/UE_4.7/Source/OpenPype/Private/OpenPypeLib.cpp b/openpype/hosts/unreal/integration/UE_4.7/OpenPype/Source/OpenPype/Private/OpenPypeLib.cpp similarity index 100% rename from openpype/hosts/unreal/integration/UE_4.7/Source/OpenPype/Private/OpenPypeLib.cpp rename to openpype/hosts/unreal/integration/UE_4.7/OpenPype/Source/OpenPype/Private/OpenPypeLib.cpp diff --git a/openpype/hosts/unreal/integration/UE_4.7/Source/OpenPype/Private/OpenPypePublishInstance.cpp b/openpype/hosts/unreal/integration/UE_4.7/OpenPype/Source/OpenPype/Private/OpenPypePublishInstance.cpp similarity index 98% rename from openpype/hosts/unreal/integration/UE_4.7/Source/OpenPype/Private/OpenPypePublishInstance.cpp rename to openpype/hosts/unreal/integration/UE_4.7/OpenPype/Source/OpenPype/Private/OpenPypePublishInstance.cpp index 38740f1cbd..424c4ed491 100644 --- a/openpype/hosts/unreal/integration/UE_4.7/Source/OpenPype/Private/OpenPypePublishInstance.cpp +++ b/openpype/hosts/unreal/integration/UE_4.7/OpenPype/Source/OpenPype/Private/OpenPypePublishInstance.cpp @@ -2,10 +2,10 @@ #include "OpenPypePublishInstance.h" #include "AssetRegistryModule.h" -#include "NotificationManager.h" #include "OpenPypeLib.h" #include "OpenPypeSettings.h" -#include "SNotificationList.h" +#include "Framework/Notifications/NotificationManager.h" +#include "Widgets/Notifications/SNotificationList.h" //Moves all the invalid pointers to the end to prepare them for the shrinking #define REMOVE_INVALID_ENTRIES(VAR) VAR.CompactStable(); \ diff --git a/openpype/hosts/unreal/integration/UE_4.7/Source/OpenPype/Private/OpenPypePublishInstanceFactory.cpp b/openpype/hosts/unreal/integration/UE_4.7/OpenPype/Source/OpenPype/Private/OpenPypePublishInstanceFactory.cpp similarity index 100% rename from openpype/hosts/unreal/integration/UE_4.7/Source/OpenPype/Private/OpenPypePublishInstanceFactory.cpp rename to openpype/hosts/unreal/integration/UE_4.7/OpenPype/Source/OpenPype/Private/OpenPypePublishInstanceFactory.cpp diff --git a/openpype/hosts/unreal/integration/UE_4.7/Source/OpenPype/Private/OpenPypePythonBridge.cpp b/openpype/hosts/unreal/integration/UE_4.7/OpenPype/Source/OpenPype/Private/OpenPypePythonBridge.cpp similarity index 100% rename from openpype/hosts/unreal/integration/UE_4.7/Source/OpenPype/Private/OpenPypePythonBridge.cpp rename to openpype/hosts/unreal/integration/UE_4.7/OpenPype/Source/OpenPype/Private/OpenPypePythonBridge.cpp diff --git a/openpype/hosts/unreal/integration/UE_4.7/Source/OpenPype/Private/OpenPypeSettings.cpp b/openpype/hosts/unreal/integration/UE_4.7/OpenPype/Source/OpenPype/Private/OpenPypeSettings.cpp similarity index 91% rename from openpype/hosts/unreal/integration/UE_4.7/Source/OpenPype/Private/OpenPypeSettings.cpp rename to openpype/hosts/unreal/integration/UE_4.7/OpenPype/Source/OpenPype/Private/OpenPypeSettings.cpp index 7134614d22..951b522308 100644 --- a/openpype/hosts/unreal/integration/UE_4.7/Source/OpenPype/Private/OpenPypeSettings.cpp +++ b/openpype/hosts/unreal/integration/UE_4.7/OpenPype/Source/OpenPype/Private/OpenPypeSettings.cpp @@ -2,8 +2,7 @@ #include "OpenPypeSettings.h" -#include "IPluginManager.h" -#include "UObjectGlobals.h" +#include "Interfaces/IPluginManager.h" /** * Mainly is used for initializing default values if the DefaultOpenPypeSettings.ini file does not exist in the saved config diff --git a/openpype/hosts/unreal/integration/UE_4.7/Source/OpenPype/Private/OpenPypeStyle.cpp b/openpype/hosts/unreal/integration/UE_4.7/OpenPype/Source/OpenPype/Private/OpenPypeStyle.cpp similarity index 93% rename from openpype/hosts/unreal/integration/UE_4.7/Source/OpenPype/Private/OpenPypeStyle.cpp rename to openpype/hosts/unreal/integration/UE_4.7/OpenPype/Source/OpenPype/Private/OpenPypeStyle.cpp index a51c2d6aa5..b7abc38156 100644 --- a/openpype/hosts/unreal/integration/UE_4.7/Source/OpenPype/Private/OpenPypeStyle.cpp +++ b/openpype/hosts/unreal/integration/UE_4.7/OpenPype/Source/OpenPype/Private/OpenPypeStyle.cpp @@ -43,7 +43,7 @@ const FVector2D Icon40x40(40.0f, 40.0f); TUniquePtr< FSlateStyleSet > FOpenPypeStyle::Create() { TUniquePtr< FSlateStyleSet > Style = MakeUnique(GetStyleSetName()); - Style->SetContentRoot(FPaths::ProjectPluginsDir() / TEXT("OpenPype/Resources")); + Style->SetContentRoot(FPaths::EnginePluginsDir() / TEXT("Marketplace/OpenPype/Resources")); return Style; } @@ -66,5 +66,4 @@ const ISlateStyle& FOpenPypeStyle::Get() { check(OpenPypeStyleInstance); return *OpenPypeStyleInstance; - return *OpenPypeStyleInstance; } diff --git a/openpype/hosts/unreal/integration/UE_4.7/OpenPype/Source/OpenPype/Public/Commandlets/Implementations/OPGenerateProjectCommandlet.h b/openpype/hosts/unreal/integration/UE_4.7/OpenPype/Source/OpenPype/Public/Commandlets/Implementations/OPGenerateProjectCommandlet.h new file mode 100644 index 0000000000..8738de6d4a --- /dev/null +++ b/openpype/hosts/unreal/integration/UE_4.7/OpenPype/Source/OpenPype/Public/Commandlets/Implementations/OPGenerateProjectCommandlet.h @@ -0,0 +1,60 @@ +#pragma once + + +#include "GameProjectUtils.h" +#include "Commandlets/OPActionResult.h" +#include "ProjectDescriptor.h" +#include "Commandlets/Commandlet.h" +#include "OPGenerateProjectCommandlet.generated.h" + +struct FProjectDescriptor; +struct FProjectInformation; + +/** +* @brief Structure which parses command line parameters and generates FProjectInformation +*/ +USTRUCT() +struct FOPGenerateProjectParams +{ + GENERATED_BODY() + +private: + FString CommandLineParams; + TArray Tokens; + TArray Switches; + +public: + FOPGenerateProjectParams(); + FOPGenerateProjectParams(const FString& CommandLineParams); + + FProjectInformation GenerateUEProjectInformation() const; + +private: + FString TryGetToken(const int32 Index) const; + FString GetProjectFileName() const; + + bool IsSwitchPresent(const FString& Switch) const; +}; + +UCLASS() +class OPENPYPE_API UOPGenerateProjectCommandlet : public UCommandlet +{ + GENERATED_BODY() + +private: + FProjectInformation ProjectInformation; + FProjectDescriptor ProjectDescriptor; + +public: + UOPGenerateProjectCommandlet(); + + virtual int32 Main(const FString& CommandLineParams) override; + +private: + FOPGenerateProjectParams ParseParameters(const FString& Params) const; + FOP_ActionResult TryCreateProject() const; + FOP_ActionResult TryLoadProjectDescriptor(); + void AttachPluginsToProjectDescriptor(); + FOP_ActionResult TrySave(); +}; + diff --git a/openpype/hosts/unreal/integration/UE_4.7/OpenPype/Source/OpenPype/Public/Commandlets/OPActionResult.h b/openpype/hosts/unreal/integration/UE_4.7/OpenPype/Source/OpenPype/Public/Commandlets/OPActionResult.h new file mode 100644 index 0000000000..f46ba9c62a --- /dev/null +++ b/openpype/hosts/unreal/integration/UE_4.7/OpenPype/Source/OpenPype/Public/Commandlets/OPActionResult.h @@ -0,0 +1,83 @@ +// Fill out your copyright notice in the Description page of Project Settings. + +#pragma once + +#include "CoreMinimal.h" +#include "OPActionResult.generated.h" + +/** + * @brief This macro returns error code when is problem or does nothing when there is no problem. + * @param ActionResult FOP_ActionResult structure + */ +#define EVALUATE_OP_ACTION_RESULT(ActionResult) \ + if(ActionResult.IsProblem()) \ + return ActionResult.GetStatus(); + +/** +* @brief This enum values are humanly readable mapping of error codes. +* Here should be all error codes to be possible find what went wrong. +* TODO: In the future should exists an web document where is mapped error code & what problem occured & how to repair it... +*/ +UENUM() +namespace EOP_ActionResult +{ + enum Type + { + Ok, + ProjectNotCreated, + ProjectNotLoaded, + ProjectNotSaved, + //....Here insert another values + + //Do not remove! + //Usable for looping through enum values + __Last UMETA(Hidden) + }; +} + + +/** + * @brief This struct holds action result enum and optionally reason of fail + */ +USTRUCT() +struct FOP_ActionResult +{ + GENERATED_BODY() + +public: + /** @brief Default constructor usable when there is no problem */ + FOP_ActionResult(); + + /** + * @brief This constructor initializes variables & attempts to log when is error + * @param InEnum Status + */ + FOP_ActionResult(const EOP_ActionResult::Type& InEnum); + + /** + * @brief This constructor initializes variables & attempts to log when is error + * @param InEnum Status + * @param InReason Reason of potential fail + */ + FOP_ActionResult(const EOP_ActionResult::Type& InEnum, const FText& InReason); + +private: + /** @brief Action status */ + EOP_ActionResult::Type Status; + + /** @brief Optional reason of fail */ + FText Reason; + +public: + /** + * @brief Checks if there is problematic state + * @return true when status is not equal to EOP_ActionResult::Ok + */ + bool IsProblem() const; + EOP_ActionResult::Type& GetStatus(); + FText& GetReason(); + +private: + void TryLog() const; +}; + diff --git a/openpype/hosts/unreal/integration/UE_4.7/OpenPype/Source/OpenPype/Public/Logging/OP_Log.h b/openpype/hosts/unreal/integration/UE_4.7/OpenPype/Source/OpenPype/Public/Logging/OP_Log.h new file mode 100644 index 0000000000..4f8af3e2e6 --- /dev/null +++ b/openpype/hosts/unreal/integration/UE_4.7/OpenPype/Source/OpenPype/Public/Logging/OP_Log.h @@ -0,0 +1,3 @@ +#pragma once + +DEFINE_LOG_CATEGORY_STATIC(LogCommandletOPGenerateProject, Log, All); \ No newline at end of file diff --git a/openpype/hosts/unreal/integration/UE_4.7/OpenPype/Source/OpenPype/Public/OPConstants.h b/openpype/hosts/unreal/integration/UE_4.7/OpenPype/Source/OpenPype/Public/OPConstants.h new file mode 100644 index 0000000000..21a033e426 --- /dev/null +++ b/openpype/hosts/unreal/integration/UE_4.7/OpenPype/Source/OpenPype/Public/OPConstants.h @@ -0,0 +1,12 @@ +#pragma once + +namespace OPConstants +{ + const FString OP_PluginName = "OpenPype"; + const FString PythonScript_PluginName = "PythonScriptPlugin"; + const FString SequencerScripting_PluginName = "SequencerScripting"; + const FString MovieRenderPipeline_PluginName = "MovieRenderPipeline"; + const FString EditorScriptingUtils_PluginName = "EditorScriptingUtilities"; +} + + diff --git a/openpype/hosts/unreal/integration/UE_4.7/Source/OpenPype/Public/OpenPype.h b/openpype/hosts/unreal/integration/UE_4.7/OpenPype/Source/OpenPype/Public/OpenPype.h similarity index 100% rename from openpype/hosts/unreal/integration/UE_4.7/Source/OpenPype/Public/OpenPype.h rename to openpype/hosts/unreal/integration/UE_4.7/OpenPype/Source/OpenPype/Public/OpenPype.h diff --git a/openpype/hosts/unreal/integration/UE_4.7/Source/OpenPype/Public/OpenPypeLib.h b/openpype/hosts/unreal/integration/UE_4.7/OpenPype/Source/OpenPype/Public/OpenPypeLib.h similarity index 100% rename from openpype/hosts/unreal/integration/UE_4.7/Source/OpenPype/Public/OpenPypeLib.h rename to openpype/hosts/unreal/integration/UE_4.7/OpenPype/Source/OpenPype/Public/OpenPypeLib.h diff --git a/openpype/hosts/unreal/integration/UE_4.7/Source/OpenPype/Public/OpenPypePublishInstance.h b/openpype/hosts/unreal/integration/UE_4.7/OpenPype/Source/OpenPype/Public/OpenPypePublishInstance.h similarity index 94% rename from openpype/hosts/unreal/integration/UE_4.7/Source/OpenPype/Public/OpenPypePublishInstance.h rename to openpype/hosts/unreal/integration/UE_4.7/OpenPype/Source/OpenPype/Public/OpenPypePublishInstance.h index cd414fe2cc..16b3194b96 100644 --- a/openpype/hosts/unreal/integration/UE_4.7/Source/OpenPype/Public/OpenPypePublishInstance.h +++ b/openpype/hosts/unreal/integration/UE_4.7/OpenPype/Source/OpenPype/Public/OpenPypePublishInstance.h @@ -16,7 +16,7 @@ public: * * @return - Set of UObjects. Careful! They are returning raw pointers. Seems like an issue in UE5 */ - UFUNCTION(BlueprintCallable, BlueprintPure) + UFUNCTION(BlueprintCallable, BlueprintPure, Category="Python") TSet GetInternalAssets() const { //For some reason it can only return Raw Pointers? Seems like an issue which they haven't fixed. @@ -33,7 +33,7 @@ public: * * @return - TSet of assets (UObjects). Careful! They are returning raw pointers. Seems like an issue in UE5 */ - UFUNCTION(BlueprintCallable, BlueprintPure) + UFUNCTION(BlueprintCallable, BlueprintPure, Category="Python") TSet GetExternalAssets() const { //For some reason it can only return Raw Pointers? Seems like an issue which they haven't fixed. @@ -53,7 +53,7 @@ public: * * @attention If the bAddExternalAssets variable is false, external assets won't be included! */ - UFUNCTION(BlueprintCallable, BlueprintPure) + UFUNCTION(BlueprintCallable, BlueprintPure, Category="Python") TSet GetAllAssets() const { const TSet>& IteratedSet = bAddExternalAssets diff --git a/openpype/hosts/unreal/integration/UE_4.7/Source/OpenPype/Public/OpenPypePublishInstanceFactory.h b/openpype/hosts/unreal/integration/UE_4.7/OpenPype/Source/OpenPype/Public/OpenPypePublishInstanceFactory.h similarity index 100% rename from openpype/hosts/unreal/integration/UE_4.7/Source/OpenPype/Public/OpenPypePublishInstanceFactory.h rename to openpype/hosts/unreal/integration/UE_4.7/OpenPype/Source/OpenPype/Public/OpenPypePublishInstanceFactory.h diff --git a/openpype/hosts/unreal/integration/UE_4.7/Source/OpenPype/Public/OpenPypePythonBridge.h b/openpype/hosts/unreal/integration/UE_4.7/OpenPype/Source/OpenPype/Public/OpenPypePythonBridge.h similarity index 100% rename from openpype/hosts/unreal/integration/UE_4.7/Source/OpenPype/Public/OpenPypePythonBridge.h rename to openpype/hosts/unreal/integration/UE_4.7/OpenPype/Source/OpenPype/Public/OpenPypePythonBridge.h diff --git a/openpype/hosts/unreal/integration/UE_4.7/Source/OpenPype/Public/OpenPypeSettings.h b/openpype/hosts/unreal/integration/UE_4.7/OpenPype/Source/OpenPype/Public/OpenPypeSettings.h similarity index 97% rename from openpype/hosts/unreal/integration/UE_4.7/Source/OpenPype/Public/OpenPypeSettings.h rename to openpype/hosts/unreal/integration/UE_4.7/OpenPype/Source/OpenPype/Public/OpenPypeSettings.h index 2df6c887cf..9bdcfb2399 100644 --- a/openpype/hosts/unreal/integration/UE_4.7/Source/OpenPype/Public/OpenPypeSettings.h +++ b/openpype/hosts/unreal/integration/UE_4.7/OpenPype/Source/OpenPype/Public/OpenPypeSettings.h @@ -3,7 +3,6 @@ #pragma once #include "CoreMinimal.h" -#include "Object.h" #include "OpenPypeSettings.generated.h" #define OPENPYPE_SETTINGS_FILEPATH IPluginManager::Get().FindPlugin("OpenPype")->GetBaseDir() / TEXT("Config") / TEXT("DefaultOpenPypeSettings.ini") diff --git a/openpype/hosts/unreal/integration/UE_4.7/Source/OpenPype/Public/OpenPypeStyle.h b/openpype/hosts/unreal/integration/UE_4.7/OpenPype/Source/OpenPype/Public/OpenPypeStyle.h similarity index 100% rename from openpype/hosts/unreal/integration/UE_4.7/Source/OpenPype/Public/OpenPypeStyle.h rename to openpype/hosts/unreal/integration/UE_4.7/OpenPype/Source/OpenPype/Public/OpenPypeStyle.h diff --git a/openpype/hosts/unreal/integration/UE_4.7/Source/OpenPype/Private/AssetContainer.cpp b/openpype/hosts/unreal/integration/UE_4.7/Source/OpenPype/Private/AssetContainer.cpp deleted file mode 100644 index c766f87a8e..0000000000 --- a/openpype/hosts/unreal/integration/UE_4.7/Source/OpenPype/Private/AssetContainer.cpp +++ /dev/null @@ -1,115 +0,0 @@ -// Fill out your copyright notice in the Description page of Project Settings. - -#include "AssetContainer.h" -#include "AssetRegistryModule.h" -#include "Misc/PackageName.h" -#include "Engine.h" -#include "Containers/UnrealString.h" - -UAssetContainer::UAssetContainer(const FObjectInitializer& ObjectInitializer) -: UAssetUserData(ObjectInitializer) -{ - FAssetRegistryModule& AssetRegistryModule = FModuleManager::LoadModuleChecked("AssetRegistry"); - FString path = UAssetContainer::GetPathName(); - UE_LOG(LogTemp, Warning, TEXT("UAssetContainer %s"), *path); - FARFilter Filter; - Filter.PackagePaths.Add(FName(*path)); - - AssetRegistryModule.Get().OnAssetAdded().AddUObject(this, &UAssetContainer::OnAssetAdded); - AssetRegistryModule.Get().OnAssetRemoved().AddUObject(this, &UAssetContainer::OnAssetRemoved); - AssetRegistryModule.Get().OnAssetRenamed().AddUObject(this, &UAssetContainer::OnAssetRenamed); -} - -void UAssetContainer::OnAssetAdded(const FAssetData& AssetData) -{ - TArray split; - - // get directory of current container - FString selfFullPath = UAssetContainer::GetPathName(); - FString selfDir = FPackageName::GetLongPackagePath(*selfFullPath); - - // get asset path and class - FString assetPath = AssetData.GetFullName(); - FString assetFName = AssetData.AssetClass.ToString(); - - // split path - assetPath.ParseIntoArray(split, TEXT(" "), true); - - FString assetDir = FPackageName::GetLongPackagePath(*split[1]); - - // take interest only in paths starting with path of current container - if (assetDir.StartsWith(*selfDir)) - { - // exclude self - if (assetFName != "AssetContainer") - { - assets.Add(assetPath); - assetsData.Add(AssetData); - UE_LOG(LogTemp, Log, TEXT("%s: asset added to %s"), *selfFullPath, *selfDir); - } - } -} - -void UAssetContainer::OnAssetRemoved(const FAssetData& AssetData) -{ - TArray split; - - // get directory of current container - FString selfFullPath = UAssetContainer::GetPathName(); - FString selfDir = FPackageName::GetLongPackagePath(*selfFullPath); - - // get asset path and class - FString assetPath = AssetData.GetFullName(); - FString assetFName = AssetData.AssetClass.ToString(); - - // split path - assetPath.ParseIntoArray(split, TEXT(" "), true); - - FString assetDir = FPackageName::GetLongPackagePath(*split[1]); - - // take interest only in paths starting with path of current container - FString path = UAssetContainer::GetPathName(); - FString lpp = FPackageName::GetLongPackagePath(*path); - - if (assetDir.StartsWith(*selfDir)) - { - // exclude self - if (assetFName != "AssetContainer") - { - // UE_LOG(LogTemp, Warning, TEXT("%s: asset removed"), *lpp); - assets.Remove(assetPath); - assetsData.Remove(AssetData); - } - } -} - -void UAssetContainer::OnAssetRenamed(const FAssetData& AssetData, const FString& str) -{ - TArray split; - - // get directory of current container - FString selfFullPath = UAssetContainer::GetPathName(); - FString selfDir = FPackageName::GetLongPackagePath(*selfFullPath); - - // get asset path and class - FString assetPath = AssetData.GetFullName(); - FString assetFName = AssetData.AssetClass.ToString(); - - // split path - assetPath.ParseIntoArray(split, TEXT(" "), true); - - FString assetDir = FPackageName::GetLongPackagePath(*split[1]); - if (assetDir.StartsWith(*selfDir)) - { - // exclude self - if (assetFName != "AssetContainer") - { - - assets.Remove(str); - assets.Add(assetPath); - assetsData.Remove(AssetData); - // UE_LOG(LogTemp, Warning, TEXT("%s: asset renamed %s"), *lpp, *str); - } - } -} - diff --git a/openpype/hosts/unreal/integration/UE_4.7/Source/OpenPype/Private/AssetContainerFactory.cpp b/openpype/hosts/unreal/integration/UE_4.7/Source/OpenPype/Private/AssetContainerFactory.cpp deleted file mode 100644 index b943150bdd..0000000000 --- a/openpype/hosts/unreal/integration/UE_4.7/Source/OpenPype/Private/AssetContainerFactory.cpp +++ /dev/null @@ -1,20 +0,0 @@ -#include "AssetContainerFactory.h" -#include "AssetContainer.h" - -UAssetContainerFactory::UAssetContainerFactory(const FObjectInitializer& ObjectInitializer) - : UFactory(ObjectInitializer) -{ - SupportedClass = UAssetContainer::StaticClass(); - bCreateNew = false; - bEditorImport = true; -} - -UObject* UAssetContainerFactory::FactoryCreateNew(UClass* Class, UObject* InParent, FName Name, EObjectFlags Flags, UObject* Context, FFeedbackContext* Warn) -{ - UAssetContainer* AssetContainer = NewObject(InParent, Class, Name, Flags); - return AssetContainer; -} - -bool UAssetContainerFactory::ShouldShowInNewMenu() const { - return false; -} diff --git a/openpype/hosts/unreal/integration/UE_4.7/Source/OpenPype/Public/AssetContainer.h b/openpype/hosts/unreal/integration/UE_4.7/Source/OpenPype/Public/AssetContainer.h deleted file mode 100644 index 3c2a360c78..0000000000 --- a/openpype/hosts/unreal/integration/UE_4.7/Source/OpenPype/Public/AssetContainer.h +++ /dev/null @@ -1,39 +0,0 @@ -// Fill out your copyright notice in the Description page of Project Settings. - -#pragma once - -#include "CoreMinimal.h" -#include "UObject/NoExportTypes.h" -#include "Engine/AssetUserData.h" -#include "AssetData.h" -#include "AssetContainer.generated.h" - -/** - * - */ -UCLASS(Blueprintable) -class OPENPYPE_API UAssetContainer : public UAssetUserData -{ - GENERATED_BODY() - -public: - - UAssetContainer(const FObjectInitializer& ObjectInitalizer); - // ~UAssetContainer(); - - UPROPERTY(EditAnywhere, BlueprintReadOnly) - TArray assets; - - // There seems to be no reflection option to expose array of FAssetData - /* - UPROPERTY(Transient, BlueprintReadOnly, Category = "Python", meta=(DisplayName="Assets Data")) - TArray assetsData; - */ -private: - TArray assetsData; - void OnAssetAdded(const FAssetData& AssetData); - void OnAssetRemoved(const FAssetData& AssetData); - void OnAssetRenamed(const FAssetData& AssetData, const FString& str); -}; - - diff --git a/openpype/hosts/unreal/integration/UE_4.7/Source/OpenPype/Public/AssetContainerFactory.h b/openpype/hosts/unreal/integration/UE_4.7/Source/OpenPype/Public/AssetContainerFactory.h deleted file mode 100644 index 331ce6bb50..0000000000 --- a/openpype/hosts/unreal/integration/UE_4.7/Source/OpenPype/Public/AssetContainerFactory.h +++ /dev/null @@ -1,21 +0,0 @@ -// Fill out your copyright notice in the Description page of Project Settings. - -#pragma once - -#include "CoreMinimal.h" -#include "Factories/Factory.h" -#include "AssetContainerFactory.generated.h" - -/** - * - */ -UCLASS() -class OPENPYPE_API UAssetContainerFactory : public UFactory -{ - GENERATED_BODY() - -public: - UAssetContainerFactory(const FObjectInitializer& ObjectInitializer); - virtual UObject* FactoryCreateNew(UClass* Class, UObject* InParent, FName Name, EObjectFlags Flags, UObject* Context, FFeedbackContext* Warn) override; - virtual bool ShouldShowInNewMenu() const override; -}; \ No newline at end of file diff --git a/openpype/hosts/unreal/integration/UE_5.0/CommandletProject/.gitignore b/openpype/hosts/unreal/integration/UE_5.0/CommandletProject/.gitignore new file mode 100644 index 0000000000..1004610e4f --- /dev/null +++ b/openpype/hosts/unreal/integration/UE_5.0/CommandletProject/.gitignore @@ -0,0 +1,6 @@ +/Saved +/DerivedDataCache +/Intermediate +/Binaries +/.idea +/.vs \ No newline at end of file diff --git a/openpype/hosts/unreal/integration/UE_5.0/CommandletProject/CommandletProject.uproject b/openpype/hosts/unreal/integration/UE_5.0/CommandletProject/CommandletProject.uproject new file mode 100644 index 0000000000..c8dc1c673e --- /dev/null +++ b/openpype/hosts/unreal/integration/UE_5.0/CommandletProject/CommandletProject.uproject @@ -0,0 +1,20 @@ +{ + "FileVersion": 3, + "EngineAssociation": "5.0", + "Category": "", + "Description": "", + "Plugins": [ + { + "Name": "ModelingToolsEditorMode", + "Enabled": true, + "TargetAllowList": [ + "Editor" + ] + }, + { + "Name": "OpenPype", + "Enabled": true, + "Type": "Editor" + } + ] +} \ No newline at end of file diff --git a/openpype/hosts/unreal/integration/UE_5.0/CommandletProject/Config/DefaultEditor.ini b/openpype/hosts/unreal/integration/UE_5.0/CommandletProject/Config/DefaultEditor.ini new file mode 100644 index 0000000000..e69de29bb2 diff --git a/openpype/hosts/unreal/integration/UE_5.0/CommandletProject/Config/DefaultEngine.ini b/openpype/hosts/unreal/integration/UE_5.0/CommandletProject/Config/DefaultEngine.ini new file mode 100644 index 0000000000..3f5357dac4 --- /dev/null +++ b/openpype/hosts/unreal/integration/UE_5.0/CommandletProject/Config/DefaultEngine.ini @@ -0,0 +1,42 @@ + + +[/Script/EngineSettings.GameMapsSettings] +GameDefaultMap=/Engine/Maps/Templates/OpenWorld + + +[/Script/HardwareTargeting.HardwareTargetingSettings] +TargetedHardwareClass=Desktop +AppliedTargetedHardwareClass=Desktop +DefaultGraphicsPerformance=Maximum +AppliedDefaultGraphicsPerformance=Maximum + +[/Script/WindowsTargetPlatform.WindowsTargetSettings] +DefaultGraphicsRHI=DefaultGraphicsRHI_DX12 + +[/Script/Engine.RendererSettings] +r.GenerateMeshDistanceFields=True +r.DynamicGlobalIlluminationMethod=1 +r.ReflectionMethod=1 +r.Shadow.Virtual.Enable=1 + +[/Script/WorldPartitionEditor.WorldPartitionEditorSettings] +CommandletClass=Class'/Script/UnrealEd.WorldPartitionConvertCommandlet' + +[/Script/Engine.Engine] ++ActiveGameNameRedirects=(OldGameName="TP_BlankBP",NewGameName="/Script/CommandletProject") ++ActiveGameNameRedirects=(OldGameName="/Script/TP_BlankBP",NewGameName="/Script/CommandletProject") + +[/Script/AndroidFileServerEditor.AndroidFileServerRuntimeSettings] +bEnablePlugin=True +bAllowNetworkConnection=True +SecurityToken=684C16AF4BD96F1D6828A6B067693175 +bIncludeInShipping=False +bAllowExternalStartInShipping=False +bCompileAFSProject=False +bUseCompression=False +bLogFiles=False +bReportStats=False +ConnectionType=USBOnly +bUseManualIPAddress=False +ManualIPAddress= + diff --git a/openpype/hosts/unreal/integration/UE_5.0/CommandletProject/Config/DefaultGame.ini b/openpype/hosts/unreal/integration/UE_5.0/CommandletProject/Config/DefaultGame.ini new file mode 100644 index 0000000000..c661b739ab --- /dev/null +++ b/openpype/hosts/unreal/integration/UE_5.0/CommandletProject/Config/DefaultGame.ini @@ -0,0 +1,4 @@ + + +[/Script/EngineSettings.GeneralProjectSettings] +ProjectID=D528076140C577E5807BA5BA135366BB diff --git a/openpype/hosts/unreal/integration/UE_5.0/.gitignore b/openpype/hosts/unreal/integration/UE_5.0/OpenPype/.gitignore similarity index 100% rename from openpype/hosts/unreal/integration/UE_5.0/.gitignore rename to openpype/hosts/unreal/integration/UE_5.0/OpenPype/.gitignore diff --git a/openpype/hosts/unreal/integration/UE_5.0/Config/DefaultOpenPypeSettings.ini b/openpype/hosts/unreal/integration/UE_5.0/OpenPype/Config/DefaultOpenPypeSettings.ini similarity index 100% rename from openpype/hosts/unreal/integration/UE_5.0/Config/DefaultOpenPypeSettings.ini rename to openpype/hosts/unreal/integration/UE_5.0/OpenPype/Config/DefaultOpenPypeSettings.ini diff --git a/openpype/hosts/unreal/integration/UE_5.0/OpenPype/Config/FilterPlugin.ini b/openpype/hosts/unreal/integration/UE_5.0/OpenPype/Config/FilterPlugin.ini new file mode 100644 index 0000000000..ccebca2f32 --- /dev/null +++ b/openpype/hosts/unreal/integration/UE_5.0/OpenPype/Config/FilterPlugin.ini @@ -0,0 +1,8 @@ +[FilterPlugin] +; This section lists additional files which will be packaged along with your plugin. Paths should be listed relative to the root plugin directory, and +; may include "...", "*", and "?" wildcards to match directories, files, and individual characters respectively. +; +; Examples: +; /README.txt +; /Extras/... +; /Binaries/ThirdParty/*.dll diff --git a/openpype/hosts/unreal/integration/UE_5.0/Content/Python/init_unreal.py b/openpype/hosts/unreal/integration/UE_5.0/OpenPype/Content/Python/init_unreal.py similarity index 100% rename from openpype/hosts/unreal/integration/UE_5.0/Content/Python/init_unreal.py rename to openpype/hosts/unreal/integration/UE_5.0/OpenPype/Content/Python/init_unreal.py diff --git a/openpype/hosts/unreal/integration/UE_4.7/OpenPype.uplugin b/openpype/hosts/unreal/integration/UE_5.0/OpenPype/OpenPype.uplugin similarity index 95% rename from openpype/hosts/unreal/integration/UE_4.7/OpenPype.uplugin rename to openpype/hosts/unreal/integration/UE_5.0/OpenPype/OpenPype.uplugin index 4c7a74403c..b89eb43949 100644 --- a/openpype/hosts/unreal/integration/UE_4.7/OpenPype.uplugin +++ b/openpype/hosts/unreal/integration/UE_5.0/OpenPype/OpenPype.uplugin @@ -11,6 +11,7 @@ "MarketplaceURL": "", "SupportURL": "https://pype.club/", "CanContainContent": true, + "EngineVersion": "5.0", "IsBetaVersion": true, "IsExperimentalVersion": false, "Installed": false, diff --git a/openpype/hosts/unreal/integration/UE_5.0/README.md b/openpype/hosts/unreal/integration/UE_5.0/OpenPype/README.md similarity index 100% rename from openpype/hosts/unreal/integration/UE_5.0/README.md rename to openpype/hosts/unreal/integration/UE_5.0/OpenPype/README.md diff --git a/openpype/hosts/unreal/integration/UE_5.0/Resources/openpype128.png b/openpype/hosts/unreal/integration/UE_5.0/OpenPype/Resources/openpype128.png similarity index 100% rename from openpype/hosts/unreal/integration/UE_5.0/Resources/openpype128.png rename to openpype/hosts/unreal/integration/UE_5.0/OpenPype/Resources/openpype128.png diff --git a/openpype/hosts/unreal/integration/UE_5.0/Resources/openpype40.png b/openpype/hosts/unreal/integration/UE_5.0/OpenPype/Resources/openpype40.png similarity index 100% rename from openpype/hosts/unreal/integration/UE_5.0/Resources/openpype40.png rename to openpype/hosts/unreal/integration/UE_5.0/OpenPype/Resources/openpype40.png diff --git a/openpype/hosts/unreal/integration/UE_5.0/Resources/openpype512.png b/openpype/hosts/unreal/integration/UE_5.0/OpenPype/Resources/openpype512.png similarity index 100% rename from openpype/hosts/unreal/integration/UE_5.0/Resources/openpype512.png rename to openpype/hosts/unreal/integration/UE_5.0/OpenPype/Resources/openpype512.png diff --git a/openpype/hosts/unreal/integration/UE_5.0/Source/OpenPype/OpenPype.Build.cs b/openpype/hosts/unreal/integration/UE_5.0/OpenPype/Source/OpenPype/OpenPype.Build.cs similarity index 92% rename from openpype/hosts/unreal/integration/UE_5.0/Source/OpenPype/OpenPype.Build.cs rename to openpype/hosts/unreal/integration/UE_5.0/OpenPype/Source/OpenPype/OpenPype.Build.cs index d853ec028f..99c1c7b306 100644 --- a/openpype/hosts/unreal/integration/UE_5.0/Source/OpenPype/OpenPype.Build.cs +++ b/openpype/hosts/unreal/integration/UE_5.0/OpenPype/Source/OpenPype/OpenPype.Build.cs @@ -10,7 +10,7 @@ public class OpenPype : ModuleRules bLegacyPublicIncludePaths = false; ShadowVariableWarningLevel = WarningLevel.Error; PCHUsage = ModuleRules.PCHUsageMode.UseExplicitOrSharedPCHs; - IncludeOrderVersion = EngineIncludeOrderVersion.Unreal5_0; + //IncludeOrderVersion = EngineIncludeOrderVersion.Unreal5_0; PublicIncludePaths.AddRange( new string[] { @@ -30,14 +30,15 @@ public class OpenPype : ModuleRules new string[] { "Core", + "CoreUObject" // ... add other public dependencies that you statically link with here ... } ); - PrivateDependencyModuleNames.AddRange( new string[] { + "GameProjectGeneration", "Projects", "InputCore", "EditorFramework", diff --git a/openpype/hosts/unreal/integration/UE_5.0/OpenPype/Source/OpenPype/Private/Commandlets/Implementations/OPGenerateProjectCommandlet.cpp b/openpype/hosts/unreal/integration/UE_5.0/OpenPype/Source/OpenPype/Private/Commandlets/Implementations/OPGenerateProjectCommandlet.cpp new file mode 100644 index 0000000000..024a6097b3 --- /dev/null +++ b/openpype/hosts/unreal/integration/UE_5.0/OpenPype/Source/OpenPype/Private/Commandlets/Implementations/OPGenerateProjectCommandlet.cpp @@ -0,0 +1,140 @@ +#include "Commandlets/Implementations/OPGenerateProjectCommandlet.h" + +#include "Editor.h" +#include "GameProjectUtils.h" +#include "OPConstants.h" +#include "Commandlets/OPActionResult.h" +#include "ProjectDescriptor.h" + +int32 UOPGenerateProjectCommandlet::Main(const FString& CommandLineParams) +{ + //Parses command line parameters & creates structure FProjectInformation + const FOPGenerateProjectParams ParsedParams = FOPGenerateProjectParams(CommandLineParams); + ProjectInformation = ParsedParams.GenerateUEProjectInformation(); + + //Creates .uproject & other UE files + EVALUATE_OP_ACTION_RESULT(TryCreateProject()); + + //Loads created .uproject + EVALUATE_OP_ACTION_RESULT(TryLoadProjectDescriptor()); + + //Adds needed plugin to .uproject + AttachPluginsToProjectDescriptor(); + + //Saves .uproject + EVALUATE_OP_ACTION_RESULT(TrySave()); + + //When we are here, there should not be problems in generating Unreal Project for OpenPype + return 0; +} + + +FOPGenerateProjectParams::FOPGenerateProjectParams(): FOPGenerateProjectParams("") +{ +} + +FOPGenerateProjectParams::FOPGenerateProjectParams(const FString& CommandLineParams): CommandLineParams( + CommandLineParams) +{ + UCommandlet::ParseCommandLine(*CommandLineParams, Tokens, Switches); +} + +FProjectInformation FOPGenerateProjectParams::GenerateUEProjectInformation() const +{ + FProjectInformation ProjectInformation = FProjectInformation(); + ProjectInformation.ProjectFilename = GetProjectFileName(); + + ProjectInformation.bShouldGenerateCode = IsSwitchPresent("GenerateCode"); + + return ProjectInformation; +} + +FString FOPGenerateProjectParams::TryGetToken(const int32 Index) const +{ + return Tokens.IsValidIndex(Index) ? Tokens[Index] : ""; +} + +FString FOPGenerateProjectParams::GetProjectFileName() const +{ + return TryGetToken(0); +} + +bool FOPGenerateProjectParams::IsSwitchPresent(const FString& Switch) const +{ + return INDEX_NONE != Switches.IndexOfByPredicate([&Switch](const FString& Item) -> bool + { + return Item.Equals(Switch); + } + ); +} + + +UOPGenerateProjectCommandlet::UOPGenerateProjectCommandlet() +{ + LogToConsole = true; +} + +FOP_ActionResult UOPGenerateProjectCommandlet::TryCreateProject() const +{ + FText FailReason; + FText FailLog; + TArray OutCreatedFiles; + + if (!GameProjectUtils::CreateProject(ProjectInformation, FailReason, FailLog, &OutCreatedFiles)) + return FOP_ActionResult(EOP_ActionResult::ProjectNotCreated, FailReason); + return FOP_ActionResult(); +} + +FOP_ActionResult UOPGenerateProjectCommandlet::TryLoadProjectDescriptor() +{ + FText FailReason; + const bool bLoaded = ProjectDescriptor.Load(ProjectInformation.ProjectFilename, FailReason); + + return FOP_ActionResult(bLoaded ? EOP_ActionResult::Ok : EOP_ActionResult::ProjectNotLoaded, FailReason); +} + +void UOPGenerateProjectCommandlet::AttachPluginsToProjectDescriptor() +{ + FPluginReferenceDescriptor OPPluginDescriptor; + OPPluginDescriptor.bEnabled = true; + OPPluginDescriptor.Name = OPConstants::OP_PluginName; + ProjectDescriptor.Plugins.Add(OPPluginDescriptor); + + FPluginReferenceDescriptor PythonPluginDescriptor; + PythonPluginDescriptor.bEnabled = true; + PythonPluginDescriptor.Name = OPConstants::PythonScript_PluginName; + ProjectDescriptor.Plugins.Add(PythonPluginDescriptor); + + FPluginReferenceDescriptor SequencerScriptingPluginDescriptor; + SequencerScriptingPluginDescriptor.bEnabled = true; + SequencerScriptingPluginDescriptor.Name = OPConstants::SequencerScripting_PluginName; + ProjectDescriptor.Plugins.Add(SequencerScriptingPluginDescriptor); + + FPluginReferenceDescriptor MovieRenderPipelinePluginDescriptor; + MovieRenderPipelinePluginDescriptor.bEnabled = true; + MovieRenderPipelinePluginDescriptor.Name = OPConstants::MovieRenderPipeline_PluginName; + ProjectDescriptor.Plugins.Add(MovieRenderPipelinePluginDescriptor); + + FPluginReferenceDescriptor EditorScriptingPluginDescriptor; + EditorScriptingPluginDescriptor.bEnabled = true; + EditorScriptingPluginDescriptor.Name = OPConstants::EditorScriptingUtils_PluginName; + ProjectDescriptor.Plugins.Add(EditorScriptingPluginDescriptor); +} + +FOP_ActionResult UOPGenerateProjectCommandlet::TrySave() +{ + FText FailReason; + const bool bSaved = ProjectDescriptor.Save(ProjectInformation.ProjectFilename, FailReason); + + return FOP_ActionResult(bSaved ? EOP_ActionResult::Ok : EOP_ActionResult::ProjectNotSaved, FailReason); +} + +FOPGenerateProjectParams UOPGenerateProjectCommandlet::ParseParameters(const FString& Params) const +{ + FOPGenerateProjectParams ParamsResult; + + TArray Tokens, Switches; + ParseCommandLine(*Params, Tokens, Switches); + + return ParamsResult; +} diff --git a/openpype/hosts/unreal/integration/UE_5.0/OpenPype/Source/OpenPype/Private/Commandlets/OPActionResult.cpp b/openpype/hosts/unreal/integration/UE_5.0/OpenPype/Source/OpenPype/Private/Commandlets/OPActionResult.cpp new file mode 100644 index 0000000000..9236fbb057 --- /dev/null +++ b/openpype/hosts/unreal/integration/UE_5.0/OpenPype/Source/OpenPype/Private/Commandlets/OPActionResult.cpp @@ -0,0 +1,41 @@ +// Fill out your copyright notice in the Description page of Project Settings. + + +#include "Commandlets/OPActionResult.h" +#include "Logging/OP_Log.h" + +EOP_ActionResult::Type& FOP_ActionResult::GetStatus() +{ + return Status; +} + +FText& FOP_ActionResult::GetReason() +{ + return Reason; +} + +FOP_ActionResult::FOP_ActionResult():Status(EOP_ActionResult::Type::Ok) +{ + +} + +FOP_ActionResult::FOP_ActionResult(const EOP_ActionResult::Type& InEnum):Status(InEnum) +{ + TryLog(); +} + +FOP_ActionResult::FOP_ActionResult(const EOP_ActionResult::Type& InEnum, const FText& InReason):Status(InEnum), Reason(InReason) +{ + TryLog(); +}; + +bool FOP_ActionResult::IsProblem() const +{ + return Status != EOP_ActionResult::Ok; +} + +void FOP_ActionResult::TryLog() const +{ + if(IsProblem()) + UE_LOG(LogCommandletOPGenerateProject, Error, TEXT("%s"), *Reason.ToString()); +} diff --git a/openpype/hosts/unreal/integration/UE_5.0/OpenPype/Source/OpenPype/Private/Logging/OP_Log.cpp b/openpype/hosts/unreal/integration/UE_5.0/OpenPype/Source/OpenPype/Private/Logging/OP_Log.cpp new file mode 100644 index 0000000000..29b1068c21 --- /dev/null +++ b/openpype/hosts/unreal/integration/UE_5.0/OpenPype/Source/OpenPype/Private/Logging/OP_Log.cpp @@ -0,0 +1 @@ +#include "Logging/OP_Log.h" diff --git a/openpype/hosts/unreal/integration/UE_5.0/Source/OpenPype/Private/OpenPype.cpp b/openpype/hosts/unreal/integration/UE_5.0/OpenPype/Source/OpenPype/Private/OpenPype.cpp similarity index 100% rename from openpype/hosts/unreal/integration/UE_5.0/Source/OpenPype/Private/OpenPype.cpp rename to openpype/hosts/unreal/integration/UE_5.0/OpenPype/Source/OpenPype/Private/OpenPype.cpp diff --git a/openpype/hosts/unreal/integration/UE_5.0/Source/OpenPype/Private/OpenPypeCommands.cpp b/openpype/hosts/unreal/integration/UE_5.0/OpenPype/Source/OpenPype/Private/OpenPypeCommands.cpp similarity index 100% rename from openpype/hosts/unreal/integration/UE_5.0/Source/OpenPype/Private/OpenPypeCommands.cpp rename to openpype/hosts/unreal/integration/UE_5.0/OpenPype/Source/OpenPype/Private/OpenPypeCommands.cpp diff --git a/openpype/hosts/unreal/integration/UE_5.0/Source/OpenPype/Private/OpenPypeLib.cpp b/openpype/hosts/unreal/integration/UE_5.0/OpenPype/Source/OpenPype/Private/OpenPypeLib.cpp similarity index 100% rename from openpype/hosts/unreal/integration/UE_5.0/Source/OpenPype/Private/OpenPypeLib.cpp rename to openpype/hosts/unreal/integration/UE_5.0/OpenPype/Source/OpenPype/Private/OpenPypeLib.cpp diff --git a/openpype/hosts/unreal/integration/UE_5.0/Source/OpenPype/Private/OpenPypePublishInstance.cpp b/openpype/hosts/unreal/integration/UE_5.0/OpenPype/Source/OpenPype/Private/OpenPypePublishInstance.cpp similarity index 99% rename from openpype/hosts/unreal/integration/UE_5.0/Source/OpenPype/Private/OpenPypePublishInstance.cpp rename to openpype/hosts/unreal/integration/UE_5.0/OpenPype/Source/OpenPype/Private/OpenPypePublishInstance.cpp index 0b56111a49..e6a85002c7 100644 --- a/openpype/hosts/unreal/integration/UE_5.0/Source/OpenPype/Private/OpenPypePublishInstance.cpp +++ b/openpype/hosts/unreal/integration/UE_5.0/OpenPype/Source/OpenPype/Private/OpenPypePublishInstance.cpp @@ -55,7 +55,7 @@ void UOpenPypePublishInstance::OnAssetCreated(const FAssetData& InAssetData) if (!IsValid(Asset)) { UE_LOG(LogAssetData, Warning, TEXT("Asset \"%s\" is not valid! Skipping the addition."), - *InAssetData.GetObjectPathString()); + *InAssetData.ObjectPath.ToString()); return; } diff --git a/openpype/hosts/unreal/integration/UE_5.0/Source/OpenPype/Private/OpenPypePublishInstanceFactory.cpp b/openpype/hosts/unreal/integration/UE_5.0/OpenPype/Source/OpenPype/Private/OpenPypePublishInstanceFactory.cpp similarity index 100% rename from openpype/hosts/unreal/integration/UE_5.0/Source/OpenPype/Private/OpenPypePublishInstanceFactory.cpp rename to openpype/hosts/unreal/integration/UE_5.0/OpenPype/Source/OpenPype/Private/OpenPypePublishInstanceFactory.cpp diff --git a/openpype/hosts/unreal/integration/UE_5.0/Source/OpenPype/Private/OpenPypePythonBridge.cpp b/openpype/hosts/unreal/integration/UE_5.0/OpenPype/Source/OpenPype/Private/OpenPypePythonBridge.cpp similarity index 100% rename from openpype/hosts/unreal/integration/UE_5.0/Source/OpenPype/Private/OpenPypePythonBridge.cpp rename to openpype/hosts/unreal/integration/UE_5.0/OpenPype/Source/OpenPype/Private/OpenPypePythonBridge.cpp diff --git a/openpype/hosts/unreal/integration/UE_5.0/Source/OpenPype/Private/OpenPypeSettings.cpp b/openpype/hosts/unreal/integration/UE_5.0/OpenPype/Source/OpenPype/Private/OpenPypeSettings.cpp similarity index 100% rename from openpype/hosts/unreal/integration/UE_5.0/Source/OpenPype/Private/OpenPypeSettings.cpp rename to openpype/hosts/unreal/integration/UE_5.0/OpenPype/Source/OpenPype/Private/OpenPypeSettings.cpp diff --git a/openpype/hosts/unreal/integration/UE_5.0/Source/OpenPype/Private/OpenPypeStyle.cpp b/openpype/hosts/unreal/integration/UE_5.0/OpenPype/Source/OpenPype/Private/OpenPypeStyle.cpp similarity index 100% rename from openpype/hosts/unreal/integration/UE_5.0/Source/OpenPype/Private/OpenPypeStyle.cpp rename to openpype/hosts/unreal/integration/UE_5.0/OpenPype/Source/OpenPype/Private/OpenPypeStyle.cpp diff --git a/openpype/hosts/unreal/integration/UE_5.0/OpenPype/Source/OpenPype/Public/Commandlets/Implementations/OPGenerateProjectCommandlet.h b/openpype/hosts/unreal/integration/UE_5.0/OpenPype/Source/OpenPype/Public/Commandlets/Implementations/OPGenerateProjectCommandlet.h new file mode 100644 index 0000000000..8738de6d4a --- /dev/null +++ b/openpype/hosts/unreal/integration/UE_5.0/OpenPype/Source/OpenPype/Public/Commandlets/Implementations/OPGenerateProjectCommandlet.h @@ -0,0 +1,60 @@ +#pragma once + + +#include "GameProjectUtils.h" +#include "Commandlets/OPActionResult.h" +#include "ProjectDescriptor.h" +#include "Commandlets/Commandlet.h" +#include "OPGenerateProjectCommandlet.generated.h" + +struct FProjectDescriptor; +struct FProjectInformation; + +/** +* @brief Structure which parses command line parameters and generates FProjectInformation +*/ +USTRUCT() +struct FOPGenerateProjectParams +{ + GENERATED_BODY() + +private: + FString CommandLineParams; + TArray Tokens; + TArray Switches; + +public: + FOPGenerateProjectParams(); + FOPGenerateProjectParams(const FString& CommandLineParams); + + FProjectInformation GenerateUEProjectInformation() const; + +private: + FString TryGetToken(const int32 Index) const; + FString GetProjectFileName() const; + + bool IsSwitchPresent(const FString& Switch) const; +}; + +UCLASS() +class OPENPYPE_API UOPGenerateProjectCommandlet : public UCommandlet +{ + GENERATED_BODY() + +private: + FProjectInformation ProjectInformation; + FProjectDescriptor ProjectDescriptor; + +public: + UOPGenerateProjectCommandlet(); + + virtual int32 Main(const FString& CommandLineParams) override; + +private: + FOPGenerateProjectParams ParseParameters(const FString& Params) const; + FOP_ActionResult TryCreateProject() const; + FOP_ActionResult TryLoadProjectDescriptor(); + void AttachPluginsToProjectDescriptor(); + FOP_ActionResult TrySave(); +}; + diff --git a/openpype/hosts/unreal/integration/UE_5.0/OpenPype/Source/OpenPype/Public/Commandlets/OPActionResult.h b/openpype/hosts/unreal/integration/UE_5.0/OpenPype/Source/OpenPype/Public/Commandlets/OPActionResult.h new file mode 100644 index 0000000000..f46ba9c62a --- /dev/null +++ b/openpype/hosts/unreal/integration/UE_5.0/OpenPype/Source/OpenPype/Public/Commandlets/OPActionResult.h @@ -0,0 +1,83 @@ +// Fill out your copyright notice in the Description page of Project Settings. + +#pragma once + +#include "CoreMinimal.h" +#include "OPActionResult.generated.h" + +/** + * @brief This macro returns error code when is problem or does nothing when there is no problem. + * @param ActionResult FOP_ActionResult structure + */ +#define EVALUATE_OP_ACTION_RESULT(ActionResult) \ + if(ActionResult.IsProblem()) \ + return ActionResult.GetStatus(); + +/** +* @brief This enum values are humanly readable mapping of error codes. +* Here should be all error codes to be possible find what went wrong. +* TODO: In the future should exists an web document where is mapped error code & what problem occured & how to repair it... +*/ +UENUM() +namespace EOP_ActionResult +{ + enum Type + { + Ok, + ProjectNotCreated, + ProjectNotLoaded, + ProjectNotSaved, + //....Here insert another values + + //Do not remove! + //Usable for looping through enum values + __Last UMETA(Hidden) + }; +} + + +/** + * @brief This struct holds action result enum and optionally reason of fail + */ +USTRUCT() +struct FOP_ActionResult +{ + GENERATED_BODY() + +public: + /** @brief Default constructor usable when there is no problem */ + FOP_ActionResult(); + + /** + * @brief This constructor initializes variables & attempts to log when is error + * @param InEnum Status + */ + FOP_ActionResult(const EOP_ActionResult::Type& InEnum); + + /** + * @brief This constructor initializes variables & attempts to log when is error + * @param InEnum Status + * @param InReason Reason of potential fail + */ + FOP_ActionResult(const EOP_ActionResult::Type& InEnum, const FText& InReason); + +private: + /** @brief Action status */ + EOP_ActionResult::Type Status; + + /** @brief Optional reason of fail */ + FText Reason; + +public: + /** + * @brief Checks if there is problematic state + * @return true when status is not equal to EOP_ActionResult::Ok + */ + bool IsProblem() const; + EOP_ActionResult::Type& GetStatus(); + FText& GetReason(); + +private: + void TryLog() const; +}; + diff --git a/openpype/hosts/unreal/integration/UE_5.0/OpenPype/Source/OpenPype/Public/Logging/OP_Log.h b/openpype/hosts/unreal/integration/UE_5.0/OpenPype/Source/OpenPype/Public/Logging/OP_Log.h new file mode 100644 index 0000000000..4f8af3e2e6 --- /dev/null +++ b/openpype/hosts/unreal/integration/UE_5.0/OpenPype/Source/OpenPype/Public/Logging/OP_Log.h @@ -0,0 +1,3 @@ +#pragma once + +DEFINE_LOG_CATEGORY_STATIC(LogCommandletOPGenerateProject, Log, All); \ No newline at end of file diff --git a/openpype/hosts/unreal/integration/UE_5.0/OpenPype/Source/OpenPype/Public/OPConstants.h b/openpype/hosts/unreal/integration/UE_5.0/OpenPype/Source/OpenPype/Public/OPConstants.h new file mode 100644 index 0000000000..21a033e426 --- /dev/null +++ b/openpype/hosts/unreal/integration/UE_5.0/OpenPype/Source/OpenPype/Public/OPConstants.h @@ -0,0 +1,12 @@ +#pragma once + +namespace OPConstants +{ + const FString OP_PluginName = "OpenPype"; + const FString PythonScript_PluginName = "PythonScriptPlugin"; + const FString SequencerScripting_PluginName = "SequencerScripting"; + const FString MovieRenderPipeline_PluginName = "MovieRenderPipeline"; + const FString EditorScriptingUtils_PluginName = "EditorScriptingUtilities"; +} + + diff --git a/openpype/hosts/unreal/integration/UE_5.0/Source/OpenPype/Public/OpenPype.h b/openpype/hosts/unreal/integration/UE_5.0/OpenPype/Source/OpenPype/Public/OpenPype.h similarity index 100% rename from openpype/hosts/unreal/integration/UE_5.0/Source/OpenPype/Public/OpenPype.h rename to openpype/hosts/unreal/integration/UE_5.0/OpenPype/Source/OpenPype/Public/OpenPype.h diff --git a/openpype/hosts/unreal/integration/UE_5.0/Source/OpenPype/Public/OpenPypeCommands.h b/openpype/hosts/unreal/integration/UE_5.0/OpenPype/Source/OpenPype/Public/OpenPypeCommands.h similarity index 100% rename from openpype/hosts/unreal/integration/UE_5.0/Source/OpenPype/Public/OpenPypeCommands.h rename to openpype/hosts/unreal/integration/UE_5.0/OpenPype/Source/OpenPype/Public/OpenPypeCommands.h diff --git a/openpype/hosts/unreal/integration/UE_5.0/Source/OpenPype/Public/OpenPypeLib.h b/openpype/hosts/unreal/integration/UE_5.0/OpenPype/Source/OpenPype/Public/OpenPypeLib.h similarity index 100% rename from openpype/hosts/unreal/integration/UE_5.0/Source/OpenPype/Public/OpenPypeLib.h rename to openpype/hosts/unreal/integration/UE_5.0/OpenPype/Source/OpenPype/Public/OpenPypeLib.h diff --git a/openpype/hosts/unreal/integration/UE_5.0/Source/OpenPype/Public/OpenPypePublishInstance.h b/openpype/hosts/unreal/integration/UE_5.0/OpenPype/Source/OpenPype/Public/OpenPypePublishInstance.h similarity index 94% rename from openpype/hosts/unreal/integration/UE_5.0/Source/OpenPype/Public/OpenPypePublishInstance.h rename to openpype/hosts/unreal/integration/UE_5.0/OpenPype/Source/OpenPype/Public/OpenPypePublishInstance.h index 146025bd6d..c221f64135 100644 --- a/openpype/hosts/unreal/integration/UE_5.0/Source/OpenPype/Public/OpenPypePublishInstance.h +++ b/openpype/hosts/unreal/integration/UE_5.0/OpenPype/Source/OpenPype/Public/OpenPypePublishInstance.h @@ -17,7 +17,7 @@ public: * * @return - Set of UObjects. Careful! They are returning raw pointers. Seems like an issue in UE5 */ - UFUNCTION(BlueprintCallable, BlueprintPure) + UFUNCTION(BlueprintCallable, BlueprintPure, Category="Python") TSet GetInternalAssets() const { //For some reason it can only return Raw Pointers? Seems like an issue which they haven't fixed. @@ -34,7 +34,7 @@ public: * * @return - TSet of assets (UObjects). Careful! They are returning raw pointers. Seems like an issue in UE5 */ - UFUNCTION(BlueprintCallable, BlueprintPure) + UFUNCTION(BlueprintCallable, BlueprintPure, Category="Python") TSet GetExternalAssets() const { //For some reason it can only return Raw Pointers? Seems like an issue which they haven't fixed. @@ -54,7 +54,7 @@ public: * * @attention If the bAddExternalAssets variable is false, external assets won't be included! */ - UFUNCTION(BlueprintCallable, BlueprintPure) + UFUNCTION(BlueprintCallable, BlueprintPure, Category="Python") TSet GetAllAssets() const { const TSet>& IteratedSet = bAddExternalAssets diff --git a/openpype/hosts/unreal/integration/UE_5.0/Source/OpenPype/Public/OpenPypePublishInstanceFactory.h b/openpype/hosts/unreal/integration/UE_5.0/OpenPype/Source/OpenPype/Public/OpenPypePublishInstanceFactory.h similarity index 100% rename from openpype/hosts/unreal/integration/UE_5.0/Source/OpenPype/Public/OpenPypePublishInstanceFactory.h rename to openpype/hosts/unreal/integration/UE_5.0/OpenPype/Source/OpenPype/Public/OpenPypePublishInstanceFactory.h diff --git a/openpype/hosts/unreal/integration/UE_5.0/Source/OpenPype/Public/OpenPypePythonBridge.h b/openpype/hosts/unreal/integration/UE_5.0/OpenPype/Source/OpenPype/Public/OpenPypePythonBridge.h similarity index 100% rename from openpype/hosts/unreal/integration/UE_5.0/Source/OpenPype/Public/OpenPypePythonBridge.h rename to openpype/hosts/unreal/integration/UE_5.0/OpenPype/Source/OpenPype/Public/OpenPypePythonBridge.h diff --git a/openpype/hosts/unreal/integration/UE_5.0/Source/OpenPype/Public/OpenPypeSettings.h b/openpype/hosts/unreal/integration/UE_5.0/OpenPype/Source/OpenPype/Public/OpenPypeSettings.h similarity index 100% rename from openpype/hosts/unreal/integration/UE_5.0/Source/OpenPype/Public/OpenPypeSettings.h rename to openpype/hosts/unreal/integration/UE_5.0/OpenPype/Source/OpenPype/Public/OpenPypeSettings.h diff --git a/openpype/hosts/unreal/integration/UE_5.0/Source/OpenPype/Public/OpenPypeStyle.h b/openpype/hosts/unreal/integration/UE_5.0/OpenPype/Source/OpenPype/Public/OpenPypeStyle.h similarity index 100% rename from openpype/hosts/unreal/integration/UE_5.0/Source/OpenPype/Public/OpenPypeStyle.h rename to openpype/hosts/unreal/integration/UE_5.0/OpenPype/Source/OpenPype/Public/OpenPypeStyle.h diff --git a/openpype/hosts/unreal/integration/UE_5.0/Source/OpenPype/Private/AssetContainer.cpp b/openpype/hosts/unreal/integration/UE_5.0/Source/OpenPype/Private/AssetContainer.cpp deleted file mode 100644 index 61e563f729..0000000000 --- a/openpype/hosts/unreal/integration/UE_5.0/Source/OpenPype/Private/AssetContainer.cpp +++ /dev/null @@ -1,115 +0,0 @@ -// Fill out your copyright notice in the Description page of Project Settings. - -#include "AssetContainer.h" -#include "AssetRegistry/AssetRegistryModule.h" -#include "Misc/PackageName.h" -#include "Engine.h" -#include "Containers/UnrealString.h" - -UAssetContainer::UAssetContainer(const FObjectInitializer& ObjectInitializer) -: UAssetUserData(ObjectInitializer) -{ - FAssetRegistryModule& AssetRegistryModule = FModuleManager::LoadModuleChecked("AssetRegistry"); - FString path = UAssetContainer::GetPathName(); - UE_LOG(LogTemp, Warning, TEXT("UAssetContainer %s"), *path); - FARFilter Filter; - Filter.PackagePaths.Add(FName(*path)); - - AssetRegistryModule.Get().OnAssetAdded().AddUObject(this, &UAssetContainer::OnAssetAdded); - AssetRegistryModule.Get().OnAssetRemoved().AddUObject(this, &UAssetContainer::OnAssetRemoved); - AssetRegistryModule.Get().OnAssetRenamed().AddUObject(this, &UAssetContainer::OnAssetRenamed); -} - -void UAssetContainer::OnAssetAdded(const FAssetData& AssetData) -{ - TArray split; - - // get directory of current container - FString selfFullPath = UAssetContainer::GetPathName(); - FString selfDir = FPackageName::GetLongPackagePath(*selfFullPath); - - // get asset path and class - FString assetPath = AssetData.GetFullName(); - FString assetFName = AssetData.AssetClassPath.ToString(); - UE_LOG(LogTemp, Log, TEXT("asset name %s"), *assetFName); - // split path - assetPath.ParseIntoArray(split, TEXT(" "), true); - - FString assetDir = FPackageName::GetLongPackagePath(*split[1]); - - // take interest only in paths starting with path of current container - if (assetDir.StartsWith(*selfDir)) - { - // exclude self - if (assetFName != "AssetContainer") - { - assets.Add(assetPath); - assetsData.Add(AssetData); - UE_LOG(LogTemp, Log, TEXT("%s: asset added to %s"), *selfFullPath, *selfDir); - } - } -} - -void UAssetContainer::OnAssetRemoved(const FAssetData& AssetData) -{ - TArray split; - - // get directory of current container - FString selfFullPath = UAssetContainer::GetPathName(); - FString selfDir = FPackageName::GetLongPackagePath(*selfFullPath); - - // get asset path and class - FString assetPath = AssetData.GetFullName(); - FString assetFName = AssetData.AssetClassPath.ToString(); - - // split path - assetPath.ParseIntoArray(split, TEXT(" "), true); - - FString assetDir = FPackageName::GetLongPackagePath(*split[1]); - - // take interest only in paths starting with path of current container - FString path = UAssetContainer::GetPathName(); - FString lpp = FPackageName::GetLongPackagePath(*path); - - if (assetDir.StartsWith(*selfDir)) - { - // exclude self - if (assetFName != "AssetContainer") - { - // UE_LOG(LogTemp, Warning, TEXT("%s: asset removed"), *lpp); - assets.Remove(assetPath); - assetsData.Remove(AssetData); - } - } -} - -void UAssetContainer::OnAssetRenamed(const FAssetData& AssetData, const FString& str) -{ - TArray split; - - // get directory of current container - FString selfFullPath = UAssetContainer::GetPathName(); - FString selfDir = FPackageName::GetLongPackagePath(*selfFullPath); - - // get asset path and class - FString assetPath = AssetData.GetFullName(); - FString assetFName = AssetData.AssetClassPath.ToString(); - - // split path - assetPath.ParseIntoArray(split, TEXT(" "), true); - - FString assetDir = FPackageName::GetLongPackagePath(*split[1]); - if (assetDir.StartsWith(*selfDir)) - { - // exclude self - if (assetFName != "AssetContainer") - { - - assets.Remove(str); - assets.Add(assetPath); - assetsData.Remove(AssetData); - // UE_LOG(LogTemp, Warning, TEXT("%s: asset renamed %s"), *lpp, *str); - } - } -} - diff --git a/openpype/hosts/unreal/integration/UE_5.0/Source/OpenPype/Private/AssetContainerFactory.cpp b/openpype/hosts/unreal/integration/UE_5.0/Source/OpenPype/Private/AssetContainerFactory.cpp deleted file mode 100644 index b943150bdd..0000000000 --- a/openpype/hosts/unreal/integration/UE_5.0/Source/OpenPype/Private/AssetContainerFactory.cpp +++ /dev/null @@ -1,20 +0,0 @@ -#include "AssetContainerFactory.h" -#include "AssetContainer.h" - -UAssetContainerFactory::UAssetContainerFactory(const FObjectInitializer& ObjectInitializer) - : UFactory(ObjectInitializer) -{ - SupportedClass = UAssetContainer::StaticClass(); - bCreateNew = false; - bEditorImport = true; -} - -UObject* UAssetContainerFactory::FactoryCreateNew(UClass* Class, UObject* InParent, FName Name, EObjectFlags Flags, UObject* Context, FFeedbackContext* Warn) -{ - UAssetContainer* AssetContainer = NewObject(InParent, Class, Name, Flags); - return AssetContainer; -} - -bool UAssetContainerFactory::ShouldShowInNewMenu() const { - return false; -} diff --git a/openpype/hosts/unreal/integration/UE_5.0/Source/OpenPype/Public/AssetContainer.h b/openpype/hosts/unreal/integration/UE_5.0/Source/OpenPype/Public/AssetContainer.h deleted file mode 100644 index 2c06e59d6f..0000000000 --- a/openpype/hosts/unreal/integration/UE_5.0/Source/OpenPype/Public/AssetContainer.h +++ /dev/null @@ -1,39 +0,0 @@ -// Fill out your copyright notice in the Description page of Project Settings. - -#pragma once - -#include "CoreMinimal.h" -#include "UObject/NoExportTypes.h" -#include "Engine/AssetUserData.h" -#include "AssetRegistry/AssetData.h" -#include "AssetContainer.generated.h" - -/** - * - */ -UCLASS(Blueprintable) -class OPENPYPE_API UAssetContainer : public UAssetUserData -{ - GENERATED_BODY() - -public: - - UAssetContainer(const FObjectInitializer& ObjectInitalizer); - // ~UAssetContainer(); - - UPROPERTY(EditAnywhere, BlueprintReadOnly) - TArray assets; - - // There seems to be no reflection option to expose array of FAssetData - /* - UPROPERTY(Transient, BlueprintReadOnly, Category = "Python", meta=(DisplayName="Assets Data")) - TArray assetsData; - */ -private: - TArray assetsData; - void OnAssetAdded(const FAssetData& AssetData); - void OnAssetRemoved(const FAssetData& AssetData); - void OnAssetRenamed(const FAssetData& AssetData, const FString& str); -}; - - diff --git a/openpype/hosts/unreal/integration/UE_5.0/Source/OpenPype/Public/AssetContainerFactory.h b/openpype/hosts/unreal/integration/UE_5.0/Source/OpenPype/Public/AssetContainerFactory.h deleted file mode 100644 index 331ce6bb50..0000000000 --- a/openpype/hosts/unreal/integration/UE_5.0/Source/OpenPype/Public/AssetContainerFactory.h +++ /dev/null @@ -1,21 +0,0 @@ -// Fill out your copyright notice in the Description page of Project Settings. - -#pragma once - -#include "CoreMinimal.h" -#include "Factories/Factory.h" -#include "AssetContainerFactory.generated.h" - -/** - * - */ -UCLASS() -class OPENPYPE_API UAssetContainerFactory : public UFactory -{ - GENERATED_BODY() - -public: - UAssetContainerFactory(const FObjectInitializer& ObjectInitializer); - virtual UObject* FactoryCreateNew(UClass* Class, UObject* InParent, FName Name, EObjectFlags Flags, UObject* Context, FFeedbackContext* Warn) override; - virtual bool ShouldShowInNewMenu() const override; -}; \ No newline at end of file diff --git a/openpype/hosts/unreal/lib.py b/openpype/hosts/unreal/lib.py index 095f5e414b..5bde65edb6 100644 --- a/openpype/hosts/unreal/lib.py +++ b/openpype/hosts/unreal/lib.py @@ -4,6 +4,10 @@ import os import platform import json + +from typing import List + +import openpype from distutils import dir_util import subprocess import re @@ -73,7 +77,7 @@ def get_engine_versions(env=None): return OrderedDict() -def get_editor_executable_path(engine_path: Path, engine_version: str) -> Path: +def get_editor_exe_path(engine_path: Path, engine_version: str) -> Path: """Get UE Editor executable path.""" ue_path = engine_path / "Engine/Binaries" if platform.system().lower() == "windows": @@ -214,77 +218,58 @@ def create_unreal_project(project_name: str, # created in different UE4 version. When user convert such project # to his UE4 version, Engine ID is replaced in uproject file. If some # other user tries to open it, it will present him with similar error. - ue_modules = Path() - if platform.system().lower() == "windows": - ue_modules_path = engine_path / "Engine/Binaries/Win64" - if ue_version.split(".")[0] == "4": - ue_modules_path /= "UE4Editor.modules" - elif ue_version.split(".")[0] == "5": - ue_modules_path /= "UnrealEditor.modules" - ue_modules = Path(ue_modules_path) - if platform.system().lower() == "linux": - ue_modules = Path(os.path.join(engine_path, "Engine", "Binaries", - "Linux", "UE4Editor.modules")) + # engine_path should be the location of UE_X.X folder - if platform.system().lower() == "darwin": - ue_modules = Path(os.path.join(engine_path, "Engine", "Binaries", - "Mac", "UE4Editor.modules")) + ue_editor_exe_path: Path = get_editor_exe_path(engine_path, ue_version) + cmdlet_project_path = get_path_to_cmdlet_project(ue_version) - if ue_modules.exists(): - print("--- Loading Engine ID from modules file ...") - with open(ue_modules, "r") as mp: - loaded_modules = json.load(mp) + project_file = pr_dir / f"{project_name}.uproject" - if loaded_modules.get("BuildId"): - ue_id = "{" + loaded_modules.get("BuildId") + "}" - - plugins_path = None - if os.path.isdir(env.get("OPENPYPE_UNREAL_PLUGIN", "")): - # copy plugin to correct path under project - plugins_path = pr_dir / "Plugins" - openpype_plugin_path = plugins_path / "OpenPype" - if not openpype_plugin_path.is_dir(): - openpype_plugin_path.mkdir(parents=True, exist_ok=True) - dir_util._path_created = {} - dir_util.copy_tree(os.environ.get("OPENPYPE_UNREAL_PLUGIN"), - openpype_plugin_path.as_posix()) - - if not (openpype_plugin_path / "Binaries").is_dir() \ - or not (openpype_plugin_path / "Intermediate").is_dir(): - dev_mode = True - - # data for project file - data = { - "FileVersion": 3, - "EngineAssociation": ue_id, - "Category": "", - "Description": "", - "Plugins": [ - {"Name": "PythonScriptPlugin", "Enabled": True}, - {"Name": "EditorScriptingUtilities", "Enabled": True}, - {"Name": "SequencerScripting", "Enabled": True}, - {"Name": "MovieRenderPipeline", "Enabled": True}, - {"Name": "OpenPype", "Enabled": True} - ] - } + print("--- Generating a new project ...") + commandlet_cmd = [f'{ue_editor_exe_path.as_posix()}', + f'{cmdlet_project_path.as_posix()}', + f'-run=OPGenerateProject', + f'{project_file.resolve().as_posix()}'] if dev_mode or preset["dev_mode"]: - # this will add the project module and necessary source file to - # make it a C++ project and to (hopefully) make Unreal Editor to - # compile all # sources at start + commandlet_cmd.append('-GenerateCode') - data["Modules"] = [{ - "Name": project_name, - "Type": "Runtime", - "LoadingPhase": "Default", - "AdditionalDependencies": ["Engine"], - }] + subprocess.run(commandlet_cmd) - # write project file - project_file = pr_dir / f"{project_name}.uproject" - with open(project_file, mode="w") as pf: - json.dump(data, pf, indent=4) + with open(project_file, mode="r+") as pf: + pf_json = json.load(pf) + pf_json["EngineAssociation"] = _get_build_id(engine_path, ue_version) + pf.seek(0) + json.dump(pf_json, pf, indent=4) + pf.truncate() + print(f'--- Engine ID has been writen into the project file') + + if dev_mode or preset["dev_mode"]: + u_build_tool = get_path_to_ubt(engine_path, ue_version) + + arch = "Win64" + if platform.system().lower() == "windows": + arch = "Win64" + elif platform.system().lower() == "linux": + arch = "Linux" + elif platform.system().lower() == "darwin": + # we need to test this out + arch = "Mac" + + command1 = [u_build_tool.as_posix(), "-projectfiles", + f"-project={project_file}", "-progress"] + + subprocess.run(command1) + + command2 = [u_build_tool.as_posix(), + f"-ModuleWithSuffix={project_name},3555", arch, + "Development", "-TargetType=Editor", + f'-Project={project_file}', + f'{project_file}', + "-IgnoreJunk"] + + subprocess.run(command2) # ensure we have PySide2 installed in engine python_path = None @@ -307,8 +292,121 @@ def create_unreal_project(project_name: str, subprocess.check_call( [python_path.as_posix(), "-m", "pip", "install", "pyside2"]) - if dev_mode or preset["dev_mode"]: - _prepare_cpp_project(project_file, engine_path, ue_version) + +def get_path_to_uat(engine_path: Path) -> Path: + if platform.system().lower() == "windows": + return engine_path / "Engine/Build/BatchFiles/RunUAT.bat" + + if platform.system().lower() == "linux" or platform.system().lower() == "darwin": + return engine_path / "Engine/Build/BatchFiles/RunUAT.sh" + + +def get_path_to_cmdlet_project(ue_version: str) -> Path: + commandlet_project_path: Path = Path(os.path.dirname(os.path.abspath(openpype.__file__))) + + # For now, only tested on Windows (For Linux and Mac it has to be implemented) + if ue_version.split(".")[0] == "4": + return commandlet_project_path / "hosts/unreal/integration/UE_4.7/CommandletProject/CommandletProject.uproject" + elif ue_version.split(".")[0] == "5": + return commandlet_project_path / "hosts/unreal/integration/UE_5.0/CommandletProject/CommandletProject.uproject" + + +def get_path_to_ubt(engine_path: Path, ue_version: str) -> Path: + u_build_tool_path = engine_path / "Engine/Binaries/DotNET" + + if ue_version.split(".")[0] == "4": + u_build_tool_path /= "UnrealBuildTool.exe" + elif ue_version.split(".")[0] == "5": + u_build_tool_path /= "UnrealBuildTool/UnrealBuildTool.exe" + + return Path(u_build_tool_path) + + +def _get_build_id(engine_path: Path, ue_version: str) -> str: + ue_modules = Path() + if platform.system().lower() == "windows": + ue_modules_path = engine_path / "Engine/Binaries/Win64" + if ue_version.split(".")[0] == "4": + ue_modules_path /= "UE4Editor.modules" + elif ue_version.split(".")[0] == "5": + ue_modules_path /= "UnrealEditor.modules" + ue_modules = Path(ue_modules_path) + + if platform.system().lower() == "linux": + ue_modules = Path(os.path.join(engine_path, "Engine", "Binaries", + "Linux", "UE4Editor.modules")) + + if platform.system().lower() == "darwin": + ue_modules = Path(os.path.join(engine_path, "Engine", "Binaries", + "Mac", "UE4Editor.modules")) + + if ue_modules.exists(): + print("--- Loading Engine ID from modules file ...") + with open(ue_modules, "r") as mp: + loaded_modules = json.load(mp) + + if loaded_modules.get("BuildId"): + return "{" + loaded_modules.get("BuildId") + "}" + + +def try_installing_plugin(engine_path: Path, + ue_version: str, + env: dict = None) -> None: + env = env or os.environ + + integration_plugin_path: Path = Path(env.get("OPENPYPE_UNREAL_PLUGIN", "")) + + if not os.path.isdir(integration_plugin_path): + raise RuntimeError("Path to the integration plugin is null!") + + # Create a path to the plugin in the engine + openpype_plugin_path: Path = engine_path / "Engine/Plugins/Marketplace/OpenPype" + + if not openpype_plugin_path.is_dir(): + print("--- OpenPype Plugin is not present. Creating a new plugin directory ...") + openpype_plugin_path.mkdir(parents=True, exist_ok=True) + + engine_plugin_config_path: Path = openpype_plugin_path / "Config" + engine_plugin_config_path.mkdir(exist_ok=True) + + dir_util._path_created = {} + + if not (openpype_plugin_path / "Binaries").is_dir() \ + or not (openpype_plugin_path / "Intermediate").is_dir(): + print("--- Binaries are not present. Building the plugin ...") + _build_and_move_integration_plugin(engine_path, openpype_plugin_path, env) + + +def _build_and_move_integration_plugin(engine_path: Path, + plugin_build_path: Path, + env: dict = None) -> None: + uat_path: Path = get_path_to_uat(engine_path) + + env = env or os.environ + integration_plugin_path: Path = Path(env.get("OPENPYPE_UNREAL_PLUGIN", "")) + + if uat_path.is_file(): + temp_dir: Path = integration_plugin_path.parent / "Temp" + temp_dir.mkdir(exist_ok=True) + uplugin_path: Path = integration_plugin_path / "OpenPype.uplugin" + + # in order to successfully build the plugin, It must be built outside the Engine directory and then moved + build_plugin_cmd: List[str] = [f'{uat_path.as_posix()}', + 'BuildPlugin', + f'-Plugin={uplugin_path.as_posix()}', + f'-Package={temp_dir.as_posix()}'] + subprocess.run(build_plugin_cmd) + + # Copy the contents of the 'Temp' dir into the 'OpenPype' directory in the engine + dir_util.copy_tree(temp_dir.as_posix(), plugin_build_path.as_posix()) + + # We need to also copy the config folder. The UAT doesn't include the Config folder in the build + plugin_install_config_path: Path = plugin_build_path / "Config" + integration_plugin_config_path = integration_plugin_path / "Config" + + dir_util.copy_tree(integration_plugin_config_path.as_posix(), plugin_install_config_path.as_posix()) + + dir_util.remove_tree(temp_dir.as_posix()) def _prepare_cpp_project(