Przeglądaj źródła

Merging stabilization/2111RTE -> development, resolved conflicts

Signed-off-by: Chris Galvan <[email protected]>
Chris Galvan 3 lat temu
rodzic
commit
049b33d2df

+ 4 - 5
Code/Tools/ProjectManager/Source/Application.cpp

@@ -198,9 +198,7 @@ namespace O3DE::ProjectManager
             return true;
         }
 
-        bool forceRegistration = false;
-
-        // check if an engine with this name is already registered
+        // check if an engine with this name is already registered and has a valid engine.json
         auto existingEngineResult = m_pythonBindings->GetEngineInfo(engineInfo.m_name);
         if (existingEngineResult)
         {
@@ -232,10 +230,11 @@ namespace O3DE::ProjectManager
                 // user elected not to change the name or force registration
                 return false;
             }
-
-            forceRegistration = true;
         }
 
+        // always force register in case there is an engine registered in o3de_manifest.json, but
+        // the engine.json is missing or corrupt in which case GetEngineInfo() fails
+        constexpr bool forceRegistration = true;
         auto registerOutcome = m_pythonBindings->SetEngineInfo(engineInfo, forceRegistration);
         if (!registerOutcome)
         {

+ 3 - 0
Code/Tools/ProjectManager/Source/PythonBindings.cpp

@@ -459,6 +459,9 @@ namespace O3DE::ProjectManager
             if (!pybind11::isinstance<pybind11::none>(enginePathResult))
             {
                 engineInfo = EngineInfoFromPath(enginePathResult);
+
+                // it is possible an engine is registered in o3de_manifest.json but the engine.json is
+                // missing or corrupt in which case we do not consider it a registered engine
             }
         });
 

+ 17 - 7
Gems/Atom/Feature/Common/Code/Source/Material/MaterialAssignmentSerializer.cpp

