From e026a27b9380467eed8ae2d2ecc082394f77cc2d Mon Sep 17 00:00:00 2001 From: Jakub Jezek Date: Mon, 12 Dec 2022 12:11:33 +0100 Subject: [PATCH 01/42] hiero: fixing thumbnail if multillayer exr --- openpype/hosts/hiero/plugins/publish/extract_thumbnail.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/openpype/hosts/hiero/plugins/publish/extract_thumbnail.py b/openpype/hosts/hiero/plugins/publish/extract_thumbnail.py index e64aa89b26..5ca79dc1dc 100644 --- a/openpype/hosts/hiero/plugins/publish/extract_thumbnail.py +++ b/openpype/hosts/hiero/plugins/publish/extract_thumbnail.py @@ -41,7 +41,7 @@ class ExtractThumnail(publish.Extractor): track_item_name, thumb_frame, ".png") thumb_path = os.path.join(staging_dir, thumb_file) - thumbnail = track_item.thumbnail(thumb_frame).save( + thumbnail = track_item.thumbnail(thumb_frame, "colour").save( thumb_path, format='png' ) From 9f61aa338536321b17730b175a8b603b0870a385 Mon Sep 17 00:00:00 2001 From: Joseff Date: Mon, 12 Dec 2022 14:27:26 +0100 Subject: [PATCH 02/42] Refactorization of folder coloring --- .../UE_4.7/Config/DefaultOpenPypeSettings.ini | 2 + .../UE_4.7/Source/OpenPype/OpenPype.Build.cs | 1 + .../Source/OpenPype/Private/OpenPype.cpp | 64 +++++++++++++++-- .../Source/OpenPype/Private/OpenPypeLib.cpp | 24 ++++--- .../Private/OpenPypePublishInstance.cpp | 51 +++++++++++++- .../OpenPype/Private/OpenPypeSettings.cpp | 21 ++++++ .../UE_4.7/Source/OpenPype/Public/OpenPype.h | 3 +- .../Source/OpenPype/Public/OpenPypeLib.h | 4 +- .../OpenPype/Public/OpenPypePublishInstance.h | 18 +++-- .../Source/OpenPype/Public/OpenPypeSettings.h | 32 +++++++++ .../UE_5.0/Config/DefaultOpenPypeSettings.ini | 2 + .../UE_5.0/Source/OpenPype/OpenPype.Build.cs | 1 + .../Source/OpenPype/Private/OpenPype.cpp | 69 +++++++++++++++++-- .../Source/OpenPype/Private/OpenPypeLib.cpp | 24 ++++--- .../Private/OpenPypePublishInstance.cpp | 69 ++++++++++++++++--- .../OpenPype/Private/OpenPypeSettings.cpp | 21 ++++++ .../UE_5.0/Source/OpenPype/Public/OpenPype.h | 2 + .../Source/OpenPype/Public/OpenPypeLib.h | 4 +- .../OpenPype/Public/OpenPypePublishInstance.h | 23 ++++--- .../Source/OpenPype/Public/OpenPypeSettings.h | 32 +++++++++ 20 files changed, 401 insertions(+), 66 deletions(-) create mode 100644 openpype/hosts/unreal/integration/UE_4.7/Config/DefaultOpenPypeSettings.ini create mode 100644 openpype/hosts/unreal/integration/UE_4.7/Source/OpenPype/Private/OpenPypeSettings.cpp create mode 100644 openpype/hosts/unreal/integration/UE_4.7/Source/OpenPype/Public/OpenPypeSettings.h create mode 100644 openpype/hosts/unreal/integration/UE_5.0/Config/DefaultOpenPypeSettings.ini create mode 100644 openpype/hosts/unreal/integration/UE_5.0/Source/OpenPype/Private/OpenPypeSettings.cpp create mode 100644 openpype/hosts/unreal/integration/UE_5.0/Source/OpenPype/Public/OpenPypeSettings.h diff --git a/openpype/hosts/unreal/integration/UE_4.7/Config/DefaultOpenPypeSettings.ini b/openpype/hosts/unreal/integration/UE_4.7/Config/DefaultOpenPypeSettings.ini new file mode 100644 index 0000000000..8a883cf1db --- /dev/null +++ b/openpype/hosts/unreal/integration/UE_4.7/Config/DefaultOpenPypeSettings.ini @@ -0,0 +1,2 @@ +[/Script/OpenPype.OpenPypeSettings] +FolderColor=(R=91,G=197,B=220,A=255) \ No newline at end of file diff --git a/openpype/hosts/unreal/integration/UE_4.7/Source/OpenPype/OpenPype.Build.cs b/openpype/hosts/unreal/integration/UE_4.7/Source/OpenPype/OpenPype.Build.cs index c30835b63d..46e5dcb2df 100644 --- a/openpype/hosts/unreal/integration/UE_4.7/Source/OpenPype/OpenPype.Build.cs +++ b/openpype/hosts/unreal/integration/UE_4.7/Source/OpenPype/OpenPype.Build.cs @@ -42,6 +42,7 @@ public class OpenPype : ModuleRules "Engine", "Slate", "SlateCore", + "AssetTools" // ... add private dependencies that you statically link with here ... } ); diff --git a/openpype/hosts/unreal/integration/UE_4.7/Source/OpenPype/Private/OpenPype.cpp b/openpype/hosts/unreal/integration/UE_4.7/Source/OpenPype/Private/OpenPype.cpp index 15c46b3862..d20abec9b1 100644 --- a/openpype/hosts/unreal/integration/UE_4.7/Source/OpenPype/Private/OpenPype.cpp +++ b/openpype/hosts/unreal/integration/UE_4.7/Source/OpenPype/Private/OpenPype.cpp @@ -1,6 +1,11 @@ #include "OpenPype.h" + +#include "ISettingsContainer.h" +#include "ISettingsModule.h" +#include "ISettingsSection.h" #include "LevelEditor.h" #include "OpenPypePythonBridge.h" +#include "OpenPypeSettings.h" #include "OpenPypeStyle.h" @@ -11,13 +16,12 @@ static const FName OpenPypeTabName("OpenPype"); // This function is triggered when the plugin is staring up void FOpenPypeModule::StartupModule() { - FOpenPypeStyle::Initialize(); FOpenPypeStyle::SetIcon("Logo", "openpype40"); // 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()); @@ -37,6 +41,7 @@ void FOpenPypeModule::StartupModule() LevelEditorModule.GetMenuExtensibilityManager()->AddExtender(MenuExtender); LevelEditorModule.GetToolBarExtensibilityManager()->AddExtender(ToolbarExtender); + RegisterSettings(); } void FOpenPypeModule::ShutdownModule() @@ -64,7 +69,6 @@ void FOpenPypeModule::AddMenuEntry(FMenuBuilder& MenuBuilder) FSlateIcon(FOpenPypeStyle::GetStyleSetName(), "OpenPype.Logo"), FUIAction(FExecuteAction::CreateRaw(this, &FOpenPypeModule::MenuDialog)) ); - } MenuBuilder.EndSection(); } @@ -89,13 +93,63 @@ void FOpenPypeModule::AddToobarEntry(FToolBarBuilder& ToolbarBuilder) ToolbarBuilder.EndSection(); } +void FOpenPypeModule::RegisterSettings() +{ + ISettingsModule& SettingsModule = FModuleManager::LoadModuleChecked("Settings"); -void FOpenPypeModule::MenuPopup() { + // Create the new category + // TODO: After the movement of the plugin from the game to editor, it might be necessary to move this! + ISettingsContainerPtr SettingsContainer = SettingsModule.GetContainer("Project"); + + SettingsContainer->DescribeCategory("OpenPypeSettings", + LOCTEXT("RuntimeWDCategoryName", "OpenPypeSettings"), + LOCTEXT("RuntimeWDCategoryDescription", + "Configuration for the Open pype module")); + + UOpenPypeSettings* Settings = GetMutableDefault(); + + // Register the settings + ISettingsSectionPtr SettingsSection = SettingsModule.RegisterSettings("Project", "OpenPype", "General", + LOCTEXT("RuntimeGeneralSettingsName", + "General"), + LOCTEXT("RuntimeGeneralSettingsDescription", + "Base configuration for Open Pype Module"), + Settings + ); + + // Register the save handler to your settings, you might want to use it to + // validate those or just act to settings changes. + if (SettingsSection.IsValid()) + { + SettingsSection->OnModified().BindRaw(this, &FOpenPypeModule::HandleSettingsSaved); + } +} + +bool FOpenPypeModule::HandleSettingsSaved() +{ + UOpenPypeSettings* Settings = GetMutableDefault(); + bool ResaveSettings = false; + + // You can put any validation code in here and resave the settings in case an invalid + // value has been entered + + if (ResaveSettings) + { + Settings->SaveConfig(); + } + + return true; +} + + +void FOpenPypeModule::MenuPopup() +{ UOpenPypePythonBridge* bridge = UOpenPypePythonBridge::Get(); bridge->RunInPython_Popup(); } -void FOpenPypeModule::MenuDialog() { +void FOpenPypeModule::MenuDialog() +{ UOpenPypePythonBridge* bridge = UOpenPypePythonBridge::Get(); bridge->RunInPython_Dialog(); } diff --git a/openpype/hosts/unreal/integration/UE_4.7/Source/OpenPype/Private/OpenPypeLib.cpp b/openpype/hosts/unreal/integration/UE_4.7/Source/OpenPype/Private/OpenPypeLib.cpp index 5facab7b8b..a58e921288 100644 --- a/openpype/hosts/unreal/integration/UE_4.7/Source/OpenPype/Private/OpenPypeLib.cpp +++ b/openpype/hosts/unreal/integration/UE_4.7/Source/OpenPype/Private/OpenPypeLib.cpp @@ -1,4 +1,6 @@ #include "OpenPypeLib.h" + +#include "AssetViewUtils.h" #include "Misc/Paths.h" #include "Misc/ConfigCacheIni.h" #include "UObject/UnrealType.h" @@ -10,21 +12,23 @@ * @warning This color will appear only after Editor restart. Is there a better way? */ -void UOpenPypeLib::CSetFolderColor(FString FolderPath, FLinearColor FolderColor, bool bForceAdd) +bool UOpenPypeLib::SetFolderColor(const FString& FolderPath, const FLinearColor& FolderColor, const bool& bForceAdd) { - auto SaveColorInternal = [](FString InPath, FLinearColor InFolderColor) + if (AssetViewUtils::DoesFolderExist(FolderPath)) { - // Saves the color of the folder to the config - if (FPaths::FileExists(GEditorPerProjectIni)) - { - GConfig->SetString(TEXT("PathColor"), *InPath, *InFolderColor.ToString(), GEditorPerProjectIni); - } + const TSharedPtr LinearColor = MakeShared(FolderColor); - }; - - SaveColorInternal(FolderPath, FolderColor); + AssetViewUtils::SaveColor(FolderPath, LinearColor, true); + UE_LOG(LogAssetData, Display, TEXT("A color {%s} has been set to folder \"%s\""), *LinearColor->ToString(), + *FolderPath) + return true; + } + UE_LOG(LogAssetData, Display, TEXT("Setting a color {%s} to folder \"%s\" has failed! Directory doesn't exist!"), + *FolderColor.ToString(), *FolderPath) + return false; } + /** * Returns all poperties on given object * @param cls - class diff --git a/openpype/hosts/unreal/integration/UE_4.7/Source/OpenPype/Private/OpenPypePublishInstance.cpp b/openpype/hosts/unreal/integration/UE_4.7/Source/OpenPype/Private/OpenPypePublishInstance.cpp index ed81104c05..38740f1cbd 100644 --- a/openpype/hosts/unreal/integration/UE_4.7/Source/OpenPype/Private/OpenPypePublishInstance.cpp +++ b/openpype/hosts/unreal/integration/UE_4.7/Source/OpenPype/Private/OpenPypePublishInstance.cpp @@ -3,6 +3,8 @@ #include "OpenPypePublishInstance.h" #include "AssetRegistryModule.h" #include "NotificationManager.h" +#include "OpenPypeLib.h" +#include "OpenPypeSettings.h" #include "SNotificationList.h" //Moves all the invalid pointers to the end to prepare them for the shrinking @@ -36,6 +38,11 @@ UOpenPypePublishInstance::UOpenPypePublishInstance(const FObjectInitializer& Obj AssetRegistryModule.Get().OnAssetAdded().AddUObject(this, &UOpenPypePublishInstance::OnAssetCreated); AssetRegistryModule.Get().OnAssetRemoved().AddUObject(this, &UOpenPypePublishInstance::OnAssetRemoved); AssetRegistryModule.Get().OnAssetUpdated().AddUObject(this, &UOpenPypePublishInstance::OnAssetUpdated); + +#ifdef WITH_EDITOR + ColorOpenPypeDirs(); +#endif + } void UOpenPypePublishInstance::OnAssetCreated(const FAssetData& InAssetData) @@ -58,7 +65,7 @@ void UOpenPypePublishInstance::OnAssetCreated(const FAssetData& InAssetData) if (AssetDataInternal.Emplace(Asset).IsValidId()) { UE_LOG(LogTemp, Log, TEXT("Added an Asset to PublishInstance - Publish Instance: %s, Asset %s"), - *this->GetName(), *Asset->GetName()); + *this->GetName(), *Asset->GetName()); } } } @@ -96,6 +103,48 @@ bool UOpenPypePublishInstance::IsUnderSameDir(const UObject* InAsset) const #ifdef WITH_EDITOR +void UOpenPypePublishInstance::ColorOpenPypeDirs() +{ + FString PathName = this->GetPathName(); + + //Check whether the path contains the defined OpenPype folder + if (!PathName.Contains(TEXT("OpenPype"))) return; + + //Get the base path for open pype + FString PathLeft, PathRight; + PathName.Split(FString("OpenPype"), &PathLeft, &PathRight); + + if (PathLeft.IsEmpty() || PathRight.IsEmpty()) + { + UE_LOG(LogAssetData, Error, TEXT("Failed to retrieve the base OpenPype directory!")) + return; + } + + PathName.RemoveFromEnd(PathRight, ESearchCase::CaseSensitive); + + //Get the current settings + const UOpenPypeSettings* Settings = GetMutableDefault(); + + //Color the base folder + UOpenPypeLib::SetFolderColor(PathName, Settings->GetFolderFColor(), false); + + //Get Sub paths, iterate through them and color them according to the folder color in UOpenPypeSettings + const FAssetRegistryModule& AssetRegistryModule = FModuleManager::LoadModuleChecked( + "AssetRegistry"); + + TArray PathList; + + AssetRegistryModule.Get().GetSubPaths(PathName, PathList, true); + + if (PathList.Num() > 0) + { + for (const FString& Path : PathList) + { + UOpenPypeLib::SetFolderColor(Path, Settings->GetFolderFColor(), false); + } + } +} + void UOpenPypePublishInstance::SendNotification(const FString& Text) const { FNotificationInfo Info{FText::FromString(Text)}; diff --git a/openpype/hosts/unreal/integration/UE_4.7/Source/OpenPype/Private/OpenPypeSettings.cpp b/openpype/hosts/unreal/integration/UE_4.7/Source/OpenPype/Private/OpenPypeSettings.cpp new file mode 100644 index 0000000000..7134614d22 --- /dev/null +++ b/openpype/hosts/unreal/integration/UE_4.7/Source/OpenPype/Private/OpenPypeSettings.cpp @@ -0,0 +1,21 @@ +// Fill out your copyright notice in the Description page of Project Settings. + +#include "OpenPypeSettings.h" + +#include "IPluginManager.h" +#include "UObjectGlobals.h" + +/** + * Mainly is used for initializing default values if the DefaultOpenPypeSettings.ini file does not exist in the saved config + */ +UOpenPypeSettings::UOpenPypeSettings(const FObjectInitializer& ObjectInitializer) +{ + + const FString ConfigFilePath = OPENPYPE_SETTINGS_FILEPATH; + + // This has to be probably in the future set using the UE Reflection system + FColor Color; + GConfig->GetColor(TEXT("/Script/OpenPype.OpenPypeSettings"), TEXT("FolderColor"), Color, ConfigFilePath); + + FolderColor = Color; +} \ No newline at end of file diff --git a/openpype/hosts/unreal/integration/UE_4.7/Source/OpenPype/Public/OpenPype.h b/openpype/hosts/unreal/integration/UE_4.7/Source/OpenPype/Public/OpenPype.h index db3f299354..9cfa60176c 100644 --- a/openpype/hosts/unreal/integration/UE_4.7/Source/OpenPype/Public/OpenPype.h +++ b/openpype/hosts/unreal/integration/UE_4.7/Source/OpenPype/Public/OpenPype.h @@ -12,10 +12,11 @@ public: virtual void ShutdownModule() override; private: + void RegisterSettings(); + bool HandleSettingsSaved(); void AddMenuEntry(FMenuBuilder& MenuBuilder); void AddToobarEntry(FToolBarBuilder& ToolbarBuilder); void MenuPopup(); void MenuDialog(); - }; diff --git a/openpype/hosts/unreal/integration/UE_4.7/Source/OpenPype/Public/OpenPypeLib.h b/openpype/hosts/unreal/integration/UE_4.7/Source/OpenPype/Public/OpenPypeLib.h index 59e9c8bd76..06425c7c7d 100644 --- a/openpype/hosts/unreal/integration/UE_4.7/Source/OpenPype/Public/OpenPypeLib.h +++ b/openpype/hosts/unreal/integration/UE_4.7/Source/OpenPype/Public/OpenPypeLib.h @@ -5,14 +5,14 @@ UCLASS(Blueprintable) -class OPENPYPE_API UOpenPypeLib : public UObject +class OPENPYPE_API UOpenPypeLib : public UBlueprintFunctionLibrary { GENERATED_BODY() public: UFUNCTION(BlueprintCallable, Category = Python) - static void CSetFolderColor(FString FolderPath, FLinearColor FolderColor, bool bForceAdd); + static bool SetFolderColor(const FString& FolderPath, const FLinearColor& FolderColor,const bool& bForceAdd); UFUNCTION(BlueprintCallable, Category = Python) static TArray GetAllProperties(UClass* cls); diff --git a/openpype/hosts/unreal/integration/UE_4.7/Source/OpenPype/Public/OpenPypePublishInstance.h b/openpype/hosts/unreal/integration/UE_4.7/Source/OpenPype/Public/OpenPypePublishInstance.h index 0e946fb039..cd414fe2cc 100644 --- a/openpype/hosts/unreal/integration/UE_4.7/Source/OpenPype/Public/OpenPypePublishInstance.h +++ b/openpype/hosts/unreal/integration/UE_4.7/Source/OpenPype/Public/OpenPypePublishInstance.h @@ -8,10 +8,8 @@ UCLASS(Blueprintable) class OPENPYPE_API UOpenPypePublishInstance : public UPrimaryDataAsset { GENERATED_UCLASS_BODY() - + public: - - /** /** * Retrieves all the assets which are monitored by the Publish Instance (Monitors assets in the directory which is * placed in) @@ -58,8 +56,10 @@ public: UFUNCTION(BlueprintCallable, BlueprintPure) TSet GetAllAssets() const { - const TSet>& IteratedSet = bAddExternalAssets ? AssetDataInternal.Union(AssetDataExternal) : AssetDataInternal; - + const TSet>& IteratedSet = bAddExternalAssets + ? AssetDataInternal.Union(AssetDataExternal) + : AssetDataInternal; + //Create a new TSet only with raw pointers. TSet ResultSet; @@ -69,12 +69,10 @@ public: return ResultSet; } - private: - UPROPERTY(VisibleAnywhere, Category="Assets") TSet> AssetDataInternal; - + /** * This property allows exposing the array to include other assets from any other directory than what it's currently * monitoring. NOTE: that these assets have to be added manually! They are not automatically registered or added! @@ -93,11 +91,11 @@ private: bool IsUnderSameDir(const UObject* InAsset) const; #ifdef WITH_EDITOR + + void ColorOpenPypeDirs(); void SendNotification(const FString& Text) const; virtual void PostEditChangeProperty(FPropertyChangedEvent& PropertyChangedEvent) override; #endif - }; - diff --git a/openpype/hosts/unreal/integration/UE_4.7/Source/OpenPype/Public/OpenPypeSettings.h b/openpype/hosts/unreal/integration/UE_4.7/Source/OpenPype/Public/OpenPypeSettings.h new file mode 100644 index 0000000000..2df6c887cf --- /dev/null +++ b/openpype/hosts/unreal/integration/UE_4.7/Source/OpenPype/Public/OpenPypeSettings.h @@ -0,0 +1,32 @@ +// Fill out your copyright notice in the Description page of Project Settings. + +#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") + +UCLASS(Config=OpenPypeSettings, DefaultConfig) +class OPENPYPE_API UOpenPypeSettings : public UObject +{ + GENERATED_UCLASS_BODY() + + UFUNCTION(BlueprintCallable, BlueprintPure, Category = Settings) + FColor GetFolderFColor() const + { + return FolderColor; + } + + UFUNCTION(BlueprintCallable, BlueprintPure, Category = Settings) + FLinearColor GetFolderFLinearColor() const + { + return FLinearColor(FolderColor); + } + +protected: + + UPROPERTY(config, EditAnywhere, Category = Folders) + FColor FolderColor = FColor(25,45,223); +}; \ No newline at end of file diff --git a/openpype/hosts/unreal/integration/UE_5.0/Config/DefaultOpenPypeSettings.ini b/openpype/hosts/unreal/integration/UE_5.0/Config/DefaultOpenPypeSettings.ini new file mode 100644 index 0000000000..8a883cf1db --- /dev/null +++ b/openpype/hosts/unreal/integration/UE_5.0/Config/DefaultOpenPypeSettings.ini @@ -0,0 +1,2 @@ +[/Script/OpenPype.OpenPypeSettings] +FolderColor=(R=91,G=197,B=220,A=255) \ No newline at end of file diff --git a/openpype/hosts/unreal/integration/UE_5.0/Source/OpenPype/OpenPype.Build.cs b/openpype/hosts/unreal/integration/UE_5.0/Source/OpenPype/OpenPype.Build.cs index fcfd268234..2ee5d9027c 100644 --- a/openpype/hosts/unreal/integration/UE_5.0/Source/OpenPype/OpenPype.Build.cs +++ b/openpype/hosts/unreal/integration/UE_5.0/Source/OpenPype/OpenPype.Build.cs @@ -44,6 +44,7 @@ public class OpenPype : ModuleRules "Engine", "Slate", "SlateCore", + "AssetTools" // ... add private dependencies that you statically link with here ... } ); diff --git a/openpype/hosts/unreal/integration/UE_5.0/Source/OpenPype/Private/OpenPype.cpp b/openpype/hosts/unreal/integration/UE_5.0/Source/OpenPype/Private/OpenPype.cpp index b3bd9a81b3..11aae0ffc2 100644 --- a/openpype/hosts/unreal/integration/UE_5.0/Source/OpenPype/Private/OpenPype.cpp +++ b/openpype/hosts/unreal/integration/UE_5.0/Source/OpenPype/Private/OpenPype.cpp @@ -1,8 +1,12 @@ #include "OpenPype.h" + +#include "ISettingsContainer.h" +#include "ISettingsModule.h" +#include "ISettingsSection.h" #include "OpenPypeStyle.h" #include "OpenPypeCommands.h" #include "OpenPypePythonBridge.h" -#include "LevelEditor.h" +#include "OpenPypeSettings.h" #include "Misc/MessageDialog.h" #include "ToolMenus.h" @@ -29,7 +33,10 @@ void FOpenPypeModule::StartupModule() FExecuteAction::CreateRaw(this, &FOpenPypeModule::MenuDialog), FCanExecuteAction()); - UToolMenus::RegisterStartupCallback(FSimpleMulticastDelegate::FDelegate::CreateRaw(this, &FOpenPypeModule::RegisterMenus)); + UToolMenus::RegisterStartupCallback( + FSimpleMulticastDelegate::FDelegate::CreateRaw(this, &FOpenPypeModule::RegisterMenus)); + + RegisterSettings(); } void FOpenPypeModule::ShutdownModule() @@ -43,6 +50,55 @@ void FOpenPypeModule::ShutdownModule() FOpenPypeCommands::Unregister(); } + +void FOpenPypeModule::RegisterSettings() +{ + ISettingsModule& SettingsModule = FModuleManager::LoadModuleChecked("Settings"); + + // Create the new category + // TODO: After the movement of the plugin from the game to editor, it might be necessary to move this! + ISettingsContainerPtr SettingsContainer = SettingsModule.GetContainer("Project"); + + SettingsContainer->DescribeCategory("OpenPypeSettings", + LOCTEXT("RuntimeWDCategoryName", "OpenPypeSettings"), + LOCTEXT("RuntimeWDCategoryDescription", + "Configuration for the Open pype module")); + + UOpenPypeSettings* Settings = GetMutableDefault(); + + // Register the settings + ISettingsSectionPtr SettingsSection = SettingsModule.RegisterSettings("Project", "OpenPype", "General", + LOCTEXT("RuntimeGeneralSettingsName", + "General"), + LOCTEXT("RuntimeGeneralSettingsDescription", + "Base configuration for Open Pype Module"), + Settings + ); + + // Register the save handler to your settings, you might want to use it to + // validate those or just act to settings changes. + if (SettingsSection.IsValid()) + { + SettingsSection->OnModified().BindRaw(this, &FOpenPypeModule::HandleSettingsSaved); + } +} + +bool FOpenPypeModule::HandleSettingsSaved() +{ + UOpenPypeSettings* Settings = GetMutableDefault(); + bool ResaveSettings = false; + + // You can put any validation code in here and resave the settings in case an invalid + // value has been entered + + if (ResaveSettings) + { + Settings->SaveConfig(); + } + + return true; +} + void FOpenPypeModule::RegisterMenus() { // Owner will be used for cleanup in call to UToolMenus::UnregisterOwner @@ -64,7 +120,8 @@ void FOpenPypeModule::RegisterMenus() { FToolMenuSection& Section = ToolbarMenu->FindOrAddSection("PluginTools"); { - FToolMenuEntry& Entry = Section.AddEntry(FToolMenuEntry::InitToolBarButton(FOpenPypeCommands::Get().OpenPypeTools)); + FToolMenuEntry& Entry = Section.AddEntry( + FToolMenuEntry::InitToolBarButton(FOpenPypeCommands::Get().OpenPypeTools)); Entry.SetCommandList(PluginCommands); } } @@ -72,12 +129,14 @@ void FOpenPypeModule::RegisterMenus() } -void FOpenPypeModule::MenuPopup() { +void FOpenPypeModule::MenuPopup() +{ UOpenPypePythonBridge* bridge = UOpenPypePythonBridge::Get(); bridge->RunInPython_Popup(); } -void FOpenPypeModule::MenuDialog() { +void FOpenPypeModule::MenuDialog() +{ UOpenPypePythonBridge* bridge = UOpenPypePythonBridge::Get(); bridge->RunInPython_Dialog(); } diff --git a/openpype/hosts/unreal/integration/UE_5.0/Source/OpenPype/Private/OpenPypeLib.cpp b/openpype/hosts/unreal/integration/UE_5.0/Source/OpenPype/Private/OpenPypeLib.cpp index 5facab7b8b..a58e921288 100644 --- a/openpype/hosts/unreal/integration/UE_5.0/Source/OpenPype/Private/OpenPypeLib.cpp +++ b/openpype/hosts/unreal/integration/UE_5.0/Source/OpenPype/Private/OpenPypeLib.cpp @@ -1,4 +1,6 @@ #include "OpenPypeLib.h" + +#include "AssetViewUtils.h" #include "Misc/Paths.h" #include "Misc/ConfigCacheIni.h" #include "UObject/UnrealType.h" @@ -10,21 +12,23 @@ * @warning This color will appear only after Editor restart. Is there a better way? */ -void UOpenPypeLib::CSetFolderColor(FString FolderPath, FLinearColor FolderColor, bool bForceAdd) +bool UOpenPypeLib::SetFolderColor(const FString& FolderPath, const FLinearColor& FolderColor, const bool& bForceAdd) { - auto SaveColorInternal = [](FString InPath, FLinearColor InFolderColor) + if (AssetViewUtils::DoesFolderExist(FolderPath)) { - // Saves the color of the folder to the config - if (FPaths::FileExists(GEditorPerProjectIni)) - { - GConfig->SetString(TEXT("PathColor"), *InPath, *InFolderColor.ToString(), GEditorPerProjectIni); - } + const TSharedPtr LinearColor = MakeShared(FolderColor); - }; - - SaveColorInternal(FolderPath, FolderColor); + AssetViewUtils::SaveColor(FolderPath, LinearColor, true); + UE_LOG(LogAssetData, Display, TEXT("A color {%s} has been set to folder \"%s\""), *LinearColor->ToString(), + *FolderPath) + return true; + } + UE_LOG(LogAssetData, Display, TEXT("Setting a color {%s} to folder \"%s\" has failed! Directory doesn't exist!"), + *FolderColor.ToString(), *FolderPath) + return false; } + /** * Returns all poperties on given object * @param cls - class diff --git a/openpype/hosts/unreal/integration/UE_5.0/Source/OpenPype/Private/OpenPypePublishInstance.cpp b/openpype/hosts/unreal/integration/UE_5.0/Source/OpenPype/Private/OpenPypePublishInstance.cpp index 322663eeec..6f41600bae 100644 --- a/openpype/hosts/unreal/integration/UE_5.0/Source/OpenPype/Private/OpenPypePublishInstance.cpp +++ b/openpype/hosts/unreal/integration/UE_5.0/Source/OpenPype/Private/OpenPypePublishInstance.cpp @@ -2,8 +2,9 @@ #include "OpenPypePublishInstance.h" #include "AssetRegistryModule.h" -#include "AssetToolsModule.h" -#include "Framework/Notifications/NotificationManager.h" +#include "NotificationManager.h" +#include "OpenPypeLib.h" +#include "OpenPypeSettings.h" #include "SNotificationList.h" //Moves all the invalid pointers to the end to prepare them for the shrinking @@ -16,8 +17,11 @@ UOpenPypePublishInstance::UOpenPypePublishInstance(const FObjectInitializer& Obj const FAssetRegistryModule& AssetRegistryModule = FModuleManager::LoadModuleChecked< FAssetRegistryModule>("AssetRegistry"); + const FPropertyEditorModule& PropertyEditorModule = FModuleManager::LoadModuleChecked( + "PropertyEditor"); + FString Left, Right; - GetPathName().Split(GetName(), &Left, &Right); + GetPathName().Split("/" + GetName(), &Left, &Right); FARFilter Filter; Filter.PackagePaths.Emplace(FName(Left)); @@ -34,15 +38,17 @@ UOpenPypePublishInstance::UOpenPypePublishInstance(const FObjectInitializer& Obj AssetRegistryModule.Get().OnAssetAdded().AddUObject(this, &UOpenPypePublishInstance::OnAssetCreated); AssetRegistryModule.Get().OnAssetRemoved().AddUObject(this, &UOpenPypePublishInstance::OnAssetRemoved); AssetRegistryModule.Get().OnAssetUpdated().AddUObject(this, &UOpenPypePublishInstance::OnAssetUpdated); - - + +#ifdef WITH_EDITOR + ColorOpenPypeDirs(); +#endif } void UOpenPypePublishInstance::OnAssetCreated(const FAssetData& InAssetData) { TArray split; - const TObjectPtr Asset = InAssetData.GetAsset(); + UObject* Asset = InAssetData.GetAsset(); if (!IsValid(Asset)) { @@ -58,7 +64,7 @@ void UOpenPypePublishInstance::OnAssetCreated(const FAssetData& InAssetData) if (AssetDataInternal.Emplace(Asset).IsValidId()) { UE_LOG(LogTemp, Log, TEXT("Added an Asset to PublishInstance - Publish Instance: %s, Asset %s"), - *this->GetName(), *Asset->GetName()); + *this->GetName(), *Asset->GetName()); } } } @@ -86,7 +92,7 @@ void UOpenPypePublishInstance::OnAssetUpdated(const FAssetData& InAssetData) REMOVE_INVALID_ENTRIES(AssetDataExternal); } -bool UOpenPypePublishInstance::IsUnderSameDir(const TObjectPtr& InAsset) const +bool UOpenPypePublishInstance::IsUnderSameDir(const UObject* InAsset) const { FString ThisLeft, ThisRight; this->GetPathName().Split(this->GetName(), &ThisLeft, &ThisRight); @@ -96,6 +102,48 @@ bool UOpenPypePublishInstance::IsUnderSameDir(const TObjectPtr& InAsset #ifdef WITH_EDITOR +void UOpenPypePublishInstance::ColorOpenPypeDirs() +{ + FString PathName = this->GetPathName(); + + //Check whether the path contains the defined OpenPype folder + if (!PathName.Contains(TEXT("OpenPype"))) return; + + //Get the base path for open pype + FString PathLeft, PathRight; + PathName.Split(FString("OpenPype"), &PathLeft, &PathRight); + + if (PathLeft.IsEmpty() || PathRight.IsEmpty()) + { + UE_LOG(LogAssetData, Error, TEXT("Failed to retrieve the base OpenPype directory!")) + return; + } + + PathName.RemoveFromEnd(PathRight, ESearchCase::CaseSensitive); + + //Get the current settings + const UOpenPypeSettings* Settings = GetMutableDefault(); + + //Color the base folder + UOpenPypeLib::SetFolderColor(PathName, Settings->GetFolderFColor(), false); + + //Get Sub paths, iterate through them and color them according to the folder color in UOpenPypeSettings + const FAssetRegistryModule& AssetRegistryModule = FModuleManager::LoadModuleChecked( + "AssetRegistry"); + + TArray PathList; + + AssetRegistryModule.Get().GetSubPaths(PathName, PathList, true); + + if (PathList.Num() > 0) + { + for (const FString& Path : PathList) + { + UOpenPypeLib::SetFolderColor(Path, Settings->GetFolderFColor(), false); + } + } +} + void UOpenPypePublishInstance::SendNotification(const FString& Text) const { FNotificationInfo Info{FText::FromString(Text)}; @@ -125,16 +173,15 @@ void UOpenPypePublishInstance::PostEditChangeProperty(FPropertyChangedEvent& Pro PropertyChangedEvent.Property->GetFName() == GET_MEMBER_NAME_CHECKED( UOpenPypePublishInstance, AssetDataExternal)) { - // Check for duplicated assets for (const auto& Asset : AssetDataInternal) { if (AssetDataExternal.Contains(Asset)) { AssetDataExternal.Remove(Asset); - return SendNotification("You are not allowed to add assets into AssetDataExternal which are already included in AssetDataInternal!"); + return SendNotification( + "You are not allowed to add assets into AssetDataExternal which are already included in AssetDataInternal!"); } - } // Check if no UOpenPypePublishInstance type assets are included diff --git a/openpype/hosts/unreal/integration/UE_5.0/Source/OpenPype/Private/OpenPypeSettings.cpp b/openpype/hosts/unreal/integration/UE_5.0/Source/OpenPype/Private/OpenPypeSettings.cpp new file mode 100644 index 0000000000..7134614d22 --- /dev/null +++ b/openpype/hosts/unreal/integration/UE_5.0/Source/OpenPype/Private/OpenPypeSettings.cpp @@ -0,0 +1,21 @@ +// Fill out your copyright notice in the Description page of Project Settings. + +#include "OpenPypeSettings.h" + +#include "IPluginManager.h" +#include "UObjectGlobals.h" + +/** + * Mainly is used for initializing default values if the DefaultOpenPypeSettings.ini file does not exist in the saved config + */ +UOpenPypeSettings::UOpenPypeSettings(const FObjectInitializer& ObjectInitializer) +{ + + const FString ConfigFilePath = OPENPYPE_SETTINGS_FILEPATH; + + // This has to be probably in the future set using the UE Reflection system + FColor Color; + GConfig->GetColor(TEXT("/Script/OpenPype.OpenPypeSettings"), TEXT("FolderColor"), Color, ConfigFilePath); + + FolderColor = Color; +} \ No newline at end of file diff --git a/openpype/hosts/unreal/integration/UE_5.0/Source/OpenPype/Public/OpenPype.h b/openpype/hosts/unreal/integration/UE_5.0/Source/OpenPype/Public/OpenPype.h index 3ee5eaa65f..4261476da8 100644 --- a/openpype/hosts/unreal/integration/UE_5.0/Source/OpenPype/Public/OpenPype.h +++ b/openpype/hosts/unreal/integration/UE_5.0/Source/OpenPype/Public/OpenPype.h @@ -14,6 +14,8 @@ public: private: void RegisterMenus(); + void RegisterSettings(); + bool HandleSettingsSaved(); void MenuPopup(); void MenuDialog(); diff --git a/openpype/hosts/unreal/integration/UE_5.0/Source/OpenPype/Public/OpenPypeLib.h b/openpype/hosts/unreal/integration/UE_5.0/Source/OpenPype/Public/OpenPypeLib.h index 59e9c8bd76..06425c7c7d 100644 --- a/openpype/hosts/unreal/integration/UE_5.0/Source/OpenPype/Public/OpenPypeLib.h +++ b/openpype/hosts/unreal/integration/UE_5.0/Source/OpenPype/Public/OpenPypeLib.h @@ -5,14 +5,14 @@ UCLASS(Blueprintable) -class OPENPYPE_API UOpenPypeLib : public UObject +class OPENPYPE_API UOpenPypeLib : public UBlueprintFunctionLibrary { GENERATED_BODY() public: UFUNCTION(BlueprintCallable, Category = Python) - static void CSetFolderColor(FString FolderPath, FLinearColor FolderColor, bool bForceAdd); + static bool SetFolderColor(const FString& FolderPath, const FLinearColor& FolderColor,const bool& bForceAdd); UFUNCTION(BlueprintCallable, Category = Python) static TArray GetAllProperties(UClass* cls); diff --git a/openpype/hosts/unreal/integration/UE_5.0/Source/OpenPype/Public/OpenPypePublishInstance.h b/openpype/hosts/unreal/integration/UE_5.0/Source/OpenPype/Public/OpenPypePublishInstance.h index 2f066bd94b..146025bd6d 100644 --- a/openpype/hosts/unreal/integration/UE_5.0/Source/OpenPype/Public/OpenPypePublishInstance.h +++ b/openpype/hosts/unreal/integration/UE_5.0/Source/OpenPype/Public/OpenPypePublishInstance.h @@ -1,6 +1,5 @@ #pragma once -#include "EditorTutorial.h" #include "Engine.h" #include "OpenPypePublishInstance.generated.h" @@ -9,7 +8,9 @@ UCLASS(Blueprintable) class OPENPYPE_API UOpenPypePublishInstance : public UPrimaryDataAsset { GENERATED_UCLASS_BODY() + public: + /** /** * Retrieves all the assets which are monitored by the Publish Instance (Monitors assets in the directory which is * placed in) @@ -56,8 +57,10 @@ public: UFUNCTION(BlueprintCallable, BlueprintPure) TSet GetAllAssets() const { - const TSet>& IteratedSet = bAddExternalAssets ? AssetDataInternal.Union(AssetDataExternal) : AssetDataInternal; - + const TSet>& IteratedSet = bAddExternalAssets + ? AssetDataInternal.Union(AssetDataExternal) + : AssetDataInternal; + //Create a new TSet only with raw pointers. TSet ResultSet; @@ -72,24 +75,26 @@ private: TSet> AssetDataInternal; /** - * This property allows the instance to include other assets from any other directory than what it's currently - * monitoring. - * @attention assets have to be added manually! They are not automatically registered or added! + * This property allows exposing the array to include other assets from any other directory than what it's currently + * monitoring. NOTE: that these assets have to be added manually! They are not automatically registered or added! */ - UPROPERTY(EditAnywhere, Category="Assets") + UPROPERTY(EditAnywhere, Category = "Assets") bool bAddExternalAssets = false; - UPROPERTY(EditAnywhere, Category="Assets", meta=(EditCondition="bAddExternalAssets")) + UPROPERTY(EditAnywhere, meta=(EditCondition="bAddExternalAssets"), Category="Assets") TSet> AssetDataExternal; + void OnAssetCreated(const FAssetData& InAssetData); void OnAssetRemoved(const FAssetData& InAssetData); void OnAssetUpdated(const FAssetData& InAssetData); - bool IsUnderSameDir(const TObjectPtr& InAsset) const; + bool IsUnderSameDir(const UObject* InAsset) const; #ifdef WITH_EDITOR + void ColorOpenPypeDirs(); + void SendNotification(const FString& Text) const; virtual void PostEditChangeProperty(FPropertyChangedEvent& PropertyChangedEvent) override; diff --git a/openpype/hosts/unreal/integration/UE_5.0/Source/OpenPype/Public/OpenPypeSettings.h b/openpype/hosts/unreal/integration/UE_5.0/Source/OpenPype/Public/OpenPypeSettings.h new file mode 100644 index 0000000000..2df6c887cf --- /dev/null +++ b/openpype/hosts/unreal/integration/UE_5.0/Source/OpenPype/Public/OpenPypeSettings.h @@ -0,0 +1,32 @@ +// Fill out your copyright notice in the Description page of Project Settings. + +#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") + +UCLASS(Config=OpenPypeSettings, DefaultConfig) +class OPENPYPE_API UOpenPypeSettings : public UObject +{ + GENERATED_UCLASS_BODY() + + UFUNCTION(BlueprintCallable, BlueprintPure, Category = Settings) + FColor GetFolderFColor() const + { + return FolderColor; + } + + UFUNCTION(BlueprintCallable, BlueprintPure, Category = Settings) + FLinearColor GetFolderFLinearColor() const + { + return FLinearColor(FolderColor); + } + +protected: + + UPROPERTY(config, EditAnywhere, Category = Folders) + FColor FolderColor = FColor(25,45,223); +}; \ No newline at end of file From fefb64ed4268db7ef278fb8ad61baf8b544a31d4 Mon Sep 17 00:00:00 2001 From: Joseff Date: Mon, 12 Dec 2022 16:47:12 +0100 Subject: [PATCH 03/42] Removed the unnecessary DescribeCategory() --- .../integration/UE_4.7/Source/OpenPype/Private/OpenPype.cpp | 5 ----- .../integration/UE_5.0/Source/OpenPype/Private/OpenPype.cpp | 5 ----- 2 files changed, 10 deletions(-) diff --git a/openpype/hosts/unreal/integration/UE_4.7/Source/OpenPype/Private/OpenPype.cpp b/openpype/hosts/unreal/integration/UE_4.7/Source/OpenPype/Private/OpenPype.cpp index d20abec9b1..d06a08eb43 100644 --- a/openpype/hosts/unreal/integration/UE_4.7/Source/OpenPype/Private/OpenPype.cpp +++ b/openpype/hosts/unreal/integration/UE_4.7/Source/OpenPype/Private/OpenPype.cpp @@ -101,11 +101,6 @@ void FOpenPypeModule::RegisterSettings() // TODO: After the movement of the plugin from the game to editor, it might be necessary to move this! ISettingsContainerPtr SettingsContainer = SettingsModule.GetContainer("Project"); - SettingsContainer->DescribeCategory("OpenPypeSettings", - LOCTEXT("RuntimeWDCategoryName", "OpenPypeSettings"), - LOCTEXT("RuntimeWDCategoryDescription", - "Configuration for the Open pype module")); - UOpenPypeSettings* Settings = GetMutableDefault(); // Register the settings diff --git a/openpype/hosts/unreal/integration/UE_5.0/Source/OpenPype/Private/OpenPype.cpp b/openpype/hosts/unreal/integration/UE_5.0/Source/OpenPype/Private/OpenPype.cpp index 11aae0ffc2..d23de61102 100644 --- a/openpype/hosts/unreal/integration/UE_5.0/Source/OpenPype/Private/OpenPype.cpp +++ b/openpype/hosts/unreal/integration/UE_5.0/Source/OpenPype/Private/OpenPype.cpp @@ -59,11 +59,6 @@ void FOpenPypeModule::RegisterSettings() // TODO: After the movement of the plugin from the game to editor, it might be necessary to move this! ISettingsContainerPtr SettingsContainer = SettingsModule.GetContainer("Project"); - SettingsContainer->DescribeCategory("OpenPypeSettings", - LOCTEXT("RuntimeWDCategoryName", "OpenPypeSettings"), - LOCTEXT("RuntimeWDCategoryDescription", - "Configuration for the Open pype module")); - UOpenPypeSettings* Settings = GetMutableDefault(); // Register the settings From c85594c324e83bf1a8a95ee11f1caaed7c82f1d3 Mon Sep 17 00:00:00 2001 From: Petr Kalis Date: Tue, 13 Dec 2022 15:06:40 +0100 Subject: [PATCH 04/42] OP-4512 - fix normalize local name 'local' should be returned for local site only --- openpype/modules/sync_server/providers/local_drive.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/openpype/modules/sync_server/providers/local_drive.py b/openpype/modules/sync_server/providers/local_drive.py index 8f55dc529b..98bdb487da 100644 --- a/openpype/modules/sync_server/providers/local_drive.py +++ b/openpype/modules/sync_server/providers/local_drive.py @@ -5,6 +5,7 @@ import threading import time from openpype.lib import Logger +from openpype.lib.local_settings import get_local_site_id from openpype.pipeline import Anatomy from .abstract_provider import AbstractProvider @@ -220,6 +221,6 @@ class LocalDriveHandler(AbstractProvider): def _normalize_site_name(self, site_name): """Transform user id to 'local' for Local settings""" - if site_name != 'studio': + if site_name == get_local_site_id(): return 'local' return site_name From d931198797a02d908803f92f53b6d1632e153b68 Mon Sep 17 00:00:00 2001 From: Kayla Man Date: Tue, 13 Dec 2022 23:28:15 +0800 Subject: [PATCH 05/42] bug fix image plane load error --- .../maya/plugins/load/load_image_plane.py | 59 +++++++++++-------- 1 file changed, 34 insertions(+), 25 deletions(-) diff --git a/openpype/hosts/maya/plugins/load/load_image_plane.py b/openpype/hosts/maya/plugins/load/load_image_plane.py index b267921bdc..82c2676982 100644 --- a/openpype/hosts/maya/plugins/load/load_image_plane.py +++ b/openpype/hosts/maya/plugins/load/load_image_plane.py @@ -23,8 +23,8 @@ class CameraWindow(QtWidgets.QDialog): self.setWindowFlags(self.windowFlags() | QtCore.Qt.FramelessWindowHint) self.camera = None - self.static_image_plane = False - self.show_in_all_views = False + # self.static_image_plane = False + # self.show_in_all_views = False self.widgets = { "label": QtWidgets.QLabel("Select camera for image plane."), @@ -45,8 +45,8 @@ class CameraWindow(QtWidgets.QDialog): for camera in cameras: self.widgets["list"].addItem(camera) - self.widgets["staticImagePlane"].setText("Make Image Plane Static") - self.widgets["showInAllViews"].setText("Show Image Plane in All Views") + # self.widgets["staticImagePlane"].setText("Make Image Plane Static") + # self.widgets["showInAllViews"].setText("Show Image Plane in All Views") # Build buttons. layout = QtWidgets.QHBoxLayout(self.widgets["buttons"]) @@ -57,13 +57,13 @@ class CameraWindow(QtWidgets.QDialog): layout = QtWidgets.QVBoxLayout(self) layout.addWidget(self.widgets["label"]) layout.addWidget(self.widgets["list"]) - layout.addWidget(self.widgets["staticImagePlane"]) - layout.addWidget(self.widgets["showInAllViews"]) + # layout.addWidget(self.widgets["staticImagePlane"]) + # layout.addWidget(self.widgets["showInAllViews"]) layout.addWidget(self.widgets["buttons"]) layout.addWidget(self.widgets["warning"]) self.widgets["okButton"].pressed.connect(self.on_ok_pressed) - self.widgets["cancelButton"].pressed.connect(self.on_cancel_pressed) + self.widgets["cancelButton"].clicked.connect(self.on_cancel_pressed) self.widgets["list"].itemPressed.connect(self.on_list_itemPressed) def on_list_itemPressed(self, item): @@ -73,8 +73,8 @@ class CameraWindow(QtWidgets.QDialog): if self.camera is None: self.widgets["warning"].setVisible(True) return - self.show_in_all_views = self.widgets["showInAllViews"].isChecked() - self.static_image_plane = self.widgets["staticImagePlane"].isChecked() + # self.show_in_all_views = self.widgets["showInAllViews"].isChecked() + # self.static_image_plane = self.widgets["staticImagePlane"].isChecked() self.close() @@ -106,12 +106,12 @@ class ImagePlaneLoader(load.LoaderPlugin): # Get camera from user selection. camera = None - is_static_image_plane = None - is_in_all_views = None + # is_static_image_plane = None + # is_in_all_views = None if data: camera = pm.PyNode(data.get("camera")) - is_static_image_plane = data.get("static_image_plane") - is_in_all_views = data.get("in_all_views") + # is_static_image_plane = data.get("static_image_plane") + # is_in_all_views = data.get("in_all_views") if not camera: cameras = pm.ls(type="camera") @@ -121,8 +121,8 @@ class ImagePlaneLoader(load.LoaderPlugin): window.exec_() camera = camera_names[window.camera] - is_static_image_plane = window.static_image_plane - is_in_all_views = window.show_in_all_views + # is_static_image_plane = window.static_image_plane + # is_in_all_views = window.show_in_all_views if camera == "create_camera": camera = pm.createNode("camera") @@ -139,18 +139,20 @@ class ImagePlaneLoader(load.LoaderPlugin): # Create image plane image_plane_transform, image_plane_shape = pm.imagePlane( fileName=context["representation"]["data"]["path"], - camera=camera, showInAllViews=is_in_all_views - ) + camera=camera) image_plane_shape.depth.set(image_plane_depth) - if is_static_image_plane: - image_plane_shape.detach() - image_plane_transform.setRotation(camera.getRotation()) + # if is_static_image_plane: + # image_plane_shape.detach() + # image_plane_transform.setRotation(camera.getRotation()) start_frame = pm.playbackOptions(q=True, min=True) end_frame = pm.playbackOptions(q=True, max=True) - image_plane_shape.frameOffset.set(1 - start_frame) + if int(start_frame) > 0: + image_plane_shape.frameOffset.set(int(start_frame)- 1) + else: + image_plane_shape.frameOffset.set(int(start_frame)) image_plane_shape.frameIn.set(start_frame) image_plane_shape.frameOut.set(end_frame) image_plane_shape.frameCache.set(end_frame) @@ -180,9 +182,13 @@ class ImagePlaneLoader(load.LoaderPlugin): QtWidgets.QMessageBox.Cancel ) if reply == QtWidgets.QMessageBox.Ok: - pm.delete( - image_plane_shape.listConnections(type="expression")[0] - ) + expressions = image_plane_shape.frameExtension.inputs(type="expression") + if expressions: + pm.delete(expressions) + + if not image_plane_shape.frameExtension.isFreeToChange(): + raise RuntimeError("Can't set frame extension for {}".format(image_plane_shape)) + image_plane_shape.frameExtension.set(start_frame) new_nodes.extend( @@ -233,7 +239,10 @@ class ImagePlaneLoader(load.LoaderPlugin): ) start_frame = asset["data"]["frameStart"] end_frame = asset["data"]["frameEnd"] - image_plane_shape.frameOffset.set(1 - start_frame) + if int(start_frame) > 0: + image_plane_shape.frameOffset.set(int(start_frame)- 1) + else: + image_plane_shape.frameOffset.set(int(start_frame)) image_plane_shape.frameIn.set(start_frame) image_plane_shape.frameOut.set(end_frame) image_plane_shape.frameCache.set(end_frame) From f09ca54d962e34735b000595889c5d54c88e2fc0 Mon Sep 17 00:00:00 2001 From: Kayla Man Date: Wed, 14 Dec 2022 15:04:34 +0800 Subject: [PATCH 06/42] bug fix image plane load error --- openpype/hosts/maya/plugins/load/load_image_plane.py | 8 -------- 1 file changed, 8 deletions(-) diff --git a/openpype/hosts/maya/plugins/load/load_image_plane.py b/openpype/hosts/maya/plugins/load/load_image_plane.py index 82c2676982..33ae61ec0d 100644 --- a/openpype/hosts/maya/plugins/load/load_image_plane.py +++ b/openpype/hosts/maya/plugins/load/load_image_plane.py @@ -23,8 +23,6 @@ class CameraWindow(QtWidgets.QDialog): self.setWindowFlags(self.windowFlags() | QtCore.Qt.FramelessWindowHint) self.camera = None - # self.static_image_plane = False - # self.show_in_all_views = False self.widgets = { "label": QtWidgets.QLabel("Select camera for image plane."), @@ -45,8 +43,6 @@ class CameraWindow(QtWidgets.QDialog): for camera in cameras: self.widgets["list"].addItem(camera) - # self.widgets["staticImagePlane"].setText("Make Image Plane Static") - # self.widgets["showInAllViews"].setText("Show Image Plane in All Views") # Build buttons. layout = QtWidgets.QHBoxLayout(self.widgets["buttons"]) @@ -57,8 +53,6 @@ class CameraWindow(QtWidgets.QDialog): layout = QtWidgets.QVBoxLayout(self) layout.addWidget(self.widgets["label"]) layout.addWidget(self.widgets["list"]) - # layout.addWidget(self.widgets["staticImagePlane"]) - # layout.addWidget(self.widgets["showInAllViews"]) layout.addWidget(self.widgets["buttons"]) layout.addWidget(self.widgets["warning"]) @@ -73,8 +67,6 @@ class CameraWindow(QtWidgets.QDialog): if self.camera is None: self.widgets["warning"].setVisible(True) return - # self.show_in_all_views = self.widgets["showInAllViews"].isChecked() - # self.static_image_plane = self.widgets["staticImagePlane"].isChecked() self.close() From 29ee8e5edb46dc58b70dfa8b78eba3a1e5c07b68 Mon Sep 17 00:00:00 2001 From: Kayla Man Date: Wed, 14 Dec 2022 15:05:42 +0800 Subject: [PATCH 07/42] bug fix image plane load error --- openpype/hosts/maya/plugins/load/load_image_plane.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/openpype/hosts/maya/plugins/load/load_image_plane.py b/openpype/hosts/maya/plugins/load/load_image_plane.py index 33ae61ec0d..cc03787a6b 100644 --- a/openpype/hosts/maya/plugins/load/load_image_plane.py +++ b/openpype/hosts/maya/plugins/load/load_image_plane.py @@ -179,7 +179,7 @@ class ImagePlaneLoader(load.LoaderPlugin): pm.delete(expressions) if not image_plane_shape.frameExtension.isFreeToChange(): - raise RuntimeError("Can't set frame extension for {}".format(image_plane_shape)) + raise RuntimeError("Can't set frame extension for {}".format(image_plane_shape)) # noqa image_plane_shape.frameExtension.set(start_frame) From 1522d78873eb5c0ce34970b0eb4c48a74d8f594b Mon Sep 17 00:00:00 2001 From: Kayla Man Date: Wed, 14 Dec 2022 15:07:47 +0800 Subject: [PATCH 08/42] bug fix image plane load error --- openpype/hosts/maya/plugins/load/load_image_plane.py | 12 ++---------- 1 file changed, 2 insertions(+), 10 deletions(-) diff --git a/openpype/hosts/maya/plugins/load/load_image_plane.py b/openpype/hosts/maya/plugins/load/load_image_plane.py index cc03787a6b..4055dc50b0 100644 --- a/openpype/hosts/maya/plugins/load/load_image_plane.py +++ b/openpype/hosts/maya/plugins/load/load_image_plane.py @@ -102,8 +102,6 @@ class ImagePlaneLoader(load.LoaderPlugin): # is_in_all_views = None if data: camera = pm.PyNode(data.get("camera")) - # is_static_image_plane = data.get("static_image_plane") - # is_in_all_views = data.get("in_all_views") if not camera: cameras = pm.ls(type="camera") @@ -113,9 +111,6 @@ class ImagePlaneLoader(load.LoaderPlugin): window.exec_() camera = camera_names[window.camera] - # is_static_image_plane = window.static_image_plane - # is_in_all_views = window.show_in_all_views - if camera == "create_camera": camera = pm.createNode("camera") @@ -134,15 +129,12 @@ class ImagePlaneLoader(load.LoaderPlugin): camera=camera) image_plane_shape.depth.set(image_plane_depth) - # if is_static_image_plane: - # image_plane_shape.detach() - # image_plane_transform.setRotation(camera.getRotation()) start_frame = pm.playbackOptions(q=True, min=True) end_frame = pm.playbackOptions(q=True, max=True) if int(start_frame) > 0: - image_plane_shape.frameOffset.set(int(start_frame)- 1) + image_plane_shape.frameOffset.set(int(start_frame)-1) else: image_plane_shape.frameOffset.set(int(start_frame)) image_plane_shape.frameIn.set(start_frame) @@ -232,7 +224,7 @@ class ImagePlaneLoader(load.LoaderPlugin): start_frame = asset["data"]["frameStart"] end_frame = asset["data"]["frameEnd"] if int(start_frame) > 0: - image_plane_shape.frameOffset.set(int(start_frame)- 1) + image_plane_shape.frameOffset.set(int(start_frame)-1) else: image_plane_shape.frameOffset.set(int(start_frame)) image_plane_shape.frameIn.set(start_frame) From 916b5b82afd4779c3e1c099aee3fae300e8e55cb Mon Sep 17 00:00:00 2001 From: Kayla Man Date: Wed, 14 Dec 2022 15:10:08 +0800 Subject: [PATCH 09/42] bug fix image plane load error --- openpype/hosts/maya/plugins/load/load_image_plane.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/openpype/hosts/maya/plugins/load/load_image_plane.py b/openpype/hosts/maya/plugins/load/load_image_plane.py index 4055dc50b0..5f1c582203 100644 --- a/openpype/hosts/maya/plugins/load/load_image_plane.py +++ b/openpype/hosts/maya/plugins/load/load_image_plane.py @@ -134,7 +134,7 @@ class ImagePlaneLoader(load.LoaderPlugin): end_frame = pm.playbackOptions(q=True, max=True) if int(start_frame) > 0: - image_plane_shape.frameOffset.set(int(start_frame)-1) + image_plane_shape.frameOffset.set(int(start_frame) - 1) else: image_plane_shape.frameOffset.set(int(start_frame)) image_plane_shape.frameIn.set(start_frame) @@ -166,7 +166,7 @@ class ImagePlaneLoader(load.LoaderPlugin): QtWidgets.QMessageBox.Cancel ) if reply == QtWidgets.QMessageBox.Ok: - expressions = image_plane_shape.frameExtension.inputs(type="expression") + expressions = image_plane_shape.frameExtension.inputs(type="expression") # noqa if expressions: pm.delete(expressions) @@ -224,7 +224,7 @@ class ImagePlaneLoader(load.LoaderPlugin): start_frame = asset["data"]["frameStart"] end_frame = asset["data"]["frameEnd"] if int(start_frame) > 0: - image_plane_shape.frameOffset.set(int(start_frame)-1) + image_plane_shape.frameOffset.set(int(start_frame) - 1) else: image_plane_shape.frameOffset.set(int(start_frame)) image_plane_shape.frameIn.set(start_frame) From 0c481f83510438c5fb6243baa3f5c83adba6dbf6 Mon Sep 17 00:00:00 2001 From: Petr Kalis Date: Thu, 15 Dec 2022 11:55:14 +0100 Subject: [PATCH 10/42] OP-4512 - safer resolution of enabled If new site is added in System setting, but project settings are not saved, 'enabled' key is missing. This should be safer in this cases. --- openpype/modules/sync_server/providers/dropbox.py | 2 +- openpype/modules/sync_server/providers/gdrive.py | 2 +- openpype/modules/sync_server/providers/sftp.py | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/openpype/modules/sync_server/providers/dropbox.py b/openpype/modules/sync_server/providers/dropbox.py index e026ae7ef6..3515aee93f 100644 --- a/openpype/modules/sync_server/providers/dropbox.py +++ b/openpype/modules/sync_server/providers/dropbox.py @@ -22,7 +22,7 @@ class DropboxHandler(AbstractProvider): ) return - if not self.presets["enabled"]: + if not self.presets.get("enabled"): self.log.debug("Sync Server: Site {} not enabled for {}.". format(site_name, project_name)) return diff --git a/openpype/modules/sync_server/providers/gdrive.py b/openpype/modules/sync_server/providers/gdrive.py index 9a3ce89cf5..297a5c9fec 100644 --- a/openpype/modules/sync_server/providers/gdrive.py +++ b/openpype/modules/sync_server/providers/gdrive.py @@ -74,7 +74,7 @@ class GDriveHandler(AbstractProvider): ) return - if not self.presets["enabled"]: + if not self.presets.get("enabled"): self.log.debug( "Sync Server: Site {} not enabled for {}.".format( site_name, project_name diff --git a/openpype/modules/sync_server/providers/sftp.py b/openpype/modules/sync_server/providers/sftp.py index 40f11cb9dd..1b4f68c585 100644 --- a/openpype/modules/sync_server/providers/sftp.py +++ b/openpype/modules/sync_server/providers/sftp.py @@ -72,7 +72,7 @@ class SFTPHandler(AbstractProvider): Returns: (boolean) """ - return self.presets["enabled"] and self.conn is not None + return self.self.presets.get("enabled") and self.conn is not None @classmethod def get_system_settings_schema(cls): From 753c876d9fd393f5f64bbf0392a91c89380bbf78 Mon Sep 17 00:00:00 2001 From: Petr Kalis Date: Thu, 15 Dec 2022 11:59:01 +0100 Subject: [PATCH 11/42] OP-4512 - create Anatomy object only for default local sites Eg. studio and local id of machine. It doesn't make much sense for Anatomy to handle other SiteSync sites. --- openpype/pipeline/anatomy.py | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/openpype/pipeline/anatomy.py b/openpype/pipeline/anatomy.py index 908dc2b187..5b4eb67247 100644 --- a/openpype/pipeline/anatomy.py +++ b/openpype/pipeline/anatomy.py @@ -24,6 +24,7 @@ from openpype.lib.path_templates import ( FormatObject, ) from openpype.lib.log import Logger +from openpype.lib import get_local_site_id log = Logger.get_logger(__name__) @@ -60,6 +61,10 @@ class BaseAnatomy(object): project_name = project_doc["name"] self.project_name = project_name + if site_name not in ["studio", get_local_site_id()]: + raise RuntimeError("Anatomy could be created only for default " + "local sites") + self._site_name = site_name self._data = self._prepare_anatomy_data( From 19ab86499a79cab738daef25850781f1409519b4 Mon Sep 17 00:00:00 2001 From: Petr Kalis Date: Thu, 15 Dec 2022 12:00:10 +0100 Subject: [PATCH 12/42] OP-4512 - update method to get all configured sites Added more details to be more useful. --- .../modules/sync_server/sync_server_module.py | 18 ++++++++++++++++-- 1 file changed, 16 insertions(+), 2 deletions(-) diff --git a/openpype/modules/sync_server/sync_server_module.py b/openpype/modules/sync_server/sync_server_module.py index 653ee50541..034121d996 100644 --- a/openpype/modules/sync_server/sync_server_module.py +++ b/openpype/modules/sync_server/sync_server_module.py @@ -1368,13 +1368,19 @@ class SyncServerModule(OpenPypeModule, ITrayModule): """ sync_sett = self.sync_system_settings project_enabled = True + project_settings = None if project_name: project_enabled = project_name in self.get_enabled_projects() + project_settings = self.get_sync_project_setting(project_name) sync_enabled = sync_sett["enabled"] and project_enabled system_sites = {} if sync_enabled: for site, detail in sync_sett.get("sites", {}).items(): + if project_settings: + site_settings = project_settings["sites"].get(site) + if site_settings: + detail.update(site_settings) system_sites[site] = detail system_sites.update(self._get_default_site_configs(sync_enabled, @@ -1396,14 +1402,22 @@ class SyncServerModule(OpenPypeModule, ITrayModule): exclude_locals=True) roots = {} for root, config in anatomy_sett["roots"].items(): - roots[root] = config[platform.system().lower()] + roots[root] = config studio_config = { + 'enabled': True, 'provider': 'local_drive', "root": roots } all_sites = {self.DEFAULT_SITE: studio_config} if sync_enabled: - all_sites[get_local_site_id()] = {'provider': 'local_drive'} + all_sites[get_local_site_id()] = {'enabled': True, + 'provider': 'local_drive', + "root": roots} + # duplicate values for normalized local name + all_sites["local"] = { + 'enabled': True, + 'provider': 'local_drive', + "root": roots} return all_sites def get_provider_for_site(self, project_name=None, site=None): From e29f8d445b762545b4dbe7f7227f668cdabd7bac Mon Sep 17 00:00:00 2001 From: Petr Kalis Date: Thu, 15 Dec 2022 12:05:42 +0100 Subject: [PATCH 13/42] OP-4512 - updated way to get sites Labels for roots are now actually changing according to selected sites --- .../local_settings/projects_widget.py | 27 ++++++++++++------- 1 file changed, 18 insertions(+), 9 deletions(-) diff --git a/openpype/tools/settings/local_settings/projects_widget.py b/openpype/tools/settings/local_settings/projects_widget.py index 30a0d212f0..2b8c56e38c 100644 --- a/openpype/tools/settings/local_settings/projects_widget.py +++ b/openpype/tools/settings/local_settings/projects_widget.py @@ -248,6 +248,9 @@ class SitesWidget(QtWidgets.QWidget): main_layout.addWidget(comboboxes_widget, 0) main_layout.addWidget(content_widget, 1) + active_site_widget.value_changed.connect(self.refresh) + remote_site_widget.value_changed.connect(self.refresh) + self.active_site_widget = active_site_widget self.remote_site_widget = remote_site_widget @@ -268,25 +271,29 @@ class SitesWidget(QtWidgets.QWidget): self.modules_manager.modules_by_name["sync_server"] ) - # This is temporary modification - # - whole logic here should be in sync module's providers - site_names = sync_server_module.get_active_sites_from_settings( - self.project_settings["project_settings"].value - ) + site_configs = sync_server_module.get_all_site_configs( + self._project_name) roots_entity = ( self.project_settings[PROJECT_ANATOMY_KEY][LOCAL_ROOTS_KEY] ) - + site_names = [self.active_site_widget.current_text(), + self.remote_site_widget.current_text()] output = [] for site_name in site_names: + if not site_name: + continue + site_inputs = [] - for root_name, path_entity in roots_entity.items(): - platform_entity = path_entity[platform.system().lower()] + site_config = site_configs[site_name] + for root_name, path_entity in site_config.get("root", {}).items(): + if not path_entity: + continue + platform_value = path_entity[platform.system().lower()] site_inputs.append({ "label": root_name, "key": root_name, - "value": platform_entity.value + "value": platform_value }) output.append( @@ -436,6 +443,7 @@ class SitesWidget(QtWidgets.QWidget): class _SiteCombobox(QtWidgets.QWidget): input_label = None + value_changed = QtCore.Signal() def __init__(self, modules_manager, project_settings, parent): super(_SiteCombobox, self).__init__(parent) @@ -661,6 +669,7 @@ class _SiteCombobox(QtWidgets.QWidget): self._set_local_settings_value(self.current_text()) self._update_style() + self.value_changed.emit() def _set_local_settings_value(self, value): raise NotImplementedError( From 61076ae7dbdf50541f9b465e0cfdc18ebe0740ef Mon Sep 17 00:00:00 2001 From: Kayla Man Date: Thu, 15 Dec 2022 19:45:29 +0800 Subject: [PATCH 14/42] fix the setAttr error --- openpype/hosts/maya/plugins/load/load_image_plane.py | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/openpype/hosts/maya/plugins/load/load_image_plane.py b/openpype/hosts/maya/plugins/load/load_image_plane.py index 5f1c582203..6f8925a083 100644 --- a/openpype/hosts/maya/plugins/load/load_image_plane.py +++ b/openpype/hosts/maya/plugins/load/load_image_plane.py @@ -166,13 +166,17 @@ class ImagePlaneLoader(load.LoaderPlugin): QtWidgets.QMessageBox.Cancel ) if reply == QtWidgets.QMessageBox.Ok: - expressions = image_plane_shape.frameExtension.inputs(type="expression") # noqa + # find the input and output of frame extension + expressions = image_plane_shape.frameExtension.inputs() + frame_ext_output = image_plane_shape.frameExtension.outputs() if expressions: - pm.delete(expressions) + # the "time1" node is non-deletable attr + # in Maya, use disconnectAttr instead + pm.disconnectAttr(expressions, frame_ext_output) if not image_plane_shape.frameExtension.isFreeToChange(): raise RuntimeError("Can't set frame extension for {}".format(image_plane_shape)) # noqa - + # get the node of time instead and set the time for it. image_plane_shape.frameExtension.set(start_frame) new_nodes.extend( From e807d7e275eb3d159b61fac28073b9b081e83c18 Mon Sep 17 00:00:00 2001 From: Kayla Man Date: Fri, 16 Dec 2022 18:10:56 +0800 Subject: [PATCH 15/42] Update load_image_plane.py set the frame offset to zero by default --- openpype/hosts/maya/plugins/load/load_image_plane.py | 11 +++-------- 1 file changed, 3 insertions(+), 8 deletions(-) diff --git a/openpype/hosts/maya/plugins/load/load_image_plane.py b/openpype/hosts/maya/plugins/load/load_image_plane.py index 6f8925a083..86816495ae 100644 --- a/openpype/hosts/maya/plugins/load/load_image_plane.py +++ b/openpype/hosts/maya/plugins/load/load_image_plane.py @@ -133,10 +133,7 @@ class ImagePlaneLoader(load.LoaderPlugin): start_frame = pm.playbackOptions(q=True, min=True) end_frame = pm.playbackOptions(q=True, max=True) - if int(start_frame) > 0: - image_plane_shape.frameOffset.set(int(start_frame) - 1) - else: - image_plane_shape.frameOffset.set(int(start_frame)) + image_plane_shape.frameOffset.set(0) image_plane_shape.frameIn.set(start_frame) image_plane_shape.frameOut.set(end_frame) image_plane_shape.frameCache.set(end_frame) @@ -227,10 +224,8 @@ class ImagePlaneLoader(load.LoaderPlugin): ) start_frame = asset["data"]["frameStart"] end_frame = asset["data"]["frameEnd"] - if int(start_frame) > 0: - image_plane_shape.frameOffset.set(int(start_frame) - 1) - else: - image_plane_shape.frameOffset.set(int(start_frame)) + + image_plane_shape.frameOffset.set(0) image_plane_shape.frameIn.set(start_frame) image_plane_shape.frameOut.set(end_frame) image_plane_shape.frameCache.set(end_frame) From e0a2f2370256212f2ea78f282a9dc3eeb156b362 Mon Sep 17 00:00:00 2001 From: Ondrej Samohel Date: Fri, 16 Dec 2022 16:35:14 +0100 Subject: [PATCH 16/42] :bug: fix node access --- openpype/hosts/houdini/plugins/create/create_hda.py | 2 +- openpype/hosts/houdini/plugins/publish/collect_active_state.py | 2 +- openpype/hosts/houdini/plugins/publish/collect_redshift_rop.py | 2 +- openpype/hosts/houdini/plugins/publish/collect_usd_layers.py | 3 ++- .../hosts/houdini/plugins/publish/extract_redshift_proxy.py | 2 +- openpype/hosts/houdini/plugins/publish/extract_usd.py | 2 +- openpype/hosts/houdini/plugins/publish/extract_usd_layered.py | 2 +- openpype/hosts/houdini/plugins/publish/extract_vdb_cache.py | 2 +- .../houdini/plugins/publish/validate_animation_settings.py | 3 +-- openpype/hosts/houdini/plugins/publish/validate_bypass.py | 2 +- .../hosts/houdini/plugins/publish/validate_cop_output_node.py | 2 +- openpype/hosts/houdini/plugins/publish/validate_frame_token.py | 3 +-- openpype/hosts/houdini/plugins/publish/validate_no_errors.py | 2 +- .../plugins/publish/validate_usd_layer_path_backslashes.py | 2 +- .../houdini/plugins/publish/validate_usd_model_and_shade.py | 2 +- .../hosts/houdini/plugins/publish/validate_usd_output_node.py | 2 +- .../hosts/houdini/plugins/publish/validate_usd_setdress.py | 2 +- .../houdini/plugins/publish/validate_usd_shade_workspace.py | 2 +- .../hosts/houdini/plugins/publish/validate_vdb_output_node.py | 2 +- 19 files changed, 20 insertions(+), 21 deletions(-) diff --git a/openpype/hosts/houdini/plugins/create/create_hda.py b/openpype/hosts/houdini/plugins/create/create_hda.py index 4bed83c2e9..5f95b2efb4 100644 --- a/openpype/hosts/houdini/plugins/create/create_hda.py +++ b/openpype/hosts/houdini/plugins/create/create_hda.py @@ -34,7 +34,7 @@ class CreateHDA(plugin.HoudiniCreator): } return subset_name.lower() in existing_subset_names_low - def _create_instance_node( + def create_instance_node( self, node_name, parent, node_type="geometry"): import hou diff --git a/openpype/hosts/houdini/plugins/publish/collect_active_state.py b/openpype/hosts/houdini/plugins/publish/collect_active_state.py index cc3f2e7fae..7fda94b288 100644 --- a/openpype/hosts/houdini/plugins/publish/collect_active_state.py +++ b/openpype/hosts/houdini/plugins/publish/collect_active_state.py @@ -25,7 +25,7 @@ class CollectInstanceActiveState(pyblish.api.InstancePlugin): # Check bypass state and reverse active = True - node = hou.node(instance.get("instance_node")) + node = hou.node(instance.data.get("instance_node")) if hasattr(node, "isBypassed"): active = not node.isBypassed() diff --git a/openpype/hosts/houdini/plugins/publish/collect_redshift_rop.py b/openpype/hosts/houdini/plugins/publish/collect_redshift_rop.py index 346bdf3421..f1d73d7523 100644 --- a/openpype/hosts/houdini/plugins/publish/collect_redshift_rop.py +++ b/openpype/hosts/houdini/plugins/publish/collect_redshift_rop.py @@ -69,7 +69,7 @@ class CollectRedshiftROPRenderProducts(pyblish.api.InstancePlugin): def process(self, instance): - rop = hou.node(instance.get("instance_node")) + rop = hou.node(instance.data.get("instance_node")) # Collect chunkSize chunk_size_parm = rop.parm("chunkSize") diff --git a/openpype/hosts/houdini/plugins/publish/collect_usd_layers.py b/openpype/hosts/houdini/plugins/publish/collect_usd_layers.py index 833add854b..696560a590 100644 --- a/openpype/hosts/houdini/plugins/publish/collect_usd_layers.py +++ b/openpype/hosts/houdini/plugins/publish/collect_usd_layers.py @@ -21,7 +21,7 @@ class CollectUsdLayers(pyblish.api.InstancePlugin): self.log.debug("No output node found..") return - rop_node = hou.node(instance.get("instance_node")) + rop_node = hou.node(instance.data["instance_node"]) save_layers = [] for layer in usdlib.get_configured_save_layers(rop_node): @@ -56,6 +56,7 @@ class CollectUsdLayers(pyblish.api.InstancePlugin): layer_inst.data["subset"] = "__stub__" layer_inst.data["label"] = label layer_inst.data["asset"] = instance.data["asset"] + layer_inst.data["instance_node"] = instance.data["instance_node"] # include same USD ROP layer_inst.append(rop_node) # include layer data diff --git a/openpype/hosts/houdini/plugins/publish/extract_redshift_proxy.py b/openpype/hosts/houdini/plugins/publish/extract_redshift_proxy.py index 29ede98a52..1d99ac665c 100644 --- a/openpype/hosts/houdini/plugins/publish/extract_redshift_proxy.py +++ b/openpype/hosts/houdini/plugins/publish/extract_redshift_proxy.py @@ -17,7 +17,7 @@ class ExtractRedshiftProxy(publish.Extractor): def process(self, instance): - ropnode = hou.node(instance.get("instance_node")) + ropnode = hou.node(instance.data.get("instance_node")) # Get the filename from the filename parameter # `.evalParm(parameter)` will make sure all tokens are resolved diff --git a/openpype/hosts/houdini/plugins/publish/extract_usd.py b/openpype/hosts/houdini/plugins/publish/extract_usd.py index cbeb5add71..61c1b477b2 100644 --- a/openpype/hosts/houdini/plugins/publish/extract_usd.py +++ b/openpype/hosts/houdini/plugins/publish/extract_usd.py @@ -18,7 +18,7 @@ class ExtractUSD(publish.Extractor): def process(self, instance): - ropnode = hou.node(instance.get("instance_node")) + ropnode = hou.node(instance.data.get("instance_node")) # Get the filename from the filename parameter output = ropnode.evalParm("lopoutput") diff --git a/openpype/hosts/houdini/plugins/publish/extract_usd_layered.py b/openpype/hosts/houdini/plugins/publish/extract_usd_layered.py index 0288b7363a..8422a3bc3e 100644 --- a/openpype/hosts/houdini/plugins/publish/extract_usd_layered.py +++ b/openpype/hosts/houdini/plugins/publish/extract_usd_layered.py @@ -187,7 +187,7 @@ class ExtractUSDLayered(publish.Extractor): # Main ROP node, either a USD Rop or ROP network with # multiple USD ROPs - node = hou.node(instance.get("instance_node")) + node = hou.node(instance.data["instance_node"]) # Collect any output dependencies that have not been processed yet # during extraction of other instances diff --git a/openpype/hosts/houdini/plugins/publish/extract_vdb_cache.py b/openpype/hosts/houdini/plugins/publish/extract_vdb_cache.py index 434d6a2160..4bca758f08 100644 --- a/openpype/hosts/houdini/plugins/publish/extract_vdb_cache.py +++ b/openpype/hosts/houdini/plugins/publish/extract_vdb_cache.py @@ -17,7 +17,7 @@ class ExtractVDBCache(publish.Extractor): def process(self, instance): - ropnode = hou.node(instance.get("instance_node")) + ropnode = hou.node(instance.data["instance_node"]) # Get the filename from the filename parameter # `.evalParm(parameter)` will make sure all tokens are resolved diff --git a/openpype/hosts/houdini/plugins/publish/validate_animation_settings.py b/openpype/hosts/houdini/plugins/publish/validate_animation_settings.py index f11f9c0c62..4878738ed3 100644 --- a/openpype/hosts/houdini/plugins/publish/validate_animation_settings.py +++ b/openpype/hosts/houdini/plugins/publish/validate_animation_settings.py @@ -37,8 +37,7 @@ class ValidateAnimationSettings(pyblish.api.InstancePlugin): @classmethod def get_invalid(cls, instance): - node = hou.node(instance.get("instance_node")) - + node = hou.node(instance.data["instance_node"]) # Check trange parm, 0 means Render Current Frame frame_range = node.evalParm("trange") if frame_range == 0: diff --git a/openpype/hosts/houdini/plugins/publish/validate_bypass.py b/openpype/hosts/houdini/plugins/publish/validate_bypass.py index 1bf51a986c..c10c5a2c05 100644 --- a/openpype/hosts/houdini/plugins/publish/validate_bypass.py +++ b/openpype/hosts/houdini/plugins/publish/validate_bypass.py @@ -37,6 +37,6 @@ class ValidateBypassed(pyblish.api.InstancePlugin): @classmethod def get_invalid(cls, instance): - rop = hou.node(instance.get("instance_node")) + rop = hou.node(instance.data["instance_node"]) if hasattr(rop, "isBypassed") and rop.isBypassed(): return [rop] diff --git a/openpype/hosts/houdini/plugins/publish/validate_cop_output_node.py b/openpype/hosts/houdini/plugins/publish/validate_cop_output_node.py index 1d0377c818..1fc767b309 100644 --- a/openpype/hosts/houdini/plugins/publish/validate_cop_output_node.py +++ b/openpype/hosts/houdini/plugins/publish/validate_cop_output_node.py @@ -48,7 +48,7 @@ class ValidateCopOutputNode(pyblish.api.InstancePlugin): ) if output_node is None: - node = hou.node(instance.get("instance_node")) + node = hou.node(instance.data.get("instance_node")) cls.log.error( "COP Output node in '%s' does not exist. " "Ensure a valid COP output path is set." % node.path() diff --git a/openpype/hosts/houdini/plugins/publish/validate_frame_token.py b/openpype/hosts/houdini/plugins/publish/validate_frame_token.py index b5f6ba71e1..06d4003295 100644 --- a/openpype/hosts/houdini/plugins/publish/validate_frame_token.py +++ b/openpype/hosts/houdini/plugins/publish/validate_frame_token.py @@ -37,8 +37,7 @@ class ValidateFrameToken(pyblish.api.InstancePlugin): @classmethod def get_invalid(cls, instance): - node = hou.node(instance.get("instance_node")) - + node = hou.node(instance.data["instance_node"]) # Check trange parm, 0 means Render Current Frame frame_range = node.evalParm("trange") if frame_range == 0: diff --git a/openpype/hosts/houdini/plugins/publish/validate_no_errors.py b/openpype/hosts/houdini/plugins/publish/validate_no_errors.py index f7c95aaf4e..6c48eae70a 100644 --- a/openpype/hosts/houdini/plugins/publish/validate_no_errors.py +++ b/openpype/hosts/houdini/plugins/publish/validate_no_errors.py @@ -38,7 +38,7 @@ class ValidateNoErrors(pyblish.api.InstancePlugin): validate_nodes = [] if len(instance) > 0: - validate_nodes.append(hou.node(instance.get("instance_node"))) + validate_nodes.append(hou.node(instance.data.get("instance_node"))) output_node = instance.data.get("output_node") if output_node: validate_nodes.append(output_node) diff --git a/openpype/hosts/houdini/plugins/publish/validate_usd_layer_path_backslashes.py b/openpype/hosts/houdini/plugins/publish/validate_usd_layer_path_backslashes.py index a0e2302495..f2c7878c4e 100644 --- a/openpype/hosts/houdini/plugins/publish/validate_usd_layer_path_backslashes.py +++ b/openpype/hosts/houdini/plugins/publish/validate_usd_layer_path_backslashes.py @@ -28,7 +28,7 @@ class ValidateUSDLayerPathBackslashes(pyblish.api.InstancePlugin): def process(self, instance): - rop = hou.node(instance.get("instance_node")) + rop = hou.node(instance.data.get("instance_node")) lop_path = hou_usdlib.get_usd_rop_loppath(rop) stage = lop_path.stage(apply_viewport_overrides=False) diff --git a/openpype/hosts/houdini/plugins/publish/validate_usd_model_and_shade.py b/openpype/hosts/houdini/plugins/publish/validate_usd_model_and_shade.py index a55eb70cb2..b8faae16d7 100644 --- a/openpype/hosts/houdini/plugins/publish/validate_usd_model_and_shade.py +++ b/openpype/hosts/houdini/plugins/publish/validate_usd_model_and_shade.py @@ -40,7 +40,7 @@ class ValidateUsdModel(pyblish.api.InstancePlugin): def process(self, instance): - rop = hou.node(instance.get("instance_node")) + rop = hou.node(instance.data.get("instance_node")) lop_path = hou_usdlib.get_usd_rop_loppath(rop) stage = lop_path.stage(apply_viewport_overrides=False) diff --git a/openpype/hosts/houdini/plugins/publish/validate_usd_output_node.py b/openpype/hosts/houdini/plugins/publish/validate_usd_output_node.py index af21efcafc..5cb5bd35fb 100644 --- a/openpype/hosts/houdini/plugins/publish/validate_usd_output_node.py +++ b/openpype/hosts/houdini/plugins/publish/validate_usd_output_node.py @@ -36,7 +36,7 @@ class ValidateUSDOutputNode(pyblish.api.InstancePlugin): output_node = instance.data["output_node"] if output_node is None: - node = hou.node(instance.get("instance_node")) + node = hou.node(instance.data.get("instance_node")) cls.log.error( "USD node '%s' LOP path does not exist. " "Ensure a valid LOP path is set." % node.path() diff --git a/openpype/hosts/houdini/plugins/publish/validate_usd_setdress.py b/openpype/hosts/houdini/plugins/publish/validate_usd_setdress.py index 01ebc0e828..b96d185482 100644 --- a/openpype/hosts/houdini/plugins/publish/validate_usd_setdress.py +++ b/openpype/hosts/houdini/plugins/publish/validate_usd_setdress.py @@ -24,7 +24,7 @@ class ValidateUsdSetDress(pyblish.api.InstancePlugin): from pxr import UsdGeom import hou - rop = hou.node(instance.get("instance_node")) + rop = hou.node(instance.data.get("instance_node")) lop_path = hou_usdlib.get_usd_rop_loppath(rop) stage = lop_path.stage(apply_viewport_overrides=False) diff --git a/openpype/hosts/houdini/plugins/publish/validate_usd_shade_workspace.py b/openpype/hosts/houdini/plugins/publish/validate_usd_shade_workspace.py index bd3366a424..cb2099437d 100644 --- a/openpype/hosts/houdini/plugins/publish/validate_usd_shade_workspace.py +++ b/openpype/hosts/houdini/plugins/publish/validate_usd_shade_workspace.py @@ -20,7 +20,7 @@ class ValidateUsdShadeWorkspace(pyblish.api.InstancePlugin): def process(self, instance): - rop = hou.node(instance.get("instance_node")) + rop = hou.node(instance.data.get("instance_node")) workspace = rop.parent() definition = workspace.type().definition() diff --git a/openpype/hosts/houdini/plugins/publish/validate_vdb_output_node.py b/openpype/hosts/houdini/plugins/publish/validate_vdb_output_node.py index 61c1209fc9..f9f88b3bf9 100644 --- a/openpype/hosts/houdini/plugins/publish/validate_vdb_output_node.py +++ b/openpype/hosts/houdini/plugins/publish/validate_vdb_output_node.py @@ -38,7 +38,7 @@ class ValidateVDBOutputNode(pyblish.api.InstancePlugin): if node is None: cls.log.error( "SOP path is not correctly set on " - "ROP node '%s'." % instance.get("instance_node") + "ROP node '%s'." % instance.data.get("instance_node") ) return [instance] From d439eec880c2703aba86b5500d28757a9bf00f25 Mon Sep 17 00:00:00 2001 From: Kayla Man Date: Tue, 20 Dec 2022 18:36:27 +0800 Subject: [PATCH 17/42] maya image plane load error --- openpype/hosts/maya/plugins/load/load_image_plane.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/openpype/hosts/maya/plugins/load/load_image_plane.py b/openpype/hosts/maya/plugins/load/load_image_plane.py index 86816495ae..664cd06fc1 100644 --- a/openpype/hosts/maya/plugins/load/load_image_plane.py +++ b/openpype/hosts/maya/plugins/load/load_image_plane.py @@ -72,6 +72,8 @@ class CameraWindow(QtWidgets.QDialog): def on_cancel_pressed(self): self.camera = None + if self.camera: + return self.close() From 8055b793ee7bd1d90466bb0cd3f6334779ba1a8c Mon Sep 17 00:00:00 2001 From: Kayla Man Date: Tue, 20 Dec 2022 18:45:14 +0800 Subject: [PATCH 18/42] maya image plane load error --- openpype/hosts/maya/plugins/load/load_image_plane.py | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/openpype/hosts/maya/plugins/load/load_image_plane.py b/openpype/hosts/maya/plugins/load/load_image_plane.py index 664cd06fc1..ce752f170f 100644 --- a/openpype/hosts/maya/plugins/load/load_image_plane.py +++ b/openpype/hosts/maya/plugins/load/load_image_plane.py @@ -71,8 +71,7 @@ class CameraWindow(QtWidgets.QDialog): self.close() def on_cancel_pressed(self): - self.camera = None - if self.camera: + if self.camera is not None: return self.close() From 9173199896975fe5d2a20e8ec99019fe1987140b Mon Sep 17 00:00:00 2001 From: Kayla Man Date: Tue, 20 Dec 2022 18:46:06 +0800 Subject: [PATCH 19/42] maya image plane load error --- openpype/hosts/maya/plugins/load/load_image_plane.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/openpype/hosts/maya/plugins/load/load_image_plane.py b/openpype/hosts/maya/plugins/load/load_image_plane.py index ce752f170f..081c646298 100644 --- a/openpype/hosts/maya/plugins/load/load_image_plane.py +++ b/openpype/hosts/maya/plugins/load/load_image_plane.py @@ -71,7 +71,7 @@ class CameraWindow(QtWidgets.QDialog): self.close() def on_cancel_pressed(self): - if self.camera is not None: + if self.camera: return self.close() From cd9f14a21d999a50e01d2ed9ce0f744a17af829c Mon Sep 17 00:00:00 2001 From: Kayla Man Date: Tue, 20 Dec 2022 19:09:17 +0800 Subject: [PATCH 20/42] maya image plane load error --- openpype/hosts/maya/plugins/load/load_image_plane.py | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/openpype/hosts/maya/plugins/load/load_image_plane.py b/openpype/hosts/maya/plugins/load/load_image_plane.py index 081c646298..c18cb5c6c8 100644 --- a/openpype/hosts/maya/plugins/load/load_image_plane.py +++ b/openpype/hosts/maya/plugins/load/load_image_plane.py @@ -57,7 +57,7 @@ class CameraWindow(QtWidgets.QDialog): layout.addWidget(self.widgets["warning"]) self.widgets["okButton"].pressed.connect(self.on_ok_pressed) - self.widgets["cancelButton"].clicked.connect(self.on_cancel_pressed) + self.widgets["cancelButton"].pressed.connect(self.on_cancel_pressed) self.widgets["list"].itemPressed.connect(self.on_list_itemPressed) def on_list_itemPressed(self, item): @@ -71,8 +71,6 @@ class CameraWindow(QtWidgets.QDialog): self.close() def on_cancel_pressed(self): - if self.camera: - return self.close() From 32f87d6324702dc24b86123d97bef40ec353a0de Mon Sep 17 00:00:00 2001 From: Kayla Man Date: Tue, 20 Dec 2022 19:47:07 +0800 Subject: [PATCH 21/42] maya image plane load error --- openpype/hosts/maya/plugins/load/load_image_plane.py | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/openpype/hosts/maya/plugins/load/load_image_plane.py b/openpype/hosts/maya/plugins/load/load_image_plane.py index c18cb5c6c8..7d5d4cb12b 100644 --- a/openpype/hosts/maya/plugins/load/load_image_plane.py +++ b/openpype/hosts/maya/plugins/load/load_image_plane.py @@ -71,8 +71,10 @@ class CameraWindow(QtWidgets.QDialog): self.close() def on_cancel_pressed(self): - self.close() + if self.camera is None: + return + self.close() class ImagePlaneLoader(load.LoaderPlugin): """Specific loader of plate for image planes on selected camera.""" From 20b85799e2f1c219254a42be2232398d8650351c Mon Sep 17 00:00:00 2001 From: Kayla Man Date: Tue, 20 Dec 2022 21:16:19 +0800 Subject: [PATCH 22/42] maya image plane load error --- openpype/hosts/maya/plugins/load/load_image_plane.py | 1 + 1 file changed, 1 insertion(+) diff --git a/openpype/hosts/maya/plugins/load/load_image_plane.py b/openpype/hosts/maya/plugins/load/load_image_plane.py index 7d5d4cb12b..5075e4b8fe 100644 --- a/openpype/hosts/maya/plugins/load/load_image_plane.py +++ b/openpype/hosts/maya/plugins/load/load_image_plane.py @@ -71,6 +71,7 @@ class CameraWindow(QtWidgets.QDialog): self.close() def on_cancel_pressed(self): + self.camera = None if self.camera is None: return From 6a4261d81a001874f4ac26f72514a70f3a34dea6 Mon Sep 17 00:00:00 2001 From: Kayla Man Date: Tue, 20 Dec 2022 21:58:50 +0800 Subject: [PATCH 23/42] maya load image plane error --- openpype/hosts/maya/plugins/load/load_image_plane.py | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/openpype/hosts/maya/plugins/load/load_image_plane.py b/openpype/hosts/maya/plugins/load/load_image_plane.py index 5075e4b8fe..2bfe6cb766 100644 --- a/openpype/hosts/maya/plugins/load/load_image_plane.py +++ b/openpype/hosts/maya/plugins/load/load_image_plane.py @@ -71,12 +71,10 @@ class CameraWindow(QtWidgets.QDialog): self.close() def on_cancel_pressed(self): - self.camera = None - if self.camera is None: + if self.camera or self.camera is None: + self.close() return - self.close() - class ImagePlaneLoader(load.LoaderPlugin): """Specific loader of plate for image planes on selected camera.""" From 0b8b2eb03a03eb25bb399d0b4d25c75b154792ca Mon Sep 17 00:00:00 2001 From: Kayla Man Date: Tue, 20 Dec 2022 22:33:04 +0800 Subject: [PATCH 24/42] maya load image plane error --- openpype/hosts/maya/plugins/load/load_image_plane.py | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/openpype/hosts/maya/plugins/load/load_image_plane.py b/openpype/hosts/maya/plugins/load/load_image_plane.py index 2bfe6cb766..9eb4c7f561 100644 --- a/openpype/hosts/maya/plugins/load/load_image_plane.py +++ b/openpype/hosts/maya/plugins/load/load_image_plane.py @@ -71,9 +71,8 @@ class CameraWindow(QtWidgets.QDialog): self.close() def on_cancel_pressed(self): - if self.camera or self.camera is None: - self.close() - return + self.camera = None + self.close() class ImagePlaneLoader(load.LoaderPlugin): """Specific loader of plate for image planes on selected camera.""" @@ -109,7 +108,10 @@ class ImagePlaneLoader(load.LoaderPlugin): camera_names["Create new camera."] = "create_camera" window = CameraWindow(camera_names.keys()) window.exec_() - camera = camera_names[window.camera] + try: + camera = camera_names[window.camera] + except KeyError: + pass if camera == "create_camera": camera = pm.createNode("camera") From c597a12601415fb6cf90f680606915b8dc2b3bcb Mon Sep 17 00:00:00 2001 From: Kayla Man Date: Wed, 21 Dec 2022 00:14:32 +0800 Subject: [PATCH 25/42] maya-image-plane-load-error --- openpype/hosts/maya/plugins/load/load_image_plane.py | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/openpype/hosts/maya/plugins/load/load_image_plane.py b/openpype/hosts/maya/plugins/load/load_image_plane.py index 9eb4c7f561..f77b755050 100644 --- a/openpype/hosts/maya/plugins/load/load_image_plane.py +++ b/openpype/hosts/maya/plugins/load/load_image_plane.py @@ -108,10 +108,10 @@ class ImagePlaneLoader(load.LoaderPlugin): camera_names["Create new camera."] = "create_camera" window = CameraWindow(camera_names.keys()) window.exec_() - try: - camera = camera_names[window.camera] - except KeyError: - pass + # Skip if no camera was selected (Dialog was closed) + if window.camera not in camera_names: + return + camera = camera_names[window.camera] if camera == "create_camera": camera = pm.createNode("camera") From 34f2c15d2dc2fa688026c46d1a8d72164321ee7e Mon Sep 17 00:00:00 2001 From: Jakub Jezek Date: Wed, 21 Dec 2022 16:28:50 +0100 Subject: [PATCH 26/42] hiero: creator gui with min max --- openpype/hosts/hiero/api/plugin.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/openpype/hosts/hiero/api/plugin.py b/openpype/hosts/hiero/api/plugin.py index 38933a1e30..07457db1a4 100644 --- a/openpype/hosts/hiero/api/plugin.py +++ b/openpype/hosts/hiero/api/plugin.py @@ -276,8 +276,8 @@ class CreatorWidget(QtWidgets.QDialog): elif v["type"] == "QSpinBox": data[k]["value"] = self.create_row( content_layout, "QSpinBox", v["label"], - setRange=(1, 9999999), setValue=v["value"], - setToolTip=tool_tip) + setValue=v["value"], setMinimum=0, + setMaximum=100000, setToolTip=tool_tip) return data From a15d41e00b8956f10bda95f2a84d55f3b0081e16 Mon Sep 17 00:00:00 2001 From: Petr Kalis Date: Thu, 22 Dec 2022 11:19:47 +0100 Subject: [PATCH 27/42] OP-4512 - add 'local' to default sites It seems that local label could come too. --- openpype/pipeline/anatomy.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/openpype/pipeline/anatomy.py b/openpype/pipeline/anatomy.py index 5b4eb67247..491ea48413 100644 --- a/openpype/pipeline/anatomy.py +++ b/openpype/pipeline/anatomy.py @@ -61,7 +61,7 @@ class BaseAnatomy(object): project_name = project_doc["name"] self.project_name = project_name - if site_name not in ["studio", get_local_site_id()]: + if site_name not in ["studio", "local", get_local_site_id()]: raise RuntimeError("Anatomy could be created only for default " "local sites") From 56cdcf3445bf49f97b86db5fade7833c2bb45c17 Mon Sep 17 00:00:00 2001 From: Petr Kalis Date: Thu, 22 Dec 2022 11:21:15 +0100 Subject: [PATCH 28/42] OP-4512 - added better logging --- openpype/pipeline/anatomy.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/openpype/pipeline/anatomy.py b/openpype/pipeline/anatomy.py index 491ea48413..a6750ede7c 100644 --- a/openpype/pipeline/anatomy.py +++ b/openpype/pipeline/anatomy.py @@ -63,7 +63,7 @@ class BaseAnatomy(object): if site_name not in ["studio", "local", get_local_site_id()]: raise RuntimeError("Anatomy could be created only for default " - "local sites") + "local sites not for {}".format(site_name)) self._site_name = site_name From 34e2ee9e7b36fd08d559c321019754cde71c03cd Mon Sep 17 00:00:00 2001 From: Petr Kalis Date: Thu, 22 Dec 2022 12:26:02 +0100 Subject: [PATCH 29/42] OP-4512 - fix typo --- openpype/modules/sync_server/providers/sftp.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/openpype/modules/sync_server/providers/sftp.py b/openpype/modules/sync_server/providers/sftp.py index 1b4f68c585..c41edc78bc 100644 --- a/openpype/modules/sync_server/providers/sftp.py +++ b/openpype/modules/sync_server/providers/sftp.py @@ -72,7 +72,7 @@ class SFTPHandler(AbstractProvider): Returns: (boolean) """ - return self.self.presets.get("enabled") and self.conn is not None + return self.presets.get("enabled") and self.conn is not None @classmethod def get_system_settings_schema(cls): From 1dc52fc3a22f3b7b29e4ce71ed1fca983498d9aa Mon Sep 17 00:00:00 2001 From: Joseff Date: Thu, 22 Dec 2022 15:08:04 +0100 Subject: [PATCH 30/42] Alter the UObject.h include MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: Ondřej Samohel <33513211+antirotor@users.noreply.github.com> --- .../UE_5.0/Source/OpenPype/Public/OpenPypeSettings.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/openpype/hosts/unreal/integration/UE_5.0/Source/OpenPype/Public/OpenPypeSettings.h b/openpype/hosts/unreal/integration/UE_5.0/Source/OpenPype/Public/OpenPypeSettings.h index 2df6c887cf..aca80946bb 100644 --- a/openpype/hosts/unreal/integration/UE_5.0/Source/OpenPype/Public/OpenPypeSettings.h +++ b/openpype/hosts/unreal/integration/UE_5.0/Source/OpenPype/Public/OpenPypeSettings.h @@ -3,7 +3,7 @@ #pragma once #include "CoreMinimal.h" -#include "Object.h" +#include "UObject/Object.h" #include "OpenPypeSettings.generated.h" #define OPENPYPE_SETTINGS_FILEPATH IPluginManager::Get().FindPlugin("OpenPype")->GetBaseDir() / TEXT("Config") / TEXT("DefaultOpenPypeSettings.ini") From d61d88d0a57fea3511eaf65954be0fba89e580ab Mon Sep 17 00:00:00 2001 From: Joseff Date: Thu, 22 Dec 2022 15:08:31 +0100 Subject: [PATCH 31/42] Alter the PluginManager and UObjectGlobals include. MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: Ondřej Samohel <33513211+antirotor@users.noreply.github.com> --- .../UE_5.0/Source/OpenPype/Private/OpenPypeSettings.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/openpype/hosts/unreal/integration/UE_5.0/Source/OpenPype/Private/OpenPypeSettings.cpp b/openpype/hosts/unreal/integration/UE_5.0/Source/OpenPype/Private/OpenPypeSettings.cpp index 7134614d22..a6b9eba749 100644 --- a/openpype/hosts/unreal/integration/UE_5.0/Source/OpenPype/Private/OpenPypeSettings.cpp +++ b/openpype/hosts/unreal/integration/UE_5.0/Source/OpenPype/Private/OpenPypeSettings.cpp @@ -2,8 +2,8 @@ #include "OpenPypeSettings.h" -#include "IPluginManager.h" -#include "UObjectGlobals.h" +#include "Interfaces/IPluginManager.h" +#include "UObject/UObjectGlobals.h" /** * Mainly is used for initializing default values if the DefaultOpenPypeSettings.ini file does not exist in the saved config From e34fee55fd5f0d00e745ab8d95663cb5be148b51 Mon Sep 17 00:00:00 2001 From: Petr Kalis Date: Thu, 22 Dec 2022 15:54:07 +0100 Subject: [PATCH 32/42] Fix for empty site_name --- openpype/pipeline/anatomy.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/openpype/pipeline/anatomy.py b/openpype/pipeline/anatomy.py index a6750ede7c..627f7198bb 100644 --- a/openpype/pipeline/anatomy.py +++ b/openpype/pipeline/anatomy.py @@ -61,7 +61,8 @@ class BaseAnatomy(object): project_name = project_doc["name"] self.project_name = project_name - if site_name not in ["studio", "local", get_local_site_id()]: + if (site_name and + site_name not in ["studio", "local", get_local_site_id()]): raise RuntimeError("Anatomy could be created only for default " "local sites not for {}".format(site_name)) From c16a5289e49286bb7c65be04a9629f846cab58ce Mon Sep 17 00:00:00 2001 From: Petr Kalis Date: Fri, 23 Dec 2022 14:09:03 +0100 Subject: [PATCH 33/42] OP-4470 - better handle missing keys Message might contain {placeholder} which are not collected. Previously it would fail without sending message. Now missing keys are double escaped {{}}. --- .../plugins/publish/integrate_slack_api.py | 28 ++++++++++++++++--- 1 file changed, 24 insertions(+), 4 deletions(-) diff --git a/openpype/modules/slack/plugins/publish/integrate_slack_api.py b/openpype/modules/slack/plugins/publish/integrate_slack_api.py index 0cd5ec9de8..9122c1c5ed 100644 --- a/openpype/modules/slack/plugins/publish/integrate_slack_api.py +++ b/openpype/modules/slack/plugins/publish/integrate_slack_api.py @@ -1,4 +1,5 @@ import os +import re import six import pyblish.api import copy @@ -132,14 +133,14 @@ class IntegrateSlackAPI(pyblish.api.InstancePlugin): fill_key = "task[{}]".format(key) fill_pairs.append((fill_key, value)) - self.log.debug("fill_pairs ::{}".format(fill_pairs)) multiple_case_variants = prepare_template_data(fill_pairs) fill_data.update(multiple_case_variants) - - message = None + message = '' try: - message = message_templ.format(**fill_data) + message = self._escape_missing_keys(message_templ, fill_data).\ + format(**fill_data) except Exception: + # shouldn't happen self.log.warning( "Some keys are missing in {}".format(message_templ), exc_info=True) @@ -263,3 +264,22 @@ class IntegrateSlackAPI(pyblish.api.InstancePlugin): msg = " - application must added to channel '{}'.".format(channel) error_str += msg + " Ask Slack admin." return error_str + + def _escape_missing_keys(self, message, fill_data): + """Double escapes placeholder which are missing in 'fill_data'""" + placeholder_keys = re.findall("\{([^}]+)\}", message) + + fill_keys = [] + for key, value in fill_data.items(): + fill_keys.append(key) + if isinstance(value, dict): + for child_key in value.keys(): + fill_keys.append("{}[{}]".format(key, child_key)) + + not_matched = set(placeholder_keys) - set(fill_keys) + + for not_matched_item in not_matched: + message = message.replace("{}".format(not_matched_item), + "{{{}}}".format(not_matched_item)) + + return message From 3a41d6a72158af0707d58f146b834076ed386b13 Mon Sep 17 00:00:00 2001 From: Petr Kalis Date: Fri, 23 Dec 2022 14:13:00 +0100 Subject: [PATCH 34/42] OP-4470 - safer handling of review path 'published_path' might be missing. Thumbnail path was fixed previously, this one was missed. --- .../slack/plugins/publish/integrate_slack_api.py | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/openpype/modules/slack/plugins/publish/integrate_slack_api.py b/openpype/modules/slack/plugins/publish/integrate_slack_api.py index 9122c1c5ed..c4d6b27726 100644 --- a/openpype/modules/slack/plugins/publish/integrate_slack_api.py +++ b/openpype/modules/slack/plugins/publish/integrate_slack_api.py @@ -163,17 +163,21 @@ class IntegrateSlackAPI(pyblish.api.InstancePlugin): def _get_review_path(self, instance): """Returns abs url for review if present in instance repres""" - published_path = None + review_path = None for repre in instance.data.get("representations", []): tags = repre.get('tags', []) if (repre.get("review") or "review" in tags or "burnin" in tags): - if os.path.exists(repre["published_path"]): - published_path = repre["published_path"] + repre_review_path = ( + repre.get("published_path") or + os.path.join(repre["stagingDir"], repre["files"]) + ) + if os.path.exists(repre_review_path): + review_path = repre_review_path if "burnin" in tags: # burnin has precedence if exists break - return published_path + return review_path def _python2_call(self, token, channel, message, publish_files): from slackclient import SlackClient From 18949a0c76ecb7033867658eacbf4f05e03ff160 Mon Sep 17 00:00:00 2001 From: OpenPype Date: Sat, 24 Dec 2022 03:27:57 +0000 Subject: [PATCH 35/42] [Automated] Bump version --- openpype/version.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/openpype/version.py b/openpype/version.py index 904579ad55..e14bc9daab 100644 --- a/openpype/version.py +++ b/openpype/version.py @@ -1,3 +1,3 @@ # -*- coding: utf-8 -*- """Package declaring Pype version.""" -__version__ = "3.14.10-nightly.2" +__version__ = "3.14.10-nightly.3" From 8b6bc8444db044391bbe340e981abc404d1ffb38 Mon Sep 17 00:00:00 2001 From: OpenPype Date: Wed, 28 Dec 2022 03:28:14 +0000 Subject: [PATCH 36/42] [Automated] Bump version --- openpype/version.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/openpype/version.py b/openpype/version.py index e14bc9daab..40abb9e9fd 100644 --- a/openpype/version.py +++ b/openpype/version.py @@ -1,3 +1,3 @@ # -*- coding: utf-8 -*- """Package declaring Pype version.""" -__version__ = "3.14.10-nightly.3" +__version__ = "3.14.10-nightly.4" From f5842d91bd49cc955f49ed53388efd565b84f0a6 Mon Sep 17 00:00:00 2001 From: iLLiCiTiT Date: Wed, 28 Dec 2022 12:18:11 +0100 Subject: [PATCH 37/42] rename variable 'max_len' to 'message_len' --- openpype/widgets/message_window.py | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/openpype/widgets/message_window.py b/openpype/widgets/message_window.py index 94e51f5d4f..8301f5e8f2 100644 --- a/openpype/widgets/message_window.py +++ b/openpype/widgets/message_window.py @@ -105,16 +105,18 @@ class ScrollMessageBox(QtWidgets.QDialog): content_widget = QtWidgets.QWidget(self) scroll_widget.setWidget(content_widget) - max_len = 0 + message_len = 0 content_layout = QtWidgets.QVBoxLayout(content_widget) for message in messages: label_widget = QtWidgets.QLabel(message, content_widget) content_layout.addWidget(label_widget) - max_len = max(max_len, len(message)) + message_len = max(message_len, len(message)) # guess size of scrollable area max_width = QtWidgets.QApplication.desktop().availableGeometry().width - scroll_widget.setMinimumWidth(min(max_width, max_len * 6)) + scroll_widget.setMinimumWidth( + min(max_width, message_len * 6) + ) layout.addWidget(scroll_widget) if not cancelable: # if no specific buttons OK only From a941aabc049ee3ec59ef829dbd58c1abca937868 Mon Sep 17 00:00:00 2001 From: iLLiCiTiT Date: Wed, 28 Dec 2022 12:21:05 +0100 Subject: [PATCH 38/42] call the width method to get the value --- openpype/widgets/message_window.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/openpype/widgets/message_window.py b/openpype/widgets/message_window.py index 8301f5e8f2..2b186475ee 100644 --- a/openpype/widgets/message_window.py +++ b/openpype/widgets/message_window.py @@ -113,7 +113,7 @@ class ScrollMessageBox(QtWidgets.QDialog): message_len = max(message_len, len(message)) # guess size of scrollable area - max_width = QtWidgets.QApplication.desktop().availableGeometry().width + max_width = QtWidgets.QApplication.desktop().availableGeometry().width() scroll_widget.setMinimumWidth( min(max_width, message_len * 6) ) From f3c13e7669c149ef4b652820a2f72f4553484ea2 Mon Sep 17 00:00:00 2001 From: iLLiCiTiT Date: Wed, 28 Dec 2022 12:26:25 +0100 Subject: [PATCH 39/42] fix too long line --- openpype/widgets/message_window.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/openpype/widgets/message_window.py b/openpype/widgets/message_window.py index 2b186475ee..a44df2ec8e 100644 --- a/openpype/widgets/message_window.py +++ b/openpype/widgets/message_window.py @@ -113,7 +113,8 @@ class ScrollMessageBox(QtWidgets.QDialog): message_len = max(message_len, len(message)) # guess size of scrollable area - max_width = QtWidgets.QApplication.desktop().availableGeometry().width() + desktop = QtWidgets.QApplication.desktop() + max_width = desktop.availableGeometry().width() scroll_widget.setMinimumWidth( min(max_width, message_len * 6) ) From efab124e0f721e03367710f1800bb6b0a8f9ca1e Mon Sep 17 00:00:00 2001 From: OpenPype Date: Sat, 31 Dec 2022 03:27:31 +0000 Subject: [PATCH 40/42] [Automated] Bump version --- openpype/version.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/openpype/version.py b/openpype/version.py index 40abb9e9fd..4fbe5a3608 100644 --- a/openpype/version.py +++ b/openpype/version.py @@ -1,3 +1,3 @@ # -*- coding: utf-8 -*- """Package declaring Pype version.""" -__version__ = "3.14.10-nightly.4" +__version__ = "3.14.10-nightly.5" From 61ef7479e8bbb842378229e87b2187924a368c7a Mon Sep 17 00:00:00 2001 From: Ondrej Samohel Date: Tue, 3 Jan 2023 17:21:14 +0100 Subject: [PATCH 41/42] =?UTF-8?q?=F0=9F=94=A7=20pass=20mongo=20url=20as=20?= =?UTF-8?q?default?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- openpype/settings/defaults/project_settings/deadline.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/openpype/settings/defaults/project_settings/deadline.json b/openpype/settings/defaults/project_settings/deadline.json index 6e1c0f3540..527f5c0d24 100644 --- a/openpype/settings/defaults/project_settings/deadline.json +++ b/openpype/settings/defaults/project_settings/deadline.json @@ -2,7 +2,7 @@ "deadline_servers": [], "publish": { "CollectDefaultDeadlineServer": { - "pass_mongo_url": false + "pass_mongo_url": true }, "CollectDeadlinePools": { "primary_pool": "", From f1111a99bda950cb79ff36675f12c34146f05ddf Mon Sep 17 00:00:00 2001 From: OpenPype Date: Wed, 4 Jan 2023 03:28:26 +0000 Subject: [PATCH 42/42] [Automated] Bump version --- openpype/version.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/openpype/version.py b/openpype/version.py index 4fbe5a3608..ae514e371e 100644 --- a/openpype/version.py +++ b/openpype/version.py @@ -1,3 +1,3 @@ # -*- coding: utf-8 -*- """Package declaring Pype version.""" -__version__ = "3.14.10-nightly.5" +__version__ = "3.14.10-nightly.6"