@@ -16,7 +16,9 @@ namespace AZ
         AZ_CLASS_ALLOCATOR_IMPL(JsonMaterialAssignmentSerializer, AZ::SystemAllocator, 0);
 
         JsonSerializationResult::Result JsonMaterialAssignmentSerializer::Load(
-            void* outputValue, [[maybe_unused]] const Uuid& outputValueTypeId, const rapidjson::Value& inputValue,
+            void* outputValue,
+            [[maybe_unused]] const Uuid& outputValueTypeId,
+            const rapidjson::Value& inputValue,
             JsonDeserializerContext& context)
         {
             namespace JSR = JsonSerializationResult;
@@ -62,6 +64,7 @@ namespace AZ
                             LoadAny<AZ::Color>(propertyValue, inputPropertyPair.value, context, result) ||
                             LoadAny<AZStd::string>(propertyValue, inputPropertyPair.value, context, result) ||
                             LoadAny<AZ::Data::AssetId>(propertyValue, inputPropertyPair.value, context, result) ||
+                            LoadAny<AZ::Data::Asset<AZ::Data::AssetData>>(propertyValue, inputPropertyPair.value, context, result) ||
                             LoadAny<AZ::Data::Asset<AZ::RPI::ImageAsset>>(propertyValue, inputPropertyPair.value, context, result) ||
                             LoadAny<AZ::Data::Asset<AZ::RPI::StreamingImageAsset>>(propertyValue, inputPropertyPair.value, context, result))
                         {
@@ -78,7 +81,10 @@ namespace AZ
         }
 
         JsonSerializationResult::Result JsonMaterialAssignmentSerializer::Store(
-            rapidjson::Value& outputValue, const void* inputValue, const void* defaultValue, [[maybe_unused]] const Uuid& valueTypeId,
+            rapidjson::Value& outputValue,
+            const void* inputValue,
+            const void* defaultValue,
+            [[maybe_unused]] const Uuid& valueTypeId,
             JsonSerializerContext& context)
         {
             namespace JSR = AZ::JsonSerializationResult;
@@ -138,9 +144,9 @@ namespace AZ
                                 StoreAny<AZ::Color>(propertyValue, outputPropertyValue, context, result) ||
                                 StoreAny<AZStd::string>(propertyValue, outputPropertyValue, context, result) ||
                                 StoreAny<AZ::Data::AssetId>(propertyValue, outputPropertyValue, context, result) ||
+                                StoreAny<AZ::Data::Asset<AZ::Data::AssetData>>(propertyValue, outputPropertyValue, context, result) ||
                                 StoreAny<AZ::Data::Asset<AZ::RPI::ImageAsset>>(propertyValue, outputPropertyValue, context, result) ||
-                                StoreAny<AZ::Data::Asset<AZ::RPI::StreamingImageAsset>>(
-                                    propertyValue, outputPropertyValue, context, result))
+                                StoreAny<AZ::Data::Asset<AZ::RPI::StreamingImageAsset>>(propertyValue, outputPropertyValue, context, result))
                             {
                                 outputPropertyValueContainer.AddMember(
                                     rapidjson::Value::StringRefType(propertyName.GetCStr()), outputPropertyValue,
@@ -164,7 +170,9 @@ namespace AZ
 
         template<typename T>
         bool JsonMaterialAssignmentSerializer::LoadAny(
-            AZStd::any& propertyValue, const rapidjson::Value& inputPropertyValue, AZ::JsonDeserializerContext& context,
+            AZStd::any& propertyValue,
+            const rapidjson::Value& inputPropertyValue,
+            AZ::JsonDeserializerContext& context,
             AZ::JsonSerializationResult::ResultCode& result)
         {
             if (inputPropertyValue.IsObject() && inputPropertyValue.HasMember("Value") && inputPropertyValue.HasMember("$type"))
@@ -187,7 +195,9 @@ namespace AZ
 
         template<typename T>
         bool JsonMaterialAssignmentSerializer::StoreAny(
-            const AZStd::any& propertyValue, rapidjson::Value& outputPropertyValue, AZ::JsonSerializerContext& context,
+            const AZStd::any& propertyValue,
+            rapidjson::Value& outputPropertyValue,
+            AZ::JsonSerializerContext& context,
             AZ::JsonSerializationResult::ResultCode& result)
         {
             if (propertyValue.is<T>())
@@ -199,7 +209,7 @@ namespace AZ
                 result.Combine(StoreTypeId(typeValue, azrtti_typeid<T>(), context));
                 outputPropertyValue.AddMember("$type", typeValue, context.GetJsonAllocator());
 
-                T value = AZStd::any_cast<T>(propertyValue);
+                const T& value = AZStd::any_cast<T>(propertyValue);
                 result.Combine(
                     ContinueStoringToJsonObjectField(outputPropertyValue, "Value", &value, nullptr, azrtti_typeid<T>(), context));
                 return true;

+ 14 - 4
Gems/Atom/Feature/Common/Code/Source/Material/MaterialAssignmentSerializer.h

@@ -25,21 +25,31 @@ namespace AZ
             AZ_CLASS_ALLOCATOR_DECL;
 
             JsonSerializationResult::Result Load(
-                void* outputValue, const Uuid& outputValueTypeId, const rapidjson::Value& inputValue,
+                void* outputValue,
+                const Uuid& outputValueTypeId,
+                const rapidjson::Value& inputValue,
                 JsonDeserializerContext& context) override;
 
             JsonSerializationResult::Result Store(
-                rapidjson::Value& outputValue, const void* inputValue, const void* defaultValue, const Uuid& valueTypeId,
+                rapidjson::Value& outputValue,
+                const void* inputValue,
+                const void* defaultValue,
+                const Uuid& valueTypeId,
                 JsonSerializerContext& context) override;
 
         private:
             template<typename T>
             bool LoadAny(
-                AZStd::any& propertyValue, const rapidjson::Value& inputPropertyValue, AZ::JsonDeserializerContext& context,
+                AZStd::any& propertyValue,
+                const rapidjson::Value& inputPropertyValue,
+                AZ::JsonDeserializerContext& context,
                 AZ::JsonSerializationResult::ResultCode& result);
+
             template<typename T>
             bool StoreAny(
-                const AZStd::any& propertyValue, rapidjson::Value& outputPropertyValue, AZ::JsonSerializerContext& context,
+                const AZStd::any& propertyValue,
+                rapidjson::Value& outputPropertyValue,
+                AZ::JsonSerializerContext& context,
                 AZ::JsonSerializationResult::ResultCode& result);
         };
     } // namespace Render

+ 7 - 5
Gems/Atom/Tools/AtomToolsFramework/Code/Source/Util/MaterialPropertyUtil.cpp

@@ -33,11 +33,13 @@ namespace AtomToolsFramework
     {
         if (value.Is<AZ::Data::Asset<AZ::RPI::ImageAsset>>())
         {
-            const AZ::Data::Asset<AZ::RPI::ImageAsset>& imageAsset = value.GetValue<AZ::Data::Asset<AZ::RPI::ImageAsset>>();
-            return AZStd::any(AZ::Data::Asset<AZ::RPI::StreamingImageAsset>(
-                imageAsset.GetId(),
-                azrtti_typeid<AZ::RPI::StreamingImageAsset>(),
-                imageAsset.GetHint()));
+            const auto& imageAsset = value.GetValue<AZ::Data::Asset<AZ::RPI::ImageAsset>>();
+            return AZStd::any(AZ::Data::Asset<AZ::RPI::StreamingImageAsset>(imageAsset.GetId(), azrtti_typeid<AZ::RPI::StreamingImageAsset>(), imageAsset.GetHint()));
+        }
+        else if (value.Is<AZ::Data::Instance<AZ::RPI::Image>>())
+        {
+            const auto& image = value.GetValue<AZ::Data::Instance<AZ::RPI::Image>>();
+            return AZStd::any(AZ::Data::Asset<AZ::RPI::StreamingImageAsset>(image->GetAssetId(), azrtti_typeid<AZ::RPI::StreamingImageAsset>()));
         }
 
         return AZ::RPI::MaterialPropertyValue::ToAny(value);

+ 33 - 0
Gems/AtomLyIntegration/CommonFeatures/Code/Source/Material/MaterialComponentController.cpp

@@ -104,6 +104,7 @@ namespace AZ
         MaterialComponentController::MaterialComponentController(const MaterialComponentConfig& config)
             : m_configuration(config)
         {
+            ConvertAssetsForSerialization();
         }
 
         void MaterialComponentController::Activate(EntityId entityId)
@@ -135,6 +136,7 @@ namespace AZ
         void MaterialComponentController::SetConfiguration(const MaterialComponentConfig& config)
         {
             m_configuration = config;
+            ConvertAssetsForSerialization();
         }
 
         const MaterialComponentConfig& MaterialComponentController::GetConfiguration() const
@@ -338,6 +340,7 @@ namespace AZ
             // before LoadMaterials() is called [LYN-2249]
             auto temp = m_configuration.m_materials;
             m_configuration.m_materials = materials;
+            ConvertAssetsForSerialization();
             LoadMaterials();
         }
 
@@ -489,6 +492,7 @@ namespace AZ
             auto& materialAssignment = m_configuration.m_materials[materialAssignmentId];
             const bool wasEmpty = materialAssignment.m_propertyOverrides.empty();
             materialAssignment.m_propertyOverrides[AZ::Name(propertyName)] = value;
+            ConvertAssetsForSerialization();
 
             if (materialAssignment.RequiresLoading())
             {
@@ -586,6 +590,7 @@ namespace AZ
             auto& materialAssignment = m_configuration.m_materials[materialAssignmentId];
             const bool wasEmpty = materialAssignment.m_propertyOverrides.empty();
             materialAssignment.m_propertyOverrides = propertyOverrides;
+            ConvertAssetsForSerialization();
 
             if (materialAssignment.RequiresLoading())
             {
@@ -667,5 +672,33 @@ namespace AZ
                 TickBus::Handler::BusConnect();
             }
         }
+
+        void MaterialComponentController::ConvertAssetsForSerialization()
+        {
+            for (auto& materialAssignmentPair : m_configuration.m_materials)
+            {
+                MaterialAssignment& materialAssignment = materialAssignmentPair.second;
+                for (auto& propertyPair : materialAssignment.m_propertyOverrides)
+                {
+                    auto& value = propertyPair.second;
+                    if (value.is<AZ::Data::Asset<AZ::Data::AssetData>>())
+                    {
+                        value = AZStd::any_cast<AZ::Data::Asset<AZ::Data::AssetData>>(value).GetId();
+                    }
+                    else if (value.is<AZ::Data::Asset<AZ::RPI::StreamingImageAsset>>())
+                    {
+                        value = AZStd::any_cast<AZ::Data::Asset<AZ::RPI::StreamingImageAsset>>(value).GetId();
+                    }
+                    else if (value.is<AZ::Data::Asset<AZ::RPI::ImageAsset>>())
+                    {
+                        value = AZStd::any_cast<AZ::Data::Asset<AZ::RPI::ImageAsset>>(value).GetId();
+                    }
+                    else if (value.is<AZ::Data::Instance<AZ::RPI::Image>>())
+                    {
+                        value = AZStd::any_cast<AZ::Data::Instance<AZ::RPI::Image>>(value)->GetAssetId();
+                    }
+                }
+            }
+        }
     } // namespace Render
 } // namespace AZ

+ 5 - 0
Gems/AtomLyIntegration/CommonFeatures/Code/Source/Material/MaterialComponentController.h

@@ -99,6 +99,11 @@ namespace AZ
             //! Queue material instance recreation notifiucations until tick
             void QueueMaterialUpdateNotification();
 
+            //! Converts property overrides storing image asset references into asset IDs. This addresses a problem where image property
+            //! overrides are lost during prefab serialization and patching. This suboptimal function will be removed once the underlying
+            //! problem is resolved.
+            void ConvertAssetsForSerialization();
+
             EntityId m_entityId;
             MaterialComponentConfig m_configuration;
             AZStd::unordered_set<MaterialAssignmentId> m_materialsWithDirtyProperties;

+ 49 - 37
scripts/o3de/o3de/manifest.py

@@ -644,7 +644,7 @@ def get_registered(engine_name: str = None,
                     except json.JSONDecodeError as e:
                         logger.warning(f'{engine_json} failed to load: {str(e)}')
                     else:
-                        this_engines_name = engine_json_data['engine_name']
+                        this_engines_name = engine_json_data.get('engine_name','')
                         if this_engines_name == engine_name:
                             return engine_path
         engines_path = json_data.get('engines_path', {})
@@ -656,60 +656,72 @@ def get_registered(engine_name: str = None,
         for project_path in projects:
             project_path = pathlib.Path(project_path).resolve()
             project_json = project_path / 'project.json'
-            with project_json.open('r') as f:
-                try:
-                    project_json_data = json.load(f)
-                except json.JSONDecodeError as e:
-                    logger.warning(f'{project_json} failed to load: {str(e)}')
-                else:
-                    this_projects_name = project_json_data['project_name']
-                    if this_projects_name == project_name:
-                        return project_path
+            if not pathlib.Path(project_json).is_file():
+                logger.warning(f'{project_json} does not exist')
+            else:
+                with project_json.open('r') as f:
+                    try:
+                        project_json_data = json.load(f)
+                    except json.JSONDecodeError as e:
+                        logger.warning(f'{project_json} failed to load: {str(e)}')
+                    else:
+                        this_projects_name = project_json_data['project_name']
+                        if this_projects_name == project_name:
+                            return project_path
 
     elif isinstance(gem_name, str):
         gems = get_all_gems(project_path)
         for gem_path in gems:
             gem_path = pathlib.Path(gem_path).resolve()
             gem_json = gem_path / 'gem.json'
-            with gem_json.open('r') as f:
-                try:
-                    gem_json_data = json.load(f)
-                except json.JSONDecodeError as e:
-                    logger.warning(f'{gem_json} failed to load: {str(e)}')
-                else:
-                    this_gems_name = gem_json_data['gem_name']
-                    if this_gems_name == gem_name:
-                        return gem_path
+            if not pathlib.Path(gem_json).is_file():
+                logger.warning(f'{gem_json} does not exist')
+            else:
+                with gem_json.open('r') as f:
+                    try:
+                        gem_json_data = json.load(f)
+                    except json.JSONDecodeError as e:
+                        logger.warning(f'{gem_json} failed to load: {str(e)}')
+                    else:
+                        this_gems_name = gem_json_data['gem_name']
+                        if this_gems_name == gem_name:
+                            return gem_path
 
     elif isinstance(template_name, str):
         templates = get_all_templates(project_path)
         for template_path in templates:
             template_path = pathlib.Path(template_path).resolve()
             template_json = template_path / 'template.json'
-            with template_json.open('r') as f:
-                try:
-                    template_json_data = json.load(f)
-                except json.JSONDecodeError as e:
-                    logger.warning(f'{template_path} failed to load: {str(e)}')
-                else:
-                    this_templates_name = template_json_data['template_name']
-                    if this_templates_name == template_name:
-                        return template_path
+            if not pathlib.Path(template_json).is_file():
+                logger.warning(f'{template_json} does not exist')
+            else:
+                with template_json.open('r') as f:
+                    try:
+                        template_json_data = json.load(f)
+                    except json.JSONDecodeError as e:
+                        logger.warning(f'{template_path} failed to load: {str(e)}')
+                    else:
+                        this_templates_name = template_json_data['template_name']
+                        if this_templates_name == template_name:
+                            return template_path
 
     elif isinstance(restricted_name, str):
         restricted = get_manifest_restricted()
         for restricted_path in restricted:
             restricted_path = pathlib.Path(restricted_path).resolve()
             restricted_json = restricted_path / 'restricted.json'
-            with restricted_json.open('r') as f:
-                try:
-                    restricted_json_data = json.load(f)
-                except json.JSONDecodeError as e:
-                    logger.warning(f'{restricted_json} failed to load: {str(e)}')
-                else:
-                    this_restricted_name = restricted_json_data['restricted_name']
-                    if this_restricted_name == restricted_name:
-                        return restricted_path
+            if not pathlib.Path(restricted_json).is_file():
+                logger.warning(f'{restricted_json} does not exist')
+            else:
+                with restricted_json.open('r') as f:
+                    try:
+                        restricted_json_data = json.load(f)
+                    except json.JSONDecodeError as e:
+                        logger.warning(f'{restricted_json} failed to load: {str(e)}')
+                    else:
+                        this_restricted_name = restricted_json_data['restricted_name']
+                        if this_restricted_name == restricted_name:
+                            return restricted_path
 
     elif isinstance(default_folder, str):
         if default_folder == 'engines':