diff --git a/AutomatedTesting/Gem/PythonTests/Atom/atom_utils/atom_constants.py b/AutomatedTesting/Gem/PythonTests/Atom/atom_utils/atom_constants.py index 0f13dd6b20..6525536f96 100644 --- a/AutomatedTesting/Gem/PythonTests/Atom/atom_utils/atom_constants.py +++ b/AutomatedTesting/Gem/PythonTests/Atom/atom_utils/atom_constants.py @@ -248,12 +248,14 @@ class AtomComponentProperties: def grid(property: str = 'name') -> str: """ Grid component properties. + - 'Grid Size': The size of the grid, default value is 32 - 'Secondary Grid Spacing': The spacing value for the secondary grid, i.e. 1.0 :param property: From the last element of the property tree path. Default 'name' for component name string. :return: Full property path OR component name if no property specified. """ properties = { 'name': 'Grid', + 'Grid Size': 'Controller|Configuration|Grid Size', 'Secondary Grid Spacing': 'Controller|Configuration|Secondary Grid Spacing', } return properties[property] @@ -384,11 +386,13 @@ class AtomComponentProperties: def physical_sky(property: str = 'name') -> str: """ Physical Sky component properties. + - 'Sky Intensity' float that determines sky intensity value, default value is 4. :param property: From the last element of the property tree path. Default 'name' for component name string. :return: Full property path OR component name if no property specified. """ properties = { 'name': 'Physical Sky', + 'Sky Intensity': 'Controller|Configuration|Sky Intensity', } return properties[property] diff --git a/AutomatedTesting/Gem/PythonTests/Atom/atom_utils/material_editor_utils.py b/AutomatedTesting/Gem/PythonTests/Atom/atom_utils/material_editor_utils.py index 96eeb4279e..c3c1c76611 100644 --- a/AutomatedTesting/Gem/PythonTests/Atom/atom_utils/material_editor_utils.py +++ b/AutomatedTesting/Gem/PythonTests/Atom/atom_utils/material_editor_utils.py @@ -114,11 +114,11 @@ def get_property(document_id, property_name): """ :return: property value or invalid value if the document is not open or the property_name can't be found """ - return azlmbr.atomtools.AtomToolsDocumentRequestBus(bus.Event, "GetPropertyValue", document_id, property_name) + return azlmbr.materialeditor.MaterialDocumentRequestBus(bus.Event, "GetPropertyValue", document_id, property_name) def set_property(document_id, property_name, value): - azlmbr.atomtools.AtomToolsDocumentRequestBus(bus.Event, "SetPropertyValue", document_id, property_name, value) + azlmbr.materialeditor.MaterialDocumentRequestBus(bus.Event, "SetPropertyValue", document_id, property_name, value) def is_pane_visible(pane_name): diff --git a/AutomatedTesting/Gem/PythonTests/Atom/tests/hydra_AtomEditorComponents_GridAdded.py b/AutomatedTesting/Gem/PythonTests/Atom/tests/hydra_AtomEditorComponents_GridAdded.py index 3c6d261f22..3a58ec80b1 100644 --- a/AutomatedTesting/Gem/PythonTests/Atom/tests/hydra_AtomEditorComponents_GridAdded.py +++ b/AutomatedTesting/Gem/PythonTests/Atom/tests/hydra_AtomEditorComponents_GridAdded.py @@ -18,6 +18,9 @@ class Tests: grid_component_added = ( "Entity has a Grid component", "Entity failed to find Grid component") + grid_size = ( + "Grid Size value set successfully", + "Grid Size value could not be set") enter_game_mode = ( "Entered game mode", "Failed to enter game mode") @@ -59,13 +62,14 @@ def AtomEditorComponents_Grid_AddedToEntity(): 2) Add a Grid component to Grid entity. 3) UNDO the entity creation and component addition. 4) REDO the entity creation and component addition. - 5) Enter/Exit game mode. - 6) Test IsHidden. - 7) Test IsVisible. - 8) Delete Grid entity. - 9) UNDO deletion. - 10) REDO deletion. - 11) Look for errors. + 5) Grid Size changed. + 6) Enter/Exit game mode. + 7) Test IsHidden. + 8) Test IsVisible. + 9) Delete Grid entity. + 10) UNDO deletion. + 11) REDO deletion. + 12) Look for errors. :return: None """ @@ -119,35 +123,42 @@ def AtomEditorComponents_Grid_AddedToEntity(): general.idle_wait_frames(1) Report.result(Tests.creation_redo, grid_entity.exists()) - # 5. Enter/Exit game mode. + # 5. Grid Size changed + grid_component.set_component_property_value( + AtomComponentProperties.grid('Grid Size'), value=64) + current_grid_size = grid_component.get_component_property_value( + AtomComponentProperties.grid('Grid Size')) + Report.result(Tests.grid_size, current_grid_size == 64) + + # 6. Enter/Exit game mode. TestHelper.enter_game_mode(Tests.enter_game_mode) general.idle_wait_frames(1) TestHelper.exit_game_mode(Tests.exit_game_mode) - # 6. Test IsHidden. + # 7. Test IsHidden. grid_entity.set_visibility_state(False) Report.result(Tests.is_hidden, grid_entity.is_hidden() is True) - # 7. Test IsVisible. + # 8. Test IsVisible. grid_entity.set_visibility_state(True) general.idle_wait_frames(1) Report.result(Tests.is_visible, grid_entity.is_visible() is True) - # 8. Delete Grid entity. + # 9. Delete Grid entity. grid_entity.delete() Report.result(Tests.entity_deleted, not grid_entity.exists()) - # 9. UNDO deletion. + # 10. UNDO deletion. general.undo() general.idle_wait_frames(1) Report.result(Tests.deletion_undo, grid_entity.exists()) - # 10. REDO deletion. + # 11. REDO deletion. general.redo() general.idle_wait_frames(1) Report.result(Tests.deletion_redo, not grid_entity.exists()) - # 11. Look for errors or asserts. + # 12. Look for errors or asserts. TestHelper.wait_for_condition(lambda: error_tracer.has_errors or error_tracer.has_asserts, 1.0) for error_info in error_tracer.errors: Report.info(f"Error: {error_info.filename} {error_info.function} | {error_info.message}") diff --git a/AutomatedTesting/Gem/PythonTests/Atom/tests/hydra_AtomEditorComponents_LightAdded.py b/AutomatedTesting/Gem/PythonTests/Atom/tests/hydra_AtomEditorComponents_LightAdded.py index 75a04612a3..d036147eb7 100644 --- a/AutomatedTesting/Gem/PythonTests/Atom/tests/hydra_AtomEditorComponents_LightAdded.py +++ b/AutomatedTesting/Gem/PythonTests/Atom/tests/hydra_AtomEditorComponents_LightAdded.py @@ -68,13 +68,14 @@ def AtomEditorComponents_Light_AddedToEntity(): 2) Add Light component to the Light entity. 3) UNDO the entity creation and component addition. 4) REDO the entity creation and component addition. - 5) Enter/Exit game mode. - 6) Test IsHidden. - 7) Test IsVisible. - 8) Delete Light entity. - 9) UNDO deletion. - 10) REDO deletion. - 11) Look for errors. + 5) Cycle through all light types. + 6) Enter/Exit game mode. + 7) Test IsHidden. + 8) Test IsVisible. + 9) Delete Light entity. + 10) UNDO deletion. + 11) REDO deletion. + 12) Look for errors. :return: None """ @@ -83,7 +84,7 @@ def AtomEditorComponents_Light_AddedToEntity(): from editor_python_test_tools.editor_entity_utils import EditorEntity from editor_python_test_tools.utils import Report, Tracer, TestHelper - from Atom.atom_utils.atom_constants import AtomComponentProperties + from Atom.atom_utils.atom_constants import AtomComponentProperties, LIGHT_TYPES with Tracer() as error_tracer: # Test setup begins. @@ -124,35 +125,46 @@ def AtomEditorComponents_Light_AddedToEntity(): general.idle_wait_frames(1) Report.result(Tests.creation_redo, light_entity.exists()) - # 5. Enter/Exit game mode. + # 5. Cycle through all light types. + for light_type in LIGHT_TYPES.keys(): + light_component.set_component_property_value( + AtomComponentProperties.light('Light type'), LIGHT_TYPES[light_type]) + current_light_type = light_component.get_component_property_value( + AtomComponentProperties.light('Light type')) + test_light_type = ( + f"Light component has {light_type} type set", + f"Light component failed to set {light_type} type") + Report.result(test_light_type, current_light_type == LIGHT_TYPES[light_type]) + + # 6. Enter/Exit game mode. TestHelper.enter_game_mode(Tests.enter_game_mode) general.idle_wait_frames(1) TestHelper.exit_game_mode(Tests.exit_game_mode) - # 6. Test IsHidden. + # 7. Test IsHidden. light_entity.set_visibility_state(False) Report.result(Tests.is_hidden, light_entity.is_hidden() is True) - # 7. Test IsVisible. + # 8. Test IsVisible. light_entity.set_visibility_state(True) general.idle_wait_frames(1) Report.result(Tests.is_visible, light_entity.is_visible() is True) - # 8. Delete Light entity. + # 9. Delete Light entity. light_entity.delete() Report.result(Tests.entity_deleted, not light_entity.exists()) - # 9. UNDO deletion. + # 10. UNDO deletion. general.undo() general.idle_wait_frames(1) Report.result(Tests.deletion_undo, light_entity.exists()) - # 10. REDO deletion. + # 11. REDO deletion. general.redo() general.idle_wait_frames(1) Report.result(Tests.deletion_redo, not light_entity.exists()) - # 11. Look for errors asserts. + # 12. Look for errors asserts. TestHelper.wait_for_condition(lambda: error_tracer.has_errors or error_tracer.has_asserts, 1.0) for error_info in error_tracer.errors: Report.info(f"Error: {error_info.filename} {error_info.function} | {error_info.message}") diff --git a/AutomatedTesting/Gem/PythonTests/Atom/tests/hydra_AtomEditorComponents_PhysicalSkyAdded.py b/AutomatedTesting/Gem/PythonTests/Atom/tests/hydra_AtomEditorComponents_PhysicalSkyAdded.py index e0c558811e..1970e38d83 100644 --- a/AutomatedTesting/Gem/PythonTests/Atom/tests/hydra_AtomEditorComponents_PhysicalSkyAdded.py +++ b/AutomatedTesting/Gem/PythonTests/Atom/tests/hydra_AtomEditorComponents_PhysicalSkyAdded.py @@ -27,6 +27,9 @@ class Tests: physical_sky_component = ( "Entity has a Physical Sky component", "Entity failed to find Physical Sky component") + sky_intensity = ( + "Sky Intensity value updated successfully", + "Sky Intensity value could not be set") enter_game_mode = ( "Entered game mode", "Failed to enter game mode") @@ -68,13 +71,14 @@ def AtomEditorComponents_PhysicalSky_AddedToEntity(): 2) Add Physical Sky component to Physical Sky entity. 3) UNDO the entity creation and component addition. 4) REDO the entity creation and component addition. - 5) Enter/Exit game mode. - 6) Test IsHidden. - 7) Test IsVisible. - 8) Delete Physical Sky entity. - 9) UNDO deletion. - 10) REDO deletion. - 11) Look for errors and asserts. + 5) Update Sky Intensity value. + 6) Enter/Exit game mode. + 7) Test IsHidden. + 8) Test IsVisible. + 9) Delete Physical Sky entity. + 10) UNDO deletion. + 11) REDO deletion. + 12) Look for errors and asserts. :return: None """ @@ -126,35 +130,42 @@ def AtomEditorComponents_PhysicalSky_AddedToEntity(): general.idle_wait_frames(1) Report.result(Tests.creation_redo, physical_sky_entity.exists()) - # 5. Enter/Exit game mode. + # 5. Set Sky Intensity value + physical_sky_component.set_component_property_value( + AtomComponentProperties.physical_sky('Sky Intensity'), value=2) + current_sky_intensity = physical_sky_component.get_component_property_value( + AtomComponentProperties.physical_sky('Sky Intensity')) + Report.result(Tests.sky_intensity, current_sky_intensity == 2) + + # 6. Enter/Exit game mode. TestHelper.enter_game_mode(Tests.enter_game_mode) general.idle_wait_frames(1) TestHelper.exit_game_mode(Tests.exit_game_mode) - # 6. Test IsHidden. + # 7. Test IsHidden. physical_sky_entity.set_visibility_state(False) Report.result(Tests.is_hidden, physical_sky_entity.is_hidden() is True) - # 7. Test IsVisible. + # 8. Test IsVisible. physical_sky_entity.set_visibility_state(True) general.idle_wait_frames(1) Report.result(Tests.is_visible, physical_sky_entity.is_visible() is True) - # 8. Delete Physical Sky entity. + # 9. Delete Physical Sky entity. physical_sky_entity.delete() Report.result(Tests.entity_deleted, not physical_sky_entity.exists()) - # 9. UNDO deletion. + # 10. UNDO deletion. general.undo() general.idle_wait_frames(1) Report.result(Tests.deletion_undo, physical_sky_entity.exists()) - # 10. REDO deletion. + # 11. REDO deletion. general.redo() general.idle_wait_frames(1) Report.result(Tests.deletion_redo, not physical_sky_entity.exists()) - # 11. Look for errors and asserts. + # 12. Look for errors and asserts. TestHelper.wait_for_condition(lambda: error_tracer.has_errors or error_tracer.has_asserts, 1.0) for error_info in error_tracer.errors: Report.info(f"Error: {error_info.filename} {error_info.function} | {error_info.message}") diff --git a/Code/Framework/AzFramework/AzFramework/azframework_files.cmake b/Code/Framework/AzFramework/AzFramework/azframework_files.cmake index 9693d75b06..4b45880c56 100644 --- a/Code/Framework/AzFramework/AzFramework/azframework_files.cmake +++ b/Code/Framework/AzFramework/AzFramework/azframework_files.cmake @@ -165,10 +165,6 @@ set(FILES Logging/MissingAssetLogger.cpp Logging/MissingAssetLogger.h Logging/MissingAssetNotificationBus.h - Matchmaking/IMatchmakingRequests.h - Matchmaking/MatchmakingRequests.cpp - Matchmaking/MatchmakingRequests.h - Matchmaking/MatchmakingNotifications.h Scene/Scene.h Scene/Scene.inl Scene/Scene.cpp @@ -182,13 +178,6 @@ set(FILES Script/ScriptDebugMsgReflection.h Script/ScriptRemoteDebugging.cpp Script/ScriptRemoteDebugging.h - Session/ISessionHandlingRequests.h - Session/ISessionRequests.h - Session/SessionRequests.cpp - Session/SessionRequests.h - Session/SessionConfig.cpp - Session/SessionConfig.h - Session/SessionNotifications.h StreamingInstall/StreamingInstall.h StreamingInstall/StreamingInstall.cpp StreamingInstall/StreamingInstallRequests.h diff --git a/Code/Framework/AzToolsFramework/AzToolsFramework/Entity/PrefabEditorEntityOwnershipInterface.h b/Code/Framework/AzToolsFramework/AzToolsFramework/Entity/PrefabEditorEntityOwnershipInterface.h index da318c98ba..2ad5308528 100644 --- a/Code/Framework/AzToolsFramework/AzToolsFramework/Entity/PrefabEditorEntityOwnershipInterface.h +++ b/Code/Framework/AzToolsFramework/AzToolsFramework/Entity/PrefabEditorEntityOwnershipInterface.h @@ -19,45 +19,69 @@ namespace AzToolsFramework { + namespace Prefab + { + //! A RootAliasPath can be used to store an alias path that starts from the Prefab EOS root instance. + //! The root instance itself is included in the path. These can be used as Instance handles across systems + //! that do not have visibility over InstanceOptionalReferences, or that need to store Instance handles + //! for longer than just the span of a function without the risk of them going out of scope. + using RootAliasPath = AliasPath; + } class PrefabEditorEntityOwnershipInterface { public: - AZ_RTTI(PrefabEditorEntityOwnershipInterface,"{38E764BA-A089-49F3-848F-46018822CE2E}"); + AZ_RTTI(PrefabEditorEntityOwnershipInterface, "{38E764BA-A089-49F3-848F-46018822CE2E}"); + + //! Returns whether the system has a root instance assigned. + //! @return True if a root prefab is assigned, false otherwise. + virtual bool IsRootPrefabAssigned() const = 0; + + //! Returns an optional reference to the root prefab instance. + virtual Prefab::InstanceOptionalReference GetRootPrefabInstance() = 0; + + //! Returns the template id for the root prefab instance. + virtual Prefab::TemplateId GetRootPrefabTemplateId() = 0; + + virtual void CreateNewLevelPrefab(AZStd::string_view filename, const AZStd::string& templateFilename) = 0; //! Creates a prefab instance with the provided entities and nestedPrefabInstances. - //! /param entities The entities to put under the new prefab. - //! /param nestedPrefabInstances The nested prefab instances to put under the new prefab. - //! /param filePath The filepath corresponding to the prefab file to be created. - //! /param instanceToParentUnder The instance the newly created prefab instance is parented under. - //! /return The optional reference to the prefab created. + //! @param entities The entities to put under the new prefab. + //! @param nestedPrefabInstances The nested prefab instances to put under the new prefab. + //! @param filePath The filepath corresponding to the prefab file to be created. + //! @param instanceToParentUnder The instance the newly created prefab instance is parented under. + //! @return The optional reference to the prefab created. virtual Prefab::InstanceOptionalReference CreatePrefab( const AZStd::vector& entities, AZStd::vector>&& nestedPrefabInstances, AZ::IO::PathView filePath, Prefab::InstanceOptionalReference instanceToParentUnder = AZStd::nullopt) = 0; //! Instantiate the prefab file provided. - //! /param filePath The filepath for the prefab file the instance should be created from. - //! /param instanceToParentUnder The instance the newly instantiated prefab instance is parented under. - //! /return The optional reference to the prefab instance. + //! @param filePath The filepath for the prefab file the instance should be created from. + //! @param instanceToParentUnder The instance the newly instantiated prefab instance is parented under. + //! @return The optional reference to the prefab instance. virtual Prefab::InstanceOptionalReference InstantiatePrefab( AZ::IO::PathView filePath, Prefab::InstanceOptionalReference instanceToParentUnder = AZStd::nullopt) = 0; - virtual Prefab::InstanceOptionalReference GetRootPrefabInstance() = 0; - - virtual Prefab::TemplateId GetRootPrefabTemplateId() = 0; + virtual void StartPlayInEditor() = 0; + virtual void StopPlayInEditor() = 0; //! Get all Assets generated by Prefab processing when entering Play-In Editor mode (Ctrl+G) - //! /return The vector of Assets generated by Prefab processing + //! @return The vector of Assets generated by Prefab processing virtual const Prefab::PrefabConversionUtils::InMemorySpawnableAssetContainer::SpawnableAssets& GetPlayInEditorAssetData() const = 0; virtual bool LoadFromStream(AZ::IO::GenericStream& stream, AZStd::string_view filename) = 0; virtual bool SaveToStream(AZ::IO::GenericStream& stream, AZStd::string_view filename) = 0; - - virtual void StartPlayInEditor() = 0; - virtual void StopPlayInEditor() = 0; - virtual void CreateNewLevelPrefab(AZStd::string_view filename, const AZStd::string& templateFilename) = 0; + //! Returns the reference to the instance corresponding to the RootAliasPath provided. + //! @param rootAliasPath The RootAliasPath to be queried. + //! @return A reference to the instance if valid, AZStd::nullopt otherwise. + virtual Prefab::InstanceOptionalReference GetInstanceReferenceFromRootAliasPath(Prefab::RootAliasPath rootAliasPath) const = 0; - virtual bool IsRootPrefabAssigned() const = 0; + //! Allows to iterate through all instances referenced in the path, from the root down. + //! @param rootAliasPath The RootAliasPath to iterate through. If invalid, callback will not be called. + //! @param callback The function to call on each instance. If it returns true, it prevents the rest of the path from being called. + //! @return True if the iteration was halted by a callback returning true, false otherwise. Also returns false if the path is invalid. + virtual bool GetInstancesInRootAliasPath( + Prefab::RootAliasPath rootAliasPath, const AZStd::function& callback) const = 0; }; } diff --git a/Code/Framework/AzToolsFramework/AzToolsFramework/Entity/PrefabEditorEntityOwnershipService.cpp b/Code/Framework/AzToolsFramework/AzToolsFramework/Entity/PrefabEditorEntityOwnershipService.cpp index 4a1198fdfe..f6bdfb0922 100644 --- a/Code/Framework/AzToolsFramework/AzToolsFramework/Entity/PrefabEditorEntityOwnershipService.cpp +++ b/Code/Framework/AzToolsFramework/AzToolsFramework/Entity/PrefabEditorEntityOwnershipService.cpp @@ -510,6 +510,70 @@ namespace AzToolsFramework m_playInEditorData.m_isEnabled = false; } + bool PrefabEditorEntityOwnershipService::IsValidRootAliasPath(Prefab::RootAliasPath rootAliasPath) const + { + return GetInstanceReferenceFromRootAliasPath(rootAliasPath) != AZStd::nullopt; + } + + Prefab::InstanceOptionalReference PrefabEditorEntityOwnershipService::GetInstanceReferenceFromRootAliasPath( + Prefab::RootAliasPath rootAliasPath) const + { + Prefab::InstanceOptionalReference instance = *m_rootInstance; + + for (const auto& pathElement : rootAliasPath) + { + if (pathElement.Native() == rootAliasPath.begin()->Native()) + { + // If the root is not the root Instance, the rootAliasPath is invalid. + if (pathElement.Native() != instance->get().GetInstanceAlias()) + { + return Prefab::InstanceOptionalReference(); + } + } + else + { + // If the instance alias can't be found, the rootAliasPath is invalid. + instance = instance->get().FindNestedInstance(pathElement.Native()); + if (!instance.has_value()) + { + return Prefab::InstanceOptionalReference(); + } + } + } + + return instance; + } + + bool PrefabEditorEntityOwnershipService::GetInstancesInRootAliasPath( + Prefab::RootAliasPath rootAliasPath, const AZStd::function& callback) const + { + if (!IsValidRootAliasPath(rootAliasPath)) + { + return false; + } + + Prefab::InstanceOptionalReference instance; + + for (const auto& pathElement : rootAliasPath) + { + if (!instance.has_value()) + { + instance = *m_rootInstance; + } + else + { + instance = instance->get().FindNestedInstance(pathElement.Native()); + } + + if(callback(instance)) + { + return true; + } + } + + return false; + } + ////////////////////////////////////////////////////////////////////////// // Slice Buses implementation with Assert(false), this will exist only during Slice->Prefab // development to pinpoint and replace specific calls to Slice system diff --git a/Code/Framework/AzToolsFramework/AzToolsFramework/Entity/PrefabEditorEntityOwnershipService.h b/Code/Framework/AzToolsFramework/AzToolsFramework/Entity/PrefabEditorEntityOwnershipService.h index 50890ffbeb..2d3db0ea72 100644 --- a/Code/Framework/AzToolsFramework/AzToolsFramework/Entity/PrefabEditorEntityOwnershipService.h +++ b/Code/Framework/AzToolsFramework/AzToolsFramework/Entity/PrefabEditorEntityOwnershipService.h @@ -169,11 +169,17 @@ namespace AzToolsFramework void CreateNewLevelPrefab(AZStd::string_view filename, const AZStd::string& templateFilename) override; bool IsRootPrefabAssigned() const override; + Prefab::InstanceOptionalReference GetInstanceReferenceFromRootAliasPath(Prefab::RootAliasPath rootAliasPath) const override; + bool GetInstancesInRootAliasPath( + Prefab::RootAliasPath rootAliasPath, const AZStd::function& callback) const override; + protected: AZ::SliceComponent::SliceInstanceAddress GetOwningSlice() override; private: + bool IsValidRootAliasPath(Prefab::RootAliasPath rootAliasPath) const; + struct PlayInEditorData { AzToolsFramework::Prefab::PrefabConversionUtils::InMemorySpawnableAssetContainer m_assetsCache; diff --git a/Code/Framework/AzToolsFramework/AzToolsFramework/Prefab/Instance/Instance.h b/Code/Framework/AzToolsFramework/AzToolsFramework/Prefab/Instance/Instance.h index 77ad526979..ebc75dc5cf 100644 --- a/Code/Framework/AzToolsFramework/AzToolsFramework/Prefab/Instance/Instance.h +++ b/Code/Framework/AzToolsFramework/AzToolsFramework/Prefab/Instance/Instance.h @@ -37,7 +37,6 @@ namespace AzToolsFramework using AliasPath = AZ::IO::Path; using AliasPathView = AZ::IO::PathView; - using RootAliasPath = AliasPath; using EntityAlias = AZStd::string; using EntityAliasView = AZStd::string_view; using InstanceAlias = AZStd::string; diff --git a/Code/Framework/AzToolsFramework/AzToolsFramework/Prefab/PrefabFocusHandler.cpp b/Code/Framework/AzToolsFramework/AzToolsFramework/Prefab/PrefabFocusHandler.cpp index d8a89109ef..c7e37258f2 100644 --- a/Code/Framework/AzToolsFramework/AzToolsFramework/Prefab/PrefabFocusHandler.cpp +++ b/Code/Framework/AzToolsFramework/AzToolsFramework/Prefab/PrefabFocusHandler.cpp @@ -11,7 +11,6 @@ #include #include #include -#include #include #include #include @@ -112,15 +111,24 @@ namespace AzToolsFramework::Prefab [[maybe_unused]] AzFramework::EntityContextId entityContextId) { // If only one instance is in the hierarchy, this operation is invalid - size_t hierarchySize = m_instanceFocusHierarchy.size(); - if (hierarchySize <= 1) + if (m_rootAliasFocusPathLength <= 1) { - return AZ::Failure( - AZStd::string("Prefab Focus Handler: Could not complete FocusOnParentOfFocusedPrefab operation while focusing on the root.")); + return AZ::Failure(AZStd::string( + "Prefab Focus Handler: Could not complete FocusOnParentOfFocusedPrefab operation while focusing on the root.")); } + RootAliasPath parentPath = m_rootAliasFocusPath; + parentPath.RemoveFilename(); + // Retrieve parent of currently focused prefab. - InstanceOptionalReference parentInstance = GetInstanceReferenceFromRootAliasPath(m_instanceFocusHierarchy[hierarchySize - 2]); + InstanceOptionalReference parentInstance = GetInstanceReference(parentPath); + + // If only one instance is in the hierarchy, this operation is invalid + if (!parentInstance.has_value()) + { + return AZ::Failure(AZStd::string( + "Prefab Focus Handler: Could not retrieve parent of current focus in FocusOnParentOfFocusedPrefab.")); + } // Use container entity of parent Instance for focus operations. AZ::EntityId entityId = parentInstance->get().GetContainerEntityId(); @@ -149,12 +157,26 @@ namespace AzToolsFramework::Prefab PrefabFocusOperationResult PrefabFocusHandler::FocusOnPathIndex([[maybe_unused]] AzFramework::EntityContextId entityContextId, int index) { - if (index < 0 || index >= m_instanceFocusHierarchy.size()) + if (index < 0 || index >= m_rootAliasFocusPathLength) { return AZ::Failure(AZStd::string("Prefab Focus Handler: Invalid index on FocusOnPathIndex.")); } - InstanceOptionalReference focusedInstance = GetInstanceReferenceFromRootAliasPath(m_instanceFocusHierarchy[index]); + int i = 0; + RootAliasPath indexedPath; + for (const auto& pathElement : m_rootAliasFocusPath) + { + indexedPath.Append(pathElement); + + if (i == index) + { + break; + } + + ++i; + } + + InstanceOptionalReference focusedInstance = GetInstanceReference(indexedPath); if (!focusedInstance.has_value()) { @@ -197,13 +219,14 @@ namespace AzToolsFramework::Prefab } // Close all container entities in the old path. - SetInstanceContainersOpenState(m_instanceFocusHierarchy, false); + SetInstanceContainersOpenState(m_rootAliasFocusPath, false); - const RootAliasPath previousContainerRootAliasPath = m_focusedInstanceRootAliasPath; - const InstanceOptionalConstReference previousFocusedInstance = GetInstanceReferenceFromRootAliasPath(previousContainerRootAliasPath); + const RootAliasPath previousContainerRootAliasPath = m_rootAliasFocusPath; + const InstanceOptionalConstReference previousFocusedInstance = GetInstanceReference(previousContainerRootAliasPath); - m_focusedInstanceRootAliasPath = focusedInstance->get().GetAbsoluteInstanceAliasPath(); + m_rootAliasFocusPath = focusedInstance->get().GetAbsoluteInstanceAliasPath(); m_focusedTemplateId = focusedInstance->get().GetTemplateId(); + m_rootAliasFocusPathLength = aznumeric_cast(AZStd::distance(m_rootAliasFocusPath.begin(), m_rootAliasFocusPath.end())); // Focus on the descendants of the container entity in the Editor, if the interface is initialized. if (m_focusModeInterface) @@ -231,11 +254,10 @@ namespace AzToolsFramework::Prefab } // Refresh path variables. - RefreshInstanceFocusList(); RefreshInstanceFocusPath(); // Open all container entities in the new path. - SetInstanceContainersOpenState(m_instanceFocusHierarchy, true); + SetInstanceContainersOpenState(m_rootAliasFocusPath, true); PrefabFocusNotificationBus::Broadcast(&PrefabFocusNotifications::OnPrefabFocusChanged); @@ -250,12 +272,12 @@ namespace AzToolsFramework::Prefab InstanceOptionalReference PrefabFocusHandler::GetFocusedPrefabInstance( [[maybe_unused]] AzFramework::EntityContextId entityContextId) const { - return GetInstanceReferenceFromRootAliasPath(m_focusedInstanceRootAliasPath); + return GetInstanceReference(m_rootAliasFocusPath); } AZ::EntityId PrefabFocusHandler::GetFocusedPrefabContainerEntityId([[maybe_unused]] AzFramework::EntityContextId entityContextId) const { - if (const InstanceOptionalConstReference instance = GetInstanceReferenceFromRootAliasPath(m_focusedInstanceRootAliasPath); instance.has_value()) + if (const InstanceOptionalConstReference instance = GetInstanceReference(m_rootAliasFocusPath); instance.has_value()) { return instance->get().GetContainerEntityId(); } @@ -276,7 +298,7 @@ namespace AzToolsFramework::Prefab return false; } - return (instance->get().GetAbsoluteInstanceAliasPath() == m_focusedInstanceRootAliasPath); + return (instance->get().GetAbsoluteInstanceAliasPath() == m_rootAliasFocusPath); } bool PrefabFocusHandler::IsOwningPrefabInFocusHierarchy(AZ::EntityId entityId) const @@ -289,7 +311,7 @@ namespace AzToolsFramework::Prefab InstanceOptionalConstReference instance = m_instanceEntityMapperInterface->FindOwningInstance(entityId); while (instance.has_value()) { - if (instance->get().GetAbsoluteInstanceAliasPath() == m_focusedInstanceRootAliasPath) + if (instance->get().GetAbsoluteInstanceAliasPath() == m_rootAliasFocusPath) { return true; } @@ -302,40 +324,47 @@ namespace AzToolsFramework::Prefab const AZ::IO::Path& PrefabFocusHandler::GetPrefabFocusPath([[maybe_unused]] AzFramework::EntityContextId entityContextId) const { - return m_instanceFocusPath; + return m_filenameFocusPath; } const int PrefabFocusHandler::GetPrefabFocusPathLength([[maybe_unused]] AzFramework::EntityContextId entityContextId) const { - return aznumeric_cast(m_instanceFocusHierarchy.size()); + return m_rootAliasFocusPathLength; } void PrefabFocusHandler::OnContextReset() { - // Clear the old focus vector - m_instanceFocusHierarchy.clear(); - // Focus on the root prefab (AZ::EntityId() will default to it) FocusOnPrefabInstanceOwningEntityId(AZ::EntityId()); } void PrefabFocusHandler::OnEntityInfoUpdatedName(AZ::EntityId entityId, [[maybe_unused]]const AZStd::string& name) { - // Determine if the entityId is the container for any of the instances in the vector. - auto result = AZStd::find_if( - m_instanceFocusHierarchy.begin(), m_instanceFocusHierarchy.end(), - [&, entityId](const RootAliasPath& rootAliasPath) - { - InstanceOptionalReference instance = GetInstanceReferenceFromRootAliasPath(rootAliasPath); - return (instance->get().GetContainerEntityId() == entityId); - } - ); + PrefabEditorEntityOwnershipInterface* prefabEditorEntityOwnershipInterface = + AZ::Interface::Get(); - if (result != m_instanceFocusHierarchy.end()) + if (prefabEditorEntityOwnershipInterface) { - // Refresh the path and notify changes. - RefreshInstanceFocusPath(); - PrefabFocusNotificationBus::Broadcast(&PrefabFocusNotifications::OnPrefabFocusChanged); + // Determine if the entityId is the container for any of the instances in the vector. + bool match = prefabEditorEntityOwnershipInterface->GetInstancesInRootAliasPath( + m_rootAliasFocusPath, + [&](const Prefab::InstanceOptionalReference instance) + { + if (instance->get().GetContainerEntityId() == entityId) + { + return true; + } + + return false; + } + ); + + if (match) + { + // Refresh the path and notify changes. + RefreshInstanceFocusPath(); + PrefabFocusNotificationBus::Broadcast(&PrefabFocusNotifications::OnPrefabFocusChanged); + } } } @@ -348,79 +377,81 @@ namespace AzToolsFramework::Prefab void PrefabFocusHandler::OnPrefabTemplateDirtyFlagUpdated(TemplateId templateId, [[maybe_unused]] bool status) { - // Determine if the templateId matches any of the instances in the vector. - auto result = AZStd::find_if( - m_instanceFocusHierarchy.begin(), m_instanceFocusHierarchy.end(), - [&, templateId](const RootAliasPath& rootAliasPath) - { - InstanceOptionalReference instance = GetInstanceReferenceFromRootAliasPath(rootAliasPath); - return (instance->get().GetTemplateId() == templateId); - } - ); + PrefabEditorEntityOwnershipInterface* prefabEditorEntityOwnershipInterface = + AZ::Interface::Get(); - if (result != m_instanceFocusHierarchy.end()) + if (prefabEditorEntityOwnershipInterface) { - // Refresh the path and notify changes. - RefreshInstanceFocusPath(); - PrefabFocusNotificationBus::Broadcast(&PrefabFocusNotifications::OnPrefabFocusChanged); - } - } + // Determine if the templateId matches any of the instances in the vector. + bool match = prefabEditorEntityOwnershipInterface->GetInstancesInRootAliasPath( + m_rootAliasFocusPath, + [&](const Prefab::InstanceOptionalReference instance) + { + if (instance->get().GetTemplateId() == templateId) + { + return true; + } - void PrefabFocusHandler::RefreshInstanceFocusList() - { - m_instanceFocusHierarchy.clear(); + return false; + } + ); - InstanceOptionalConstReference currentInstance = GetInstanceReferenceFromRootAliasPath(m_focusedInstanceRootAliasPath); - while (currentInstance.has_value()) - { - m_instanceFocusHierarchy.emplace_back(currentInstance->get().GetAbsoluteInstanceAliasPath()); - currentInstance = currentInstance->get().GetParentInstance(); + if (match) + { + // Refresh the path and notify changes. + RefreshInstanceFocusPath(); + PrefabFocusNotificationBus::Broadcast(&PrefabFocusNotifications::OnPrefabFocusChanged); + } } - - // Invert the vector, since we need the top instance to be at index 0. - AZStd::reverse(m_instanceFocusHierarchy.begin(), m_instanceFocusHierarchy.end()); } void PrefabFocusHandler::RefreshInstanceFocusPath() { - auto prefabSystemComponentInterface = AZ::Interface::Get(); - - m_instanceFocusPath.clear(); - - size_t index = 0; - size_t maxIndex = m_instanceFocusHierarchy.size() - 1; + m_filenameFocusPath.clear(); + + PrefabEditorEntityOwnershipInterface* prefabEditorEntityOwnershipInterface = + AZ::Interface::Get(); + PrefabSystemComponentInterface* prefabSystemComponentInterface = AZ::Interface::Get(); - for (const RootAliasPath& rootAliasPath : m_instanceFocusHierarchy) + if (prefabEditorEntityOwnershipInterface && prefabSystemComponentInterface) { - const InstanceOptionalConstReference instance = GetInstanceReferenceFromRootAliasPath(rootAliasPath); - if (instance.has_value()) - { - AZStd::string prefabName; + int i = 0; - if (index < maxIndex) + prefabEditorEntityOwnershipInterface->GetInstancesInRootAliasPath( + m_rootAliasFocusPath, + [&](const Prefab::InstanceOptionalReference instance) { - // Get the filename without the extension (stem). - prefabName = instance->get().GetTemplateSourcePath().Stem().Native(); - } - else - { - // Get the full filename. - prefabName = instance->get().GetTemplateSourcePath().Filename().Native(); - } + if (instance.has_value()) + { + AZStd::string prefabName; + + if (i == m_rootAliasFocusPathLength - 1) + { + // Get the full filename. + prefabName = instance->get().GetTemplateSourcePath().Filename().Native(); + } + else + { + // Get the filename without the extension (stem). + prefabName = instance->get().GetTemplateSourcePath().Stem().Native(); + } + + if (prefabSystemComponentInterface->IsTemplateDirty(instance->get().GetTemplateId())) + { + prefabName += "*"; + } + + m_filenameFocusPath.Append(prefabName); + } - if (prefabSystemComponentInterface->IsTemplateDirty(instance->get().GetTemplateId())) - { - prefabName += "*"; + ++i; + return false; } - - m_instanceFocusPath.Append(prefabName); - } - - ++index; + ); } } - void PrefabFocusHandler::SetInstanceContainersOpenState(const AZStd::vector& instances, bool openState) const + void PrefabFocusHandler::SetInstanceContainersOpenState(const RootAliasPath& rootAliasPath, bool openState) const { // If this is called outside the Editor, this interface won't be initialized. if (!m_containerEntityInterface) @@ -428,51 +459,34 @@ namespace AzToolsFramework::Prefab return; } - for (const RootAliasPath& rootAliasPath : instances) + PrefabEditorEntityOwnershipInterface* prefabEditorEntityOwnershipInterface = + AZ::Interface::Get(); + + if (prefabEditorEntityOwnershipInterface) { - InstanceOptionalReference instance = GetInstanceReferenceFromRootAliasPath(rootAliasPath); + prefabEditorEntityOwnershipInterface->GetInstancesInRootAliasPath( + rootAliasPath, + [&](const Prefab::InstanceOptionalReference instance) + { + m_containerEntityInterface->SetContainerOpen(instance->get().GetContainerEntityId(), openState); - if (instance.has_value()) - { - m_containerEntityInterface->SetContainerOpen(instance->get().GetContainerEntityId(), openState); - } + return false; + } + ); } } - InstanceOptionalReference PrefabFocusHandler::GetInstanceReferenceFromRootAliasPath(RootAliasPath rootAliasPath) const + InstanceOptionalReference PrefabFocusHandler::GetInstanceReference(RootAliasPath rootAliasPath) const { PrefabEditorEntityOwnershipInterface* prefabEditorEntityOwnershipInterface = AZ::Interface::Get(); if (prefabEditorEntityOwnershipInterface) { - InstanceOptionalReference instance = prefabEditorEntityOwnershipInterface->GetRootPrefabInstance(); - - for (const auto& pathElement : rootAliasPath) - { - if (pathElement.Native() == rootAliasPath.begin()->Native()) - { - // If the root is not the root Instance, the rootAliasPath is invalid. - if (pathElement.Native() != instance->get().GetInstanceAlias()) - { - return InstanceOptionalReference(); - } - } - else - { - // If the instance alias can't be found, the rootAliasPath is invalid. - instance = instance->get().FindNestedInstance(pathElement.Native()); - if (!instance.has_value()) - { - return InstanceOptionalReference(); - } - } - } - - return instance; + return prefabEditorEntityOwnershipInterface->GetInstanceReferenceFromRootAliasPath(rootAliasPath); } - return InstanceOptionalReference(); + return AZStd::nullopt; } } // namespace AzToolsFramework::Prefab diff --git a/Code/Framework/AzToolsFramework/AzToolsFramework/Prefab/PrefabFocusHandler.h b/Code/Framework/AzToolsFramework/AzToolsFramework/Prefab/PrefabFocusHandler.h index 75e0a9f1f4..e08a2fa7f5 100644 --- a/Code/Framework/AzToolsFramework/AzToolsFramework/Prefab/PrefabFocusHandler.h +++ b/Code/Framework/AzToolsFramework/AzToolsFramework/Prefab/PrefabFocusHandler.h @@ -12,6 +12,7 @@ #include #include +#include #include #include #include @@ -28,6 +29,7 @@ namespace AzToolsFramework namespace AzToolsFramework::Prefab { class InstanceEntityMapperInterface; + class PrefabSystemComponentInterface; //! Handles Prefab Focus mode, determining which prefab file entity changes will target. class PrefabFocusHandler final @@ -73,22 +75,20 @@ namespace AzToolsFramework::Prefab private: PrefabFocusOperationResult FocusOnPrefabInstance(InstanceOptionalReference focusedInstance); - void RefreshInstanceFocusList(); void RefreshInstanceFocusPath(); - void SetInstanceContainersOpenState(const AZStd::vector& instances, bool openState) const; + void SetInstanceContainersOpenState(const RootAliasPath& rootAliasPath, bool openState) const; - InstanceOptionalReference GetInstanceReferenceFromRootAliasPath(RootAliasPath rootAliasPath) const; + InstanceOptionalReference GetInstanceReference(RootAliasPath rootAliasPath) const; //! The alias path for the instance the editor is currently focusing on, starting from the root instance. - RootAliasPath m_focusedInstanceRootAliasPath = RootAliasPath(); + RootAliasPath m_rootAliasFocusPath = RootAliasPath(); //! The templateId of the focused instance. TemplateId m_focusedTemplateId; - //! The list of instances going from the root (index 0) to the focused instance, - //! referenced by their alias path from the root instance. - AZStd::vector m_instanceFocusHierarchy; //! A path containing the filenames of the instances in the focus hierarchy, separated with a /. - AZ::IO::Path m_instanceFocusPath; + AZ::IO::Path m_filenameFocusPath; + //! The length of the current focus path. Stored to simplify internal checks. + int m_rootAliasFocusPathLength = 0; ContainerEntityInterface* m_containerEntityInterface = nullptr; FocusModeInterface* m_focusModeInterface = nullptr; diff --git a/Code/Framework/AzToolsFramework/AzToolsFramework/Prefab/PrefabSystemComponent.cpp b/Code/Framework/AzToolsFramework/AzToolsFramework/Prefab/PrefabSystemComponent.cpp index 9648a9af09..38ffb98fcb 100644 --- a/Code/Framework/AzToolsFramework/AzToolsFramework/Prefab/PrefabSystemComponent.cpp +++ b/Code/Framework/AzToolsFramework/AzToolsFramework/Prefab/PrefabSystemComponent.cpp @@ -815,7 +815,8 @@ namespace AzToolsFramework if (templateRef.has_value()) { - return templateRef->get().IsDirty(); + return !templateRef->get().IsProcedural() && // all procedural prefabs are read-only + templateRef->get().IsDirty(); } return false; diff --git a/Code/Tools/LuaIDE/Source/LUA/LUAEditorMainWindow.cpp b/Code/Tools/LuaIDE/Source/LUA/LUAEditorMainWindow.cpp index 776e290042..6441ad2d56 100644 --- a/Code/Tools/LuaIDE/Source/LUA/LUAEditorMainWindow.cpp +++ b/Code/Tools/LuaIDE/Source/LUA/LUAEditorMainWindow.cpp @@ -108,7 +108,7 @@ namespace LUAEditor m_settingsDialog = aznew LUAEditorSettingsDialog(this); actionTabForwards = new QAction(tr("Next Document Tab"), this); - actionTabBackwards = new QAction(tr("Prev Document Tab"), this); + actionTabBackwards = new QAction(tr("Previous Document Tab"), this); actionTabForwards->setShortcut(QKeySequence("Ctrl+Tab")); connect(actionTabForwards, SIGNAL(triggered(bool)), this, SLOT(OnTabForwards())); diff --git a/Code/Tools/SceneAPI/SceneData/GraphData/AnimationData.cpp b/Code/Tools/SceneAPI/SceneData/GraphData/AnimationData.cpp index 01355f0a75..66d2adf549 100644 --- a/Code/Tools/SceneAPI/SceneData/GraphData/AnimationData.cpp +++ b/Code/Tools/SceneAPI/SceneData/GraphData/AnimationData.cpp @@ -29,6 +29,7 @@ namespace AZ if (behaviorContext) { behaviorContext->Class() + ->Attribute(AZ::Script::Attributes::ExcludeFrom, AZ::Script::Attributes::ExcludeFlags::ListOnly) ->Attribute(AZ::Script::Attributes::Scope, AZ::Script::Attributes::ScopeFlags::Common) ->Attribute(AZ::Script::Attributes::Module, "scene") ->Method("GetKeyFrameCount", &SceneAPI::DataTypes::IAnimationData::GetKeyFrameCount) @@ -97,6 +98,7 @@ namespace AZ if (behaviorContext) { behaviorContext->Class() + ->Attribute(AZ::Script::Attributes::ExcludeFrom, AZ::Script::Attributes::ExcludeFlags::ListOnly) ->Attribute(AZ::Script::Attributes::Scope, AZ::Script::Attributes::ScopeFlags::Common) ->Attribute(AZ::Script::Attributes::Module, "scene") ->Method("GetBlendShapeName", &SceneAPI::DataTypes::IBlendShapeAnimationData::GetBlendShapeName) diff --git a/Code/Tools/SceneAPI/SceneData/GraphData/BlendShapeData.cpp b/Code/Tools/SceneAPI/SceneData/GraphData/BlendShapeData.cpp index 066129f974..402ade6878 100644 --- a/Code/Tools/SceneAPI/SceneData/GraphData/BlendShapeData.cpp +++ b/Code/Tools/SceneAPI/SceneData/GraphData/BlendShapeData.cpp @@ -37,6 +37,7 @@ namespace AZ if (behaviorContext) { behaviorContext->Class() + ->Attribute(AZ::Script::Attributes::ExcludeFrom, AZ::Script::Attributes::ExcludeFlags::ListOnly) ->Attribute(AZ::Script::Attributes::Scope, AZ::Script::Attributes::ScopeFlags::Common) ->Attribute(AZ::Script::Attributes::Module, "scene") ->Method("GetUsedControlPointCount", &SceneAPI::DataTypes::IBlendShapeData::GetUsedControlPointCount) diff --git a/Code/Tools/SceneAPI/SceneData/GraphData/BoneData.cpp b/Code/Tools/SceneAPI/SceneData/GraphData/BoneData.cpp index e1a6c2608f..f29174f923 100644 --- a/Code/Tools/SceneAPI/SceneData/GraphData/BoneData.cpp +++ b/Code/Tools/SceneAPI/SceneData/GraphData/BoneData.cpp @@ -47,6 +47,7 @@ namespace AZ if (behaviorContext) { behaviorContext->Class() + ->Attribute(AZ::Script::Attributes::ExcludeFrom, AZ::Script::Attributes::ExcludeFlags::ListOnly) ->Attribute(AZ::Script::Attributes::Scope, AZ::Script::Attributes::ScopeFlags::Common) ->Attribute(AZ::Script::Attributes::Module, "scene"); behaviorContext->Class() diff --git a/Code/Tools/SceneAPI/SceneData/GraphData/MaterialData.cpp b/Code/Tools/SceneAPI/SceneData/GraphData/MaterialData.cpp index b6b87fecc7..f05395860b 100644 --- a/Code/Tools/SceneAPI/SceneData/GraphData/MaterialData.cpp +++ b/Code/Tools/SceneAPI/SceneData/GraphData/MaterialData.cpp @@ -304,6 +304,7 @@ namespace AZ if (behaviorContext) { behaviorContext->Class() + ->Attribute(AZ::Script::Attributes::ExcludeFrom, AZ::Script::Attributes::ExcludeFlags::ListOnly) ->Attribute(AZ::Script::Attributes::ExcludeFrom, AZ::Script::Attributes::ExcludeFlags::All) ->Attribute(AZ::Script::Attributes::Scope, AZ::Script::Attributes::ScopeFlags::Common) ->Attribute(AZ::Script::Attributes::Module, "scene"); diff --git a/Code/Tools/SceneAPI/SceneData/GraphData/MeshData.cpp b/Code/Tools/SceneAPI/SceneData/GraphData/MeshData.cpp index f324f598ec..7f1618d857 100644 --- a/Code/Tools/SceneAPI/SceneData/GraphData/MeshData.cpp +++ b/Code/Tools/SceneAPI/SceneData/GraphData/MeshData.cpp @@ -33,6 +33,7 @@ namespace AZ if (behaviorContext) { behaviorContext->Class() + ->Attribute(Script::Attributes::ExcludeFrom, Script::Attributes::ExcludeFlags::ListOnly) ->Attribute(AZ::Script::Attributes::Scope, AZ::Script::Attributes::ScopeFlags::Common) ->Attribute(AZ::Script::Attributes::Module, "scene") ->Method("GetUnitSizeInMeters", &MeshData::GetUnitSizeInMeters) diff --git a/Gems/AWSGameLift/Code/AWSGameLiftClient/CMakeLists.txt b/Gems/AWSGameLift/Code/AWSGameLiftClient/CMakeLists.txt index bdc831c439..4435637c4b 100644 --- a/Gems/AWSGameLift/Code/AWSGameLiftClient/CMakeLists.txt +++ b/Gems/AWSGameLift/Code/AWSGameLiftClient/CMakeLists.txt @@ -24,8 +24,8 @@ ly_add_target( BUILD_DEPENDENCIES PRIVATE AZ::AzCore - AZ::AzFramework Gem::AWSCore + Gem::Multiplayer.Static 3rdParty::AWSNativeSDK::GameLiftClient ) @@ -85,10 +85,10 @@ if(PAL_TRAIT_BUILD_TESTS_SUPPORTED) BUILD_DEPENDENCIES PRIVATE AZ::AzCore - AZ::AzFramework AZ::AzTest Gem::AWSCore Gem::AWSGameLift.Client.Static + Gem::Multiplayer.Static 3rdParty::AWSNativeSDK::GameLiftClient AZ::AWSNativeSDKTestLibs ) diff --git a/Gems/AWSGameLift/Code/AWSGameLiftClient/Include/Request/AWSGameLiftAcceptMatchRequest.h b/Gems/AWSGameLift/Code/AWSGameLiftClient/Include/Request/AWSGameLiftAcceptMatchRequest.h index 415550b6bc..f5f2c6d04d 100644 --- a/Gems/AWSGameLift/Code/AWSGameLiftClient/Include/Request/AWSGameLiftAcceptMatchRequest.h +++ b/Gems/AWSGameLift/Code/AWSGameLiftClient/Include/Request/AWSGameLiftAcceptMatchRequest.h @@ -8,7 +8,7 @@ #pragma once -#include +#include namespace AWSGameLift { @@ -17,10 +17,10 @@ namespace AWSGameLift //! Registers a player's acceptance or rejection of a proposed FlexMatch match. //! AcceptMatchRequest struct AWSGameLiftAcceptMatchRequest - : public AzFramework::AcceptMatchRequest + : public Multiplayer::AcceptMatchRequest { public: - AZ_RTTI(AWSGameLiftAcceptMatchRequest, "{8372B297-88E8-4C13-B31D-BE87236CA416}", AzFramework::AcceptMatchRequest); + AZ_RTTI(AWSGameLiftAcceptMatchRequest, "{8372B297-88E8-4C13-B31D-BE87236CA416}", Multiplayer::AcceptMatchRequest); static void Reflect(AZ::ReflectContext* context); AWSGameLiftAcceptMatchRequest() = default; diff --git a/Gems/AWSGameLift/Code/AWSGameLiftClient/Include/Request/AWSGameLiftCreateSessionOnQueueRequest.h b/Gems/AWSGameLift/Code/AWSGameLiftClient/Include/Request/AWSGameLiftCreateSessionOnQueueRequest.h index 24dfce1dfa..f867516427 100644 --- a/Gems/AWSGameLift/Code/AWSGameLiftClient/Include/Request/AWSGameLiftCreateSessionOnQueueRequest.h +++ b/Gems/AWSGameLift/Code/AWSGameLiftClient/Include/Request/AWSGameLiftCreateSessionOnQueueRequest.h @@ -8,7 +8,7 @@ #pragma once -#include +#include namespace AWSGameLift { @@ -16,10 +16,10 @@ namespace AWSGameLift //! GameLift create session on queue request which corresponds to Amazon GameLift //! StartGameSessionPlacement struct AWSGameLiftCreateSessionOnQueueRequest - : public AzFramework::CreateSessionRequest + : public Multiplayer::CreateSessionRequest { public: - AZ_RTTI(AWSGameLiftCreateSessionOnQueueRequest, "{2B99E594-CE81-4EB0-8888-74EF4242B59F}", AzFramework::CreateSessionRequest); + AZ_RTTI(AWSGameLiftCreateSessionOnQueueRequest, "{2B99E594-CE81-4EB0-8888-74EF4242B59F}", Multiplayer::CreateSessionRequest); static void Reflect(AZ::ReflectContext* context); AWSGameLiftCreateSessionOnQueueRequest() = default; diff --git a/Gems/AWSGameLift/Code/AWSGameLiftClient/Include/Request/AWSGameLiftCreateSessionRequest.h b/Gems/AWSGameLift/Code/AWSGameLiftClient/Include/Request/AWSGameLiftCreateSessionRequest.h index 97ffd0b321..908efe6454 100644 --- a/Gems/AWSGameLift/Code/AWSGameLiftClient/Include/Request/AWSGameLiftCreateSessionRequest.h +++ b/Gems/AWSGameLift/Code/AWSGameLiftClient/Include/Request/AWSGameLiftCreateSessionRequest.h @@ -8,7 +8,7 @@ #pragma once -#include +#include namespace AWSGameLift { @@ -16,10 +16,10 @@ namespace AWSGameLift //! GameLift create session on fleet request which corresponds to Amazon GameLift //! CreateGameSessionRequest struct AWSGameLiftCreateSessionRequest - : public AzFramework::CreateSessionRequest + : public Multiplayer::CreateSessionRequest { public: - AZ_RTTI(AWSGameLiftCreateSessionRequest, "{69612D5D-F899-4DEB-AD63-4C497ABC5C0D}", AzFramework::CreateSessionRequest); + AZ_RTTI(AWSGameLiftCreateSessionRequest, "{69612D5D-F899-4DEB-AD63-4C497ABC5C0D}", Multiplayer::CreateSessionRequest); static void Reflect(AZ::ReflectContext* context); AWSGameLiftCreateSessionRequest() = default; diff --git a/Gems/AWSGameLift/Code/AWSGameLiftClient/Include/Request/AWSGameLiftJoinSessionRequest.h b/Gems/AWSGameLift/Code/AWSGameLiftClient/Include/Request/AWSGameLiftJoinSessionRequest.h index 07d6da3870..2794c5cdd9 100644 --- a/Gems/AWSGameLift/Code/AWSGameLiftClient/Include/Request/AWSGameLiftJoinSessionRequest.h +++ b/Gems/AWSGameLift/Code/AWSGameLiftClient/Include/Request/AWSGameLiftJoinSessionRequest.h @@ -8,7 +8,7 @@ #pragma once -#include +#include namespace AWSGameLift { @@ -17,10 +17,10 @@ namespace AWSGameLift //! Once player session has been created successfully in game session, gamelift client manager will //! signal Multiplayer Gem to setup networking connection. struct AWSGameLiftJoinSessionRequest - : public AzFramework::JoinSessionRequest + : public Multiplayer::JoinSessionRequest { public: - AZ_RTTI(AWSGameLiftJoinSessionRequest, "{6EED6D15-531A-4956-90D0-2EDA31AC9CBA}", AzFramework::JoinSessionRequest); + AZ_RTTI(AWSGameLiftJoinSessionRequest, "{6EED6D15-531A-4956-90D0-2EDA31AC9CBA}", Multiplayer::JoinSessionRequest); static void Reflect(AZ::ReflectContext* context); AWSGameLiftJoinSessionRequest() = default; diff --git a/Gems/AWSGameLift/Code/AWSGameLiftClient/Include/Request/AWSGameLiftMatchmakingRequestBus.h b/Gems/AWSGameLift/Code/AWSGameLiftClient/Include/Request/AWSGameLiftMatchmakingRequestBus.h index 8ab215d741..20fa08e950 100644 --- a/Gems/AWSGameLift/Code/AWSGameLiftClient/Include/Request/AWSGameLiftMatchmakingRequestBus.h +++ b/Gems/AWSGameLift/Code/AWSGameLiftClient/Include/Request/AWSGameLiftMatchmakingRequestBus.h @@ -10,7 +10,7 @@ #include #include -#include +#include namespace AWSGameLift { @@ -23,7 +23,7 @@ namespace AWSGameLift static const AZ::EBusHandlerPolicy HandlerPolicy = AZ::EBusHandlerPolicy::Single; static const AZ::EBusAddressPolicy AddressPolicy = AZ::EBusAddressPolicy::Single; }; - using AWSGameLiftMatchmakingAsyncRequestBus = AZ::EBus; + using AWSGameLiftMatchmakingAsyncRequestBus = AZ::EBus; // IMatchmakingRequests EBus wrapper class AWSGameLiftMatchmakingRequests @@ -34,7 +34,7 @@ namespace AWSGameLift static const AZ::EBusHandlerPolicy HandlerPolicy = AZ::EBusHandlerPolicy::Single; static const AZ::EBusAddressPolicy AddressPolicy = AZ::EBusAddressPolicy::Single; }; - using AWSGameLiftMatchmakingRequestBus = AZ::EBus; + using AWSGameLiftMatchmakingRequestBus = AZ::EBus; //! IAWSGameLiftMatchmakingEventRequests //! GameLift Gem matchmaking event interfaces which is used to track matchmaking ticket event diff --git a/Gems/AWSGameLift/Code/AWSGameLiftClient/Include/Request/AWSGameLiftSearchSessionsRequest.h b/Gems/AWSGameLift/Code/AWSGameLiftClient/Include/Request/AWSGameLiftSearchSessionsRequest.h index 02f3638998..834e6c6d22 100644 --- a/Gems/AWSGameLift/Code/AWSGameLiftClient/Include/Request/AWSGameLiftSearchSessionsRequest.h +++ b/Gems/AWSGameLift/Code/AWSGameLiftClient/Include/Request/AWSGameLiftSearchSessionsRequest.h @@ -8,7 +8,7 @@ #pragma once -#include +#include namespace AWSGameLift { @@ -16,10 +16,10 @@ namespace AWSGameLift //! GameLift search sessions request which corresponds to Amazon GameLift //! SearchSessionsRequest struct AWSGameLiftSearchSessionsRequest - : public AzFramework::SearchSessionsRequest + : public Multiplayer::SearchSessionsRequest { public: - AZ_RTTI(AWSGameLiftSearchSessionsRequest, "{864C91C0-CA53-4585-BF07-066C0DF3E198}", AzFramework::SearchSessionsRequest); + AZ_RTTI(AWSGameLiftSearchSessionsRequest, "{864C91C0-CA53-4585-BF07-066C0DF3E198}", Multiplayer::SearchSessionsRequest); static void Reflect(AZ::ReflectContext* context); AWSGameLiftSearchSessionsRequest() = default; diff --git a/Gems/AWSGameLift/Code/AWSGameLiftClient/Include/Request/AWSGameLiftSessionRequestBus.h b/Gems/AWSGameLift/Code/AWSGameLiftClient/Include/Request/AWSGameLiftSessionRequestBus.h index c99509ca3f..3c6c9135bc 100644 --- a/Gems/AWSGameLift/Code/AWSGameLiftClient/Include/Request/AWSGameLiftSessionRequestBus.h +++ b/Gems/AWSGameLift/Code/AWSGameLiftClient/Include/Request/AWSGameLiftSessionRequestBus.h @@ -10,7 +10,7 @@ #include #include -#include +#include namespace AWSGameLift { @@ -23,7 +23,7 @@ namespace AWSGameLift static const AZ::EBusHandlerPolicy HandlerPolicy = AZ::EBusHandlerPolicy::Single; static const AZ::EBusAddressPolicy AddressPolicy = AZ::EBusAddressPolicy::Single; }; - using AWSGameLiftSessionAsyncRequestBus = AZ::EBus; + using AWSGameLiftSessionAsyncRequestBus = AZ::EBus; // ISessionRequests EBus wrapper class AWSGameLiftSessionRequests @@ -34,5 +34,5 @@ namespace AWSGameLift static const AZ::EBusHandlerPolicy HandlerPolicy = AZ::EBusHandlerPolicy::Single; static const AZ::EBusAddressPolicy AddressPolicy = AZ::EBusAddressPolicy::Single; }; - using AWSGameLiftSessionRequestBus = AZ::EBus; + using AWSGameLiftSessionRequestBus = AZ::EBus; } // namespace AWSGameLift diff --git a/Gems/AWSGameLift/Code/AWSGameLiftClient/Include/Request/AWSGameLiftStartMatchmakingRequest.h b/Gems/AWSGameLift/Code/AWSGameLiftClient/Include/Request/AWSGameLiftStartMatchmakingRequest.h index b2060032e8..295e966e88 100644 --- a/Gems/AWSGameLift/Code/AWSGameLiftClient/Include/Request/AWSGameLiftStartMatchmakingRequest.h +++ b/Gems/AWSGameLift/Code/AWSGameLiftClient/Include/Request/AWSGameLiftStartMatchmakingRequest.h @@ -10,7 +10,7 @@ #include #include -#include +#include #include @@ -21,10 +21,10 @@ namespace AWSGameLift //! Uses FlexMatch to create a game match for a group of players based on custom matchmaking rules //! StartMatchmakingRequest struct AWSGameLiftStartMatchmakingRequest - : public AzFramework::StartMatchmakingRequest + : public Multiplayer::StartMatchmakingRequest { public: - AZ_RTTI(AWSGameLiftStartMatchmakingRequest, "{D273DF71-9C55-48C1-95F9-8D7B66B9CF3E}", AzFramework::StartMatchmakingRequest); + AZ_RTTI(AWSGameLiftStartMatchmakingRequest, "{D273DF71-9C55-48C1-95F9-8D7B66B9CF3E}", Multiplayer::StartMatchmakingRequest); static void Reflect(AZ::ReflectContext* context); AWSGameLiftStartMatchmakingRequest() = default; diff --git a/Gems/AWSGameLift/Code/AWSGameLiftClient/Include/Request/AWSGameLiftStopMatchmakingRequest.h b/Gems/AWSGameLift/Code/AWSGameLiftClient/Include/Request/AWSGameLiftStopMatchmakingRequest.h index 81d811d32d..3fb9c2a1a9 100644 --- a/Gems/AWSGameLift/Code/AWSGameLiftClient/Include/Request/AWSGameLiftStopMatchmakingRequest.h +++ b/Gems/AWSGameLift/Code/AWSGameLiftClient/Include/Request/AWSGameLiftStopMatchmakingRequest.h @@ -8,7 +8,7 @@ #pragma once -#include +#include namespace AWSGameLift { @@ -17,10 +17,10 @@ namespace AWSGameLift //! Cancels a matchmaking ticket or match backfill ticket that is currently being processed. //! StopMatchmakingRequest struct AWSGameLiftStopMatchmakingRequest - : public AzFramework::StopMatchmakingRequest + : public Multiplayer::StopMatchmakingRequest { public: - AZ_RTTI(AWSGameLiftStopMatchmakingRequest, "{2766BC03-9F84-4346-A52B-49129BBAF38B}", AzFramework::StopMatchmakingRequest); + AZ_RTTI(AWSGameLiftStopMatchmakingRequest, "{2766BC03-9F84-4346-A52B-49129BBAF38B}", Multiplayer::StopMatchmakingRequest); static void Reflect(AZ::ReflectContext* context); AWSGameLiftStopMatchmakingRequest() = default; diff --git a/Gems/AWSGameLift/Code/AWSGameLiftClient/Source/AWSGameLiftClientLocalTicketTracker.cpp b/Gems/AWSGameLift/Code/AWSGameLiftClient/Source/AWSGameLiftClientLocalTicketTracker.cpp index 2e978402cd..969f00de0e 100644 --- a/Gems/AWSGameLift/Code/AWSGameLiftClient/Source/AWSGameLiftClientLocalTicketTracker.cpp +++ b/Gems/AWSGameLift/Code/AWSGameLiftClient/Source/AWSGameLiftClientLocalTicketTracker.cpp @@ -9,8 +9,8 @@ #include #include #include -#include -#include +#include +#include #include #include @@ -97,7 +97,7 @@ namespace AWSGameLift AZ_TracePrintf(AWSGameLiftClientLocalTicketTrackerName, "Matchmaking ticket %s is complete.", ticket.GetTicketId().c_str()); RequestPlayerJoinMatch(ticket, playerId); - AzFramework::MatchmakingNotificationBus::Broadcast(&AzFramework::MatchmakingNotifications::OnMatchComplete); + Multiplayer::MatchmakingNotificationBus::Broadcast(&Multiplayer::MatchmakingNotifications::OnMatchComplete); m_status = TicketTrackerStatus::Idle; return; } @@ -107,7 +107,7 @@ namespace AWSGameLift { AZ_Warning(AWSGameLiftClientLocalTicketTrackerName, false, "Matchmaking ticket %s is not complete, %s", ticket.GetTicketId().c_str(), ticket.GetStatusMessage().c_str()); - AzFramework::MatchmakingNotificationBus::Broadcast(&AzFramework::MatchmakingNotifications::OnMatchFailure); + Multiplayer::MatchmakingNotificationBus::Broadcast(&Multiplayer::MatchmakingNotifications::OnMatchFailure); m_status = TicketTrackerStatus::Idle; return; } @@ -115,7 +115,7 @@ namespace AWSGameLift { AZ_TracePrintf(AWSGameLiftClientLocalTicketTrackerName, "Matchmaking ticket %s is pending on acceptance, %s.", ticket.GetTicketId().c_str(), ticket.GetStatusMessage().c_str()); - AzFramework::MatchmakingNotificationBus::Broadcast(&AzFramework::MatchmakingNotifications::OnMatchAcceptance); + Multiplayer::MatchmakingNotificationBus::Broadcast(&Multiplayer::MatchmakingNotifications::OnMatchAcceptance); } else { @@ -126,7 +126,7 @@ namespace AWSGameLift else { AZ_Error(AWSGameLiftClientLocalTicketTrackerName, false, "Unable to find expected ticket with id %s", ticketId.c_str()); - AzFramework::MatchmakingNotificationBus::Broadcast(&AzFramework::MatchmakingNotifications::OnMatchError); + Multiplayer::MatchmakingNotificationBus::Broadcast(&Multiplayer::MatchmakingNotifications::OnMatchError); } } else @@ -134,13 +134,13 @@ namespace AWSGameLift AZ_Error(AWSGameLiftClientLocalTicketTrackerName, false, AWSGameLiftErrorMessageTemplate, describeMatchmakingOutcome.GetError().GetExceptionName().c_str(), describeMatchmakingOutcome.GetError().GetMessage().c_str()); - AzFramework::MatchmakingNotificationBus::Broadcast(&AzFramework::MatchmakingNotifications::OnMatchError); + Multiplayer::MatchmakingNotificationBus::Broadcast(&Multiplayer::MatchmakingNotifications::OnMatchError); } } else { AZ_Error(AWSGameLiftClientLocalTicketTrackerName, false, AWSGameLiftClientMissingErrorMessage); - AzFramework::MatchmakingNotificationBus::Broadcast(&AzFramework::MatchmakingNotifications::OnMatchError); + Multiplayer::MatchmakingNotificationBus::Broadcast(&Multiplayer::MatchmakingNotifications::OnMatchError); } m_waitEvent.try_acquire_for(AZStd::chrono::milliseconds(m_pollingPeriodInMS)); } @@ -150,7 +150,7 @@ namespace AWSGameLift const Aws::GameLift::Model::MatchmakingTicket& ticket, const AZStd::string& playerId) { auto connectionInfo = ticket.GetGameSessionConnectionInfo(); - AzFramework::SessionConnectionConfig sessionConnectionConfig; + Multiplayer::SessionConnectionConfig sessionConnectionConfig; sessionConnectionConfig.m_ipAddress = connectionInfo.GetIpAddress().c_str(); for (auto matchedPlayer : connectionInfo.GetMatchedPlayerSessions()) { @@ -168,7 +168,7 @@ namespace AWSGameLift "Requesting and validating player session %s to connect to the match ...", sessionConnectionConfig.m_playerSessionId.c_str()); bool result = - AZ::Interface::Get()->RequestPlayerJoinSession(sessionConnectionConfig); + AZ::Interface::Get()->RequestPlayerJoinSession(sessionConnectionConfig); if (result) { AZ_TracePrintf(AWSGameLiftClientLocalTicketTrackerName, diff --git a/Gems/AWSGameLift/Code/AWSGameLiftClient/Source/AWSGameLiftClientManager.cpp b/Gems/AWSGameLift/Code/AWSGameLiftClient/Source/AWSGameLiftClientManager.cpp index f900310078..1134481f96 100644 --- a/Gems/AWSGameLift/Code/AWSGameLiftClient/Source/AWSGameLiftClientManager.cpp +++ b/Gems/AWSGameLift/Code/AWSGameLiftClient/Source/AWSGameLiftClientManager.cpp @@ -10,7 +10,7 @@ #include #include #include -#include +#include #include #include @@ -42,32 +42,32 @@ namespace AWSGameLift AZ::Interface::Register(this); AWSGameLiftRequestBus::Handler::BusConnect(); - AZ::Interface::Register(this); + AZ::Interface::Register(this); AWSGameLiftSessionAsyncRequestBus::Handler::BusConnect(); - AZ::Interface::Register(this); + AZ::Interface::Register(this); AWSGameLiftSessionRequestBus::Handler::BusConnect(); - AZ::Interface::Register(this); + AZ::Interface::Register(this); AWSGameLiftMatchmakingAsyncRequestBus::Handler::BusConnect(); - AZ::Interface::Register(this); + AZ::Interface::Register(this); AWSGameLiftMatchmakingRequestBus::Handler::BusConnect(); } void AWSGameLiftClientManager::DeactivateManager() { AWSGameLiftMatchmakingRequestBus::Handler::BusDisconnect(); - AZ::Interface::Unregister(this); + AZ::Interface::Unregister(this); AWSGameLiftMatchmakingAsyncRequestBus::Handler::BusDisconnect(); - AZ::Interface::Unregister(this); + AZ::Interface::Unregister(this); AWSGameLiftSessionRequestBus::Handler::BusDisconnect(); - AZ::Interface::Unregister(this); + AZ::Interface::Unregister(this); AWSGameLiftSessionAsyncRequestBus::Handler::BusDisconnect(); - AZ::Interface::Unregister(this); + AZ::Interface::Unregister(this); AWSGameLiftRequestBus::Handler::BusDisconnect(); AZ::Interface::Unregister(this); @@ -133,7 +133,7 @@ namespace AWSGameLift return AZ::Uuid::CreateRandom().ToString(includeBrackets, includeDashes); } - void AWSGameLiftClientManager::AcceptMatch(const AzFramework::AcceptMatchRequest& acceptMatchRequest) + void AWSGameLiftClientManager::AcceptMatch(const Multiplayer::AcceptMatchRequest& acceptMatchRequest) { if (AcceptMatchActivity::ValidateAcceptMatchRequest(acceptMatchRequest)) { @@ -143,12 +143,12 @@ namespace AWSGameLift } } - void AWSGameLiftClientManager::AcceptMatchAsync(const AzFramework::AcceptMatchRequest& acceptMatchRequest) + void AWSGameLiftClientManager::AcceptMatchAsync(const Multiplayer::AcceptMatchRequest& acceptMatchRequest) { if (!AcceptMatchActivity::ValidateAcceptMatchRequest(acceptMatchRequest)) { - AzFramework::MatchmakingAsyncRequestNotificationBus::Broadcast( - &AzFramework::MatchmakingAsyncRequestNotifications::OnAcceptMatchAsyncComplete); + Multiplayer::MatchmakingAsyncRequestNotificationBus::Broadcast( + &Multiplayer::MatchmakingAsyncRequestNotifications::OnAcceptMatchAsyncComplete); return; } @@ -161,15 +161,15 @@ namespace AWSGameLift { AcceptMatchActivity::AcceptMatch(gameliftStartMatchmakingRequest); - AzFramework::MatchmakingAsyncRequestNotificationBus::Broadcast( - &AzFramework::MatchmakingAsyncRequestNotifications::OnAcceptMatchAsyncComplete); + Multiplayer::MatchmakingAsyncRequestNotificationBus::Broadcast( + &Multiplayer::MatchmakingAsyncRequestNotifications::OnAcceptMatchAsyncComplete); }, true, jobContext); acceptMatchJob->Start(); } - AZStd::string AWSGameLiftClientManager::CreateSession(const AzFramework::CreateSessionRequest& createSessionRequest) + AZStd::string AWSGameLiftClientManager::CreateSession(const Multiplayer::CreateSessionRequest& createSessionRequest) { AZStd::string result = ""; if (CreateSessionActivity::ValidateCreateSessionRequest(createSessionRequest)) @@ -192,7 +192,7 @@ namespace AWSGameLift return result; } - void AWSGameLiftClientManager::CreateSessionAsync(const AzFramework::CreateSessionRequest& createSessionRequest) + void AWSGameLiftClientManager::CreateSessionAsync(const Multiplayer::CreateSessionRequest& createSessionRequest) { if (CreateSessionActivity::ValidateCreateSessionRequest(createSessionRequest)) { @@ -206,8 +206,8 @@ namespace AWSGameLift { AZStd::string result = CreateSessionActivity::CreateSession(gameliftCreateSessionRequest); - AzFramework::SessionAsyncRequestNotificationBus::Broadcast( - &AzFramework::SessionAsyncRequestNotifications::OnCreateSessionAsyncComplete, result); + Multiplayer::SessionAsyncRequestNotificationBus::Broadcast( + &Multiplayer::SessionAsyncRequestNotifications::OnCreateSessionAsyncComplete, result); }, true, jobContext); createSessionJob->Start(); @@ -224,8 +224,8 @@ namespace AWSGameLift { AZStd::string result = CreateSessionOnQueueActivity::CreateSessionOnQueue(gameliftCreateSessionOnQueueRequest); - AzFramework::SessionAsyncRequestNotificationBus::Broadcast( - &AzFramework::SessionAsyncRequestNotifications::OnCreateSessionAsyncComplete, result); + Multiplayer::SessionAsyncRequestNotificationBus::Broadcast( + &Multiplayer::SessionAsyncRequestNotifications::OnCreateSessionAsyncComplete, result); }, true, jobContext); createSessionOnQueueJob->Start(); @@ -233,12 +233,12 @@ namespace AWSGameLift else { AZ_Error(AWSGameLiftClientManagerName, false, AWSGameLiftCreateSessionRequestInvalidErrorMessage); - AzFramework::SessionAsyncRequestNotificationBus::Broadcast( - &AzFramework::SessionAsyncRequestNotifications::OnCreateSessionAsyncComplete, ""); + Multiplayer::SessionAsyncRequestNotificationBus::Broadcast( + &Multiplayer::SessionAsyncRequestNotifications::OnCreateSessionAsyncComplete, ""); } } - bool AWSGameLiftClientManager::JoinSession(const AzFramework::JoinSessionRequest& joinSessionRequest) + bool AWSGameLiftClientManager::JoinSession(const Multiplayer::JoinSessionRequest& joinSessionRequest) { bool result = false; if (JoinSessionActivity::ValidateJoinSessionRequest(joinSessionRequest)) @@ -252,12 +252,12 @@ namespace AWSGameLift return result; } - void AWSGameLiftClientManager::JoinSessionAsync(const AzFramework::JoinSessionRequest& joinSessionRequest) + void AWSGameLiftClientManager::JoinSessionAsync(const Multiplayer::JoinSessionRequest& joinSessionRequest) { if (!JoinSessionActivity::ValidateJoinSessionRequest(joinSessionRequest)) { - AzFramework::SessionAsyncRequestNotificationBus::Broadcast( - &AzFramework::SessionAsyncRequestNotifications::OnJoinSessionAsyncComplete, false); + Multiplayer::SessionAsyncRequestNotificationBus::Broadcast( + &Multiplayer::SessionAsyncRequestNotifications::OnJoinSessionAsyncComplete, false); return; } @@ -272,8 +272,8 @@ namespace AWSGameLift auto createPlayerSessionOutcome = JoinSessionActivity::CreatePlayerSession(gameliftJoinSessionRequest); bool result = JoinSessionActivity::RequestPlayerJoinSession(createPlayerSessionOutcome); - AzFramework::SessionAsyncRequestNotificationBus::Broadcast( - &AzFramework::SessionAsyncRequestNotifications::OnJoinSessionAsyncComplete, result); + Multiplayer::SessionAsyncRequestNotificationBus::Broadcast( + &Multiplayer::SessionAsyncRequestNotifications::OnJoinSessionAsyncComplete, result); }, true, jobContext); @@ -293,18 +293,18 @@ namespace AWSGameLift [this]() { LeaveSession(); - AzFramework::SessionAsyncRequestNotificationBus::Broadcast( - &AzFramework::SessionAsyncRequestNotifications::OnLeaveSessionAsyncComplete); + Multiplayer::SessionAsyncRequestNotificationBus::Broadcast( + &Multiplayer::SessionAsyncRequestNotifications::OnLeaveSessionAsyncComplete); }, true, jobContext); leaveSessionJob->Start(); } - AzFramework::SearchSessionsResponse AWSGameLiftClientManager::SearchSessions( - const AzFramework::SearchSessionsRequest& searchSessionsRequest) const + Multiplayer::SearchSessionsResponse AWSGameLiftClientManager::SearchSessions( + const Multiplayer::SearchSessionsRequest& searchSessionsRequest) const { - AzFramework::SearchSessionsResponse response; + Multiplayer::SearchSessionsResponse response; if (SearchSessionsActivity::ValidateSearchSessionsRequest(searchSessionsRequest)) { const AWSGameLiftSearchSessionsRequest& gameliftSearchSessionsRequest = @@ -315,12 +315,12 @@ namespace AWSGameLift return response; } - void AWSGameLiftClientManager::SearchSessionsAsync(const AzFramework::SearchSessionsRequest& searchSessionsRequest) const + void AWSGameLiftClientManager::SearchSessionsAsync(const Multiplayer::SearchSessionsRequest& searchSessionsRequest) const { if (!SearchSessionsActivity::ValidateSearchSessionsRequest(searchSessionsRequest)) { - AzFramework::SessionAsyncRequestNotificationBus::Broadcast( - &AzFramework::SessionAsyncRequestNotifications::OnSearchSessionsAsyncComplete, AzFramework::SearchSessionsResponse()); + Multiplayer::SessionAsyncRequestNotificationBus::Broadcast( + &Multiplayer::SessionAsyncRequestNotifications::OnSearchSessionsAsyncComplete, Multiplayer::SearchSessionsResponse()); return; } @@ -332,17 +332,17 @@ namespace AWSGameLift AZ::Job* searchSessionsJob = AZ::CreateJobFunction( [gameliftSearchSessionsRequest]() { - AzFramework::SearchSessionsResponse response = SearchSessionsActivity::SearchSessions(gameliftSearchSessionsRequest); + Multiplayer::SearchSessionsResponse response = SearchSessionsActivity::SearchSessions(gameliftSearchSessionsRequest); - AzFramework::SessionAsyncRequestNotificationBus::Broadcast( - &AzFramework::SessionAsyncRequestNotifications::OnSearchSessionsAsyncComplete, response); + Multiplayer::SessionAsyncRequestNotificationBus::Broadcast( + &Multiplayer::SessionAsyncRequestNotifications::OnSearchSessionsAsyncComplete, response); }, true, jobContext); searchSessionsJob->Start(); } - AZStd::string AWSGameLiftClientManager::StartMatchmaking(const AzFramework::StartMatchmakingRequest& startMatchmakingRequest) + AZStd::string AWSGameLiftClientManager::StartMatchmaking(const Multiplayer::StartMatchmakingRequest& startMatchmakingRequest) { AZStd::string response; if (StartMatchmakingActivity::ValidateStartMatchmakingRequest(startMatchmakingRequest)) @@ -355,12 +355,12 @@ namespace AWSGameLift return response; } - void AWSGameLiftClientManager::StartMatchmakingAsync(const AzFramework::StartMatchmakingRequest& startMatchmakingRequest) + void AWSGameLiftClientManager::StartMatchmakingAsync(const Multiplayer::StartMatchmakingRequest& startMatchmakingRequest) { if (!StartMatchmakingActivity::ValidateStartMatchmakingRequest(startMatchmakingRequest)) { - AzFramework::MatchmakingAsyncRequestNotificationBus::Broadcast( - &AzFramework::MatchmakingAsyncRequestNotifications::OnStartMatchmakingAsyncComplete, AZStd::string{}); + Multiplayer::MatchmakingAsyncRequestNotificationBus::Broadcast( + &Multiplayer::MatchmakingAsyncRequestNotifications::OnStartMatchmakingAsyncComplete, AZStd::string{}); return; } @@ -374,15 +374,15 @@ namespace AWSGameLift { AZStd::string response = StartMatchmakingActivity::StartMatchmaking(gameliftStartMatchmakingRequest); - AzFramework::MatchmakingAsyncRequestNotificationBus::Broadcast( - &AzFramework::MatchmakingAsyncRequestNotifications::OnStartMatchmakingAsyncComplete, response); + Multiplayer::MatchmakingAsyncRequestNotificationBus::Broadcast( + &Multiplayer::MatchmakingAsyncRequestNotifications::OnStartMatchmakingAsyncComplete, response); }, true, jobContext); startMatchmakingJob->Start(); } - void AWSGameLiftClientManager::StopMatchmaking(const AzFramework::StopMatchmakingRequest& stopMatchmakingRequest) + void AWSGameLiftClientManager::StopMatchmaking(const Multiplayer::StopMatchmakingRequest& stopMatchmakingRequest) { if (StopMatchmakingActivity::ValidateStopMatchmakingRequest(stopMatchmakingRequest)) { @@ -393,12 +393,12 @@ namespace AWSGameLift } } - void AWSGameLiftClientManager::StopMatchmakingAsync(const AzFramework::StopMatchmakingRequest& stopMatchmakingRequest) + void AWSGameLiftClientManager::StopMatchmakingAsync(const Multiplayer::StopMatchmakingRequest& stopMatchmakingRequest) { if (!StopMatchmakingActivity::ValidateStopMatchmakingRequest(stopMatchmakingRequest)) { - AzFramework::MatchmakingAsyncRequestNotificationBus::Broadcast( - &AzFramework::MatchmakingAsyncRequestNotifications::OnStopMatchmakingAsyncComplete); + Multiplayer::MatchmakingAsyncRequestNotificationBus::Broadcast( + &Multiplayer::MatchmakingAsyncRequestNotifications::OnStopMatchmakingAsyncComplete); return; } @@ -412,8 +412,8 @@ namespace AWSGameLift { StopMatchmakingActivity::StopMatchmaking(gameliftStopMatchmakingRequest); - AzFramework::MatchmakingAsyncRequestNotificationBus::Broadcast( - &AzFramework::MatchmakingAsyncRequestNotifications::OnStopMatchmakingAsyncComplete); + Multiplayer::MatchmakingAsyncRequestNotificationBus::Broadcast( + &Multiplayer::MatchmakingAsyncRequestNotifications::OnStopMatchmakingAsyncComplete); }, true, jobContext); diff --git a/Gems/AWSGameLift/Code/AWSGameLiftClient/Source/AWSGameLiftClientManager.h b/Gems/AWSGameLift/Code/AWSGameLiftClient/Source/AWSGameLiftClientManager.h index f37152bc60..22fc9ceb3f 100644 --- a/Gems/AWSGameLift/Code/AWSGameLiftClient/Source/AWSGameLiftClientManager.h +++ b/Gems/AWSGameLift/Code/AWSGameLiftClient/Source/AWSGameLiftClientManager.h @@ -10,7 +10,7 @@ #include #include -#include +#include #include #include @@ -28,7 +28,7 @@ namespace AWSGameLift // MatchmakingNotificationBus EBus handler for scripting class AWSGameLiftMatchmakingNotificationBusHandler - : public AzFramework::MatchmakingNotificationBus::Handler + : public Multiplayer::MatchmakingNotificationBus::Handler , public AZ::BehaviorEBusHandler { public: @@ -61,7 +61,7 @@ namespace AWSGameLift // MatchmakingAsyncRequestNotificationBus EBus handler for scripting class AWSGameLiftMatchmakingAsyncRequestNotificationBusHandler - : public AzFramework::MatchmakingAsyncRequestNotificationBus::Handler + : public Multiplayer::MatchmakingAsyncRequestNotificationBus::Handler , public AZ::BehaviorEBusHandler { public: @@ -91,7 +91,7 @@ namespace AWSGameLift // SessionAsyncRequestNotificationBus EBus handler for scripting class AWSGameLiftSessionAsyncRequestNotificationBusHandler - : public AzFramework::SessionAsyncRequestNotificationBus::Handler + : public Multiplayer::SessionAsyncRequestNotificationBus::Handler , public AZ::BehaviorEBusHandler { public: @@ -109,7 +109,7 @@ namespace AWSGameLift Call(FN_OnCreateSessionAsyncComplete, createSessionReponse); } - void OnSearchSessionsAsyncComplete(const AzFramework::SearchSessionsResponse& searchSessionsResponse) override + void OnSearchSessionsAsyncComplete(const Multiplayer::SearchSessionsResponse& searchSessionsResponse) override { Call(FN_OnSearchSessionsAsyncComplete, searchSessionsResponse); } @@ -155,25 +155,25 @@ namespace AWSGameLift AZStd::string CreatePlayerId(bool includeBrackets, bool includeDashes) override; // AWSGameLiftMatchmakingAsyncRequestBus interface implementation - void AcceptMatchAsync(const AzFramework::AcceptMatchRequest& acceptMatchRequest) override; - void StartMatchmakingAsync(const AzFramework::StartMatchmakingRequest& startMatchmakingRequest) override; - void StopMatchmakingAsync(const AzFramework::StopMatchmakingRequest& stopMatchmakingRequest) override; + void AcceptMatchAsync(const Multiplayer::AcceptMatchRequest& acceptMatchRequest) override; + void StartMatchmakingAsync(const Multiplayer::StartMatchmakingRequest& startMatchmakingRequest) override; + void StopMatchmakingAsync(const Multiplayer::StopMatchmakingRequest& stopMatchmakingRequest) override; // AWSGameLiftSessionAsyncRequestBus interface implementation - void CreateSessionAsync(const AzFramework::CreateSessionRequest& createSessionRequest) override; - void JoinSessionAsync(const AzFramework::JoinSessionRequest& joinSessionRequest) override; - void SearchSessionsAsync(const AzFramework::SearchSessionsRequest& searchSessionsRequest) const override; + void CreateSessionAsync(const Multiplayer::CreateSessionRequest& createSessionRequest) override; + void JoinSessionAsync(const Multiplayer::JoinSessionRequest& joinSessionRequest) override; + void SearchSessionsAsync(const Multiplayer::SearchSessionsRequest& searchSessionsRequest) const override; void LeaveSessionAsync() override; // AWSGameLiftMatchmakingRequestBus interface implementation - void AcceptMatch(const AzFramework::AcceptMatchRequest& acceptMatchRequest) override; - AZStd::string StartMatchmaking(const AzFramework::StartMatchmakingRequest& startMatchmakingRequest) override; - void StopMatchmaking(const AzFramework::StopMatchmakingRequest& stopMatchmakingRequest) override; + void AcceptMatch(const Multiplayer::AcceptMatchRequest& acceptMatchRequest) override; + AZStd::string StartMatchmaking(const Multiplayer::StartMatchmakingRequest& startMatchmakingRequest) override; + void StopMatchmaking(const Multiplayer::StopMatchmakingRequest& stopMatchmakingRequest) override; // AWSGameLiftSessionRequestBus interface implementation - AZStd::string CreateSession(const AzFramework::CreateSessionRequest& createSessionRequest) override; - bool JoinSession(const AzFramework::JoinSessionRequest& joinSessionRequest) override; - AzFramework::SearchSessionsResponse SearchSessions(const AzFramework::SearchSessionsRequest& searchSessionsRequest) const override; + AZStd::string CreateSession(const Multiplayer::CreateSessionRequest& createSessionRequest) override; + bool JoinSession(const Multiplayer::JoinSessionRequest& joinSessionRequest) override; + Multiplayer::SearchSessionsResponse SearchSessions(const Multiplayer::SearchSessionsRequest& searchSessionsRequest) const override; void LeaveSession() override; }; } // namespace AWSGameLift diff --git a/Gems/AWSGameLift/Code/AWSGameLiftClient/Source/AWSGameLiftClientSystemComponent.cpp b/Gems/AWSGameLift/Code/AWSGameLiftClient/Source/AWSGameLiftClientSystemComponent.cpp index d256c6c33c..8ab00e8038 100644 --- a/Gems/AWSGameLift/Code/AWSGameLiftClient/Source/AWSGameLiftClientSystemComponent.cpp +++ b/Gems/AWSGameLift/Code/AWSGameLiftClient/Source/AWSGameLiftClientSystemComponent.cpp @@ -10,7 +10,7 @@ #include #include #include -#include +#include #include #include @@ -129,7 +129,7 @@ namespace AWSGameLift ->Event("StopMatchmakingAsync", &AWSGameLiftMatchmakingAsyncRequestBus::Events::StopMatchmakingAsync, { { { "StopMatchmakingRequest", "" } } }); - behaviorContext->EBus("AWSGameLiftMatchmakingAsyncRequestNotificationBus") + behaviorContext->EBus("AWSGameLiftMatchmakingAsyncRequestNotificationBus") ->Attribute(AZ::Script::Attributes::Category, "AWSGameLift/Matchmaking") ->Handler(); @@ -149,7 +149,7 @@ namespace AWSGameLift { "PlayerId", "" } } }) ->Event("StopPolling", &AWSGameLiftMatchmakingEventRequestBus::Events::StopPolling); - behaviorContext->EBus("AWSGameLiftMatchmakingNotificationBus") + behaviorContext->EBus("AWSGameLiftMatchmakingNotificationBus") ->Attribute(AZ::Script::Attributes::Category, "AWSGameLift/Matchmaking") ->Handler(); } @@ -175,7 +175,7 @@ namespace AWSGameLift { { { "SearchSessionsRequest", "" } } }) ->Event("LeaveSessionAsync", &AWSGameLiftSessionAsyncRequestBus::Events::LeaveSessionAsync); - behaviorContext->EBus("AWSGameLiftSessionAsyncRequestNotificationBus") + behaviorContext->EBus("AWSGameLiftSessionAsyncRequestNotificationBus") ->Attribute(AZ::Script::Attributes::Category, "AWSGameLift/Session") ->Handler(); @@ -190,10 +190,10 @@ namespace AWSGameLift void AWSGameLiftClientSystemComponent::ReflectCreateSessionRequest(AZ::ReflectContext* context) { - AzFramework::CreateSessionRequest::Reflect(context); + Multiplayer::CreateSessionRequest::Reflect(context); if (AZ::BehaviorContext* behaviorContext = azrtti_cast(context)) { - behaviorContext->Class("CreateSessionRequest") + behaviorContext->Class("CreateSessionRequest") ->Attribute(AZ::Script::Attributes::Storage, AZ::Script::Attributes::StorageType::Value) // Expose base type to BehaviorContext, but hide it to be used directly ->Attribute(AZ::Script::Attributes::ExcludeFrom, AZ::Script::Attributes::ExcludeFlags::All) @@ -204,34 +204,34 @@ namespace AWSGameLift void AWSGameLiftClientSystemComponent::ReflectSearchSessionsResponse(AZ::ReflectContext* context) { // As it is a common response type, reflection could be moved to AzFramework to avoid duplication - AzFramework::SessionConfig::Reflect(context); - AzFramework::SearchSessionsResponse::Reflect(context); + Multiplayer::SessionConfig::Reflect(context); + Multiplayer::SearchSessionsResponse::Reflect(context); if (AZ::BehaviorContext* behaviorContext = azrtti_cast(context)) { - behaviorContext->Class("SessionConfig") + behaviorContext->Class("SessionConfig") ->Attribute(AZ::Script::Attributes::Category, "Session") ->Attribute(AZ::Script::Attributes::Storage, AZ::Script::Attributes::StorageType::Value) - ->Property("CreationTime", BehaviorValueProperty(&AzFramework::SessionConfig::m_creationTime)) - ->Property("CreatorId", BehaviorValueProperty(&AzFramework::SessionConfig::m_creatorId)) - ->Property("CurrentPlayer", BehaviorValueProperty(&AzFramework::SessionConfig::m_currentPlayer)) - ->Property("DnsName", BehaviorValueProperty(&AzFramework::SessionConfig::m_dnsName)) - ->Property("IpAddress", BehaviorValueProperty(&AzFramework::SessionConfig::m_ipAddress)) - ->Property("MaxPlayer", BehaviorValueProperty(&AzFramework::SessionConfig::m_maxPlayer)) - ->Property("Port", BehaviorValueProperty(&AzFramework::SessionConfig::m_port)) - ->Property("SessionId", BehaviorValueProperty(&AzFramework::SessionConfig::m_sessionId)) - ->Property("SessionName", BehaviorValueProperty(&AzFramework::SessionConfig::m_sessionName)) - ->Property("SessionProperties", BehaviorValueProperty(&AzFramework::SessionConfig::m_sessionProperties)) - ->Property("MatchmakingData", BehaviorValueProperty(&AzFramework::SessionConfig::m_matchmakingData)) - ->Property("Status", BehaviorValueProperty(&AzFramework::SessionConfig::m_status)) - ->Property("StatusReason", BehaviorValueProperty(&AzFramework::SessionConfig::m_statusReason)) - ->Property("TerminationTime", BehaviorValueProperty(&AzFramework::SessionConfig::m_terminationTime)) + ->Property("CreationTime", BehaviorValueProperty(&Multiplayer::SessionConfig::m_creationTime)) + ->Property("CreatorId", BehaviorValueProperty(&Multiplayer::SessionConfig::m_creatorId)) + ->Property("CurrentPlayer", BehaviorValueProperty(&Multiplayer::SessionConfig::m_currentPlayer)) + ->Property("DnsName", BehaviorValueProperty(&Multiplayer::SessionConfig::m_dnsName)) + ->Property("IpAddress", BehaviorValueProperty(&Multiplayer::SessionConfig::m_ipAddress)) + ->Property("MaxPlayer", BehaviorValueProperty(&Multiplayer::SessionConfig::m_maxPlayer)) + ->Property("Port", BehaviorValueProperty(&Multiplayer::SessionConfig::m_port)) + ->Property("SessionId", BehaviorValueProperty(&Multiplayer::SessionConfig::m_sessionId)) + ->Property("SessionName", BehaviorValueProperty(&Multiplayer::SessionConfig::m_sessionName)) + ->Property("SessionProperties", BehaviorValueProperty(&Multiplayer::SessionConfig::m_sessionProperties)) + ->Property("MatchmakingData", BehaviorValueProperty(&Multiplayer::SessionConfig::m_matchmakingData)) + ->Property("Status", BehaviorValueProperty(&Multiplayer::SessionConfig::m_status)) + ->Property("StatusReason", BehaviorValueProperty(&Multiplayer::SessionConfig::m_statusReason)) + ->Property("TerminationTime", BehaviorValueProperty(&Multiplayer::SessionConfig::m_terminationTime)) ; - behaviorContext->Class("SearchSessionsResponse") + behaviorContext->Class("SearchSessionsResponse") ->Attribute(AZ::Script::Attributes::Category, "Session") ->Attribute(AZ::Script::Attributes::Storage, AZ::Script::Attributes::StorageType::Value) - ->Property("NextToken", BehaviorValueProperty(&AzFramework::SearchSessionsResponse::m_nextToken)) - ->Property("SessionConfigs", BehaviorValueProperty(&AzFramework::SearchSessionsResponse::m_sessionConfigs)) + ->Property("NextToken", BehaviorValueProperty(&Multiplayer::SearchSessionsResponse::m_nextToken)) + ->Property("SessionConfigs", BehaviorValueProperty(&Multiplayer::SearchSessionsResponse::m_sessionConfigs)) ; } } diff --git a/Gems/AWSGameLift/Code/AWSGameLiftClient/Source/Activity/AWSGameLiftAcceptMatchActivity.cpp b/Gems/AWSGameLift/Code/AWSGameLiftClient/Source/Activity/AWSGameLiftAcceptMatchActivity.cpp index dbeced1728..1a39b5c944 100644 --- a/Gems/AWSGameLift/Code/AWSGameLiftClient/Source/Activity/AWSGameLiftAcceptMatchActivity.cpp +++ b/Gems/AWSGameLift/Code/AWSGameLiftClient/Source/Activity/AWSGameLiftAcceptMatchActivity.cpp @@ -69,7 +69,7 @@ namespace AWSGameLift } } - bool ValidateAcceptMatchRequest(const AzFramework::AcceptMatchRequest& AcceptMatchRequest) + bool ValidateAcceptMatchRequest(const Multiplayer::AcceptMatchRequest& AcceptMatchRequest) { auto gameliftAcceptMatchRequest = azrtti_cast(&AcceptMatchRequest); bool isValid = gameliftAcceptMatchRequest && diff --git a/Gems/AWSGameLift/Code/AWSGameLiftClient/Source/Activity/AWSGameLiftAcceptMatchActivity.h b/Gems/AWSGameLift/Code/AWSGameLiftClient/Source/Activity/AWSGameLiftAcceptMatchActivity.h index ac4012c347..a3b637168a 100644 --- a/Gems/AWSGameLift/Code/AWSGameLiftClient/Source/Activity/AWSGameLiftAcceptMatchActivity.h +++ b/Gems/AWSGameLift/Code/AWSGameLiftClient/Source/Activity/AWSGameLiftAcceptMatchActivity.h @@ -26,6 +26,6 @@ namespace AWSGameLift void AcceptMatch(const AWSGameLiftAcceptMatchRequest& AcceptMatchRequest); // Validate AcceptMatchRequest and check required request parameters - bool ValidateAcceptMatchRequest(const AzFramework::AcceptMatchRequest& AcceptMatchRequest); + bool ValidateAcceptMatchRequest(const Multiplayer::AcceptMatchRequest& AcceptMatchRequest); } // namespace AcceptMatchActivity } // namespace AWSGameLift diff --git a/Gems/AWSGameLift/Code/AWSGameLiftClient/Source/Activity/AWSGameLiftCreateSessionActivity.cpp b/Gems/AWSGameLift/Code/AWSGameLiftClient/Source/Activity/AWSGameLiftCreateSessionActivity.cpp index ee93f022a1..8b2182488f 100644 --- a/Gems/AWSGameLift/Code/AWSGameLiftClient/Source/Activity/AWSGameLiftCreateSessionActivity.cpp +++ b/Gems/AWSGameLift/Code/AWSGameLiftClient/Source/Activity/AWSGameLiftCreateSessionActivity.cpp @@ -99,7 +99,7 @@ namespace AWSGameLift return result; } - bool ValidateCreateSessionRequest(const AzFramework::CreateSessionRequest& createSessionRequest) + bool ValidateCreateSessionRequest(const Multiplayer::CreateSessionRequest& createSessionRequest) { auto gameliftCreateSessionRequest = azrtti_cast(&createSessionRequest); diff --git a/Gems/AWSGameLift/Code/AWSGameLiftClient/Source/Activity/AWSGameLiftCreateSessionActivity.h b/Gems/AWSGameLift/Code/AWSGameLiftClient/Source/Activity/AWSGameLiftCreateSessionActivity.h index af236dbfa4..103231a0ed 100644 --- a/Gems/AWSGameLift/Code/AWSGameLiftClient/Source/Activity/AWSGameLiftCreateSessionActivity.h +++ b/Gems/AWSGameLift/Code/AWSGameLiftClient/Source/Activity/AWSGameLiftCreateSessionActivity.h @@ -25,7 +25,7 @@ namespace AWSGameLift AZStd::string CreateSession(const AWSGameLiftCreateSessionRequest& createSessionRequest); // Validate CreateSessionRequest and check required request parameters - bool ValidateCreateSessionRequest(const AzFramework::CreateSessionRequest& createSessionRequest); + bool ValidateCreateSessionRequest(const Multiplayer::CreateSessionRequest& createSessionRequest); } // namespace CreateSessionActivity } // namespace AWSGameLift diff --git a/Gems/AWSGameLift/Code/AWSGameLiftClient/Source/Activity/AWSGameLiftCreateSessionOnQueueActivity.cpp b/Gems/AWSGameLift/Code/AWSGameLiftClient/Source/Activity/AWSGameLiftCreateSessionOnQueueActivity.cpp index 8e8d7e23c5..d1cd7a2a39 100644 --- a/Gems/AWSGameLift/Code/AWSGameLiftClient/Source/Activity/AWSGameLiftCreateSessionOnQueueActivity.cpp +++ b/Gems/AWSGameLift/Code/AWSGameLiftClient/Source/Activity/AWSGameLiftCreateSessionOnQueueActivity.cpp @@ -87,7 +87,7 @@ namespace AWSGameLift return result; } - bool ValidateCreateSessionOnQueueRequest(const AzFramework::CreateSessionRequest& createSessionRequest) + bool ValidateCreateSessionOnQueueRequest(const Multiplayer::CreateSessionRequest& createSessionRequest) { auto gameliftCreateSessionOnQueueRequest = azrtti_cast(&createSessionRequest); diff --git a/Gems/AWSGameLift/Code/AWSGameLiftClient/Source/Activity/AWSGameLiftCreateSessionOnQueueActivity.h b/Gems/AWSGameLift/Code/AWSGameLiftClient/Source/Activity/AWSGameLiftCreateSessionOnQueueActivity.h index 5f16bf0b31..014431ef3f 100644 --- a/Gems/AWSGameLift/Code/AWSGameLiftClient/Source/Activity/AWSGameLiftCreateSessionOnQueueActivity.h +++ b/Gems/AWSGameLift/Code/AWSGameLiftClient/Source/Activity/AWSGameLiftCreateSessionOnQueueActivity.h @@ -26,7 +26,7 @@ namespace AWSGameLift AZStd::string CreateSessionOnQueue(const AWSGameLiftCreateSessionOnQueueRequest& createSessionOnQueueRequest); // Validate CreateSessionOnQueueRequest and check required request parameters - bool ValidateCreateSessionOnQueueRequest(const AzFramework::CreateSessionRequest& createSessionRequest); + bool ValidateCreateSessionOnQueueRequest(const Multiplayer::CreateSessionRequest& createSessionRequest); } // namespace CreateSessionOnQueueActivity } // namespace AWSGameLift diff --git a/Gems/AWSGameLift/Code/AWSGameLiftClient/Source/Activity/AWSGameLiftJoinSessionActivity.cpp b/Gems/AWSGameLift/Code/AWSGameLiftClient/Source/Activity/AWSGameLiftJoinSessionActivity.cpp index 71ef9e9737..f93f9e5378 100644 --- a/Gems/AWSGameLift/Code/AWSGameLiftClient/Source/Activity/AWSGameLiftJoinSessionActivity.cpp +++ b/Gems/AWSGameLift/Code/AWSGameLiftClient/Source/Activity/AWSGameLiftJoinSessionActivity.cpp @@ -39,10 +39,10 @@ namespace AWSGameLift return request; } - AzFramework::SessionConnectionConfig BuildSessionConnectionConfig( + Multiplayer::SessionConnectionConfig BuildSessionConnectionConfig( const Aws::GameLift::Model::CreatePlayerSessionOutcome& createPlayerSessionOutcome) { - AzFramework::SessionConnectionConfig sessionConnectionConfig; + Multiplayer::SessionConnectionConfig sessionConnectionConfig; auto createPlayerSessionResult = createPlayerSessionOutcome.GetResult(); // TODO: AWSNativeSDK needs to be updated to support this attribute, and it is a must have for TLS certificate enabled fleet //sessionConnectionConfig.m_dnsName = createPlayerSessionResult.GetPlayerSession().GetDnsName().c_str(); @@ -95,10 +95,10 @@ namespace AWSGameLift bool result = false; if (createPlayerSessionOutcome.IsSuccess()) { - auto clientRequestHandler = AZ::Interface::Get(); + auto clientRequestHandler = AZ::Interface::Get(); if (clientRequestHandler) { - AzFramework::SessionConnectionConfig sessionConnectionConfig = + Multiplayer::SessionConnectionConfig sessionConnectionConfig = BuildSessionConnectionConfig(createPlayerSessionOutcome); AZ_TracePrintf(AWSGameLiftJoinSessionActivityName, @@ -114,7 +114,7 @@ namespace AWSGameLift return result; } - bool ValidateJoinSessionRequest(const AzFramework::JoinSessionRequest& joinSessionRequest) + bool ValidateJoinSessionRequest(const Multiplayer::JoinSessionRequest& joinSessionRequest) { auto gameliftJoinSessionRequest = azrtti_cast(&joinSessionRequest); diff --git a/Gems/AWSGameLift/Code/AWSGameLiftClient/Source/Activity/AWSGameLiftJoinSessionActivity.h b/Gems/AWSGameLift/Code/AWSGameLiftClient/Source/Activity/AWSGameLiftJoinSessionActivity.h index b011f4877b..8e79ee961c 100644 --- a/Gems/AWSGameLift/Code/AWSGameLiftClient/Source/Activity/AWSGameLiftJoinSessionActivity.h +++ b/Gems/AWSGameLift/Code/AWSGameLiftClient/Source/Activity/AWSGameLiftJoinSessionActivity.h @@ -8,7 +8,7 @@ #pragma once -#include +#include #include @@ -31,7 +31,7 @@ namespace AWSGameLift const AWSGameLiftJoinSessionRequest& joinSessionRequest); // Build session connection config by using CreatePlayerSessionOutcome - AzFramework::SessionConnectionConfig BuildSessionConnectionConfig( + Multiplayer::SessionConnectionConfig BuildSessionConnectionConfig( const Aws::GameLift::Model::CreatePlayerSessionOutcome& createPlayerSessionOutcome); // Create CreatePlayerSessionRequest and make a CreatePlayerSession call through GameLift client @@ -43,7 +43,7 @@ namespace AWSGameLift const Aws::GameLift::Model::CreatePlayerSessionOutcome& createPlayerSessionOutcome); // Validate JoinSessionRequest and check required request parameters - bool ValidateJoinSessionRequest(const AzFramework::JoinSessionRequest& joinSessionRequest); + bool ValidateJoinSessionRequest(const Multiplayer::JoinSessionRequest& joinSessionRequest); } // namespace JoinSessionActivity } // namespace AWSGameLift diff --git a/Gems/AWSGameLift/Code/AWSGameLiftClient/Source/Activity/AWSGameLiftLeaveSessionActivity.cpp b/Gems/AWSGameLift/Code/AWSGameLiftClient/Source/Activity/AWSGameLiftLeaveSessionActivity.cpp index fd3b3d6ebc..38f5c39377 100644 --- a/Gems/AWSGameLift/Code/AWSGameLiftClient/Source/Activity/AWSGameLiftLeaveSessionActivity.cpp +++ b/Gems/AWSGameLift/Code/AWSGameLiftClient/Source/Activity/AWSGameLiftLeaveSessionActivity.cpp @@ -8,7 +8,7 @@ #include #include -#include +#include #include @@ -18,7 +18,7 @@ namespace AWSGameLift { void LeaveSession() { - auto clientRequestHandler = AZ::Interface::Get(); + auto clientRequestHandler = AZ::Interface::Get(); if (clientRequestHandler) { AZ_TracePrintf(AWSGameLiftLeaveSessionActivityName, "Requesting player to leave the current session ..."); diff --git a/Gems/AWSGameLift/Code/AWSGameLiftClient/Source/Activity/AWSGameLiftSearchSessionsActivity.cpp b/Gems/AWSGameLift/Code/AWSGameLiftClient/Source/Activity/AWSGameLiftSearchSessionsActivity.cpp index b7917e6d59..e755f52cd2 100644 --- a/Gems/AWSGameLift/Code/AWSGameLiftClient/Source/Activity/AWSGameLiftSearchSessionsActivity.cpp +++ b/Gems/AWSGameLift/Code/AWSGameLiftClient/Source/Activity/AWSGameLiftSearchSessionsActivity.cpp @@ -8,7 +8,7 @@ #include #include -#include +#include #include #include @@ -67,10 +67,10 @@ namespace AWSGameLift return request; } - AzFramework::SearchSessionsResponse SearchSessions( + Multiplayer::SearchSessionsResponse SearchSessions( const AWSGameLiftSearchSessionsRequest& searchSessionsRequest) { - AzFramework::SearchSessionsResponse response; + Multiplayer::SearchSessionsResponse response; auto gameliftClient = AZ::Interface::Get()->GetGameLiftClient(); if (!gameliftClient) @@ -98,15 +98,15 @@ namespace AWSGameLift return response; } - AzFramework::SearchSessionsResponse ParseResponse( + Multiplayer::SearchSessionsResponse ParseResponse( const Aws::GameLift::Model::SearchGameSessionsResult& gameLiftSearchSessionsResult) { - AzFramework::SearchSessionsResponse response; + Multiplayer::SearchSessionsResponse response; response.m_nextToken = gameLiftSearchSessionsResult.GetNextToken().c_str(); for (const Aws::GameLift::Model::GameSession& gameSession : gameLiftSearchSessionsResult.GetGameSessions()) { - AzFramework::SessionConfig session; + Multiplayer::SessionConfig session; session.m_creationTime = gameSession.GetCreationTime().Millis(); session.m_creatorId = gameSession.GetCreatorId().c_str(); session.m_currentPlayer = gameSession.GetCurrentPlayerSessionCount(); @@ -133,7 +133,7 @@ namespace AWSGameLift return response; }; - bool ValidateSearchSessionsRequest(const AzFramework::SearchSessionsRequest& searchSessionsRequest) + bool ValidateSearchSessionsRequest(const Multiplayer::SearchSessionsRequest& searchSessionsRequest) { auto gameliftSearchSessionsRequest = azrtti_cast(&searchSessionsRequest); if (gameliftSearchSessionsRequest && diff --git a/Gems/AWSGameLift/Code/AWSGameLiftClient/Source/Activity/AWSGameLiftSearchSessionsActivity.h b/Gems/AWSGameLift/Code/AWSGameLiftClient/Source/Activity/AWSGameLiftSearchSessionsActivity.h index d5bcda992c..10095448d3 100644 --- a/Gems/AWSGameLift/Code/AWSGameLiftClient/Source/Activity/AWSGameLiftSearchSessionsActivity.h +++ b/Gems/AWSGameLift/Code/AWSGameLiftClient/Source/Activity/AWSGameLiftSearchSessionsActivity.h @@ -25,14 +25,14 @@ namespace AWSGameLift const AWSGameLiftSearchSessionsRequest& searchSessionsRequest); // Create SearchGameSessionsRequest and make a SeachGameSessions call through GameLift client - AzFramework::SearchSessionsResponse SearchSessions( + Multiplayer::SearchSessionsResponse SearchSessions( const AWSGameLiftSearchSessionsRequest& searchSessionsRequest); - // Convert from Aws::GameLift::Model::SearchGameSessionsResult to AzFramework::SearchSessionsResponse. - AzFramework::SearchSessionsResponse ParseResponse( + // Convert from Aws::GameLift::Model::SearchGameSessionsResult to Multiplayer::SearchSessionsResponse. + Multiplayer::SearchSessionsResponse ParseResponse( const Aws::GameLift::Model::SearchGameSessionsResult& gameLiftSearchSessionsResult); // Validate SearchSessionsRequest and check required request parameters - bool ValidateSearchSessionsRequest(const AzFramework::SearchSessionsRequest& searchSessionsRequest); + bool ValidateSearchSessionsRequest(const Multiplayer::SearchSessionsRequest& searchSessionsRequest); } // namespace SearchSessionsActivity } // namespace AWSGameLift diff --git a/Gems/AWSGameLift/Code/AWSGameLiftClient/Source/Activity/AWSGameLiftStartMatchmakingActivity.cpp b/Gems/AWSGameLift/Code/AWSGameLiftClient/Source/Activity/AWSGameLiftStartMatchmakingActivity.cpp index 6f6c7fccc0..5c436ea9e3 100644 --- a/Gems/AWSGameLift/Code/AWSGameLiftClient/Source/Activity/AWSGameLiftStartMatchmakingActivity.cpp +++ b/Gems/AWSGameLift/Code/AWSGameLiftClient/Source/Activity/AWSGameLiftStartMatchmakingActivity.cpp @@ -110,7 +110,7 @@ namespace AWSGameLift return result; } - bool ValidateStartMatchmakingRequest(const AzFramework::StartMatchmakingRequest& startMatchmakingRequest) + bool ValidateStartMatchmakingRequest(const Multiplayer::StartMatchmakingRequest& startMatchmakingRequest) { auto gameliftStartMatchmakingRequest = azrtti_cast(&startMatchmakingRequest); bool isValid = gameliftStartMatchmakingRequest && diff --git a/Gems/AWSGameLift/Code/AWSGameLiftClient/Source/Activity/AWSGameLiftStartMatchmakingActivity.h b/Gems/AWSGameLift/Code/AWSGameLiftClient/Source/Activity/AWSGameLiftStartMatchmakingActivity.h index f736e318fb..190f690434 100644 --- a/Gems/AWSGameLift/Code/AWSGameLiftClient/Source/Activity/AWSGameLiftStartMatchmakingActivity.h +++ b/Gems/AWSGameLift/Code/AWSGameLiftClient/Source/Activity/AWSGameLiftStartMatchmakingActivity.h @@ -26,6 +26,6 @@ namespace AWSGameLift AZStd::string StartMatchmaking(const AWSGameLiftStartMatchmakingRequest& startMatchmakingRequest); // Validate StartMatchmakingRequest and check required request parameters - bool ValidateStartMatchmakingRequest(const AzFramework::StartMatchmakingRequest& startMatchmakingRequest); + bool ValidateStartMatchmakingRequest(const Multiplayer::StartMatchmakingRequest& startMatchmakingRequest); } // namespace StartMatchmakingActivity } // namespace AWSGameLift diff --git a/Gems/AWSGameLift/Code/AWSGameLiftClient/Source/Activity/AWSGameLiftStopMatchmakingActivity.cpp b/Gems/AWSGameLift/Code/AWSGameLiftClient/Source/Activity/AWSGameLiftStopMatchmakingActivity.cpp index 022861570a..f67f0dffd7 100644 --- a/Gems/AWSGameLift/Code/AWSGameLiftClient/Source/Activity/AWSGameLiftStopMatchmakingActivity.cpp +++ b/Gems/AWSGameLift/Code/AWSGameLiftClient/Source/Activity/AWSGameLiftStopMatchmakingActivity.cpp @@ -59,7 +59,7 @@ namespace AWSGameLift } } - bool ValidateStopMatchmakingRequest(const AzFramework::StopMatchmakingRequest& StopMatchmakingRequest) + bool ValidateStopMatchmakingRequest(const Multiplayer::StopMatchmakingRequest& StopMatchmakingRequest) { auto gameliftStopMatchmakingRequest = azrtti_cast(&StopMatchmakingRequest); bool isValid = gameliftStopMatchmakingRequest && (!gameliftStopMatchmakingRequest->m_ticketId.empty()); diff --git a/Gems/AWSGameLift/Code/AWSGameLiftClient/Source/Activity/AWSGameLiftStopMatchmakingActivity.h b/Gems/AWSGameLift/Code/AWSGameLiftClient/Source/Activity/AWSGameLiftStopMatchmakingActivity.h index b5f19d35df..81903b11e0 100644 --- a/Gems/AWSGameLift/Code/AWSGameLiftClient/Source/Activity/AWSGameLiftStopMatchmakingActivity.h +++ b/Gems/AWSGameLift/Code/AWSGameLiftClient/Source/Activity/AWSGameLiftStopMatchmakingActivity.h @@ -26,6 +26,6 @@ namespace AWSGameLift void StopMatchmaking(const AWSGameLiftStopMatchmakingRequest& stopMatchmakingRequest); // Validate StopMatchmakingRequest and check required request parameters - bool ValidateStopMatchmakingRequest(const AzFramework::StopMatchmakingRequest& stopMatchmakingRequest); + bool ValidateStopMatchmakingRequest(const Multiplayer::StopMatchmakingRequest& stopMatchmakingRequest); } // namespace StopMatchmakingActivity } // namespace AWSGameLift diff --git a/Gems/AWSGameLift/Code/AWSGameLiftClient/Source/Request/AWSGameLiftAcceptMatchRequest.cpp b/Gems/AWSGameLift/Code/AWSGameLiftClient/Source/Request/AWSGameLiftAcceptMatchRequest.cpp index 0d5f2c7198..a52467052e 100644 --- a/Gems/AWSGameLift/Code/AWSGameLiftClient/Source/Request/AWSGameLiftAcceptMatchRequest.cpp +++ b/Gems/AWSGameLift/Code/AWSGameLiftClient/Source/Request/AWSGameLiftAcceptMatchRequest.cpp @@ -16,11 +16,11 @@ namespace AWSGameLift { void AWSGameLiftAcceptMatchRequest::Reflect(AZ::ReflectContext* context) { - AzFramework::AcceptMatchRequest::Reflect(context); + Multiplayer::AcceptMatchRequest::Reflect(context); if (auto serializeContext = azrtti_cast(context)) { - serializeContext->Class() + serializeContext->Class() ->Version(0); if (AZ::EditContext* editContext = serializeContext->GetEditContext()) @@ -33,7 +33,7 @@ namespace AWSGameLift if (AZ::BehaviorContext* behaviorContext = azrtti_cast(context)) { - behaviorContext->Class("AcceptMatchRequest") + behaviorContext->Class("AcceptMatchRequest") ->Attribute(AZ::Script::Attributes::Storage, AZ::Script::Attributes::StorageType::Value) // Expose base type to BehaviorContext, but hide it to be used directly ->Attribute(AZ::Script::Attributes::ExcludeFrom, AZ::Script::Attributes::ExcludeFlags::All); diff --git a/Gems/AWSGameLift/Code/AWSGameLiftClient/Source/Request/AWSGameLiftCreateSessionOnQueueRequest.cpp b/Gems/AWSGameLift/Code/AWSGameLiftClient/Source/Request/AWSGameLiftCreateSessionOnQueueRequest.cpp index a6cb024ba8..b28669f0f3 100644 --- a/Gems/AWSGameLift/Code/AWSGameLiftClient/Source/Request/AWSGameLiftCreateSessionOnQueueRequest.cpp +++ b/Gems/AWSGameLift/Code/AWSGameLiftClient/Source/Request/AWSGameLiftCreateSessionOnQueueRequest.cpp @@ -18,7 +18,7 @@ namespace AWSGameLift { if (auto serializeContext = azrtti_cast(context)) { - serializeContext->Class() + serializeContext->Class() ->Version(0) ->Field("queueName", &AWSGameLiftCreateSessionOnQueueRequest::m_queueName) ->Field("placementId", &AWSGameLiftCreateSessionOnQueueRequest::m_placementId) diff --git a/Gems/AWSGameLift/Code/AWSGameLiftClient/Source/Request/AWSGameLiftCreateSessionRequest.cpp b/Gems/AWSGameLift/Code/AWSGameLiftClient/Source/Request/AWSGameLiftCreateSessionRequest.cpp index 1c9669e474..53a7203f46 100644 --- a/Gems/AWSGameLift/Code/AWSGameLiftClient/Source/Request/AWSGameLiftCreateSessionRequest.cpp +++ b/Gems/AWSGameLift/Code/AWSGameLiftClient/Source/Request/AWSGameLiftCreateSessionRequest.cpp @@ -18,7 +18,7 @@ namespace AWSGameLift { if (auto serializeContext = azrtti_cast(context)) { - serializeContext->Class() + serializeContext->Class() ->Version(0) ->Field("aliasId", &AWSGameLiftCreateSessionRequest::m_aliasId) ->Field("fleetId", &AWSGameLiftCreateSessionRequest::m_fleetId) diff --git a/Gems/AWSGameLift/Code/AWSGameLiftClient/Source/Request/AWSGameLiftJoinSessionRequest.cpp b/Gems/AWSGameLift/Code/AWSGameLiftClient/Source/Request/AWSGameLiftJoinSessionRequest.cpp index 7d23a4b581..47dfa05012 100644 --- a/Gems/AWSGameLift/Code/AWSGameLiftClient/Source/Request/AWSGameLiftJoinSessionRequest.cpp +++ b/Gems/AWSGameLift/Code/AWSGameLiftClient/Source/Request/AWSGameLiftJoinSessionRequest.cpp @@ -15,11 +15,11 @@ namespace AWSGameLift { void AWSGameLiftJoinSessionRequest::Reflect(AZ::ReflectContext* context) { - AzFramework::JoinSessionRequest::Reflect(context); + Multiplayer::JoinSessionRequest::Reflect(context); if (auto serializeContext = azrtti_cast(context)) { - serializeContext->Class() + serializeContext->Class() ->Version(0) ; @@ -34,7 +34,7 @@ namespace AWSGameLift if (AZ::BehaviorContext* behaviorContext = azrtti_cast(context)) { - behaviorContext->Class("JoinSessionRequest") + behaviorContext->Class("JoinSessionRequest") ->Attribute(AZ::Script::Attributes::Storage, AZ::Script::Attributes::StorageType::Value) // Expose base type to BehaviorContext, but hide it to be used directly ->Attribute(AZ::Script::Attributes::ExcludeFrom, AZ::Script::Attributes::ExcludeFlags::All) diff --git a/Gems/AWSGameLift/Code/AWSGameLiftClient/Source/Request/AWSGameLiftSearchSessionsRequest.cpp b/Gems/AWSGameLift/Code/AWSGameLiftClient/Source/Request/AWSGameLiftSearchSessionsRequest.cpp index b78320dc32..56aa8bce5c 100644 --- a/Gems/AWSGameLift/Code/AWSGameLiftClient/Source/Request/AWSGameLiftSearchSessionsRequest.cpp +++ b/Gems/AWSGameLift/Code/AWSGameLiftClient/Source/Request/AWSGameLiftSearchSessionsRequest.cpp @@ -12,17 +12,17 @@ #include #include #include -#include +#include namespace AWSGameLift { void AWSGameLiftSearchSessionsRequest::Reflect(AZ::ReflectContext* context) { - AzFramework::SearchSessionsRequest::Reflect(context); + Multiplayer::SearchSessionsRequest::Reflect(context); if (auto serializeContext = azrtti_cast(context)) { - serializeContext->Class() + serializeContext->Class() ->Version(0) ->Field("aliasId", &AWSGameLiftSearchSessionsRequest::m_aliasId) ->Field("fleetId", &AWSGameLiftSearchSessionsRequest::m_fleetId) @@ -47,7 +47,7 @@ namespace AWSGameLift if (AZ::BehaviorContext* behaviorContext = azrtti_cast(context)) { - behaviorContext->Class("SearchSessionsRequest") + behaviorContext->Class("SearchSessionsRequest") ->Attribute(AZ::Script::Attributes::Storage, AZ::Script::Attributes::StorageType::Value) // Expose base type to BehaviorContext, but hide it to be used directly ->Attribute(AZ::Script::Attributes::ExcludeFrom, AZ::Script::Attributes::ExcludeFlags::All); diff --git a/Gems/AWSGameLift/Code/AWSGameLiftClient/Source/Request/AWSGameLiftStartMatchmakingRequest.cpp b/Gems/AWSGameLift/Code/AWSGameLiftClient/Source/Request/AWSGameLiftStartMatchmakingRequest.cpp index 3ec98d554f..162db200a8 100644 --- a/Gems/AWSGameLift/Code/AWSGameLiftClient/Source/Request/AWSGameLiftStartMatchmakingRequest.cpp +++ b/Gems/AWSGameLift/Code/AWSGameLiftClient/Source/Request/AWSGameLiftStartMatchmakingRequest.cpp @@ -16,12 +16,12 @@ namespace AWSGameLift { void AWSGameLiftStartMatchmakingRequest::Reflect(AZ::ReflectContext* context) { - AzFramework::StartMatchmakingRequest::Reflect(context); + Multiplayer::StartMatchmakingRequest::Reflect(context); AWSGameLiftPlayer::Reflect(context); if (auto serializeContext = azrtti_cast(context)) { - serializeContext->Class() + serializeContext->Class() ->Version(0) ->Field("configurationName", &AWSGameLiftStartMatchmakingRequest::m_configurationName) ->Field("players", &AWSGameLiftStartMatchmakingRequest::m_players); @@ -40,7 +40,7 @@ namespace AWSGameLift if (AZ::BehaviorContext* behaviorContext = azrtti_cast(context)) { - behaviorContext->Class("StartMatchmakingRequest") + behaviorContext->Class("StartMatchmakingRequest") ->Attribute(AZ::Script::Attributes::Storage, AZ::Script::Attributes::StorageType::Value) // Expose base type to BehaviorContext, but hide it to be used directly ->Attribute(AZ::Script::Attributes::ExcludeFrom, AZ::Script::Attributes::ExcludeFlags::All); diff --git a/Gems/AWSGameLift/Code/AWSGameLiftClient/Source/Request/AWSGameLiftStopMatchmakingRequest.cpp b/Gems/AWSGameLift/Code/AWSGameLiftClient/Source/Request/AWSGameLiftStopMatchmakingRequest.cpp index c462d45da7..babbeba7e8 100644 --- a/Gems/AWSGameLift/Code/AWSGameLiftClient/Source/Request/AWSGameLiftStopMatchmakingRequest.cpp +++ b/Gems/AWSGameLift/Code/AWSGameLiftClient/Source/Request/AWSGameLiftStopMatchmakingRequest.cpp @@ -16,11 +16,11 @@ namespace AWSGameLift { void AWSGameLiftStopMatchmakingRequest::Reflect(AZ::ReflectContext* context) { - AzFramework::StopMatchmakingRequest::Reflect(context); + Multiplayer::StopMatchmakingRequest::Reflect(context); if (auto serializeContext = azrtti_cast(context)) { - serializeContext->Class() + serializeContext->Class() ->Version(0); if (AZ::EditContext* editContext = serializeContext->GetEditContext()) @@ -33,7 +33,7 @@ namespace AWSGameLift if (AZ::BehaviorContext* behaviorContext = azrtti_cast(context)) { - behaviorContext->Class("StopMatchmakingRequest") + behaviorContext->Class("StopMatchmakingRequest") ->Attribute(AZ::Script::Attributes::Storage, AZ::Script::Attributes::StorageType::Value) // Expose base type to BehaviorContext, but hide it to be used directly ->Attribute(AZ::Script::Attributes::ExcludeFrom, AZ::Script::Attributes::ExcludeFlags::All); diff --git a/Gems/AWSGameLift/Code/AWSGameLiftClient/Tests/AWSGameLiftClientManagerTest.cpp b/Gems/AWSGameLift/Code/AWSGameLiftClient/Tests/AWSGameLiftClientManagerTest.cpp index 6ce0cb8f64..405eab613e 100644 --- a/Gems/AWSGameLift/Code/AWSGameLiftClient/Tests/AWSGameLiftClientManagerTest.cpp +++ b/Gems/AWSGameLift/Code/AWSGameLiftClient/Tests/AWSGameLiftClientManagerTest.cpp @@ -10,7 +10,7 @@ #include #include #include -#include +#include #include #include @@ -201,9 +201,9 @@ protected: return Aws::GameLift::Model::SearchGameSessionsOutcome(result); } - AzFramework::SearchSessionsResponse GetValidSearchSessionsResponse() + Multiplayer::SearchSessionsResponse GetValidSearchSessionsResponse() { - AzFramework::SessionConfig sessionConfig; + Multiplayer::SessionConfig sessionConfig; sessionConfig.m_creationTime = 0; sessionConfig.m_terminationTime = 0; sessionConfig.m_creatorId = "dummyCreatorId"; @@ -220,7 +220,7 @@ protected: // TODO: Update the AWS Native SDK to set the new game session attributes. // sessionConfig.m_dnsName = "dummyDnsName"; - AzFramework::SearchSessionsResponse response; + Multiplayer::SearchSessionsResponse response; response.m_nextToken = "dummyNextToken"; response.m_sessionConfigs = { sessionConfig }; @@ -344,7 +344,7 @@ TEST_F(AWSGameLiftClientManagerTest, CreateSession_CallWithoutClientSetup_GetEmp TEST_F(AWSGameLiftClientManagerTest, CreateSession_CallWithInvalidRequest_GetEmptyResponse) { AZ_TEST_START_TRACE_SUPPRESSION; - auto response = m_gameliftClientManager->CreateSession(AzFramework::CreateSessionRequest()); + auto response = m_gameliftClientManager->CreateSession(Multiplayer::CreateSessionRequest()); AZ_TEST_STOP_TRACE_SUPPRESSION(1); // capture 1 error message EXPECT_TRUE(response == ""); } @@ -381,7 +381,7 @@ TEST_F(AWSGameLiftClientManagerTest, CreateSessionAsync_CallWithInvalidRequest_G AZ_TEST_START_TRACE_SUPPRESSION; SessionAsyncRequestNotificationsHandlerMock sessionHandlerMock; EXPECT_CALL(sessionHandlerMock, OnCreateSessionAsyncComplete(AZStd::string())).Times(1); - m_gameliftClientManager->CreateSessionAsync(AzFramework::CreateSessionRequest()); + m_gameliftClientManager->CreateSessionAsync(Multiplayer::CreateSessionRequest()); AZ_TEST_STOP_TRACE_SUPPRESSION(1); // capture 1 error message } @@ -513,7 +513,7 @@ TEST_F(AWSGameLiftClientManagerTest, JoinSession_CallWithoutClientSetup_GetFalse TEST_F(AWSGameLiftClientManagerTest, JoinSession_CallWithInvalidRequest_GetFalseResponse) { AZ_TEST_START_TRACE_SUPPRESSION; - auto response = m_gameliftClientManager->JoinSession(AzFramework::JoinSessionRequest()); + auto response = m_gameliftClientManager->JoinSession(Multiplayer::JoinSessionRequest()); AZ_TEST_STOP_TRACE_SUPPRESSION(1); // capture 1 error message EXPECT_FALSE(response); } @@ -590,7 +590,7 @@ TEST_F(AWSGameLiftClientManagerTest, JoinSessionAsync_CallWithInvalidRequest_Get AZ_TEST_START_TRACE_SUPPRESSION; SessionAsyncRequestNotificationsHandlerMock sessionHandlerMock; EXPECT_CALL(sessionHandlerMock, OnJoinSessionAsyncComplete(false)).Times(1); - m_gameliftClientManager->JoinSessionAsync(AzFramework::JoinSessionRequest()); + m_gameliftClientManager->JoinSessionAsync(Multiplayer::JoinSessionRequest()); AZ_TEST_STOP_TRACE_SUPPRESSION(1); // capture 1 error message } @@ -698,7 +698,7 @@ TEST_F(AWSGameLiftClientManagerTest, SearchSessions_CallWithValidRequestAndSucce .Times(1) .WillOnce(::testing::Return(outcome)); - AzFramework::SearchSessionsResponse expectedResponse = GetValidSearchSessionsResponse(); + Multiplayer::SearchSessionsResponse expectedResponse = GetValidSearchSessionsResponse(); auto result = m_gameliftClientManager->SearchSessions(request); EXPECT_TRUE(result.m_sessionConfigs.size() != 0); } @@ -713,7 +713,7 @@ TEST_F(AWSGameLiftClientManagerTest, SearchSessionsAsync_CallWithoutClientSetup_ SessionAsyncRequestNotificationsHandlerMock sessionHandlerMock; EXPECT_CALL(sessionHandlerMock, - OnSearchSessionsAsyncComplete(SearchSessionsResponseMatcher(AzFramework::SearchSessionsResponse()))).Times(1); + OnSearchSessionsAsyncComplete(SearchSessionsResponseMatcher(Multiplayer::SearchSessionsResponse()))).Times(1); AZ_TEST_START_TRACE_SUPPRESSION; m_gameliftClientManager->SearchSessionsAsync(request); @@ -725,9 +725,9 @@ TEST_F(AWSGameLiftClientManagerTest, SearchSessionsAsync_CallWithInvalidRequest_ AZ_TEST_START_TRACE_SUPPRESSION; SessionAsyncRequestNotificationsHandlerMock sessionHandlerMock; EXPECT_CALL(sessionHandlerMock, - OnSearchSessionsAsyncComplete(SearchSessionsResponseMatcher(AzFramework::SearchSessionsResponse()))).Times(1); + OnSearchSessionsAsyncComplete(SearchSessionsResponseMatcher(Multiplayer::SearchSessionsResponse()))).Times(1); - m_gameliftClientManager->SearchSessionsAsync(AzFramework::SearchSessionsRequest()); + m_gameliftClientManager->SearchSessionsAsync(Multiplayer::SearchSessionsRequest()); AZ_TEST_STOP_TRACE_SUPPRESSION(1); // capture 1 error message } @@ -746,7 +746,7 @@ TEST_F(AWSGameLiftClientManagerTest, SearchSessionsAsync_CallWithValidRequestAnd SessionAsyncRequestNotificationsHandlerMock sessionHandlerMock; EXPECT_CALL(sessionHandlerMock, - OnSearchSessionsAsyncComplete(SearchSessionsResponseMatcher(AzFramework::SearchSessionsResponse()))).Times(1); + OnSearchSessionsAsyncComplete(SearchSessionsResponseMatcher(Multiplayer::SearchSessionsResponse()))).Times(1); AZ_TEST_START_TRACE_SUPPRESSION; m_gameliftClientManager->SearchSessionsAsync(request); @@ -765,7 +765,7 @@ TEST_F(AWSGameLiftClientManagerTest, SearchSessionsAsync_CallWithValidRequestAnd .Times(1) .WillOnce(::testing::Return(outcome)); - AzFramework::SearchSessionsResponse expectedResponse = GetValidSearchSessionsResponse(); + Multiplayer::SearchSessionsResponse expectedResponse = GetValidSearchSessionsResponse(); SessionAsyncRequestNotificationsHandlerMock sessionHandlerMock; EXPECT_CALL(sessionHandlerMock, OnSearchSessionsAsyncComplete(SearchSessionsResponseMatcher(expectedResponse))).Times(1); @@ -926,7 +926,7 @@ TEST_F(AWSGameLiftClientManagerTest, StopMatchmaking_CallWithoutClientSetup_GetE TEST_F(AWSGameLiftClientManagerTest, StopMatchmaking_CallWithInvalidRequest_GetError) { AZ_TEST_START_TRACE_SUPPRESSION; - m_gameliftClientManager->StopMatchmaking(AzFramework::StopMatchmakingRequest()); + m_gameliftClientManager->StopMatchmaking(Multiplayer::StopMatchmakingRequest()); AZ_TEST_STOP_TRACE_SUPPRESSION(1); // capture 1 error message } @@ -1029,7 +1029,7 @@ TEST_F(AWSGameLiftClientManagerTest, AcceptMatch_CallWithoutClientSetup_GetError TEST_F(AWSGameLiftClientManagerTest, AcceptMatch_CallWithInvalidRequest_GetError) { AZ_TEST_START_TRACE_SUPPRESSION; - m_gameliftClientManager->AcceptMatch(AzFramework::AcceptMatchRequest()); + m_gameliftClientManager->AcceptMatch(Multiplayer::AcceptMatchRequest()); AZ_TEST_STOP_TRACE_SUPPRESSION(1); // capture 1 error message } diff --git a/Gems/AWSGameLift/Code/AWSGameLiftClient/Tests/AWSGameLiftClientMocks.h b/Gems/AWSGameLift/Code/AWSGameLiftClient/Tests/AWSGameLiftClientMocks.h index d685f61d30..0950e38463 100644 --- a/Gems/AWSGameLift/Code/AWSGameLiftClient/Tests/AWSGameLiftClientMocks.h +++ b/Gems/AWSGameLift/Code/AWSGameLiftClient/Tests/AWSGameLiftClientMocks.h @@ -9,10 +9,10 @@ #pragma once #include -#include -#include -#include -#include +#include +#include +#include +#include #include #include @@ -58,17 +58,17 @@ public: }; class MatchmakingAsyncRequestNotificationsHandlerMock - : public AzFramework::MatchmakingAsyncRequestNotificationBus::Handler + : public Multiplayer::MatchmakingAsyncRequestNotificationBus::Handler { public: MatchmakingAsyncRequestNotificationsHandlerMock() { - AzFramework::MatchmakingAsyncRequestNotificationBus::Handler::BusConnect(); + Multiplayer::MatchmakingAsyncRequestNotificationBus::Handler::BusConnect(); } ~MatchmakingAsyncRequestNotificationsHandlerMock() { - AzFramework::MatchmakingAsyncRequestNotificationBus::Handler::BusDisconnect(); + Multiplayer::MatchmakingAsyncRequestNotificationBus::Handler::BusDisconnect(); } MOCK_METHOD0(OnAcceptMatchAsyncComplete, void()); @@ -77,17 +77,17 @@ public: }; class MatchmakingNotificationsHandlerMock - : public AzFramework::MatchmakingNotificationBus::Handler + : public Multiplayer::MatchmakingNotificationBus::Handler { public: MatchmakingNotificationsHandlerMock() { - AzFramework::MatchmakingNotificationBus::Handler::BusConnect(); + Multiplayer::MatchmakingNotificationBus::Handler::BusConnect(); } ~MatchmakingNotificationsHandlerMock() { - AzFramework::MatchmakingNotificationBus::Handler::BusDisconnect(); + Multiplayer::MatchmakingNotificationBus::Handler::BusDisconnect(); } void OnMatchAcceptance() override @@ -117,39 +117,39 @@ public: }; class SessionAsyncRequestNotificationsHandlerMock - : public AzFramework::SessionAsyncRequestNotificationBus::Handler + : public Multiplayer::SessionAsyncRequestNotificationBus::Handler { public: SessionAsyncRequestNotificationsHandlerMock() { - AzFramework::SessionAsyncRequestNotificationBus::Handler::BusConnect(); + Multiplayer::SessionAsyncRequestNotificationBus::Handler::BusConnect(); } ~SessionAsyncRequestNotificationsHandlerMock() { - AzFramework::SessionAsyncRequestNotificationBus::Handler::BusDisconnect(); + Multiplayer::SessionAsyncRequestNotificationBus::Handler::BusDisconnect(); } MOCK_METHOD1(OnCreateSessionAsyncComplete, void(const AZStd::string&)); - MOCK_METHOD1(OnSearchSessionsAsyncComplete, void(const AzFramework::SearchSessionsResponse&)); + MOCK_METHOD1(OnSearchSessionsAsyncComplete, void(const Multiplayer::SearchSessionsResponse&)); MOCK_METHOD1(OnJoinSessionAsyncComplete, void(bool)); MOCK_METHOD0(OnLeaveSessionAsyncComplete, void()); }; class SessionHandlingClientRequestsMock - : public AzFramework::ISessionHandlingClientRequests + : public Multiplayer::ISessionHandlingClientRequests { public: SessionHandlingClientRequestsMock() { - AZ::Interface::Register(this); + AZ::Interface::Register(this); } virtual ~SessionHandlingClientRequestsMock() { - AZ::Interface::Unregister(this); + AZ::Interface::Unregister(this); } - MOCK_METHOD1(RequestPlayerJoinSession, bool(const AzFramework::SessionConnectionConfig&)); + MOCK_METHOD1(RequestPlayerJoinSession, bool(const Multiplayer::SessionConnectionConfig&)); MOCK_METHOD0(RequestPlayerLeaveSession, void()); }; diff --git a/Gems/AWSGameLift/Code/AWSGameLiftClient/Tests/Activity/AWSGameLiftAcceptMatchActivityTest.cpp b/Gems/AWSGameLift/Code/AWSGameLiftClient/Tests/Activity/AWSGameLiftAcceptMatchActivityTest.cpp index af78ca8c0c..50ed0b526d 100644 --- a/Gems/AWSGameLift/Code/AWSGameLiftClient/Tests/Activity/AWSGameLiftAcceptMatchActivityTest.cpp +++ b/Gems/AWSGameLift/Code/AWSGameLiftClient/Tests/Activity/AWSGameLiftAcceptMatchActivityTest.cpp @@ -35,7 +35,7 @@ TEST_F(AWSGameLiftAcceptMatchActivityTest, BuildAWSGameLiftAcceptMatchRequest_Ca TEST_F(AWSGameLiftAcceptMatchActivityTest, ValidateAcceptMatchRequest_CallWithBaseType_GetFalseResult) { AZ_TEST_START_TRACE_SUPPRESSION; - auto result = AcceptMatchActivity::ValidateAcceptMatchRequest(AzFramework::AcceptMatchRequest()); + auto result = AcceptMatchActivity::ValidateAcceptMatchRequest(Multiplayer::AcceptMatchRequest()); EXPECT_FALSE(result); AZ_TEST_STOP_TRACE_SUPPRESSION(1); // capture 1 error message } diff --git a/Gems/AWSGameLift/Code/AWSGameLiftClient/Tests/Activity/AWSGameLiftCreateSessionActivityTest.cpp b/Gems/AWSGameLift/Code/AWSGameLiftClient/Tests/Activity/AWSGameLiftCreateSessionActivityTest.cpp index fcf867138b..6940a3eb01 100644 --- a/Gems/AWSGameLift/Code/AWSGameLiftClient/Tests/Activity/AWSGameLiftCreateSessionActivityTest.cpp +++ b/Gems/AWSGameLift/Code/AWSGameLiftClient/Tests/Activity/AWSGameLiftCreateSessionActivityTest.cpp @@ -39,7 +39,7 @@ TEST_F(AWSGameLiftCreateSessionActivityTest, BuildAWSGameLiftCreateGameSessionRe TEST_F(AWSGameLiftCreateSessionActivityTest, ValidateCreateSessionRequest_CallWithBaseType_GetFalseResult) { - auto result = CreateSessionActivity::ValidateCreateSessionRequest(AzFramework::CreateSessionRequest()); + auto result = CreateSessionActivity::ValidateCreateSessionRequest(Multiplayer::CreateSessionRequest()); EXPECT_FALSE(result); } diff --git a/Gems/AWSGameLift/Code/AWSGameLiftClient/Tests/Activity/AWSGameLiftCreateSessionOnQueueActivityTest.cpp b/Gems/AWSGameLift/Code/AWSGameLiftClient/Tests/Activity/AWSGameLiftCreateSessionOnQueueActivityTest.cpp index 4845586e47..b60b091a2f 100644 --- a/Gems/AWSGameLift/Code/AWSGameLiftClient/Tests/Activity/AWSGameLiftCreateSessionOnQueueActivityTest.cpp +++ b/Gems/AWSGameLift/Code/AWSGameLiftClient/Tests/Activity/AWSGameLiftCreateSessionOnQueueActivityTest.cpp @@ -35,7 +35,7 @@ TEST_F(AWSGameLiftCreateSessionOnQueueActivityTest, BuildAWSGameLiftCreateGameSe TEST_F(AWSGameLiftCreateSessionOnQueueActivityTest, ValidateCreateSessionOnQueueRequest_CallWithBaseType_GetFalseResult) { - auto result = CreateSessionOnQueueActivity::ValidateCreateSessionOnQueueRequest(AzFramework::CreateSessionRequest()); + auto result = CreateSessionOnQueueActivity::ValidateCreateSessionOnQueueRequest(Multiplayer::CreateSessionRequest()); EXPECT_FALSE(result); } diff --git a/Gems/AWSGameLift/Code/AWSGameLiftClient/Tests/Activity/AWSGameLiftJoinSessionActivityTest.cpp b/Gems/AWSGameLift/Code/AWSGameLiftClient/Tests/Activity/AWSGameLiftJoinSessionActivityTest.cpp index 33b03649c7..664baa55cb 100644 --- a/Gems/AWSGameLift/Code/AWSGameLiftClient/Tests/Activity/AWSGameLiftJoinSessionActivityTest.cpp +++ b/Gems/AWSGameLift/Code/AWSGameLiftClient/Tests/Activity/AWSGameLiftJoinSessionActivityTest.cpp @@ -6,7 +6,7 @@ * */ -#include +#include #include #include @@ -47,7 +47,7 @@ TEST_F(AWSGameLiftJoinSessionActivityTest, BuildSessionConnectionConfig_Call_Get TEST_F(AWSGameLiftJoinSessionActivityTest, ValidateJoinSessionRequest_CallWithBaseType_GetFalseResult) { AZ_TEST_START_TRACE_SUPPRESSION; - auto result = JoinSessionActivity::ValidateJoinSessionRequest(AzFramework::JoinSessionRequest()); + auto result = JoinSessionActivity::ValidateJoinSessionRequest(Multiplayer::JoinSessionRequest()); AZ_TEST_STOP_TRACE_SUPPRESSION(1); // capture 1 error message EXPECT_FALSE(result); } diff --git a/Gems/AWSGameLift/Code/AWSGameLiftClient/Tests/Activity/AWSGameLiftSearchSessionsActivityTest.cpp b/Gems/AWSGameLift/Code/AWSGameLiftClient/Tests/Activity/AWSGameLiftSearchSessionsActivityTest.cpp index 0d3c8c137b..d627731a02 100644 --- a/Gems/AWSGameLift/Code/AWSGameLiftClient/Tests/Activity/AWSGameLiftSearchSessionsActivityTest.cpp +++ b/Gems/AWSGameLift/Code/AWSGameLiftClient/Tests/Activity/AWSGameLiftSearchSessionsActivityTest.cpp @@ -6,7 +6,7 @@ * */ -#include +#include #include #include @@ -45,7 +45,7 @@ TEST_F(AWSGameLiftSearchSessionsActivityTest, BuildAWSGameLiftSearchGameSessions TEST_F(AWSGameLiftSearchSessionsActivityTest, ValidateSearchSessionsRequest_CallWithBaseType_GetFalseResult) { AZ_TEST_START_TRACE_SUPPRESSION; - auto result = SearchSessionsActivity::ValidateSearchSessionsRequest(AzFramework::SearchSessionsRequest()); + auto result = SearchSessionsActivity::ValidateSearchSessionsRequest(Multiplayer::SearchSessionsRequest()); AZ_TEST_STOP_TRACE_SUPPRESSION(1); // capture 1 error message EXPECT_FALSE(result); } diff --git a/Gems/AWSGameLift/Code/AWSGameLiftClient/Tests/Activity/AWSGameLiftStartMatchmakingActivityTest.cpp b/Gems/AWSGameLift/Code/AWSGameLiftClient/Tests/Activity/AWSGameLiftStartMatchmakingActivityTest.cpp index 6da932828c..66b253c33d 100644 --- a/Gems/AWSGameLift/Code/AWSGameLiftClient/Tests/Activity/AWSGameLiftStartMatchmakingActivityTest.cpp +++ b/Gems/AWSGameLift/Code/AWSGameLiftClient/Tests/Activity/AWSGameLiftStartMatchmakingActivityTest.cpp @@ -49,7 +49,7 @@ TEST_F(AWSGameLiftStartMatchmakingActivityTest, BuildAWSGameLiftStartMatchmaking TEST_F(AWSGameLiftStartMatchmakingActivityTest, ValidateStartMatchmakingRequest_CallWithBaseType_GetFalseResult) { AZ_TEST_START_TRACE_SUPPRESSION; - auto result = StartMatchmakingActivity::ValidateStartMatchmakingRequest(AzFramework::StartMatchmakingRequest()); + auto result = StartMatchmakingActivity::ValidateStartMatchmakingRequest(Multiplayer::StartMatchmakingRequest()); EXPECT_FALSE(result); AZ_TEST_STOP_TRACE_SUPPRESSION(1); // capture 1 error message } diff --git a/Gems/AWSGameLift/Code/AWSGameLiftClient/Tests/Activity/AWSGameLiftStopMatchmakingActivityTest.cpp b/Gems/AWSGameLift/Code/AWSGameLiftClient/Tests/Activity/AWSGameLiftStopMatchmakingActivityTest.cpp index ba0e40c7e6..6c99f59240 100644 --- a/Gems/AWSGameLift/Code/AWSGameLiftClient/Tests/Activity/AWSGameLiftStopMatchmakingActivityTest.cpp +++ b/Gems/AWSGameLift/Code/AWSGameLiftClient/Tests/Activity/AWSGameLiftStopMatchmakingActivityTest.cpp @@ -26,7 +26,7 @@ TEST_F(AWSGameLiftStopMatchmakingActivityTest, BuildAWSGameLiftStopMatchmakingRe TEST_F(AWSGameLiftStopMatchmakingActivityTest, ValidateStopMatchmakingRequest_CallWithoutTicketId_GetFalseResult) { AZ_TEST_START_TRACE_SUPPRESSION; - auto result = StopMatchmakingActivity::ValidateStopMatchmakingRequest(AzFramework::StopMatchmakingRequest()); + auto result = StopMatchmakingActivity::ValidateStopMatchmakingRequest(Multiplayer::StopMatchmakingRequest()); EXPECT_FALSE(result); AZ_TEST_STOP_TRACE_SUPPRESSION(1); // capture 1 error message } diff --git a/Gems/AWSGameLift/Code/AWSGameLiftServer/CMakeLists.txt b/Gems/AWSGameLift/Code/AWSGameLiftServer/CMakeLists.txt index d05ec46b52..9702130c04 100644 --- a/Gems/AWSGameLift/Code/AWSGameLiftServer/CMakeLists.txt +++ b/Gems/AWSGameLift/Code/AWSGameLiftServer/CMakeLists.txt @@ -25,7 +25,7 @@ ly_add_target( BUILD_DEPENDENCIES PRIVATE AZ::AzCore - AZ::AzFramework + Gem::Multiplayer.Static 3rdParty::AWSGameLiftServerSDK ) @@ -62,8 +62,8 @@ if(PAL_TRAIT_BUILD_TESTS_SUPPORTED) BUILD_DEPENDENCIES PRIVATE AZ::AzCore - AZ::AzFramework AZ::AzTest + Gem::Multiplayer.Static Gem::AWSGameLift.Server.Static 3rdParty::AWSGameLiftServerSDK ) diff --git a/Gems/AWSGameLift/Code/AWSGameLiftServer/Source/AWSGameLiftServerManager.cpp b/Gems/AWSGameLift/Code/AWSGameLiftServer/Source/AWSGameLiftServerManager.cpp index 0ef028219c..898aa54c98 100644 --- a/Gems/AWSGameLift/Code/AWSGameLiftServer/Source/AWSGameLiftServerManager.cpp +++ b/Gems/AWSGameLift/Code/AWSGameLiftServer/Source/AWSGameLiftServerManager.cpp @@ -21,7 +21,7 @@ #include #include #include -#include +#include namespace AWSGameLift { @@ -50,7 +50,7 @@ namespace AWSGameLift AZ::Interface::Unregister(this); } - bool AWSGameLiftServerManager::AddConnectedPlayer(const AzFramework::PlayerConnectionConfig& playerConnectionConfig) + bool AWSGameLiftServerManager::AddConnectedPlayer(const Multiplayer::PlayerConnectionConfig& playerConnectionConfig) { AZStd::lock_guard lock(m_gameliftMutex); if (m_connectedPlayers.contains(playerConnectionConfig.m_playerConnectionId)) @@ -100,9 +100,9 @@ namespace AWSGameLift return serverProcessDesc; } - AzFramework::SessionConfig AWSGameLiftServerManager::BuildSessionConfig(const Aws::GameLift::Server::Model::GameSession& gameSession) + Multiplayer::SessionConfig AWSGameLiftServerManager::BuildSessionConfig(const Aws::GameLift::Server::Model::GameSession& gameSession) { - AzFramework::SessionConfig sessionConfig; + Multiplayer::SessionConfig sessionConfig; sessionConfig.m_dnsName = gameSession.GetDnsName().c_str(); AZStd::string propertiesOutput = ""; @@ -437,9 +437,9 @@ namespace AWSGameLift void AWSGameLiftServerManager::HandleDestroySession() { // No further request should be handled by GameLift server manager at this point - if (AZ::Interface::Get()) + if (AZ::Interface::Get()) { - AZ::Interface::Unregister(this); + AZ::Interface::Unregister(this); } AZ_TracePrintf(AWSGameLiftServerManagerName, "Server process is scheduled to be shut down at %s", @@ -448,7 +448,7 @@ namespace AWSGameLift // Send notifications to handler(s) to gracefully shut down the server process. bool destroySessionResult = true; AZ::EBusReduceResult> result(destroySessionResult); - AzFramework::SessionNotificationBus::BroadcastResult(result, &AzFramework::SessionNotifications::OnDestroySessionBegin); + Multiplayer::SessionNotificationBus::BroadcastResult(result, &Multiplayer::SessionNotifications::OnDestroySessionBegin); if (!destroySessionResult) { @@ -461,7 +461,7 @@ namespace AWSGameLift if (processEndingOutcome.IsSuccess()) { AZ_TracePrintf(AWSGameLiftServerManagerName, "ProcessEnding request against Amazon GameLift service succeeded."); - AzFramework::SessionNotificationBus::Broadcast(&AzFramework::SessionNotifications::OnDestroySessionEnd); + Multiplayer::SessionNotificationBus::Broadcast(&Multiplayer::SessionNotifications::OnDestroySessionEnd); } else { @@ -470,7 +470,7 @@ namespace AWSGameLift } } - void AWSGameLiftServerManager::HandlePlayerLeaveSession(const AzFramework::PlayerConnectionConfig& playerConnectionConfig) + void AWSGameLiftServerManager::HandlePlayerLeaveSession(const Multiplayer::PlayerConnectionConfig& playerConnectionConfig) { AZStd::string playerSessionId = ""; RemoveConnectedPlayer(playerConnectionConfig.m_playerConnectionId, playerSessionId); @@ -536,12 +536,12 @@ namespace AWSGameLift void AWSGameLiftServerManager::OnStartGameSession(const Aws::GameLift::Server::Model::GameSession& gameSession) { UpdateGameSessionData(gameSession); - AzFramework::SessionConfig sessionConfig = BuildSessionConfig(gameSession); + Multiplayer::SessionConfig sessionConfig = BuildSessionConfig(gameSession); bool createSessionResult = true; AZ::EBusReduceResult> result(createSessionResult); - AzFramework::SessionNotificationBus::BroadcastResult( - result, &AzFramework::SessionNotifications::OnCreateSessionBegin, sessionConfig); + Multiplayer::SessionNotificationBus::BroadcastResult( + result, &Multiplayer::SessionNotifications::OnCreateSessionBegin, sessionConfig); if (createSessionResult) { @@ -552,11 +552,11 @@ namespace AWSGameLift { AZ_TracePrintf(AWSGameLiftServerManagerName, "ActivateGameSession request against Amazon GameLift service succeeded."); // Register server manager as handler once game session has been activated - if (!AZ::Interface::Get()) + if (!AZ::Interface::Get()) { - AZ::Interface::Register(this); + AZ::Interface::Register(this); } - AzFramework::SessionNotificationBus::Broadcast(&AzFramework::SessionNotifications::OnCreateSessionEnd); + Multiplayer::SessionNotificationBus::Broadcast(&Multiplayer::SessionNotifications::OnCreateSessionEnd); } else { @@ -583,16 +583,16 @@ namespace AWSGameLift { bool healthCheckResult = true; AZ::EBusReduceResult> result(healthCheckResult); - AzFramework::SessionNotificationBus::BroadcastResult(result, &AzFramework::SessionNotifications::OnSessionHealthCheck); + Multiplayer::SessionNotificationBus::BroadcastResult(result, &Multiplayer::SessionNotifications::OnSessionHealthCheck); return m_serverSDKInitialized && healthCheckResult; } void AWSGameLiftServerManager::OnUpdateGameSession(const Aws::GameLift::Server::Model::UpdateGameSession& updateGameSession) { - AzFramework::SessionConfig sessionConfig = BuildSessionConfig(updateGameSession.GetGameSession()); + Multiplayer::SessionConfig sessionConfig = BuildSessionConfig(updateGameSession.GetGameSession()); Aws::GameLift::Server::Model::UpdateReason updateReason = updateGameSession.GetUpdateReason(); - AzFramework::SessionNotificationBus::Broadcast(&AzFramework::SessionNotifications::OnUpdateSessionBegin, + Multiplayer::SessionNotificationBus::Broadcast(&Multiplayer::SessionNotifications::OnUpdateSessionBegin, sessionConfig, Aws::GameLift::Server::Model::UpdateReasonMapper::GetNameForUpdateReason(updateReason).c_str()); // Update game session data locally @@ -601,7 +601,7 @@ namespace AWSGameLift UpdateGameSessionData(updateGameSession.GetGameSession()); } - AzFramework::SessionNotificationBus::Broadcast(&AzFramework::SessionNotifications::OnUpdateSessionEnd); + Multiplayer::SessionNotificationBus::Broadcast(&Multiplayer::SessionNotifications::OnUpdateSessionEnd); } bool AWSGameLiftServerManager::RemoveConnectedPlayer(uint32_t playerConnectionId, AZStd::string& outPlayerSessionId) @@ -713,7 +713,7 @@ namespace AWSGameLift } } - bool AWSGameLiftServerManager::ValidatePlayerJoinSession(const AzFramework::PlayerConnectionConfig& playerConnectionConfig) + bool AWSGameLiftServerManager::ValidatePlayerJoinSession(const Multiplayer::PlayerConnectionConfig& playerConnectionConfig) { uint32_t playerConnectionId = playerConnectionConfig.m_playerConnectionId; AZStd::string playerSessionId = playerConnectionConfig.m_playerSessionId; diff --git a/Gems/AWSGameLift/Code/AWSGameLiftServer/Source/AWSGameLiftServerManager.h b/Gems/AWSGameLift/Code/AWSGameLiftServer/Source/AWSGameLiftServerManager.h index 6e7ce4e005..673172dc9a 100644 --- a/Gems/AWSGameLift/Code/AWSGameLiftServer/Source/AWSGameLiftServerManager.h +++ b/Gems/AWSGameLift/Code/AWSGameLiftServer/Source/AWSGameLiftServerManager.h @@ -16,8 +16,8 @@ #include #include #include -#include -#include +#include +#include #include #include @@ -37,7 +37,7 @@ namespace AWSGameLift //! Manage the server process for hosting game sessions via GameLiftServerSDK. class AWSGameLiftServerManager : public AWSGameLiftServerRequestBus::Handler - , public AzFramework::ISessionHandlingProviderRequests + , public Multiplayer::ISessionHandlingProviderRequests { public: static constexpr const char AWSGameLiftServerManagerName[] = "AWSGameLiftServerManager"; @@ -117,8 +117,8 @@ namespace AWSGameLift // ISessionHandlingProviderRequests interface implementation void HandleDestroySession() override; - bool ValidatePlayerJoinSession(const AzFramework::PlayerConnectionConfig& playerConnectionConfig) override; - void HandlePlayerLeaveSession(const AzFramework::PlayerConnectionConfig& playerConnectionConfig) override; + bool ValidatePlayerJoinSession(const Multiplayer::PlayerConnectionConfig& playerConnectionConfig) override; + void HandlePlayerLeaveSession(const Multiplayer::PlayerConnectionConfig& playerConnectionConfig) override; AZ::IO::Path GetExternalSessionCertificate() override; AZ::IO::Path GetInternalSessionCertificate() override; @@ -126,7 +126,7 @@ namespace AWSGameLift void SetGameLiftServerSDKWrapper(AZStd::unique_ptr gameLiftServerSDKWrapper); //! Add connected player session id. - bool AddConnectedPlayer(const AzFramework::PlayerConnectionConfig& playerConnectionConfig); + bool AddConnectedPlayer(const Multiplayer::PlayerConnectionConfig& playerConnectionConfig); //! Get active server player data from lazy loaded game session for server match backfill AZStd::vector GetActiveServerMatchBackfillPlayers(); @@ -157,7 +157,7 @@ namespace AWSGameLift void BuildStopMatchBackfillRequest(const AZStd::string& ticketId, Aws::GameLift::Server::Model::StopMatchBackfillRequest& outRequest); //! Build session config by using AWS GameLift Server GameSession Model. - AzFramework::SessionConfig BuildSessionConfig(const Aws::GameLift::Server::Model::GameSession& gameSession); + Multiplayer::SessionConfig BuildSessionConfig(const Aws::GameLift::Server::Model::GameSession& gameSession); //! Check whether matchmaking data is in proper format bool IsMatchmakingDataValid(); diff --git a/Gems/AWSGameLift/Code/AWSGameLiftServer/Tests/AWSGameLiftServerManagerTest.cpp b/Gems/AWSGameLift/Code/AWSGameLiftServer/Tests/AWSGameLiftServerManagerTest.cpp index 96d6a69d96..4f69fd7d4c 100644 --- a/Gems/AWSGameLift/Code/AWSGameLiftServer/Tests/AWSGameLiftServerManagerTest.cpp +++ b/Gems/AWSGameLift/Code/AWSGameLiftServer/Tests/AWSGameLiftServerManagerTest.cpp @@ -11,8 +11,8 @@ #include #include -#include -#include +#include +#include namespace UnitTest { @@ -154,25 +154,25 @@ R"({ } class SessionNotificationsHandlerMock - : public AzFramework::SessionNotificationBus::Handler + : public Multiplayer::SessionNotificationBus::Handler { public: SessionNotificationsHandlerMock() { - AzFramework::SessionNotificationBus::Handler::BusConnect(); + Multiplayer::SessionNotificationBus::Handler::BusConnect(); } ~SessionNotificationsHandlerMock() { - AzFramework::SessionNotificationBus::Handler::BusDisconnect(); + Multiplayer::SessionNotificationBus::Handler::BusDisconnect(); } MOCK_METHOD0(OnSessionHealthCheck, bool()); - MOCK_METHOD1(OnCreateSessionBegin, bool(const AzFramework::SessionConfig&)); + MOCK_METHOD1(OnCreateSessionBegin, bool(const Multiplayer::SessionConfig&)); MOCK_METHOD0(OnCreateSessionEnd, void()); MOCK_METHOD0(OnDestroySessionBegin, bool()); MOCK_METHOD0(OnDestroySessionEnd, void()); - MOCK_METHOD2(OnUpdateSessionBegin, void(const AzFramework::SessionConfig&, const AZStd::string&)); + MOCK_METHOD2(OnUpdateSessionBegin, void(const Multiplayer::SessionConfig&, const AZStd::string&)); MOCK_METHOD0(OnUpdateSessionEnd, void()); }; @@ -255,9 +255,9 @@ R"({ { m_serverManager->InitializeGameLiftServerSDK(); m_serverManager->NotifyGameLiftProcessReady(); - if (!AZ::Interface::Get()) + if (!AZ::Interface::Get()) { - AZ::Interface::Register(m_serverManager.get()); + AZ::Interface::Register(m_serverManager.get()); } SessionNotificationsHandlerMock handlerMock; @@ -270,16 +270,16 @@ R"({ m_serverManager->m_gameLiftServerSDKWrapperMockPtr->m_onProcessTerminateFunc(); AZ_TEST_STOP_TRACE_SUPPRESSION(1); - EXPECT_FALSE(AZ::Interface::Get()); + EXPECT_FALSE(AZ::Interface::Get()); } TEST_F(GameLiftServerManagerTest, OnProcessTerminate_OnDestroySessionBeginReturnsTrue_TerminationNotificationSent) { m_serverManager->InitializeGameLiftServerSDK(); m_serverManager->NotifyGameLiftProcessReady(); - if (!AZ::Interface::Get()) + if (!AZ::Interface::Get()) { - AZ::Interface::Register(m_serverManager.get()); + AZ::Interface::Register(m_serverManager.get()); } SessionNotificationsHandlerMock handlerMock; @@ -292,16 +292,16 @@ R"({ m_serverManager->m_gameLiftServerSDKWrapperMockPtr->m_onProcessTerminateFunc(); - EXPECT_FALSE(AZ::Interface::Get()); + EXPECT_FALSE(AZ::Interface::Get()); } TEST_F(GameLiftServerManagerTest, OnProcessTerminate_OnDestroySessionBeginReturnsTrue_TerminationNotificationSentButFail) { m_serverManager->InitializeGameLiftServerSDK(); m_serverManager->NotifyGameLiftProcessReady(); - if (!AZ::Interface::Get()) + if (!AZ::Interface::Get()) { - AZ::Interface::Register(m_serverManager.get()); + AZ::Interface::Register(m_serverManager.get()); } SessionNotificationsHandlerMock handlerMock; @@ -316,7 +316,7 @@ R"({ m_serverManager->m_gameLiftServerSDKWrapperMockPtr->m_onProcessTerminateFunc(); AZ_TEST_STOP_TRACE_SUPPRESSION(1); - EXPECT_FALSE(AZ::Interface::Get()); + EXPECT_FALSE(AZ::Interface::Get()); } TEST_F(GameLiftServerManagerTest, OnHealthCheck_OnSessionHealthCheckReturnsTrue_CallbackFunctionReturnsTrue) @@ -379,7 +379,7 @@ R"({ testProperty.SetValue("testValue"); testSession.AddGameProperties(testProperty); m_serverManager->m_gameLiftServerSDKWrapperMockPtr->m_onStartGameSessionFunc(testSession); - EXPECT_TRUE(AZ::Interface::Get()); + EXPECT_TRUE(AZ::Interface::Get()); m_serverManager->HandleDestroySession(); } @@ -465,14 +465,14 @@ R"({ TEST_F(GameLiftServerManagerTest, ValidatePlayerJoinSession_CallWithInvalidConnectionConfig_GetFalseResultAndExpectedErrorLog) { AZ_TEST_START_TRACE_SUPPRESSION; - auto result = m_serverManager->ValidatePlayerJoinSession(AzFramework::PlayerConnectionConfig()); + auto result = m_serverManager->ValidatePlayerJoinSession(Multiplayer::PlayerConnectionConfig()); AZ_TEST_STOP_TRACE_SUPPRESSION(1); EXPECT_FALSE(result); } TEST_F(GameLiftServerManagerTest, ValidatePlayerJoinSession_CallWithDuplicatedConnectionId_GetFalseResultAndExpectedErrorLog) { - AzFramework::PlayerConnectionConfig connectionConfig1; + Multiplayer::PlayerConnectionConfig connectionConfig1; connectionConfig1.m_playerConnectionId = 123; connectionConfig1.m_playerSessionId = "dummyPlayerSessionId1"; GenericOutcome successOutcome(nullptr); @@ -480,7 +480,7 @@ R"({ .Times(1) .WillOnce(Return(successOutcome)); m_serverManager->ValidatePlayerJoinSession(connectionConfig1); - AzFramework::PlayerConnectionConfig connectionConfig2; + Multiplayer::PlayerConnectionConfig connectionConfig2; connectionConfig2.m_playerConnectionId = 123; connectionConfig2.m_playerSessionId = "dummyPlayerSessionId2"; AZ_TEST_START_TRACE_SUPPRESSION; @@ -491,7 +491,7 @@ R"({ TEST_F(GameLiftServerManagerTest, ValidatePlayerJoinSession_CallWithValidConnectionConfigButErrorOutcome_GetFalseResultAndExpectedErrorLog) { - AzFramework::PlayerConnectionConfig connectionConfig; + Multiplayer::PlayerConnectionConfig connectionConfig; connectionConfig.m_playerConnectionId = 123; connectionConfig.m_playerSessionId = "dummyPlayerSessionId1"; EXPECT_CALL(*(m_serverManager->m_gameLiftServerSDKWrapperMockPtr), AcceptPlayerSession(testing::_)).Times(1); @@ -503,7 +503,7 @@ R"({ TEST_F(GameLiftServerManagerTest, ValidatePlayerJoinSession_CallWithValidConnectionConfigAndSuccessOutcome_GetTrueResult) { - AzFramework::PlayerConnectionConfig connectionConfig; + Multiplayer::PlayerConnectionConfig connectionConfig; connectionConfig.m_playerConnectionId = 123; connectionConfig.m_playerSessionId = "dummyPlayerSessionId1"; GenericOutcome successOutcome(nullptr); @@ -516,7 +516,7 @@ R"({ TEST_F(GameLiftServerManagerTest, ValidatePlayerJoinSession_CallWithFirstErrorSecondSuccess_GetFirstFalseSecondTrueResult) { - AzFramework::PlayerConnectionConfig connectionConfig1; + Multiplayer::PlayerConnectionConfig connectionConfig1; connectionConfig1.m_playerConnectionId = 123; connectionConfig1.m_playerSessionId = "dummyPlayerSessionId1"; GenericOutcome successOutcome(nullptr); @@ -530,7 +530,7 @@ R"({ auto result = m_serverManager->ValidatePlayerJoinSession(connectionConfig1); AZ_TEST_STOP_TRACE_SUPPRESSION(1); EXPECT_FALSE(result); - AzFramework::PlayerConnectionConfig connectionConfig2; + Multiplayer::PlayerConnectionConfig connectionConfig2; connectionConfig2.m_playerConnectionId = 123; connectionConfig2.m_playerSessionId = "dummyPlayerSessionId2"; result = m_serverManager->ValidatePlayerJoinSession(connectionConfig2); @@ -549,7 +549,7 @@ R"({ for (int index = 0; index < testThreadNumber; index++) { testThreadPool.emplace_back(AZStd::thread([&]() { - AzFramework::PlayerConnectionConfig connectionConfig; + Multiplayer::PlayerConnectionConfig connectionConfig; connectionConfig.m_playerConnectionId = 123; connectionConfig.m_playerSessionId = "dummyPlayerSessionId"; auto result = m_serverManager->ValidatePlayerJoinSession(connectionConfig); @@ -571,19 +571,19 @@ R"({ EXPECT_CALL(*(m_serverManager->m_gameLiftServerSDKWrapperMockPtr), RemovePlayerSession(testing::_)).Times(0); AZ_TEST_START_TRACE_SUPPRESSION; - m_serverManager->HandlePlayerLeaveSession(AzFramework::PlayerConnectionConfig()); + m_serverManager->HandlePlayerLeaveSession(Multiplayer::PlayerConnectionConfig()); AZ_TEST_STOP_TRACE_SUPPRESSION(1); } TEST_F(GameLiftServerManagerTest, HandlePlayerLeaveSession_CallWithNonExistentPlayerConnectionId_GetExpectedErrorLog) { - AzFramework::PlayerConnectionConfig connectionConfig; + Multiplayer::PlayerConnectionConfig connectionConfig; connectionConfig.m_playerConnectionId = 123; connectionConfig.m_playerSessionId = "dummyPlayerSessionId"; auto result = m_serverManager->AddConnectedTestPlayer(connectionConfig); EXPECT_TRUE(result); - AzFramework::PlayerConnectionConfig connectionConfig1; + Multiplayer::PlayerConnectionConfig connectionConfig1; connectionConfig1.m_playerConnectionId = 456; connectionConfig1.m_playerSessionId = "dummyPlayerSessionId"; @@ -596,7 +596,7 @@ R"({ TEST_F(GameLiftServerManagerTest, HandlePlayerLeaveSession_CallWithValidConnectionConfigButErrorOutcome_GetExpectedErrorLog) { - AzFramework::PlayerConnectionConfig connectionConfig; + Multiplayer::PlayerConnectionConfig connectionConfig; connectionConfig.m_playerConnectionId = 123; connectionConfig.m_playerSessionId = "dummyPlayerSessionId"; auto result = m_serverManager->AddConnectedTestPlayer(connectionConfig); @@ -615,7 +615,7 @@ R"({ TEST_F(GameLiftServerManagerTest, HandlePlayerLeaveSession_CallWithValidConnectionConfigAndSuccessOutcome_RemovePlayerSessionNotificationSent) { - AzFramework::PlayerConnectionConfig connectionConfig; + Multiplayer::PlayerConnectionConfig connectionConfig; connectionConfig.m_playerConnectionId = 123; connectionConfig.m_playerSessionId = "dummyPlayerSessionId"; auto result = m_serverManager->AddConnectedTestPlayer(connectionConfig); @@ -631,7 +631,7 @@ R"({ TEST_F(GameLiftServerManagerTest, HandlePlayerLeaveSession_CallWithMultithread_OnlyOneNotificationIsSent) { - AzFramework::PlayerConnectionConfig connectionConfig; + Multiplayer::PlayerConnectionConfig connectionConfig; connectionConfig.m_playerConnectionId = 123; connectionConfig.m_playerSessionId = "dummyPlayerSessionId"; auto result = m_serverManager->AddConnectedTestPlayer(connectionConfig); diff --git a/Gems/AWSGameLift/Code/AWSGameLiftServer/Tests/AWSGameLiftServerMocks.h b/Gems/AWSGameLift/Code/AWSGameLiftServer/Tests/AWSGameLiftServerMocks.h index 7ab9c51cd1..37f7d5595e 100644 --- a/Gems/AWSGameLift/Code/AWSGameLiftServer/Tests/AWSGameLiftServerMocks.h +++ b/Gems/AWSGameLift/Code/AWSGameLiftServer/Tests/AWSGameLiftServerMocks.h @@ -95,7 +95,7 @@ namespace UnitTest UpdateGameSessionData(m_testGameSession); } - bool AddConnectedTestPlayer(const AzFramework::PlayerConnectionConfig& playerConnectionConfig) + bool AddConnectedTestPlayer(const Multiplayer::PlayerConnectionConfig& playerConnectionConfig) { return AddConnectedPlayer(playerConnectionConfig); } diff --git a/Gems/Atom/Feature/Common/Assets/Materials/Special/DebugVertexStreams.azsl b/Gems/Atom/Feature/Common/Assets/Materials/Special/DebugVertexStreams.azsl new file mode 100644 index 0000000000..b4ad624266 --- /dev/null +++ b/Gems/Atom/Feature/Common/Assets/Materials/Special/DebugVertexStreams.azsl @@ -0,0 +1,154 @@ +/* + * Copyright (c) Contributors to the Open 3D Engine Project. + * For complete copyright and license terms please see the LICENSE at the root of this distribution. + * + * SPDX-License-Identifier: Apache-2.0 OR MIT + * + */ + +#include +#define UvSetCount 2 +#include +#include +#include + +// These enums need to be kept in sync with the enum values in DebugVertexStreams_IncompatibleEnums.lua +option enum class DebugVertexStream { Normals, Tangents, Bitangents, Uvs, TangentW } o_debugVertexStream = DebugVertexStream::Normals; +option enum class TangentOptions { UseVertexData, UseSurfaceGradient} o_tangentOptions = TangentOptions::UseVertexData; +option enum class BitangentOptions { UseVertexData, UseSurfaceGradient, ReconstructBitangent} o_bitangentOptions = BitangentOptions::UseVertexData; +option enum class ColorDisplayMode {ColorSpace, UnitSpace} o_colorDisplayMode = ColorDisplayMode::ColorSpace; + +ShaderResourceGroup MaterialSrg : SRG_PerMaterial +{ + uint m_uvIndex; +} + +struct VSInput +{ + // Base fields (required by the template azsli file)... + float3 m_position : POSITION; + float3 m_normal : NORMAL; + float4 m_tangent : TANGENT; + float3 m_bitangent : BITANGENT; + + // Extended fields (only referenced in this azsl file)... + float2 m_uv0 : UV0; + float2 m_uv1 : UV1; +}; + +struct VSOutput +{ + // Base fields (required by the template azsli file)... + // "centroid" is needed for SV_Depth to compile + precise linear centroid float4 m_position : SV_Position; + float3 m_normal: NORMAL; + float4 m_tangent : TANGENT; + float3 m_bitangent : BITANGENT; + float3 m_worldPosition : UV0; + + // Extended fields (only referenced in this azsl file)... + float2 m_uv[UvSetCount] : UV1; +}; + +VSOutput MainVS(VSInput IN) +{ + VSOutput OUT; + OUT.m_worldPosition = mul(ObjectSrg::GetWorldMatrix(), float4(IN.m_position, 1.0)).xyz; + OUT.m_position = mul(ViewSrg::m_viewProjectionMatrix, float4(OUT.m_worldPosition, 1.0)); + + // Only UV0 is supported + OUT.m_uv[0] = IN.m_uv0; + OUT.m_uv[1] = IN.m_uv1; + + float4x4 objectToWorld = ObjectSrg::GetWorldMatrix(); + float3x3 objectToWorldIT = ObjectSrg::GetWorldMatrixInverseTranspose(); + + ConstructTBN(IN.m_normal, IN.m_tangent, IN.m_bitangent, objectToWorld, objectToWorldIT, OUT.m_normal, OUT.m_tangent.xyz, OUT.m_bitangent); + + OUT.m_tangent.w = IN.m_tangent.w; + return OUT; +} + +struct PixelOutput +{ + float4 m_color : SV_Target0; +}; + + +float3 OffsetColor(float3 color) +{ + if(o_colorDisplayMode == ColorDisplayMode::ColorSpace) + { + // Represent a vector in the (-1, -1, -1) to (1, 1, 1) range as a color in the (0, 0, 0) to (1, 1, 1) range + // Color key + // + x-axis: Light Coral + // - x-axis: Teal + // + y-axis: Bright Green + // - y-axis: Dark Magenta + // + z-axis: Medium Slate Blue + // - z-axis: Olive + return normalize(color) * 0.5 + 0.5; + } + else + { + // Use the normalized color, with any negative values represented as black + // + x-axis: Red + // - x-axis: Black + // + y-axis: Green + // - y-axis: Black + // + z-axis: Blue + // - z-axis: Black + return normalize(color); + } +} + +PixelOutput MainPS(VSOutput IN) +{ + PixelOutput OUT; + + float3 tangents[UvSetCount] = { IN.m_tangent.xyz, IN.m_tangent.xyz }; + float3 bitangents[UvSetCount] = { IN.m_bitangent.xyz, IN.m_bitangent.xyz }; + + if(o_bitangentOptions == BitangentOptions::ReconstructBitangent && MaterialSrg::m_uvIndex == 0) + { + bitangents[MaterialSrg::m_uvIndex] = cross(IN.m_normal.xyz, IN.m_tangent.xyz) * sign(IN.m_tangent.w); + } + else if((o_debugVertexStream == DebugVertexStream::Tangents && o_tangentOptions == TangentOptions::UseSurfaceGradient) + || (o_debugVertexStream == DebugVertexStream::Bitangents && o_bitangentOptions == BitangentOptions::UseSurfaceGradient) + || MaterialSrg::m_uvIndex > 0) + { + const bool isBackface = false; + SurfaceGradientNormalMapping_Init(IN.m_normal, IN.m_worldPosition, isBackface); + SurfaceGradientNormalMapping_GenerateTB(IN.m_uv[MaterialSrg::m_uvIndex], tangents[MaterialSrg::m_uvIndex], bitangents[MaterialSrg::m_uvIndex]); + } + + + float3 outColor = float3(1.0, 1.0, 1.0); + switch(o_debugVertexStream) + { + case DebugVertexStream::Normals: + outColor = OffsetColor(IN.m_normal); + break; + case DebugVertexStream::Tangents: + outColor = OffsetColor(tangents[MaterialSrg::m_uvIndex]); + break; + case DebugVertexStream::Bitangents: + outColor = OffsetColor(bitangents[MaterialSrg::m_uvIndex]); + break; + case DebugVertexStream::Uvs: + // Assume a tiled uv visualization, where anything greater than 1 wraps back around to 0 + outColor = float3(frac(IN.m_uv[MaterialSrg::m_uvIndex].x), frac(IN.m_uv[MaterialSrg::m_uvIndex].y), 0.0f); + break; + case DebugVertexStream::TangentW: + float red = IN.m_tangent.w >= 0.0f ? 1.0f : 0.0f; + float green = IN.m_tangent.w <= 0.0f ? 1.0f : 0.0f; + float blue = IN.m_tangent.w == 0.0f ? 1.0f : 0.0f; + outColor = float3(red, green, blue); + break; + } + + OUT.m_color.rgb = outColor; + OUT.m_color.a = 1.0; + + return OUT; +} diff --git a/Gems/Atom/Feature/Common/Assets/Materials/Special/DebugVertexStreams.material b/Gems/Atom/Feature/Common/Assets/Materials/Special/DebugVertexStreams.material new file mode 100644 index 0000000000..34171c4457 --- /dev/null +++ b/Gems/Atom/Feature/Common/Assets/Materials/Special/DebugVertexStreams.material @@ -0,0 +1,4 @@ +{ + "materialType": "Materials/Special/DebugVertexStreams.materialtype", + "materialTypeVersion": 1 +} \ No newline at end of file diff --git a/Gems/Atom/Feature/Common/Assets/Materials/Special/DebugVertexStreams.materialtype b/Gems/Atom/Feature/Common/Assets/Materials/Special/DebugVertexStreams.materialtype new file mode 100644 index 0000000000..1377cbca8b --- /dev/null +++ b/Gems/Atom/Feature/Common/Assets/Materials/Special/DebugVertexStreams.materialtype @@ -0,0 +1,94 @@ +{ + "description": "A simple default base material for Atom testing.", + "version": 1, + "propertyLayout": { + "groups": [ + { + "name": "general", + "displayName": "General Settings", + "description": "General settings." + } + ], + "properties": { + "general": [ + { + "name": "debugVertexStream", + "displayName": "Display Vertex Stream", + "description": "Display vertex stream interpolated over the triangle.", + "type": "Enum", + "defaultValue": "Normals", + "enumValues": [ "Normals", "Tangents", "Bitangents", "Uvs", "TangentW" ], + "connection": { + "type": "ShaderOption", + "name": "o_debugVertexStream" + } + }, + { + "name": "tangentOptions", + "displayName": "Tangent Options", + "description": "Use the data from the vertices or use the Surface Gradient technique for calculating tangents.", + "type": "Enum", + "defaultValue": "UseVertexData", + "enumValues": [ "UseVertexData", "UseSurfaceGradient"], + "connection": { + "type": "ShaderOption", + "name": "o_tangentOptions" + } + }, + { + "name": "bitangentOptions", + "displayName": "Bitangent Options", + "description": "Use the data from the vertices, use the Surface Gradient technique for calculating bitangents, or use the cross product to reconstruct the bitangents.", + "type": "Enum", + "defaultValue": "UseVertexData", + "enumValues": [ "UseVertexData", "UseSurfaceGradient", "ReconstructBitangent" ], + "connection": { + "type": "ShaderOption", + "name": "o_bitangentOptions" + } + }, + { + "name": "colorDisplayMode", + "displayName": "Display Mode", + "description": "Offset the vector into the 0-1 range (ColorSpace), or display the raw unit vector including negative values (UnitSpace)", + "type": "Enum", + "defaultValue": "ColorSpace", + "enumValues": [ "ColorSpace", "UnitSpace"], + "connection": { + "type": "ShaderOption", + "name": "o_colorDisplayMode" + } + }, + { + "name": "uvIndex", + "displayName": "UV Index", + "description": "UV set to display and use for tangents/bitangents.", + "type": "Enum", + "enumIsUv": true, + "defaultValue": "Tiled", + "connection": { + "type": "ShaderInput", + "name": "m_uvIndex" + } + } + ] + } + }, + "shaders": [ + { + "file": "Materials/Special/DebugVertexStreams.shader" + } + ], + "functors": [ + { + "type": "Lua", + "args": { + "file": "DebugVertexStreams_IncompatibleEnums.lua" + } + } + ], + "uvNameMap": { + "UV0": "Tiled", + "UV1": "Unwrapped" + } +} diff --git a/Gems/Atom/Feature/Common/Assets/Materials/Special/DebugVertexStreams.shader b/Gems/Atom/Feature/Common/Assets/Materials/Special/DebugVertexStreams.shader new file mode 100644 index 0000000000..c4578971c2 --- /dev/null +++ b/Gems/Atom/Feature/Common/Assets/Materials/Special/DebugVertexStreams.shader @@ -0,0 +1,24 @@ +{ + "Source" : "DebugVertexStreams.azsl", + + "DepthStencilState" : { + "Depth" : { "Enable" : true, "CompareFunc" : "GreaterEqual" } + }, + + "DrawList" : "auxgeom", + + "ProgramSettings": + { + "EntryPoints": + [ + { + "name": "MainVS", + "type": "Vertex" + }, + { + "name": "MainPS", + "type": "Fragment" + } + ] + } +} diff --git a/Gems/Atom/Feature/Common/Assets/Materials/Special/DebugVertexStreams_IncompatibleEnums.lua b/Gems/Atom/Feature/Common/Assets/Materials/Special/DebugVertexStreams_IncompatibleEnums.lua new file mode 100644 index 0000000000..08ccb2217d --- /dev/null +++ b/Gems/Atom/Feature/Common/Assets/Materials/Special/DebugVertexStreams_IncompatibleEnums.lua @@ -0,0 +1,71 @@ +-------------------------------------------------------------------------------------- +-- +-- Copyright (c) Contributors to the Open 3D Engine Project. +-- For complete copyright and license terms please see the LICENSE at the root of this distribution. +-- +-- SPDX-License-Identifier: Apache-2.0 OR MIT +-- +-- +-- +---------------------------------------------------------------------------------------------------- + + +DebugVertexStream_Normals = 0 +DebugVertexStream_Tangents = 1 +DebugVertexStream_Bitangents = 2 +DebugVertexStream_Uvs = 3 +DebugVertexStream_TangentW = 4 + +function GetMaterialPropertyDependencies() + return { "general.debugVertexStream", "general.uvIndex"} +end + +function ProcessEditor(context) + local vertexStream = context:GetMaterialPropertyValue_enum("general.debugVertexStream"); + + -- Depending on which vertex stream is being visualized, only certain settings are applicable + if(vertexStream == DebugVertexStream_Normals) then + -- Normals can be viewed as colors using either method + context:SetMaterialPropertyVisibility("general.colorDisplayMode", MaterialPropertyVisibility_Enabled) + + -- Uv set and tangent/bitangent options do not impact normals + context:SetMaterialPropertyVisibility("general.tangentOptions", MaterialPropertyVisibility_Hidden) + context:SetMaterialPropertyVisibility("general.bitangentOptions", MaterialPropertyVisibility_Hidden) + context:SetMaterialPropertyVisibility("general.uvIndex", MaterialPropertyVisibility_Hidden) + elseif(vertexStream == DebugVertexStream_Tangents) then + -- Tangents can be viewed using either color display mode, and are affected by tangent options and uv index + context:SetMaterialPropertyVisibility("general.tangentOptions", MaterialPropertyVisibility_Enabled) + context:SetMaterialPropertyVisibility("general.colorDisplayMode", MaterialPropertyVisibility_Enabled) + context:SetMaterialPropertyVisibility("general.uvIndex", MaterialPropertyVisibility_Enabled) + + context:SetMaterialPropertyVisibility("general.bitangentOptions", MaterialPropertyVisibility_Hidden) + elseif(vertexStream == DebugVertexStream_Bitangents) then + -- Bitangents can be viewed using either color display mode, and are affected by tangent options and uv index + context:SetMaterialPropertyVisibility("general.bitangentOptions", MaterialPropertyVisibility_Enabled) + context:SetMaterialPropertyVisibility("general.colorDisplayMode", MaterialPropertyVisibility_Enabled) + context:SetMaterialPropertyVisibility("general.uvIndex", MaterialPropertyVisibility_Enabled) + + context:SetMaterialPropertyVisibility("general.tangentOptions", MaterialPropertyVisibility_Hidden) + elseif(vertexStream == DebugVertexStream_Uvs) then + -- Uvs are only impacted by uv index + context:SetMaterialPropertyVisibility("general.uvIndex", MaterialPropertyVisibility_Enabled) + + context:SetMaterialPropertyVisibility("general.tangentOptions", MaterialPropertyVisibility_Hidden) + context:SetMaterialPropertyVisibility("general.bitangentOptions", MaterialPropertyVisibility_Hidden) + context:SetMaterialPropertyVisibility("general.colorDisplayMode", MaterialPropertyVisibility_Hidden) + elseif(vertexStream == DebugVertexStream_TangentW) then + -- Tangent.w can only use per-vertex data, and only for the first uv set, and is only displayed one way, + -- so it is not impacted by any settings + context:SetMaterialPropertyVisibility("general.tangentOptions", MaterialPropertyVisibility_Hidden) + context:SetMaterialPropertyVisibility("general.bitangentOptions", MaterialPropertyVisibility_Hidden) + context:SetMaterialPropertyVisibility("general.colorDisplayMode", MaterialPropertyVisibility_Hidden) + context:SetMaterialPropertyVisibility("general.uvIndex", MaterialPropertyVisibility_Hidden) + end + + -- For the second uv set, only the surface gradient technique is supported for generating tangents and bitangents + local uvSet = context:GetMaterialPropertyValue_enum("general.uvIndex"); + if(uvSet > 0) then + context:SetMaterialPropertyVisibility("general.tangentOptions", MaterialPropertyVisibility_Hidden) + context:SetMaterialPropertyVisibility("general.bitangentOptions", MaterialPropertyVisibility_Hidden) + end +end diff --git a/Gems/Atom/Feature/Common/Assets/Passes/SsaoCompute.pass b/Gems/Atom/Feature/Common/Assets/Passes/SsaoCompute.pass index 3c4a8c76f1..2c48506f8f 100644 --- a/Gems/Atom/Feature/Common/Assets/Passes/SsaoCompute.pass +++ b/Gems/Atom/Feature/Common/Assets/Passes/SsaoCompute.pass @@ -50,7 +50,8 @@ "FilePath": "Shaders/PostProcessing/SsaoCompute.shader" }, "Make Fullscreen Pass": true, - "PipelineViewTag": "MainCamera" + "PipelineViewTag": "MainCamera", + "Use Async Compute": true }, "FallbackConnections": [ { diff --git a/Gems/Atom/Feature/Common/Assets/Textures/BRDFTexture.attimage b/Gems/Atom/Feature/Common/Assets/Textures/BRDFTexture.attimage index c31954c5c6..5511b62baa 100644 --- a/Gems/Atom/Feature/Common/Assets/Textures/BRDFTexture.attimage +++ b/Gems/Atom/Feature/Common/Assets/Textures/BRDFTexture.attimage @@ -5,14 +5,16 @@ "ClassData": { "m_imageDescriptor": { "BindFlags": [ - "ShaderRead", - "ShaderWrite" - ], + "ShaderRead", + "ShaderWrite" + ], "Size": { "Width": 256, "Height": 256 }, "Format": 24 - } + }, + "Name": "$BrdfTexture", + "IsUniqueName": true } } diff --git a/Gems/Atom/Feature/Common/Code/Source/DiffuseGlobalIllumination/DiffuseProbeGridVisualizationAccelerationStructurePass.cpp b/Gems/Atom/Feature/Common/Code/Source/DiffuseGlobalIllumination/DiffuseProbeGridVisualizationAccelerationStructurePass.cpp index 29e50fb158..94a441c769 100644 --- a/Gems/Atom/Feature/Common/Code/Source/DiffuseGlobalIllumination/DiffuseProbeGridVisualizationAccelerationStructurePass.cpp +++ b/Gems/Atom/Feature/Common/Code/Source/DiffuseGlobalIllumination/DiffuseProbeGridVisualizationAccelerationStructurePass.cpp @@ -72,7 +72,7 @@ namespace AZ void DiffuseProbeGridVisualizationAccelerationStructurePass::BuildInternal() { - SetScopeId(RHI::ScopeId(GetPathName())); + InitScope(RHI::ScopeId(GetPathName())); } void DiffuseProbeGridVisualizationAccelerationStructurePass::FrameBeginInternal(FramePrepareParams params) diff --git a/Gems/Atom/Feature/Common/Code/Source/Material/Transform2DFunctor.cpp b/Gems/Atom/Feature/Common/Code/Source/Material/Transform2DFunctor.cpp index e7baff7f93..e9fdd6e06e 100644 --- a/Gems/Atom/Feature/Common/Code/Source/Material/Transform2DFunctor.cpp +++ b/Gems/Atom/Feature/Common/Code/Source/Material/Transform2DFunctor.cpp @@ -39,59 +39,21 @@ namespace AZ ; } } - + void Transform2DFunctor::Process(RuntimeContext& context) { using namespace RPI; - auto center = context.GetMaterialPropertyValue(m_center); - auto scale = context.GetMaterialPropertyValue(m_scale); - auto scaleX = context.GetMaterialPropertyValue(m_scaleX); - auto scaleY = context.GetMaterialPropertyValue(m_scaleY); - auto translateX = context.GetMaterialPropertyValue(m_translateX); - auto translateY = context.GetMaterialPropertyValue(m_translateY); - auto rotateDegrees = context.GetMaterialPropertyValue(m_rotateDegrees); - - if (scaleX != 0.0f) - { - translateX *= (1.0f / scaleX); - } - - if (scaleY != 0.0f) - { - translateY *= (1.0f / scaleY); - } - - Matrix3x3 translateCenter2D = Matrix3x3::CreateIdentity(); - translateCenter2D.SetBasisZ(-center.GetX(), -center.GetY(), 1.0f); - - Matrix3x3 translateCenterInv2D = Matrix3x3::CreateIdentity(); - translateCenterInv2D.SetBasisZ(center.GetX(), center.GetY(), 1.0f); - - Matrix3x3 scale2D = Matrix3x3::CreateDiagonal(AZ::Vector3(scaleX * scale, scaleY * scale, 1.0f)); - - Matrix3x3 translate2D = Matrix3x3::CreateIdentity(); - translate2D.SetBasisZ(translateX, translateY, 1.0f); + UvTransformDescriptor desc; + desc.m_center = context.GetMaterialPropertyValue(m_center); + desc.m_scale = context.GetMaterialPropertyValue(m_scale); + desc.m_scaleX = context.GetMaterialPropertyValue(m_scaleX); + desc.m_scaleY = context.GetMaterialPropertyValue(m_scaleY); + desc.m_translateX = context.GetMaterialPropertyValue(m_translateX); + desc.m_translateY = context.GetMaterialPropertyValue(m_translateY); + desc.m_rotateDegrees = context.GetMaterialPropertyValue(m_rotateDegrees); - Matrix3x3 rotate2D = Matrix3x3::CreateRotationZ(AZ::DegToRad(rotateDegrees)); - - Matrix3x3 transform = translateCenter2D; - for (auto transformType : m_transformOrder) - { - switch (transformType) - { - case TransformType::Scale: - transform = scale2D * transform; - break; - case TransformType::Rotate: - transform = rotate2D * transform; - break; - case TransformType::Translate: - transform = translate2D * transform; - break; - } - } - transform = translateCenterInv2D * transform; + Matrix3x3 transform = CreateUvTransformMatrix(desc, m_transformOrder); context.GetShaderResourceGroup()->SetConstant(m_transformMatrix, transform); diff --git a/Gems/Atom/Feature/Common/Code/Source/Material/Transform2DFunctor.h b/Gems/Atom/Feature/Common/Code/Source/Material/Transform2DFunctor.h index 2ef5af6913..58dcd7ebb7 100644 --- a/Gems/Atom/Feature/Common/Code/Source/Material/Transform2DFunctor.h +++ b/Gems/Atom/Feature/Common/Code/Source/Material/Transform2DFunctor.h @@ -11,6 +11,7 @@ #include #include #include +#include namespace AZ { @@ -24,14 +25,6 @@ namespace AZ public: AZ_RTTI(Transform2DFunctor, "{3E9C4357-6B2D-4A22-89DB-462441C9D8CD}", RPI::MaterialFunctor); - enum class TransformType - { - Invalid, - Scale, - Rotate, - Translate - }; - static void Reflect(ReflectContext* context); using RPI::MaterialFunctor::Process; @@ -57,6 +50,4 @@ namespace AZ } // namespace Render - AZ_TYPE_INFO_SPECIALIZE(Render::Transform2DFunctor::TransformType, "{D8C15D33-CE3D-4297-A646-030B0625BF84}"); - } // namespace AZ diff --git a/Gems/Atom/Feature/Common/Code/Source/Material/Transform2DFunctorSourceData.cpp b/Gems/Atom/Feature/Common/Code/Source/Material/Transform2DFunctorSourceData.cpp index 26e7983a4b..7436cb06b7 100644 --- a/Gems/Atom/Feature/Common/Code/Source/Material/Transform2DFunctorSourceData.cpp +++ b/Gems/Atom/Feature/Common/Code/Source/Material/Transform2DFunctorSourceData.cpp @@ -85,13 +85,13 @@ namespace AZ functor->m_transformOrder = m_transformOrder; - AZStd::set transformSet{m_transformOrder.begin(), m_transformOrder.end()}; + AZStd::set transformSet{m_transformOrder.begin(), m_transformOrder.end()}; if (m_transformOrder.size() != transformSet.size()) { AZ_Warning("Transform2DFunctor", false, "transformOrder field contains duplicate entries"); } - if (transformSet.find(Transform2DFunctor::TransformType::Invalid) != transformSet.end()) + if (transformSet.find(TransformType::Invalid) != transformSet.end()) { AZ_Warning("Transform2DFunctor", false, "transformOrder contains invalid entries"); } diff --git a/Gems/Atom/Feature/Common/Code/Source/Material/Transform2DFunctorSourceData.h b/Gems/Atom/Feature/Common/Code/Source/Material/Transform2DFunctorSourceData.h index db7e65fedc..ae97879884 100644 --- a/Gems/Atom/Feature/Common/Code/Source/Material/Transform2DFunctorSourceData.h +++ b/Gems/Atom/Feature/Common/Code/Source/Material/Transform2DFunctorSourceData.h @@ -10,6 +10,7 @@ #include "./Transform2DFunctor.h" #include +#include namespace AZ { @@ -30,7 +31,7 @@ namespace AZ private: - AZStd::vector m_transformOrder; //!< Controls the order in which Scale, Translate, Rotate are performed + AZStd::vector m_transformOrder; //!< Controls the order in which Scale, Translate, Rotate are performed // Material property inputs... AZStd::string m_center; //!< material property for center of scaling and rotation diff --git a/Gems/Atom/Feature/Common/Code/Source/PostProcessing/DepthOfFieldCopyFocusDepthToCpuPass.cpp b/Gems/Atom/Feature/Common/Code/Source/PostProcessing/DepthOfFieldCopyFocusDepthToCpuPass.cpp index 3a0efaa371..c79e98e345 100644 --- a/Gems/Atom/Feature/Common/Code/Source/PostProcessing/DepthOfFieldCopyFocusDepthToCpuPass.cpp +++ b/Gems/Atom/Feature/Common/Code/Source/PostProcessing/DepthOfFieldCopyFocusDepthToCpuPass.cpp @@ -50,7 +50,7 @@ namespace AZ void DepthOfFieldCopyFocusDepthToCpuPass::BuildInternal() { - SetScopeId(RHI::ScopeId(GetPathName())); + InitScope(RHI::ScopeId(GetPathName())); } void DepthOfFieldCopyFocusDepthToCpuPass::FrameBeginInternal(FramePrepareParams params) diff --git a/Gems/Atom/Feature/Common/Code/Source/RayTracing/RayTracingAccelerationStructurePass.cpp b/Gems/Atom/Feature/Common/Code/Source/RayTracing/RayTracingAccelerationStructurePass.cpp index 2073c0b8c0..9a99a9f82a 100644 --- a/Gems/Atom/Feature/Common/Code/Source/RayTracing/RayTracingAccelerationStructurePass.cpp +++ b/Gems/Atom/Feature/Common/Code/Source/RayTracing/RayTracingAccelerationStructurePass.cpp @@ -40,7 +40,7 @@ namespace AZ void RayTracingAccelerationStructurePass::BuildInternal() { - SetScopeId(RHI::ScopeId(GetPathName())); + InitScope(RHI::ScopeId(GetPathName())); } void RayTracingAccelerationStructurePass::FrameBeginInternal(FramePrepareParams params) diff --git a/Gems/Atom/RHI/Code/Include/Atom/RHI/Scope.h b/Gems/Atom/RHI/Code/Include/Atom/RHI/Scope.h index 0bcf35f107..2c5acf4c18 100644 --- a/Gems/Atom/RHI/Code/Include/Atom/RHI/Scope.h +++ b/Gems/Atom/RHI/Code/Include/Atom/RHI/Scope.h @@ -76,6 +76,9 @@ namespace AZ /// Returns the hardware queue class for this scope. HardwareQueueClass GetHardwareQueueClass() const; + /// Sets the hardware queue class for this scope. + void SetHardwareQueueClass(HardwareQueueClass hardwareQueueClass); + /** * Returns the estimated number of draw / dispatch / copy items that the user will submit * while in this scope. This is an estimation intended to be used by the platform-specific @@ -120,7 +123,7 @@ namespace AZ const AZStd::vector>& GetFencesToSignal() const; /// Initializes the scope. - void Init(const ScopeId& scopeId); + void Init(const ScopeId& scopeId, HardwareQueueClass hardwareQueueClass = HardwareQueueClass::Graphics); /// Activates the scope for the current frame. void Activate(const FrameGraph* frameGraph, uint32_t index, const GraphGroupId& groupId); diff --git a/Gems/Atom/RHI/Code/Include/Atom/RHI/ScopeProducer.h b/Gems/Atom/RHI/Code/Include/Atom/RHI/ScopeProducer.h index f27172afca..690b65803f 100644 --- a/Gems/Atom/RHI/Code/Include/Atom/RHI/ScopeProducer.h +++ b/Gems/Atom/RHI/Code/Include/Atom/RHI/ScopeProducer.h @@ -86,11 +86,22 @@ namespace AZ ScopeProducer(); /** - * Sets ID of the scope producer. Used by class that inherit from - * ScopeProducer but that can't supply a ScopeId at construction. + * Sets the HardwareQueueClass on the scope + */ + void SetHardwareQueueClass(HardwareQueueClass hardwareQueueClass); + + /** + * DEPRECATED. + * @deprecated Use InitScope instead */ void SetScopeId(const ScopeId& scopeId); + /** + * Initializes the scope with a ScopeId and HardwareQueueClass. + * Used by classes that inherit from ScopeProducer but can't supply a ScopeId at construction. + */ + void InitScope(const ScopeId& scopeId, HardwareQueueClass hardwareQueueClass = HardwareQueueClass::Graphics); + private: ////////////////////////////////////////////////////////////////////////// // User Overrides - Derived classes should override from these methods. diff --git a/Gems/Atom/RHI/Code/Source/RHI/Scope.cpp b/Gems/Atom/RHI/Code/Source/RHI/Scope.cpp index 472309929e..1fdfc137d8 100644 --- a/Gems/Atom/RHI/Code/Source/RHI/Scope.cpp +++ b/Gems/Atom/RHI/Code/Source/RHI/Scope.cpp @@ -24,12 +24,13 @@ namespace AZ return m_isActive; } - void Scope::Init(const ScopeId& scopeId) + void Scope::Init(const ScopeId& scopeId, HardwareQueueClass hardwareQueueClass) { AZ_Assert(!scopeId.IsEmpty(), "Scope id is not valid."); AZ_Assert(IsInitialized() == false, "Scope was previously initialized."); SetName(scopeId); m_id = scopeId; + m_hardwareQueueClass = hardwareQueueClass; InitInternal(); m_isInitialized = true; } @@ -134,6 +135,11 @@ namespace AZ return m_hardwareQueueClass; } + void Scope::SetHardwareQueueClass(HardwareQueueClass hardwareQueueClass) + { + m_hardwareQueueClass = hardwareQueueClass; + } + uint32_t Scope::GetEstimatedItemCount() const { return m_estimatedItemCount; diff --git a/Gems/Atom/RHI/Code/Source/RHI/ScopeProducer.cpp b/Gems/Atom/RHI/Code/Source/RHI/ScopeProducer.cpp index 7017deb862..6df5a18296 100644 --- a/Gems/Atom/RHI/Code/Source/RHI/ScopeProducer.cpp +++ b/Gems/Atom/RHI/Code/Source/RHI/ScopeProducer.cpp @@ -40,7 +40,18 @@ namespace AZ return m_scope.get(); } + void ScopeProducer::SetHardwareQueueClass(HardwareQueueClass hardwareQueueClass) + { + m_scope->SetHardwareQueueClass(hardwareQueueClass); + } + + // DEPRECATED: use InitScope instead void ScopeProducer::SetScopeId(const ScopeId& scopeId) + { + InitScope(scopeId); + } + + void ScopeProducer::InitScope(const ScopeId& scopeId, HardwareQueueClass hardwareQueueClass) { m_scopeId = scopeId; @@ -49,7 +60,7 @@ namespace AZ m_scope->Shutdown(); } - m_scope->Init(scopeId); + m_scope->Init(scopeId, hardwareQueueClass); } } } diff --git a/Gems/Atom/RPI/Assets/ShaderLib/Atom/RPI/TangentSpace.azsli b/Gems/Atom/RPI/Assets/ShaderLib/Atom/RPI/TangentSpace.azsli index 4ef1f82b11..005499e0ed 100644 --- a/Gems/Atom/RPI/Assets/ShaderLib/Atom/RPI/TangentSpace.azsli +++ b/Gems/Atom/RPI/Assets/ShaderLib/Atom/RPI/TangentSpace.azsli @@ -26,13 +26,12 @@ float3 WorldSpaceToTangent(float3 vectorWS, float3 normalWS, float3 tangentWS, f return float3(a,b,c); } -//! Utility function for vertex shaders to transform vertex tangent, bitangent, and normal vectors into world space based on MikkT conventions. +//! Utility function for vertex shaders to transform vertex tangent, bitangent, and normal vectors into world space. void ConstructTBN(float3 vertexNormal, float4 vertexTangent, float3 vertexBitangent, float4x4 localToWorld, float3x3 localToWorldInverseTranspose, out float3 normalWS, out float3 tangentWS, out float3 bitangentWS) { normalWS = normalize(mul(localToWorldInverseTranspose, vertexNormal)); tangentWS = normalize(mul(localToWorld, float4(vertexTangent.xyz, 0)).xyz); - float bitangentSign = -vertexTangent.w; - bitangentWS = normalize(mul(localToWorld, float4(vertexBitangent, 0)).xyz) * bitangentSign; + bitangentWS = normalize(mul(localToWorld, float4(vertexBitangent, 0)).xyz); } // ---------- Normal Calculation ---------- diff --git a/Gems/Atom/RPI/Code/Include/Atom/RPI.Public/Image/AttachmentImage.h b/Gems/Atom/RPI/Code/Include/Atom/RPI.Public/Image/AttachmentImage.h index 15786a3a44..fc1c326cbf 100644 --- a/Gems/Atom/RPI/Code/Include/Atom/RPI.Public/Image/AttachmentImage.h +++ b/Gems/Atom/RPI/Code/Include/Atom/RPI.Public/Image/AttachmentImage.h @@ -21,6 +21,27 @@ namespace AZ class AttachmentImagePool; class ResourcePoolAsset; + struct CreateAttachmentImageRequest + { + //! The name of this image. It will be used as RHI object name (for gpu debug). + Name m_imageName; + //! If true, the AttachmentImage create function may fail if the attachment image with same name already exist. + //! The m_imageName will be used as the attachment id of the created attachment image. + //! The attachment image can be found by its name (same as its attachment id). + //! If false, a random generated uuid will be used for instance id as well as attachment id. + bool m_isUniqueName = false; + //! The ImageDescriptor for this AttachmentImage + RHI::ImageDescriptor m_imageDescriptor; + //! The attachment image pool which the AttachmentImage is created from. + //! A default system attachment image pool will be used if it's set to nullptr + const AttachmentImagePool* m_imagePool = nullptr; + + // (Optional) Set the default clear value for this image + const RHI::ClearValue* m_optimizedClearValue = nullptr; + //! (Optional) The imageViewDescriptor for this image which overides the default ImageViewDescriptor. + const RHI::ImageViewDescriptor* m_imageViewDescriptor = nullptr; + }; + //! AttachmentImage is intended for use, primarily, as an attachment on a pass. Image data can //! be produced by the GPU or uploaded directly from CPU data. Use this class to represent //! color / depth stencil targets, read-write images, etc. @@ -33,20 +54,32 @@ namespace AZ AZ_INSTANCE_DATA(AttachmentImage, "{85691099-5143-4C11-88B0-897DA9064FDF}", Image); AZ_CLASS_ALLOCATOR(AttachmentImage, AZ::SystemAllocator, 0); - ~AttachmentImage() = default; + ~AttachmentImage(); //! Instantiates or returns an existing image instance using its paired asset. static Data::Instance FindOrCreate(const Data::Asset& imageAsset); - //! Instantiates a unique instance with a random id, using data provided at runtime. + //! Creates an AttachmentImage + //! @param imagePool The attachment image pool which the AttachmentImage is created from + //! @param imageDescriptor The ImageDescriptor for this AttachmentImage + //! @param imageName The name of this image. It will be used as RHI object name (for gpu debug). + //! @param optimizedClearValue (Optional) set the default clear value for this image + //! @param imageViewDescriptor (Optional) The imageViewDescriptor for this image which overides the default ImageViewDescriptor. static Data::Instance Create( const AttachmentImagePool& imagePool, const RHI::ImageDescriptor& imageDescriptor, const Name& imageName, const RHI::ClearValue* optimizedClearValue = nullptr, const RHI::ImageViewDescriptor* imageViewDescriptor = nullptr); + + //! Creates an AttachmentImage + static Data::Instance Create(const CreateAttachmentImageRequest& createImageRequest); - const RHI::AttachmentId& GetAttachmentId(); + //! Finds an AttachmentImage by an unique attachment name + static Data::Instance FindByUniqueName(const Name& uniqueAttachmentName); + + //! Return an unique id which can be used as an attachment id in frame graph attachment database + const RHI::AttachmentId& GetAttachmentId() const; private: AttachmentImage() = default; @@ -54,10 +87,14 @@ namespace AZ //! Standard instance creation path. static Data::Instance CreateInternal(AttachmentImageAsset& imageAsset); RHI::ResultCode Init(const AttachmentImageAsset& imageAsset); + void Shutdown(); Data::Instance m_imagePool; RHI::AttachmentId m_attachmentId; + + // Need to keep a reference of the asset so the asset system won't release the asset after AttachmentImage was created + Data::Asset m_imageAsset; }; } } diff --git a/Gems/Atom/RPI/Code/Include/Atom/RPI.Public/Image/ImageSystem.h b/Gems/Atom/RPI/Code/Include/Atom/RPI.Public/Image/ImageSystem.h index e42cfebc86..4a75f9bd62 100644 --- a/Gems/Atom/RPI/Code/Include/Atom/RPI.Public/Image/ImageSystem.h +++ b/Gems/Atom/RPI/Code/Include/Atom/RPI.Public/Image/ImageSystem.h @@ -58,6 +58,9 @@ namespace AZ const Data::Instance& GetSystemStreamingPool() const override; const Data::Instance& GetSystemAttachmentPool() const override; const Data::Instance& GetStreamingPool() const override; + bool RegisterAttachmentImage(AttachmentImage* attachmentImage) override; + void UnregisterAttachmentImage(AttachmentImage* attachmentImage) override; + Data::Instance FindRegisteredAttachmentImage(const Name& uniqueName) const override; ////////////////////////////////////////////////////////////////////////// private: @@ -78,6 +81,10 @@ namespace AZ AZStd::fixed_vector, static_cast(SystemImage::Count)> m_systemImages; bool m_initialized = false; + + // a collections of regirested attachment images + // Note: use AttachmentImage* instead of Data::Instance so it can be released properly + AZStd::unordered_map m_registeredAttachmentImages; }; } } diff --git a/Gems/Atom/RPI/Code/Include/Atom/RPI.Public/Image/ImageSystemInterface.h b/Gems/Atom/RPI/Code/Include/Atom/RPI.Public/Image/ImageSystemInterface.h index 920b763bc3..00f628758b 100644 --- a/Gems/Atom/RPI/Code/Include/Atom/RPI.Public/Image/ImageSystemInterface.h +++ b/Gems/Atom/RPI/Code/Include/Atom/RPI.Public/Image/ImageSystemInterface.h @@ -14,9 +14,12 @@ namespace AZ { + class Name; + namespace RPI { class Image; + class AttachmentImage; class AttachmentImagePool; class StreamingImagePool; @@ -63,7 +66,20 @@ namespace AZ //! Returns the system attachment image pool. Use this if you do not need a custom pool for your allocation. virtual const Data::Instance& GetSystemAttachmentPool() const = 0; - + + //! Register an attachment image by its unique name (attachment id) + //! Return false if the image was failed to register. + //! It could be the image with same name was already registered. + //! Note: this function is only intended to be used by AttachmentImage class + //! Only attachment images created with an unique name will be registered + virtual bool RegisterAttachmentImage(AttachmentImage* attachmentImage) = 0; + + //! Unregister an attachment image (if it's was registered) + virtual void UnregisterAttachmentImage(AttachmentImage* attachmentImage) = 0; + + //! Find an attachment image by its unique name (same as its attachment id) from registered attachment images. + //! Note: only attachment image created with an uqniue name will be registered. + virtual Data::Instance FindRegisteredAttachmentImage(const Name& uniqueName) const = 0; virtual void Update() = 0; }; diff --git a/Gems/Atom/RPI/Code/Include/Atom/RPI.Public/Pass/ParentPass.h b/Gems/Atom/RPI/Code/Include/Atom/RPI.Public/Pass/ParentPass.h index c9db343203..e739547255 100644 --- a/Gems/Atom/RPI/Code/Include/Atom/RPI.Public/Pass/ParentPass.h +++ b/Gems/Atom/RPI/Code/Include/Atom/RPI.Public/Pass/ParentPass.h @@ -63,6 +63,10 @@ namespace AZ //! Adds pass to list of children void AddChild(const Ptr& child); + //! Inserts a pass at specified position + //! If the position is invalid, the child pass won't be added, and the function returns false + bool InsertChild(const Ptr& child, ChildPassIndex position); + //! Searches for a child pass with the given name. Returns the child's index if found, null index otherwise ChildPassIndex FindChildPassIndex(const Name& passName) const; diff --git a/Gems/Atom/RPI/Code/Include/Atom/RPI.Public/Pass/RenderPass.h b/Gems/Atom/RPI/Code/Include/Atom/RPI.Public/Pass/RenderPass.h index bdd305b4eb..9ccfb2764e 100644 --- a/Gems/Atom/RPI/Code/Include/Atom/RPI.Public/Pass/RenderPass.h +++ b/Gems/Atom/RPI/Code/Include/Atom/RPI.Public/Pass/RenderPass.h @@ -113,6 +113,9 @@ namespace AZ // The shader resource group for this pass Data::Instance m_shaderResourceGroup = nullptr; + // Determines which hardware queue the pass will run on + RHI::HardwareQueueClass m_hardwareQueueClass = RHI::HardwareQueueClass::Graphics; + private: // Helper function that binds a single attachment to the pass shader resource group void BindAttachment(const RHI::FrameGraphCompileContext& context, PassAttachmentBinding& binding, int16_t& imageIndex, int16_t& bufferIndex); diff --git a/Gems/Atom/RPI/Code/Include/Atom/RPI.Public/Pass/Specific/ImageAttachmentPreviewPass.h b/Gems/Atom/RPI/Code/Include/Atom/RPI.Public/Pass/Specific/ImageAttachmentPreviewPass.h index 8ee7a44b6f..4453d62ec0 100644 --- a/Gems/Atom/RPI/Code/Include/Atom/RPI.Public/Pass/Specific/ImageAttachmentPreviewPass.h +++ b/Gems/Atom/RPI/Code/Include/Atom/RPI.Public/Pass/Specific/ImageAttachmentPreviewPass.h @@ -10,6 +10,7 @@ #include #include +#include #include #include @@ -103,6 +104,7 @@ namespace AZ void LoadShader(); // Pass overrides + void BuildInternal() override; void FrameBeginInternal(FramePrepareParams params) override; // RHI::ScopeProducer overrides... diff --git a/Gems/Atom/RPI/Code/Include/Atom/RPI.Public/Scene.h b/Gems/Atom/RPI/Code/Include/Atom/RPI.Public/Scene.h index a87184b4b2..0d41e0b5e9 100644 --- a/Gems/Atom/RPI/Code/Include/Atom/RPI.Public/Scene.h +++ b/Gems/Atom/RPI/Code/Include/Atom/RPI.Public/Scene.h @@ -165,6 +165,11 @@ namespace AZ //! User should use this event to update the part scene srg they know of void ConnectEvent(PrepareSceneSrgEvent::Handler& handler); + //! Rebuild pipeline states lookup table. + //! This function is called every time scene's render pipelines change. + //! User may call this function explicitly if render pipelines were changed + void RebuildPipelineStatesLookup(); + protected: // SceneFinder overrides... void OnSceneNotifictaionHandlerConnected(SceneNotification* handler); @@ -190,9 +195,6 @@ namespace AZ private: Scene(); - // Rebuild pipeline states lookup table. - // This function is called every time scene's render pipelines change. - void RebuildPipelineStatesLookup(); // Helper function to wait for end of TaskGraph and then delete the TaskGraphEvent void WaitAndCleanTGEvent(AZStd::unique_ptr&& completionTGEvent); diff --git a/Gems/Atom/RPI/Code/Include/Atom/RPI.Reflect/Image/AttachmentImageAsset.h b/Gems/Atom/RPI/Code/Include/Atom/RPI.Reflect/Image/AttachmentImageAsset.h index ceb2dd725d..7f7a6d6e48 100644 --- a/Gems/Atom/RPI/Code/Include/Atom/RPI.Reflect/Image/AttachmentImageAsset.h +++ b/Gems/Atom/RPI/Code/Include/Atom/RPI.Reflect/Image/AttachmentImageAsset.h @@ -42,12 +42,28 @@ namespace AZ //! Return the clear value of the image. The clear value may only be useful for certain type of images such as render targets (color/depth stencil). const RHI::ClearValue* GetOptimizedClearValue() const; + //! Return the name which can be used as debug name + const AZ::Name& GetName() const; + + //! Return an unique name id which can be used as attachment id + RHI::AttachmentId GetAttachmentId() const; + + //! Return ture if the attachment image has an unique name + //! An attachment image with an unique name will be registered to image system + //! and it can be found by ImageSystemInterface::FindRegisteredAttachmentImage() function + //! The unique name is same as its attachment Id + bool HasUniqueName() const; + private: Data::Asset m_poolAsset; - // Clear value of the image. The value is only valid when m_isClearValueValid is true - RHI::ClearValue m_optimizedClearValue; - bool m_isClearValueValid = false; + // an name id + AZ::Name m_name; + + bool m_isUniqueName = false; + + // Clear value of the image + AZStd::shared_ptr m_optimizedClearValue; }; using AttachmentImageAssetHandler = AssetHandler; diff --git a/Gems/Atom/RPI/Code/Include/Atom/RPI.Reflect/Image/AttachmentImageAssetCreator.h b/Gems/Atom/RPI/Code/Include/Atom/RPI.Reflect/Image/AttachmentImageAssetCreator.h index 5d7851b05f..dbeb4b674a 100644 --- a/Gems/Atom/RPI/Code/Include/Atom/RPI.Reflect/Image/AttachmentImageAssetCreator.h +++ b/Gems/Atom/RPI/Code/Include/Atom/RPI.Reflect/Image/AttachmentImageAssetCreator.h @@ -36,9 +36,17 @@ namespace AZ //! Assigns the attachment image pool, which the runtime attachment image will allocate from. Required. void SetPoolAsset(const Data::Asset& poolAsset); + //! @deprecated. Deprecated, use SetName() instead //! Set a string to asset's hint. This info is only kept for runtime generated asset. //! For asset on disc, the asset system will assign asset path to asset hint void SetAssetHint(AZStd::string_view hint); + + //! Set a name for this attachment image. + //! This name will be used for AttachmentImage's RHI Image's debug name. + //! @param isUniqueName If true the image will be registered to Image System and the unique need to be unique + //! among other attachment image with unique names. And the image can be found by + //! ImageSystemInterface::FindRegisteredAttachmentImage() function + void SetName(const AZ::Name& name, bool isUniqueName); //! Finalizes and assigns ownership of the asset to result, if successful. //! Otherwise false is returned and result is left untouched. diff --git a/Gems/Atom/RPI/Code/Include/Atom/RPI.Reflect/Pass/ComputePassData.h b/Gems/Atom/RPI/Code/Include/Atom/RPI.Reflect/Pass/ComputePassData.h index f7b71b9483..e5e6c60c7f 100644 --- a/Gems/Atom/RPI/Code/Include/Atom/RPI.Reflect/Pass/ComputePassData.h +++ b/Gems/Atom/RPI/Code/Include/Atom/RPI.Reflect/Pass/ComputePassData.h @@ -29,12 +29,13 @@ namespace AZ if (auto* serializeContext = azrtti_cast(context)) { serializeContext->Class() - ->Version(1) + ->Version(2) ->Field("ShaderAsset", &ComputePassData::m_shaderReference) ->Field("Target Thread Count X", &ComputePassData::m_totalNumberOfThreadsX) ->Field("Target Thread Count Y", &ComputePassData::m_totalNumberOfThreadsY) ->Field("Target Thread Count Z", &ComputePassData::m_totalNumberOfThreadsZ) ->Field("Make Fullscreen Pass", &ComputePassData::m_makeFullscreenPass) + ->Field("Use Async Compute", &ComputePassData::m_useAsyncCompute) ; } } @@ -46,6 +47,9 @@ namespace AZ uint32_t m_totalNumberOfThreadsZ = 0; bool m_makeFullscreenPass = false; + + // Whether the pass should use async compute and run on the compute hardware queue. + bool m_useAsyncCompute = false; }; } // namespace RPI } // namespace AZ diff --git a/Gems/Atom/RPI/Code/Include/Atom/RPI.Reflect/Pass/CopyPassData.h b/Gems/Atom/RPI/Code/Include/Atom/RPI.Reflect/Pass/CopyPassData.h index 5f4e5b7f6c..3808dd35d1 100644 --- a/Gems/Atom/RPI/Code/Include/Atom/RPI.Reflect/Pass/CopyPassData.h +++ b/Gems/Atom/RPI/Code/Include/Atom/RPI.Reflect/Pass/CopyPassData.h @@ -32,7 +32,7 @@ namespace AZ if (auto* serializeContext = azrtti_cast(context)) { serializeContext->Class() - ->Version(0) + ->Version(1) ->Field("BufferSize", &CopyPassData::m_bufferSize) ->Field("BufferSourceOffset", &CopyPassData::m_bufferSourceOffset) ->Field("BufferSourceBytesPerRow", &CopyPassData::m_bufferSourceBytesPerRow) @@ -46,6 +46,7 @@ namespace AZ ->Field("ImageDestinationSubresource", &CopyPassData::m_imageDestinationSubresource) ->Field("ImageDestinationOrigin", &CopyPassData::m_imageDestinationOrigin) ->Field("CloneInput", &CopyPassData::m_cloneInput) + ->Field("UseCopyQueue", &CopyPassData::m_useCopyQueue) ; } } @@ -75,6 +76,9 @@ namespace AZ // If set to true, pass will automatically create a transient output attachment based on input // If false, the output target of the copy will need to be specified bool m_cloneInput = true; + + // Whether the pass should use the copy queue. + bool m_useCopyQueue = false; }; } // namespace RPI } // namespace AZ diff --git a/Gems/Atom/RPI/Code/Source/RPI.Builders/Common/AnyAssetBuilder.cpp b/Gems/Atom/RPI/Code/Source/RPI.Builders/Common/AnyAssetBuilder.cpp index 4d060b97b1..b16c9e6a24 100644 --- a/Gems/Atom/RPI/Code/Source/RPI.Builders/Common/AnyAssetBuilder.cpp +++ b/Gems/Atom/RPI/Code/Source/RPI.Builders/Common/AnyAssetBuilder.cpp @@ -60,7 +60,7 @@ namespace AZ AZStd::placeholders::_1, AZStd::placeholders::_2); builderDescriptor.m_processJobFunction = AZStd::bind(&AnyAssetBuilder::ProcessJob, this, AZStd::placeholders::_1, AZStd::placeholders::_2); - builderDescriptor.m_version = 9; + builderDescriptor.m_version = 10; BusConnect(builderDescriptor.m_busId); diff --git a/Gems/Atom/RPI/Code/Source/RPI.Public/DynamicDraw/DynamicDrawSystem.cpp b/Gems/Atom/RPI/Code/Source/RPI.Public/DynamicDraw/DynamicDrawSystem.cpp index 85391d854a..95e3294292 100644 --- a/Gems/Atom/RPI/Code/Source/RPI.Public/DynamicDraw/DynamicDrawSystem.cpp +++ b/Gems/Atom/RPI/Code/Source/RPI.Public/DynamicDraw/DynamicDrawSystem.cpp @@ -70,7 +70,7 @@ namespace AZ void DynamicDrawSystem::AddDrawPacket(Scene* scene, AZStd::unique_ptr drawPacket) { AZStd::lock_guard lock(m_mutexDrawPackets); - m_drawPackets[scene].emplace_back(ConstPtr(AZStd::move(drawPacket.get()))); + m_drawPackets[scene].emplace_back(ConstPtr(drawPacket.release())); } void DynamicDrawSystem::AddDrawPacket(Scene* scene, ConstPtr drawPacket) diff --git a/Gems/Atom/RPI/Code/Source/RPI.Public/Image/AttachmentImage.cpp b/Gems/Atom/RPI/Code/Source/RPI.Public/Image/AttachmentImage.cpp index 14eda8af79..64b5b154d3 100644 --- a/Gems/Atom/RPI/Code/Source/RPI.Public/Image/AttachmentImage.cpp +++ b/Gems/Atom/RPI/Code/Source/RPI.Public/Image/AttachmentImage.cpp @@ -25,15 +25,9 @@ namespace AZ { Data::Instance AttachmentImage::FindOrCreate(const Data::Asset& imageAsset) { - auto image = Data::InstanceDatabase::Instance().FindOrCreate( + return Data::InstanceDatabase::Instance().FindOrCreate( Data::InstanceId::CreateFromAssetId(imageAsset.GetId()), imageAsset); - if (image && image->m_image) - { - image->m_image->SetName(Name(imageAsset.GetHint())); - image->m_attachmentId = image->m_image->GetName(); - } - return image; } Data::Instance AttachmentImage::Create( @@ -42,24 +36,52 @@ namespace AZ const Name& imageName, const RHI::ClearValue* optimizedClearValue, const RHI::ImageViewDescriptor* imageViewDescriptor) + { + CreateAttachmentImageRequest createImageRequest; + createImageRequest.m_imagePool = &imagePool; + createImageRequest.m_imageDescriptor = imageDescriptor; + createImageRequest.m_imageName = imageName; + createImageRequest.m_isUniqueName = false; + createImageRequest.m_optimizedClearValue = optimizedClearValue; + createImageRequest.m_imageViewDescriptor = imageViewDescriptor; + return Create(createImageRequest); + } + + Data::Instance AttachmentImage::Create(const CreateAttachmentImageRequest& createImageRequest) { Data::Asset imageAsset; + AZ::Uuid uuid; + if (createImageRequest.m_isUniqueName) + { + uuid = Uuid::CreateName(createImageRequest.m_imageName.GetCStr()); + Data::InstanceId instanceId = Data::InstanceId::CreateFromAssetId(uuid); + if (Data::InstanceDatabase::Instance().Find(instanceId)) + { + AZ_Error("AttchmentImage", false, "AttachmentImage with an unique name '%s' was already created", createImageRequest.m_imageName.GetCStr()); + return nullptr; + } + } + else + { + uuid = Uuid::CreateRandom(); + } + AttachmentImageAssetCreator imageAssetCreator; - auto uuid = Uuid::CreateRandom(); imageAssetCreator.Begin(uuid); - imageAssetCreator.SetImageDescriptor(imageDescriptor); - imageAssetCreator.SetPoolAsset({imagePool.GetAssetId(), azrtti_typeid()}); - imageAssetCreator.SetAssetHint(imageName.GetCStr()); + imageAssetCreator.SetImageDescriptor(createImageRequest.m_imageDescriptor); + imageAssetCreator.SetPoolAsset({createImageRequest.m_imagePool->GetAssetId(), azrtti_typeid()}); + + imageAssetCreator.SetName(createImageRequest.m_imageName, createImageRequest.m_isUniqueName); - if (imageViewDescriptor) + if (createImageRequest.m_imageViewDescriptor) { - imageAssetCreator.SetImageViewDescriptor(*imageViewDescriptor); + imageAssetCreator.SetImageViewDescriptor(*createImageRequest.m_imageViewDescriptor); } - if (optimizedClearValue) + if (createImageRequest.m_optimizedClearValue) { - imageAssetCreator.SetOptimizedClearValue(*optimizedClearValue); + imageAssetCreator.SetOptimizedClearValue(*createImageRequest.m_optimizedClearValue); } if (imageAssetCreator.End(imageAsset)) @@ -70,6 +92,11 @@ namespace AZ return nullptr; } + Data::Instance AttachmentImage::FindByUniqueName(const Name& uniqueAttachmentName) + { + return ImageSystemInterface::Get()->FindRegisteredAttachmentImage(uniqueAttachmentName); + } + Data::Instance AttachmentImage::CreateInternal(AttachmentImageAsset& imageAsset) { Data::Instance image = aznew AttachmentImage(); @@ -77,18 +104,33 @@ namespace AZ if (result == RHI::ResultCode::Success) { + image->m_imageAsset = { &imageAsset, AZ::Data::AssetLoadBehavior::PreLoad }; return image; } return nullptr; } + + AttachmentImage::~AttachmentImage() + { + Shutdown(); + } RHI::ResultCode AttachmentImage::Init(const AttachmentImageAsset& imageAsset) { - Data::Instance pool = ImageSystemInterface::Get()->GetSystemAttachmentPool(); + Data::Instance pool; + if (imageAsset.GetPoolAsset().GetId().IsValid()) + { + pool = AttachmentImagePool::FindOrCreate(imageAsset.GetPoolAsset()); + } + else + { + pool = ImageSystemInterface::Get()->GetSystemAttachmentPool(); + } + if (!pool) { - AZ_Error("AttachmentImage", false, "Failed to acquire the image pool instance."); + AZ_Error("AttachmentImage", false, "Failed to acquire the attachment image pool instance."); return RHI::ResultCode::Fail; } @@ -109,6 +151,14 @@ namespace AZ AZ_Error("AttachmentImage", false, "AttachmentImage::Init() failed to initialize RHI image view."); return RHI::ResultCode::Fail; } + + m_image->SetName(imageAsset.GetName()); + m_attachmentId = imageAsset.GetAttachmentId(); + + if (imageAsset.HasUniqueName()) + { + ImageSystemInterface::Get()->RegisterAttachmentImage(this); + } return RHI::ResultCode::Success; } @@ -117,9 +167,17 @@ namespace AZ return resultCode; } - const RHI::AttachmentId& AttachmentImage::GetAttachmentId() + const RHI::AttachmentId& AttachmentImage::GetAttachmentId() const { return m_attachmentId; } + + void AttachmentImage::Shutdown() + { + if (m_imageAsset->HasUniqueName()) + { + ImageSystemInterface::Get()->UnregisterAttachmentImage(this); + } + } } } diff --git a/Gems/Atom/RPI/Code/Source/RPI.Public/Image/ImageSystem.cpp b/Gems/Atom/RPI/Code/Source/RPI.Public/Image/ImageSystem.cpp index 2c85f85424..981af2e2ab 100644 --- a/Gems/Atom/RPI/Code/Source/RPI.Public/Image/ImageSystem.cpp +++ b/Gems/Atom/RPI/Code/Source/RPI.Public/Image/ImageSystem.cpp @@ -200,6 +200,49 @@ namespace AZ return m_systemImages[static_cast(simpleImage)]; } + bool ImageSystem::RegisterAttachmentImage(AttachmentImage* attachmentImage) + { + if (!attachmentImage) + { + return false; + } + + auto itr = m_registeredAttachmentImages.find(attachmentImage->GetAttachmentId()); + if (itr != m_registeredAttachmentImages.end()) + { + AZ_Assert(false, "AttachmangeImage with name '%s' was already registered", attachmentImage->GetAttachmentId().GetCStr()); + return false; + } + + m_registeredAttachmentImages[attachmentImage->GetAttachmentId()] = attachmentImage; + + return true; + } + + void ImageSystem::UnregisterAttachmentImage(AttachmentImage* attachmentImage) + { + if (!attachmentImage) + { + return; + } + auto itr = m_registeredAttachmentImages.find(attachmentImage->GetAttachmentId()); + if (itr != m_registeredAttachmentImages.end()) + { + m_registeredAttachmentImages.erase(itr); + } + } + + Data::Instance ImageSystem::FindRegisteredAttachmentImage(const Name& uniqueName) const + { + auto itr = m_registeredAttachmentImages.find(uniqueName); + + if (itr != m_registeredAttachmentImages.end()) + { + return itr->second; + } + return nullptr; + } + void ImageSystem::CreateDefaultResources(const ImageSystemDescriptor& desc) { struct SystemImageDescriptor diff --git a/Gems/Atom/RPI/Code/Source/RPI.Public/Pass/ComputePass.cpp b/Gems/Atom/RPI/Code/Source/RPI.Public/Pass/ComputePass.cpp index 8bcf9b1b85..f20da50cc8 100644 --- a/Gems/Atom/RPI/Code/Source/RPI.Public/Pass/ComputePass.cpp +++ b/Gems/Atom/RPI/Code/Source/RPI.Public/Pass/ComputePass.cpp @@ -58,6 +58,12 @@ namespace AZ return; } + // Hardware Queue Class + if (passData->m_useAsyncCompute) + { + m_hardwareQueueClass = RHI::HardwareQueueClass::Compute; + } + // Load Shader Data::Asset shaderAsset; if (passData->m_shaderReference.m_assetId.IsValid()) diff --git a/Gems/Atom/RPI/Code/Source/RPI.Public/Pass/CopyPass.cpp b/Gems/Atom/RPI/Code/Source/RPI.Public/Pass/CopyPass.cpp index 1dde615f77..fdc58ef97d 100644 --- a/Gems/Atom/RPI/Code/Source/RPI.Public/Pass/CopyPass.cpp +++ b/Gems/Atom/RPI/Code/Source/RPI.Public/Pass/CopyPass.cpp @@ -38,6 +38,11 @@ namespace AZ if (copyData) { m_data = *copyData; + + if (copyData->m_useCopyQueue) + { + m_hardwareQueueClass = RHI::HardwareQueueClass::Copy; + } } } diff --git a/Gems/Atom/RPI/Code/Source/RPI.Public/Pass/ParentPass.cpp b/Gems/Atom/RPI/Code/Source/RPI.Public/Pass/ParentPass.cpp index 77a3e1524a..3933649f13 100644 --- a/Gems/Atom/RPI/Code/Source/RPI.Public/Pass/ParentPass.cpp +++ b/Gems/Atom/RPI/Code/Source/RPI.Public/Pass/ParentPass.cpp @@ -53,7 +53,11 @@ namespace AZ void ParentPass::AddChild(const Ptr& child) { - AZ_Assert(child->m_parent == nullptr, "Can't add Pass that already has a parent. Remove the Pass from it's parent before adding it to another Pass."); + if (child->m_parent != nullptr) + { + AZ_Assert(false, "Can't add Pass that already has a parent. Remove the Pass from it's parent before adding it to another Pass."); + return; + } m_children.push_back(child); child->m_parent = this; @@ -71,6 +75,39 @@ namespace AZ } } + bool ParentPass::InsertChild(const Ptr& child, ChildPassIndex position) + { + if (child->m_parent != nullptr) + { + AZ_Assert(false, "Can't add Pass that already has a parent. Remove the Pass from it's parent before adding it to another Pass."); + return false; + } + + if (!position.IsValid() || position.GetIndex() > m_children.size()) + { + AZ_Assert(false, "Can't insert a child pass with invalid position"); + return false; + } + + auto insertPos = m_children.cbegin() + position.GetIndex(); + m_children.insert(insertPos, child); + + child->m_parent = this; + child->OnHierarchyChange(); + + QueueForBuildAndInitialization(); + + // Notify pipeline + if (m_pipeline) + { + m_pipeline->SetPassModified(); + + // Set child's pipeline if the parent has a owning pipeline + child->SetRenderPipeline(m_pipeline); + } + return true; + } + void ParentPass::OnHierarchyChange() { Pass::OnHierarchyChange(); diff --git a/Gems/Atom/RPI/Code/Source/RPI.Public/Pass/Pass.cpp b/Gems/Atom/RPI/Code/Source/RPI.Public/Pass/Pass.cpp index 4b68094f9d..3985972223 100644 --- a/Gems/Atom/RPI/Code/Source/RPI.Public/Pass/Pass.cpp +++ b/Gems/Atom/RPI/Code/Source/RPI.Public/Pass/Pass.cpp @@ -644,6 +644,7 @@ namespace AZ { attachment->m_path = buffer->GetAttachmentId(); attachment->m_importedResource = buffer; + attachment->m_descriptor = buffer->GetRHIBuffer()->GetDescriptor(); } } } @@ -658,6 +659,7 @@ namespace AZ { attachment->m_path = image->GetAttachmentId(); attachment->m_importedResource = image; + attachment->m_descriptor = image->GetDescriptor(); } } } diff --git a/Gems/Atom/RPI/Code/Source/RPI.Public/Pass/RenderPass.cpp b/Gems/Atom/RPI/Code/Source/RPI.Public/Pass/RenderPass.cpp index fa5f41e615..661c03b34a 100644 --- a/Gems/Atom/RPI/Code/Source/RPI.Public/Pass/RenderPass.cpp +++ b/Gems/Atom/RPI/Code/Source/RPI.Public/Pass/RenderPass.cpp @@ -183,7 +183,7 @@ namespace AZ { if (GetScopeId().IsEmpty()) { - SetScopeId(RHI::ScopeId(GetPathName())); + InitScope(RHI::ScopeId(GetPathName()), m_hardwareQueueClass); } params.m_frameGraphBuilder->ImportScopeProducer(*this); diff --git a/Gems/Atom/RPI/Code/Source/RPI.Public/Pass/Specific/ImageAttachmentPreviewPass.cpp b/Gems/Atom/RPI/Code/Source/RPI.Public/Pass/Specific/ImageAttachmentPreviewPass.cpp index f173b2b544..0bbc17bf45 100644 --- a/Gems/Atom/RPI/Code/Source/RPI.Public/Pass/Specific/ImageAttachmentPreviewPass.cpp +++ b/Gems/Atom/RPI/Code/Source/RPI.Public/Pass/Specific/ImageAttachmentPreviewPass.cpp @@ -32,7 +32,7 @@ namespace AZ m_destAttachmentId = destAttachmentId; // Use the unique destination attachment id as scope id - SetScopeId(m_destAttachmentId); + InitScope(m_destAttachmentId); // Clear the previous attachment and copy item m_copyItem = {}; @@ -54,13 +54,14 @@ namespace AZ void ImageAttachmentCopy::FrameBegin(Pass::FramePrepareParams params) { + RHI::FrameGraphAttachmentInterface attachmentDatabase = params.m_frameGraphBuilder->GetAttachmentDatabase(); + if (m_srcAttachmentId.IsEmpty()) { return; } // Return if the source attachment is not imported - RHI::FrameGraphAttachmentInterface attachmentDatabase = params.m_frameGraphBuilder->GetAttachmentDatabase(); if (!attachmentDatabase.IsAttachmentValid(m_srcAttachmentId)) { Reset(); @@ -123,7 +124,7 @@ namespace AZ ImageAttachmentPreviewPass::ImageAttachmentPreviewPass(const PassDescriptor& descriptor) : Pass(descriptor) { - SetScopeId(RHI::ScopeId(GetPathName())); + InitScope(RHI::ScopeId(GetPathName())); } ImageAttachmentPreviewPass::~ImageAttachmentPreviewPass() @@ -310,13 +311,31 @@ namespace AZ Data::AssetBus::Handler::BusConnect(shaderAsset.GetId()); } + void ImageAttachmentPreviewPass::BuildInternal() + { + m_updateDrawData = true; + } + void ImageAttachmentPreviewPass::FrameBeginInternal(FramePrepareParams params) { bool scopeImported = false; if (!m_imageAttachmentId.IsEmpty() && m_outputColorAttachment) { // Only import the scope if the attachment is valid - if (params.m_frameGraphBuilder->GetAttachmentDatabase().IsAttachmentValid(m_imageAttachmentId)) + auto attachmentDatabase = params.m_frameGraphBuilder->GetAttachmentDatabase(); + bool isAttachmentValid = attachmentDatabase.IsAttachmentValid(m_imageAttachmentId); + if (!isAttachmentValid) + { + // Import the cached copy dest image if it exists (copied) + // So the attachment can be still previewed when the pass is disabled. + if (m_attachmentCopy && m_attachmentCopy->m_destImage) + { + attachmentDatabase.ImportImage(m_attachmentCopy->m_destAttachmentId, m_attachmentCopy->m_destImage->GetRHIImage()); + isAttachmentValid = true; + } + } + + if (isAttachmentValid) { if (m_needsShaderLoad) { diff --git a/Gems/Atom/RPI/Code/Source/RPI.Reflect/Image/AttachmentImageAsset.cpp b/Gems/Atom/RPI/Code/Source/RPI.Reflect/Image/AttachmentImageAsset.cpp index 57bc548045..b8e8ee9a22 100644 --- a/Gems/Atom/RPI/Code/Source/RPI.Reflect/Image/AttachmentImageAsset.cpp +++ b/Gems/Atom/RPI/Code/Source/RPI.Reflect/Image/AttachmentImageAsset.cpp @@ -21,7 +21,10 @@ namespace AZ if (auto* serializeContext = azrtti_cast(context)) { serializeContext->Class() - ->Version(1) + ->Version(2) + ->Field("Name", &AttachmentImageAsset::m_name) + ->Field("IsUniqueName", &AttachmentImageAsset::m_isUniqueName) + ->Field("OptimizedClearValue", &AttachmentImageAsset::m_optimizedClearValue) ; } } @@ -33,7 +36,27 @@ namespace AZ const RHI::ClearValue* AttachmentImageAsset::GetOptimizedClearValue() const { - return m_isClearValueValid ? &m_optimizedClearValue : nullptr; + return m_optimizedClearValue.get(); + } + + const AZ::Name& AttachmentImageAsset::GetName() const + { + return m_name; + } + + RHI::AttachmentId AttachmentImageAsset::GetAttachmentId() const + { + if (HasUniqueName()) + { + return m_name; + } + return Name(m_assetId.ToString()); + } + + bool AttachmentImageAsset::HasUniqueName() const + { + // The name can still be empty if the asset was loaded for data file but not from AttachmentImageAssetCreator + return m_isUniqueName && !m_name.IsEmpty(); } } } diff --git a/Gems/Atom/RPI/Code/Source/RPI.Reflect/Image/AttachmentImageAssetCreator.cpp b/Gems/Atom/RPI/Code/Source/RPI.Reflect/Image/AttachmentImageAssetCreator.cpp index 1cd1cfd7c3..19fa3fb604 100644 --- a/Gems/Atom/RPI/Code/Source/RPI.Reflect/Image/AttachmentImageAssetCreator.cpp +++ b/Gems/Atom/RPI/Code/Source/RPI.Reflect/Image/AttachmentImageAssetCreator.cpp @@ -7,6 +7,8 @@ */ #include +#include +#include #include @@ -47,8 +49,7 @@ namespace AZ { if (ValidateIsReady()) { - m_asset->m_isClearValueValid = true; - m_asset->m_optimizedClearValue = clearValue; + m_asset->m_optimizedClearValue = AZStd::make_shared(clearValue); } } @@ -59,12 +60,11 @@ namespace AZ return false; } - // Validate assetId instead of validate AssetData* exist. This is mainly because the Asset 's serializer only need serialize asset id instead of asset data - // Instead of create a complete Asset, we could use new Asset(assetId, type, hint) to create a placeholder to save the asset id for serialization. + // If the pool wasn't provided, use the system default attachment pool if (!m_asset->m_poolAsset.GetId().IsValid()) { - ReportError("You must assign a pool asset before calling End()."); - return false; + Data::Instance pool = RPI::ImageSystemInterface::Get()->GetSystemAttachmentPool(); + m_asset->m_poolAsset = {pool->GetAssetId(), azrtti_typeid()}; } m_asset->SetReady(); @@ -75,5 +75,20 @@ namespace AZ { m_asset.SetHint(hint); } + + void AttachmentImageAssetCreator::SetName(const AZ::Name& uniqueName, bool isUniqueName) + { + if (uniqueName.IsEmpty()) + { + m_asset->m_isUniqueName = false; + AZ_Warning("RPI", false, "Can't set empty string as unique name"); + } + else + { + m_asset->m_isUniqueName = isUniqueName; + } + m_asset->m_name = uniqueName; + + } } } diff --git a/Gems/Atom/Tools/AtomToolsFramework/Code/Include/AtomToolsFramework/Document/AtomToolsDocument.h b/Gems/Atom/Tools/AtomToolsFramework/Code/Include/AtomToolsFramework/Document/AtomToolsDocument.h index cb64d23cd0..2c9497df8e 100644 --- a/Gems/Atom/Tools/AtomToolsFramework/Code/Include/AtomToolsFramework/Document/AtomToolsDocument.h +++ b/Gems/Atom/Tools/AtomToolsFramework/Code/Include/AtomToolsFramework/Document/AtomToolsDocument.h @@ -32,10 +32,7 @@ namespace AtomToolsFramework // AtomToolsDocumentRequestBus::Handler overrides... AZStd::string_view GetAbsolutePath() const override; - const AZStd::any& GetPropertyValue(const AZ::Name& propertyId) const override; - const AtomToolsFramework::DynamicProperty& GetProperty(const AZ::Name& propertyId) const override; - bool IsPropertyGroupVisible(const AZ::Name& propertyGroupFullName) const override; - void SetPropertyValue(const AZ::Name& propertyId, const AZStd::any& value) override; + AZStd::vector GetObjectInfo() const override; bool Open(AZStd::string_view loadPath) override; bool Reopen() override; bool Save() override; @@ -78,10 +75,6 @@ namespace AtomToolsFramework //! The normalized, absolute path where the document will be saved. AZStd::string m_savePathNormalized; - AZStd::any m_invalidValue; - - AtomToolsFramework::DynamicProperty m_invalidProperty; - //! This contains absolute paths of other source files that affect this document. //! If any of the source files in this container are modified, the document system is notified to reload this document. AZStd::unordered_set m_sourceDependencies; diff --git a/Gems/Atom/Tools/AtomToolsFramework/Code/Include/AtomToolsFramework/Document/AtomToolsDocumentNotificationBus.h b/Gems/Atom/Tools/AtomToolsFramework/Code/Include/AtomToolsFramework/Document/AtomToolsDocumentNotificationBus.h index 9c3a536333..b9af219b9e 100644 --- a/Gems/Atom/Tools/AtomToolsFramework/Code/Include/AtomToolsFramework/Document/AtomToolsDocumentNotificationBus.h +++ b/Gems/Atom/Tools/AtomToolsFramework/Code/Include/AtomToolsFramework/Document/AtomToolsDocumentNotificationBus.h @@ -10,11 +10,10 @@ #include #include -#include -#include - namespace AtomToolsFramework { + struct DocumentObjectInfo; + class AtomToolsDocumentNotifications : public AZ::EBusTraits { @@ -61,22 +60,12 @@ namespace AtomToolsFramework //! Signal that a document undo state was updated //! @param documentId unique id of document for which the notification is sent virtual void OnDocumentUndoStateChanged([[maybe_unused]] const AZ::Uuid& documentId) {} - - //! Signal that a property changed - //! @param documentId unique id of document for which the notification is sent - //! @param property object containing the property value and configuration that was modified - virtual void OnDocumentPropertyValueModified([[maybe_unused]] const AZ::Uuid& documentId, [[maybe_unused]] const AtomToolsFramework::DynamicProperty& property) {} - - //! Signal that the property configuration has been changed. - //! @param documentId unique id of document for which the notification is sent - //! @param property object containing the property value and configuration that was modified - virtual void OnDocumentPropertyConfigModified([[maybe_unused]] const AZ::Uuid& documentId, [[maybe_unused]] const AtomToolsFramework::DynamicProperty& property) {} - //! Signal that the property group visibility has been changed. + //! Signal that the group has been changed. //! @param documentId unique id of document for which the notification is sent - //! @param groupId id of the group that changed - //! @param visible whether the property group is visible - virtual void OnDocumentPropertyGroupVisibilityChanged([[maybe_unused]] const AZ::Uuid& documentId, [[maybe_unused]] const AZ::Name& groupId, [[maybe_unused]] bool visible) {} + //! @param objectInfo description of the reflected object that's been modified + //! @param rebuilt signifies if it was a structural change that might require ui to be rebuilt + virtual void OnDocumentObjectInfoChanged([[maybe_unused]] const AZ::Uuid& documentId, [[maybe_unused]] const DocumentObjectInfo& objectInfo, [[maybe_unused]] bool rebuilt) {} }; using AtomToolsDocumentNotificationBus = AZ::EBus; diff --git a/Gems/Atom/Tools/AtomToolsFramework/Code/Include/AtomToolsFramework/Document/AtomToolsDocumentRequestBus.h b/Gems/Atom/Tools/AtomToolsFramework/Code/Include/AtomToolsFramework/Document/AtomToolsDocumentRequestBus.h index b6b3f65110..29cd8bede7 100644 --- a/Gems/Atom/Tools/AtomToolsFramework/Code/Include/AtomToolsFramework/Document/AtomToolsDocumentRequestBus.h +++ b/Gems/Atom/Tools/AtomToolsFramework/Code/Include/AtomToolsFramework/Document/AtomToolsDocumentRequestBus.h @@ -14,6 +14,20 @@ namespace AtomToolsFramework { + //! Structure used as an opaque description of objects reflected inside of a document. + //! An example use would be semi automatic handling of serialization or reflection to a property editor. + struct DocumentObjectInfo + { + bool m_visible = true; + AZStd::string m_name; + AZStd::string m_displayName; + AZStd::string m_description; + AZ::Uuid m_objectType = AZ::Uuid::CreateNull(); + void* m_objectPtr = {}; + }; + + //! This bus provides the most basic interface for implementing a document that works with the document system. + //! Any extensions or application specific functionality should be added using a domain specific buses. class AtomToolsDocumentRequests : public AZ::EBusTraits { @@ -25,20 +39,8 @@ namespace AtomToolsFramework //! Get absolute path of document virtual AZStd::string_view GetAbsolutePath() const = 0; - //! Return property value - //! If the document is not open or the id can't be found, an invalid value is returned instead. - virtual const AZStd::any& GetPropertyValue(const AZ::Name& propertyFullName) const = 0; - - //! Returns a property object - //! If the document is not open or the id can't be found, an invalid property is returned. - virtual const AtomToolsFramework::DynamicProperty& GetProperty(const AZ::Name& propertyFullName) const = 0; - - //! Returns whether a property group is visible - //! If the document is not open or the id can't be found, returns false. - virtual bool IsPropertyGroupVisible(const AZ::Name& propertyGroupFullName) const = 0; - - //! Modify document property value - virtual void SetPropertyValue(const AZ::Name& propertyFullName, const AZStd::any& value) = 0; + //! Returns a container describing all reflected objects contained in a document + virtual AZStd::vector GetObjectInfo() const = 0; //! Load document and related data //! @param loadPath absolute path of document to load diff --git a/Gems/Atom/Tools/AtomToolsFramework/Code/Include/AtomToolsFramework/Document/AtomToolsDocumentSystemRequestBus.h b/Gems/Atom/Tools/AtomToolsFramework/Code/Include/AtomToolsFramework/Document/AtomToolsDocumentSystemRequestBus.h index b12cf5e580..88b5acd3be 100644 --- a/Gems/Atom/Tools/AtomToolsFramework/Code/Include/AtomToolsFramework/Document/AtomToolsDocumentSystemRequestBus.h +++ b/Gems/Atom/Tools/AtomToolsFramework/Code/Include/AtomToolsFramework/Document/AtomToolsDocumentSystemRequestBus.h @@ -25,11 +25,11 @@ namespace AtomToolsFramework //! Register a document factory function used to create specific document types virtual void RegisterDocumentType(AZStd::function documentCreator) = 0; - //! Create a document object + //! Create a document //! @return Uuid of new document, or null Uuid if failed virtual AZ::Uuid CreateDocument() = 0; - //! Destroy a document object with the specified id + //! Destroy a document with the specified id //! @return true if Uuid was found and removed, otherwise false virtual bool DestroyDocument(const AZ::Uuid& documentId) = 0; diff --git a/Gems/Atom/Tools/AtomToolsFramework/Code/Include/AtomToolsFramework/DynamicProperty/DynamicProperty.h b/Gems/Atom/Tools/AtomToolsFramework/Code/Include/AtomToolsFramework/DynamicProperty/DynamicProperty.h index 5af0fcc845..2612b3be1b 100644 --- a/Gems/Atom/Tools/AtomToolsFramework/Code/Include/AtomToolsFramework/DynamicProperty/DynamicProperty.h +++ b/Gems/Atom/Tools/AtomToolsFramework/Code/Include/AtomToolsFramework/DynamicProperty/DynamicProperty.h @@ -46,6 +46,7 @@ namespace AtomToolsFramework AZStd::string m_name; AZStd::string m_displayName; AZStd::string m_groupName; + AZStd::string m_groupDisplayName; AZStd::string m_description; AZStd::any m_defaultValue; AZStd::any m_parentValue; @@ -60,6 +61,7 @@ namespace AtomToolsFramework bool m_visible = true; bool m_readOnly = false; bool m_showThumbnail = false; + AZStd::function m_dataChangeCallback; }; //! Wraps an AZStd::any value and configuration so that it can be displayed and edited in a ReflectedPropertyEditor. @@ -106,7 +108,7 @@ namespace AtomToolsFramework private: // Functions used to configure edit data attributes. AZStd::string GetDisplayName() const; - AZStd::string GetGroupName() const; + AZStd::string GetGroupDisplayName() const; AZStd::string GetAssetPickerTitle() const; AZStd::string GetDescription() const; AZStd::vector> GetEnumValues() const; diff --git a/Gems/Atom/Tools/AtomToolsFramework/Code/Include/AtomToolsFramework/DynamicProperty/DynamicPropertyGroup.h b/Gems/Atom/Tools/AtomToolsFramework/Code/Include/AtomToolsFramework/DynamicProperty/DynamicPropertyGroup.h index 91705f3428..7d5e25b95f 100644 --- a/Gems/Atom/Tools/AtomToolsFramework/Code/Include/AtomToolsFramework/DynamicProperty/DynamicPropertyGroup.h +++ b/Gems/Atom/Tools/AtomToolsFramework/Code/Include/AtomToolsFramework/DynamicProperty/DynamicPropertyGroup.h @@ -9,6 +9,7 @@ #pragma once #include +#include #include namespace AtomToolsFramework @@ -22,6 +23,11 @@ namespace AtomToolsFramework static void Reflect(AZ::ReflectContext* context); + bool m_visible = true; + AZStd::string m_name; + AZStd::string m_displayName; + AZStd::string m_description; AZStd::vector m_properties; + AZStd::vector> m_groups; }; } // namespace AtomToolsFramework diff --git a/Gems/Atom/Tools/AtomToolsFramework/Code/Source/Document/AtomToolsDocument.cpp b/Gems/Atom/Tools/AtomToolsFramework/Code/Source/Document/AtomToolsDocument.cpp index 84638eefc4..2660a1e8fb 100644 --- a/Gems/Atom/Tools/AtomToolsFramework/Code/Source/Document/AtomToolsDocument.cpp +++ b/Gems/Atom/Tools/AtomToolsFramework/Code/Source/Document/AtomToolsDocument.cpp @@ -36,32 +36,10 @@ namespace AtomToolsFramework return m_absolutePath; } - const AZStd::any& AtomToolsDocument::GetPropertyValue([[maybe_unused]] const AZ::Name& propertyId) const + AZStd::vector AtomToolsDocument::GetObjectInfo() const { - AZ_UNUSED(propertyId); - AZ_Error("AtomToolsDocument", false, "%s not implemented.", __FUNCTION__); - return m_invalidValue; - } - - const AtomToolsFramework::DynamicProperty& AtomToolsDocument::GetProperty([[maybe_unused]] const AZ::Name& propertyId) const - { - AZ_UNUSED(propertyId); - AZ_Error("AtomToolsDocument", false, "%s not implemented.", __FUNCTION__); - return m_invalidProperty; - } - - bool AtomToolsDocument::IsPropertyGroupVisible([[maybe_unused]] const AZ::Name& propertyGroupFullName) const - { - AZ_UNUSED(propertyGroupFullName); - AZ_Error("AtomToolsDocument", false, "%s not implemented.", __FUNCTION__); - return false; - } - - void AtomToolsDocument::SetPropertyValue([[maybe_unused]] const AZ::Name& propertyId, [[maybe_unused]] const AZStd::any& value) - { - AZ_UNUSED(propertyId); - AZ_UNUSED(value); - AZ_Error("AtomToolsDocument", false, "%s not implemented.", __FUNCTION__); + AZ_Warning("AtomToolsDocument", false, "%s not implemented.", __FUNCTION__); + return AZStd::vector(); } bool AtomToolsDocument::Open(AZStd::string_view loadPath) @@ -256,13 +234,13 @@ namespace AtomToolsFramework bool AtomToolsDocument::BeginEdit() { - AZ_Error("AtomToolsDocument", false, "%s not implemented.", __FUNCTION__); + AZ_Warning("AtomToolsDocument", false, "%s not implemented.", __FUNCTION__); return false; } bool AtomToolsDocument::EndEdit() { - AZ_Error("AtomToolsDocument", false, "%s not implemented.", __FUNCTION__); + AZ_Warning("AtomToolsDocument", false, "%s not implemented.", __FUNCTION__); return false; } diff --git a/Gems/Atom/Tools/AtomToolsFramework/Code/Source/Document/AtomToolsDocumentSystemComponent.cpp b/Gems/Atom/Tools/AtomToolsFramework/Code/Source/Document/AtomToolsDocumentSystemComponent.cpp index b5a3f5322c..c05bb56391 100644 --- a/Gems/Atom/Tools/AtomToolsFramework/Code/Source/Document/AtomToolsDocumentSystemComponent.cpp +++ b/Gems/Atom/Tools/AtomToolsFramework/Code/Source/Document/AtomToolsDocumentSystemComponent.cpp @@ -77,8 +77,6 @@ namespace AtomToolsFramework ->Attribute(AZ::Script::Attributes::Category, "Editor") ->Attribute(AZ::Script::Attributes::Module, "atomtools") ->Event("GetAbsolutePath", &AtomToolsDocumentRequestBus::Events::GetAbsolutePath) - ->Event("GetPropertyValue", &AtomToolsDocumentRequestBus::Events::GetPropertyValue) - ->Event("SetPropertyValue", &AtomToolsDocumentRequestBus::Events::SetPropertyValue) ->Event("Open", &AtomToolsDocumentRequestBus::Events::Open) ->Event("Reopen", &AtomToolsDocumentRequestBus::Events::Reopen) ->Event("Close", &AtomToolsDocumentRequestBus::Events::Close) diff --git a/Gems/Atom/Tools/AtomToolsFramework/Code/Source/DynamicProperty/DynamicProperty.cpp b/Gems/Atom/Tools/AtomToolsFramework/Code/Source/DynamicProperty/DynamicProperty.cpp index 830f71933c..bd83fef320 100644 --- a/Gems/Atom/Tools/AtomToolsFramework/Code/Source/DynamicProperty/DynamicProperty.cpp +++ b/Gems/Atom/Tools/AtomToolsFramework/Code/Source/DynamicProperty/DynamicProperty.cpp @@ -195,14 +195,14 @@ namespace AtomToolsFramework return !m_config.m_displayName.empty() ? m_config.m_displayName : m_config.m_name; } - AZStd::string DynamicProperty::GetGroupName() const + AZStd::string DynamicProperty::GetGroupDisplayName() const { - return m_config.m_groupName; + return m_config.m_groupDisplayName; } AZStd::string DynamicProperty::GetAssetPickerTitle() const { - return GetGroupName().empty() ? GetDisplayName() : GetGroupName() + " " + GetDisplayName(); + return GetGroupDisplayName().empty() ? GetDisplayName() : GetGroupDisplayName() + " " + GetDisplayName(); } AZStd::string DynamicProperty::GetDescription() const @@ -235,6 +235,10 @@ namespace AtomToolsFramework AZ::u32 DynamicProperty::OnDataChanged() const { + if (m_config.m_dataChangeCallback) + { + return m_config.m_dataChangeCallback(GetValue()); + } return AZ::Edit::PropertyRefreshLevels::AttributesAndValues; } diff --git a/Gems/Atom/Tools/AtomToolsFramework/Code/Source/DynamicProperty/DynamicPropertyGroup.cpp b/Gems/Atom/Tools/AtomToolsFramework/Code/Source/DynamicProperty/DynamicPropertyGroup.cpp index 41e96976e6..2647eb180a 100644 --- a/Gems/Atom/Tools/AtomToolsFramework/Code/Source/DynamicProperty/DynamicPropertyGroup.cpp +++ b/Gems/Atom/Tools/AtomToolsFramework/Code/Source/DynamicProperty/DynamicPropertyGroup.cpp @@ -17,7 +17,12 @@ namespace AtomToolsFramework if (auto serializeContext = azrtti_cast(context)) { serializeContext->Class() + ->Field("visible", &DynamicPropertyGroup::m_visible) + ->Field("name", &DynamicPropertyGroup::m_name) + ->Field("displayName", &DynamicPropertyGroup::m_displayName) + ->Field("description", &DynamicPropertyGroup::m_description) ->Field("properties", &DynamicPropertyGroup::m_properties) + ->Field("groups", &DynamicPropertyGroup::m_groups) ; if (auto editContext = serializeContext->GetEditContext()) @@ -28,6 +33,9 @@ namespace AtomToolsFramework ->DataElement(AZ::Edit::UIHandlers::Default, &DynamicPropertyGroup::m_properties, "properties", "") ->Attribute(AZ::Edit::Attributes::Visibility, AZ::Edit::PropertyVisibility::ShowChildrenOnly) // hides the m_properties row ->Attribute(AZ::Edit::Attributes::ContainerCanBeModified, false) // probably not necessary since Visibility is children-only + ->DataElement(AZ::Edit::UIHandlers::Default, &DynamicPropertyGroup::m_groups, "groups", "") + ->Attribute(AZ::Edit::Attributes::Visibility, AZ::Edit::PropertyVisibility::ShowChildrenOnly) // hides the m_groups row + ->Attribute(AZ::Edit::Attributes::ContainerCanBeModified, false) // probably not necessary since Visibility is children-only ; } } diff --git a/Gems/Atom/Tools/MaterialEditor/Code/Source/Document/MaterialDocument.cpp b/Gems/Atom/Tools/MaterialEditor/Code/Source/Document/MaterialDocument.cpp index 7490fa5848..6f576c9e02 100644 --- a/Gems/Atom/Tools/MaterialEditor/Code/Source/Document/MaterialDocument.cpp +++ b/Gems/Atom/Tools/MaterialEditor/Code/Source/Document/MaterialDocument.cpp @@ -53,112 +53,93 @@ namespace MaterialEditor return &m_materialTypeSourceData; } - const AZStd::any& MaterialDocument::GetPropertyValue(const AZ::Name& propertyId) const + void MaterialDocument::SetPropertyValue(const AZ::Name& propertyId, const AZStd::any& value) { if (!IsOpen()) { AZ_Error("MaterialDocument", false, "Document is not open."); - return m_invalidValue; + return; } - const auto it = m_properties.find(propertyId); - if (it == m_properties.end()) - { - AZ_Error("MaterialDocument", false, "Document property could not be found: '%s'.", propertyId.GetCStr()); - return m_invalidValue; - } + AtomToolsFramework::DynamicProperty* foundProperty = {}; + TraverseGroups(m_groups, [&, this](auto& group) { + for (auto& property : group->m_properties) + { + if (property.GetId() == propertyId) + { + foundProperty = &property; - const AtomToolsFramework::DynamicProperty& property = it->second; - return property.GetValue(); - } + // This first converts to an acceptable runtime type in case the value came from script + const AZ::RPI::MaterialPropertyValue propertyValue = AtomToolsFramework::ConvertToRuntimeType(value); - const AtomToolsFramework::DynamicProperty& MaterialDocument::GetProperty(const AZ::Name& propertyId) const - { - if (!IsOpen()) - { - AZ_Error("MaterialDocument", false, "Document is not open."); - return m_invalidProperty; - } + property.SetValue(AtomToolsFramework::ConvertToEditableType(propertyValue)); + + const auto propertyIndex = m_materialInstance->FindPropertyIndex(propertyId); + if (!propertyIndex.IsNull()) + { + if (m_materialInstance->SetPropertyValue(propertyIndex, propertyValue)) + { + AZ::RPI::MaterialPropertyFlags dirtyFlags = m_materialInstance->GetPropertyDirtyFlags(); - const auto it = m_properties.find(propertyId); - if (it == m_properties.end()) + Recompile(); + RunEditorMaterialFunctors(dirtyFlags); + } + } + + AtomToolsFramework::AtomToolsDocumentNotificationBus::Broadcast( + &AtomToolsFramework::AtomToolsDocumentNotificationBus::Events::OnDocumentObjectInfoChanged, m_id, + GetObjectInfoFromDynamicPropertyGroup(group.get()), false); + + AtomToolsFramework::AtomToolsDocumentNotificationBus::Broadcast( + &AtomToolsFramework::AtomToolsDocumentNotificationBus::Events::OnDocumentModified, m_id); + return false; + } + } + return true; + }); + + if (!foundProperty) { AZ_Error("MaterialDocument", false, "Document property could not be found: '%s'.", propertyId.GetCStr()); - return m_invalidProperty; } - - const AtomToolsFramework::DynamicProperty& property = it->second; - return property; } - - bool MaterialDocument::IsPropertyGroupVisible(const AZ::Name& propertyGroupFullName) const + + const AZStd::any& MaterialDocument::GetPropertyValue(const AZ::Name& propertyId) const { if (!IsOpen()) { AZ_Error("MaterialDocument", false, "Document is not open."); - return false; + return m_invalidValue; } - const auto it = m_propertyGroupVisibility.find(propertyGroupFullName); - if (it == m_propertyGroupVisibility.end()) + auto property = FindProperty(propertyId); + if (!property) { - AZ_Error("MaterialDocument", false, "Document property group could not be found: '%s'.", propertyGroupFullName.GetCStr()); - return false; + AZ_Error("MaterialDocument", false, "Document property could not be found: '%s'.", propertyId.GetCStr()); + return m_invalidValue; } - return it->second; + return property->GetValue(); } - void MaterialDocument::SetPropertyValue(const AZ::Name& propertyId, const AZStd::any& value) + AZStd::vector MaterialDocument::GetObjectInfo() const { if (!IsOpen()) { AZ_Error("MaterialDocument", false, "Document is not open."); - return; - } - - const auto it = m_properties.find(propertyId); - if (it == m_properties.end()) - { - AZ_Error("MaterialDocument", false, "Document property could not be found: '%s'.", propertyId.GetCStr()); - return; + return {}; } - // This first converts to an acceptable runtime type in case the value came from script - const AZ::RPI::MaterialPropertyValue propertyValue = AtomToolsFramework::ConvertToRuntimeType(value); + AZStd::vector objects; + objects.reserve(m_groups.size()); - AtomToolsFramework::DynamicProperty& property = it->second; - property.SetValue(AtomToolsFramework::ConvertToEditableType(propertyValue)); - - const auto propertyIndex = m_materialInstance->FindPropertyIndex(propertyId); - if (!propertyIndex.IsNull()) + AtomToolsFramework::DocumentObjectInfo objectInfo; + for (const auto& group : m_groups) { - if (m_materialInstance->SetPropertyValue(propertyIndex, propertyValue)) - { - AZ::RPI::MaterialPropertyFlags dirtyFlags = m_materialInstance->GetPropertyDirtyFlags(); - - Recompile(); - - EditorMaterialFunctorResult result = RunEditorMaterialFunctors(dirtyFlags); - for (const AZ::Name& changedPropertyGroupName : result.m_updatedPropertyGroups) - { - AtomToolsFramework::AtomToolsDocumentNotificationBus::Broadcast( - &AtomToolsFramework::AtomToolsDocumentNotificationBus::Events::OnDocumentPropertyGroupVisibilityChanged, m_id, - changedPropertyGroupName, IsPropertyGroupVisible(changedPropertyGroupName)); - } - for (const AZ::Name& changedPropertyName : result.m_updatedProperties) - { - AtomToolsFramework::AtomToolsDocumentNotificationBus::Broadcast( - &AtomToolsFramework::AtomToolsDocumentNotificationBus::Events::OnDocumentPropertyConfigModified, m_id, - GetProperty(changedPropertyName)); - } - } + objects.push_back(GetObjectInfoFromDynamicPropertyGroup(group.get())); } - AtomToolsFramework::AtomToolsDocumentNotificationBus::Broadcast( - &AtomToolsFramework::AtomToolsDocumentNotificationBus::Events::OnDocumentPropertyValueModified, m_id, property); - AtomToolsFramework::AtomToolsDocumentNotificationBus::Broadcast( - &AtomToolsFramework::AtomToolsDocumentNotificationBus::Events::OnDocumentModified, m_id); + return objects; } bool MaterialDocument::Save() @@ -185,14 +166,15 @@ namespace MaterialEditor } // after saving, reset to a clean state - for (auto& propertyPair : m_properties) - { - AtomToolsFramework::DynamicProperty& property = propertyPair.second; - auto propertyConfig = property.GetConfig(); - propertyConfig.m_originalValue = property.GetValue(); - property.SetConfig(propertyConfig); - } - + TraverseGroups(m_groups, [&](auto& group) { + for (auto& property : group->m_properties) + { + auto propertyConfig = property.GetConfig(); + propertyConfig.m_originalValue = property.GetValue(); + property.SetConfig(propertyConfig); + } + return true; + }); return SaveSucceeded(); } @@ -273,12 +255,19 @@ namespace MaterialEditor bool MaterialDocument::IsModified() const { - return AZStd::any_of(m_properties.begin(), m_properties.end(), - [](const auto& propertyPair) - { - const AtomToolsFramework::DynamicProperty& property = propertyPair.second; - return !AtomToolsFramework::ArePropertyValuesEqual(property.GetValue(), property.GetConfig().m_originalValue); + bool result = false; + TraverseGroups(m_groups, [&](auto& group) { + for (auto& property : group->m_properties) + { + if (!AtomToolsFramework::ArePropertyValuesEqual(property.GetValue(), property.GetConfig().m_originalValue)) + { + result = true; + return false; + } + } + return true; }); + return result; } bool MaterialDocument::IsSavable() const @@ -290,11 +279,13 @@ namespace MaterialEditor { // Save the current properties as a momento for undo before any changes are applied m_propertyValuesBeforeEdit.clear(); - for (const auto& propertyPair : m_properties) - { - const AtomToolsFramework::DynamicProperty& property = propertyPair.second; - m_propertyValuesBeforeEdit[property.GetId()] = property.GetValue(); - } + TraverseGroups(m_groups, [this](auto& group) { + for (auto& property : group->m_properties) + { + m_propertyValuesBeforeEdit[property.GetId()] = property.GetValue(); + } + return true; + }); return true; } @@ -348,10 +339,10 @@ namespace MaterialEditor AZ::Name propertyId{propertyIdContext + propertyDefinition->GetName()}; - const auto it = m_properties.find(propertyId); - if (it != m_properties.end() && propertyFilter(it->second)) + const auto property = FindProperty(propertyId); + if (property && propertyFilter(*property)) { - AZ::RPI::MaterialPropertyValue propertyValue = AtomToolsFramework::ConvertToRuntimeType(it->second.GetValue()); + AZ::RPI::MaterialPropertyValue propertyValue = AtomToolsFramework::ConvertToRuntimeType(property->GetValue()); if (propertyValue.IsValid()) { if (!AtomToolsFramework::ConvertToExportFormat(m_savePathNormalized, propertyId, *propertyDefinition, propertyValue)) @@ -394,55 +385,17 @@ namespace MaterialEditor // The material document and inspector are constructed from source data if (AzFramework::StringFunc::Path::IsExtension(m_absolutePath.c_str(), AZ::RPI::MaterialSourceData::Extension)) { - // Load the material source data so that we can check properties and create a material asset from it - auto loadResult = AZ::RPI::MaterialUtils::LoadMaterialSourceData(m_absolutePath); - if (!loadResult) + if (!LoadMaterialSourceData()) { - AZ_Error("MaterialDocument", false, "Material source data could not be loaded: '%s'.", m_absolutePath.c_str()); return OpenFailed(); } - - m_materialSourceData = loadResult.TakeValue(); - - // We always need the absolute path for the material type and parent material to load source data and resolving - // relative paths when saving. This will convert and store them as absolute paths for use within the document. - if (!m_materialSourceData.m_parentMaterial.empty()) - { - m_materialSourceData.m_parentMaterial = - AZ::RPI::AssetUtils::ResolvePathReference(m_absolutePath, m_materialSourceData.m_parentMaterial); - } - - if (!m_materialSourceData.m_materialType.empty()) - { - m_materialSourceData.m_materialType = - AZ::RPI::AssetUtils::ResolvePathReference(m_absolutePath, m_materialSourceData.m_materialType); - } - - // Load the material type source data which provides the layout and default values of all of the properties - auto materialTypeOutcome = AZ::RPI::MaterialUtils::LoadMaterialTypeSourceData(m_materialSourceData.m_materialType); - if (!materialTypeOutcome.IsSuccess()) - { - AZ_Error("MaterialDocument", false, "Material type source data could not be loaded: '%s'.", m_materialSourceData.m_materialType.c_str()); - return OpenFailed(); - } - m_materialTypeSourceData = materialTypeOutcome.TakeValue(); } else if (AzFramework::StringFunc::Path::IsExtension(m_absolutePath.c_str(), AZ::RPI::MaterialTypeSourceData::Extension)) { - // A material document can be created or loaded from material or material type source data. If we are attempting to load - // material type source data then the material source data object can be created just by referencing the document path as the - // material type path. - auto materialTypeOutcome = AZ::RPI::MaterialUtils::LoadMaterialTypeSourceData(m_absolutePath); - if (!materialTypeOutcome.IsSuccess()) + if (!LoadMaterialTypeSourceData()) { - AZ_Error("MaterialDocument", false, "Material type source data could not be loaded: '%s'.", m_absolutePath.c_str()); return OpenFailed(); } - m_materialTypeSourceData = materialTypeOutcome.TakeValue(); - - // We are storing absolute paths in the loaded version of the source data so that the files can be resolved at all times. - m_materialSourceData.m_materialType = m_absolutePath; - m_materialSourceData.m_parentMaterial.clear(); } else { @@ -525,58 +478,21 @@ namespace MaterialEditor // where such changes are supported at runtime. m_materialInstance->SetPsoHandlingOverride(AZ::RPI::MaterialPropertyPsoHandling::Allowed); - // Populate the property map from a combination of source data and assets - // Assets must still be used for now because they contain the final accumulated value after all other materials - // in the hierarchy are applied - m_materialTypeSourceData.EnumeratePropertyGroups([this, &parentPropertyValues](const AZStd::string& propertyIdContext, const AZ::RPI::MaterialTypeSourceData::PropertyGroup* propertyGroup) - { - AtomToolsFramework::DynamicPropertyConfig propertyConfig; - - for (const auto& propertyDefinition : propertyGroup->GetProperties()) - { - // Assign id before conversion so it can be used in dynamic description - propertyConfig.m_id = propertyIdContext + propertyGroup->GetName() + "." + propertyDefinition->GetName(); - - const auto& propertyIndex = m_materialAsset->GetMaterialPropertiesLayout()->FindPropertyIndex(propertyConfig.m_id); - const bool propertyIndexInBounds = propertyIndex.IsValid() && propertyIndex.GetIndex() < m_materialAsset->GetPropertyValues().size(); - AZ_Warning("MaterialDocument", propertyIndexInBounds, "Failed to add material property '%s' to document '%s'.", propertyConfig.m_id.GetCStr(), m_absolutePath.c_str()); - - if (propertyIndexInBounds) - { - AtomToolsFramework::ConvertToPropertyConfig(propertyConfig, *propertyDefinition); - propertyConfig.m_showThumbnail = true; - propertyConfig.m_originalValue = AtomToolsFramework::ConvertToEditableType(m_materialAsset->GetPropertyValues()[propertyIndex.GetIndex()]); - propertyConfig.m_parentValue = AtomToolsFramework::ConvertToEditableType(parentPropertyValues[propertyIndex.GetIndex()]); - - // TODO: Support populating the Material Editor with nested property groups, not just the top level. - // (Does DynamicPropertyConfig really even need m_groupName?) - propertyConfig.m_groupName = propertyGroup->GetDisplayName(); - m_properties[propertyConfig.m_id] = AtomToolsFramework::DynamicProperty(propertyConfig); - } - } - - return true; - }); + // Adding properties for material type and parent as part of making dynamic properties and the inspector more general purpose. This + // allows the read only properties to appear in the inspector like any other property. This may change or be removed once support + // for changing the material parent is implemented. + m_groups.emplace_back(aznew AtomToolsFramework::DynamicPropertyGroup); + m_groups.back()->m_name = "overview"; + m_groups.back()->m_displayName = "Overview"; + m_groups.back()->m_description = m_materialSourceData.m_description; - // Populate the property group visibility map - // TODO: Support populating the Material Editor with nested property groups, not just the top level. - for (const AZStd::unique_ptr& propertyGroup : m_materialTypeSourceData.GetPropertyLayout().m_propertyGroups) - { - m_propertyGroupVisibility[AZ::Name{propertyGroup->GetName()}] = true; - } - - // Adding properties for material type and parent as part of making dynamic - // properties and the inspector more general purpose. - // This allows the read only properties to appear in the inspector like any - // other property. - // This may change or be removed once support for changing the material parent - // is implemented. AtomToolsFramework::DynamicPropertyConfig propertyConfig; propertyConfig.m_dataType = AtomToolsFramework::DynamicPropertyType::Asset; propertyConfig.m_id = "overview.materialType"; propertyConfig.m_name = "materialType"; propertyConfig.m_displayName = "Material Type"; - propertyConfig.m_groupName = "Overview"; + propertyConfig.m_groupName = "overview"; + propertyConfig.m_groupDisplayName = "Overview"; propertyConfig.m_description = "The material type defines the layout, properties, default values, shader connections, and other " "data needed to create and edit a derived material."; propertyConfig.m_defaultValue = AZStd::any(materialTypeAsset); @@ -584,14 +500,15 @@ namespace MaterialEditor propertyConfig.m_parentValue = propertyConfig.m_defaultValue; propertyConfig.m_readOnly = true; - m_properties[propertyConfig.m_id] = AtomToolsFramework::DynamicProperty(propertyConfig); + m_groups.back()->m_properties.push_back(AtomToolsFramework::DynamicProperty(propertyConfig)); propertyConfig = {}; propertyConfig.m_dataType = AtomToolsFramework::DynamicPropertyType::Asset; propertyConfig.m_id = "overview.parentMaterial"; propertyConfig.m_name = "parentMaterial"; propertyConfig.m_displayName = "Parent Material"; - propertyConfig.m_groupName = "Overview"; + propertyConfig.m_groupName = "overview"; + propertyConfig.m_groupDisplayName = "Overview"; propertyConfig.m_description = "The parent material provides an initial configuration whose properties are inherited and overriden by a derived material."; propertyConfig.m_defaultValue = AZStd::any(parentMaterialAsset); @@ -600,9 +517,14 @@ namespace MaterialEditor propertyConfig.m_readOnly = true; propertyConfig.m_showThumbnail = true; - m_properties[propertyConfig.m_id] = AtomToolsFramework::DynamicProperty(propertyConfig); + m_groups.back()->m_properties.push_back(AtomToolsFramework::DynamicProperty(propertyConfig)); - //Add UV name customization properties + m_groups.emplace_back(aznew AtomToolsFramework::DynamicPropertyGroup); + m_groups.back()->m_name = UvGroupName; + m_groups.back()->m_displayName = "UV Sets"; + m_groups.back()->m_description = "UV set names in this material, which can be renamed to match those in the model."; + + // Add UV name customization properties const AZ::RPI::MaterialUvNameMap& uvNameMap = materialTypeAsset->GetUvNameMap(); for (const AZ::RPI::UvNamePair& uvNamePair : uvNameMap) { @@ -614,61 +536,69 @@ namespace MaterialEditor propertyConfig.m_id = AZ::RPI::MaterialPropertyId(UvGroupName, shaderInput); propertyConfig.m_name = shaderInput; propertyConfig.m_displayName = shaderInput; - propertyConfig.m_groupName = "UV Sets"; + propertyConfig.m_groupName = UvGroupName; + propertyConfig.m_groupDisplayName = "UV Sets"; propertyConfig.m_description = shaderInput; propertyConfig.m_defaultValue = uvName; propertyConfig.m_originalValue = uvName; propertyConfig.m_parentValue = uvName; propertyConfig.m_readOnly = true; - m_properties[propertyConfig.m_id] = AtomToolsFramework::DynamicProperty(propertyConfig); + m_groups.back()->m_properties.push_back(AtomToolsFramework::DynamicProperty(propertyConfig)); } - // Add material functors that are in the top-level functors list. - const AZ::RPI::MaterialFunctorSourceData::EditorContext editorContext = - AZ::RPI::MaterialFunctorSourceData::EditorContext(m_materialSourceData.m_materialType, m_materialAsset->GetMaterialPropertiesLayout()); - for (AZ::RPI::Ptr functorData : m_materialTypeSourceData.m_materialFunctorSourceData) - { - AZ::RPI::MaterialFunctorSourceData::FunctorResult result2 = functorData->CreateFunctor(editorContext); - - if (result2.IsSuccess()) + // Populate the property map from a combination of source data and assets + // Assets must still be used for now because they contain the final accumulated value after all other materials + // in the hierarchy are applied + bool enumerateResult = m_materialTypeSourceData.EnumeratePropertyGroups( + [this, &parentPropertyValues]( + const AZStd::string& propertyIdContext, const AZ::RPI::MaterialTypeSourceData::PropertyGroup* propertyGroup) { - AZ::RPI::Ptr& functor = result2.GetValue(); - if (functor != nullptr) + // Add any material functors that are located inside each property group. + if (!AddEditorMaterialFunctors(propertyGroup->GetFunctors())) { - m_editorFunctors.push_back(functor); + return false; } - } - else - { - AZ_Error("MaterialDocument", false, "Material functors were not created: '%s'.", m_absolutePath.c_str()); - return OpenFailed(); - } - } - - // Add any material functors that are located inside each property group. - bool enumerateResult = m_materialTypeSourceData.EnumeratePropertyGroups( - [this](const AZStd::string&, const AZ::RPI::MaterialTypeSourceData::PropertyGroup* propertyGroup) - { - const AZ::RPI::MaterialFunctorSourceData::EditorContext editorContext = AZ::RPI::MaterialFunctorSourceData::EditorContext( - m_materialSourceData.m_materialType, m_materialAsset->GetMaterialPropertiesLayout()); - for (AZ::RPI::Ptr functorData : propertyGroup->GetFunctors()) + m_groups.emplace_back(aznew AtomToolsFramework::DynamicPropertyGroup); + m_groups.back()->m_name = propertyIdContext + propertyGroup->GetName(); + m_groups.back()->m_displayName = propertyGroup->GetDisplayName(); + m_groups.back()->m_description = propertyGroup->GetDescription(); + + for (const auto& propertyDefinition : propertyGroup->GetProperties()) { - AZ::RPI::MaterialFunctorSourceData::FunctorResult result = functorData->CreateFunctor(editorContext); + // Assign id before conversion so it can be used in dynamic description + AtomToolsFramework::DynamicPropertyConfig propertyConfig; + propertyConfig.m_id = m_groups.back()->m_name + "." + propertyDefinition->GetName(); + + const auto& propertyIndex = m_materialAsset->GetMaterialPropertiesLayout()->FindPropertyIndex(propertyConfig.m_id); + const bool propertyIndexInBounds = + propertyIndex.IsValid() && propertyIndex.GetIndex() < m_materialAsset->GetPropertyValues().size(); + AZ_Warning( + "MaterialDocument", propertyIndexInBounds, "Failed to add material property '%s' to document '%s'.", + propertyConfig.m_id.GetCStr(), m_absolutePath.c_str()); - if (result.IsSuccess()) + if (propertyIndexInBounds) { - AZ::RPI::Ptr& functor = result.GetValue(); - if (functor != nullptr) + AtomToolsFramework::ConvertToPropertyConfig(propertyConfig, *propertyDefinition); + + // TODO: Support populating the Material Editor with nested property groups, not just the top level. + // (Does DynamicPropertyConfig really even need m_groupDisplayName?) + propertyConfig.m_groupName = m_groups.back()->m_name; + propertyConfig.m_groupDisplayName = m_groups.back()->m_displayName; + propertyConfig.m_showThumbnail = true; + propertyConfig.m_originalValue = + AtomToolsFramework::ConvertToEditableType(m_materialAsset->GetPropertyValues()[propertyIndex.GetIndex()]); + propertyConfig.m_parentValue = + AtomToolsFramework::ConvertToEditableType(parentPropertyValues[propertyIndex.GetIndex()]); + propertyConfig.m_dataChangeCallback = [documentId = m_id, propertyId = propertyConfig.m_id](const AZStd::any& value) { - m_editorFunctors.push_back(functor); - } - } - else - { - AZ_Error("MaterialDocument", false, "Material functors were not created: '%s'.", m_absolutePath.c_str()); - return false; + MaterialDocumentRequestBus::Event( + documentId, &MaterialDocumentRequestBus::Events::SetPropertyValue, propertyId, value); + return AZ::Edit::PropertyRefreshLevels::AttributesAndValues; + }; + + m_groups.back()->m_properties.push_back(AtomToolsFramework::DynamicProperty(propertyConfig)); } } @@ -680,6 +610,12 @@ namespace MaterialEditor return OpenFailed(); } + // Add material functors that are in the top-level functors list. + if (!AddEditorMaterialFunctors(m_materialTypeSourceData.m_materialFunctorSourceData)) + { + return OpenFailed(); + } + AZ::RPI::MaterialPropertyFlags dirtyFlags; dirtyFlags.set(); // Mark all properties as dirty since we just loaded the material and need to initialize property visibility RunEditorMaterialFunctors(dirtyFlags); @@ -687,17 +623,35 @@ namespace MaterialEditor return OpenSucceeded(); } + void MaterialDocument::Clear() + { + AtomToolsFramework::AtomToolsDocument::Clear(); + + AZ::TickBus::Handler::BusDisconnect(); + + m_materialAsset = {}; + m_materialInstance = {}; + m_compilePending = {}; + m_groups.clear(); + m_editorFunctors.clear(); + m_materialTypeSourceData = AZ::RPI::MaterialTypeSourceData(); + m_materialSourceData = AZ::RPI::MaterialSourceData(); + m_propertyValuesBeforeEdit.clear(); + } + bool MaterialDocument::ReopenRecordState() { m_propertyValuesBeforeReopen.clear(); - for (const auto& propertyPair : m_properties) - { - const AtomToolsFramework::DynamicProperty& property = propertyPair.second; - if (!AtomToolsFramework::ArePropertyValuesEqual(property.GetValue(), property.GetConfig().m_parentValue)) + TraverseGroups(m_groups, [this](auto& group) { + for (auto& property : group->m_properties) { - m_propertyValuesBeforeReopen[property.GetId()] = property.GetValue(); + if (!AtomToolsFramework::ArePropertyValuesEqual(property.GetValue(), property.GetConfig().m_parentValue)) + { + m_propertyValuesBeforeReopen[property.GetId()] = property.GetValue(); + } } - } + return true; + }); return AtomToolsDocument::ReopenRecordState(); } @@ -717,20 +671,61 @@ namespace MaterialEditor } } - void MaterialDocument::Clear() + bool MaterialDocument::LoadMaterialSourceData() { - AtomToolsFramework::AtomToolsDocument::Clear(); + auto loadResult = AZ::RPI::MaterialUtils::LoadMaterialSourceData(m_absolutePath); + if (!loadResult) + { + AZ_Error("MaterialDocument", false, "Material source data could not be loaded: '%s'.", m_absolutePath.c_str()); + return OpenFailed(); + } - AZ::TickBus::Handler::BusDisconnect(); + m_materialSourceData = loadResult.TakeValue(); - m_materialAsset = {}; - m_materialInstance = {}; - m_compilePending = {}; - m_properties.clear(); - m_editorFunctors.clear(); - m_materialTypeSourceData = AZ::RPI::MaterialTypeSourceData(); - m_materialSourceData = AZ::RPI::MaterialSourceData(); - m_propertyValuesBeforeEdit.clear(); + // We always need the absolute path for the material type and parent material to load source data and resolving + // relative paths when saving. This will convert and store them as absolute paths for use within the document. + if (!m_materialSourceData.m_parentMaterial.empty()) + { + m_materialSourceData.m_parentMaterial = + AZ::RPI::AssetUtils::ResolvePathReference(m_absolutePath, m_materialSourceData.m_parentMaterial); + } + + if (!m_materialSourceData.m_materialType.empty()) + { + m_materialSourceData.m_materialType = + AZ::RPI::AssetUtils::ResolvePathReference(m_absolutePath, m_materialSourceData.m_materialType); + } + + // Load the material type source data which provides the layout and default values of all of the properties + auto materialTypeOutcome = AZ::RPI::MaterialUtils::LoadMaterialTypeSourceData(m_materialSourceData.m_materialType); + if (!materialTypeOutcome.IsSuccess()) + { + AZ_Error("MaterialDocument", false, "Material type source data could not be loaded: '%s'.", m_materialSourceData.m_materialType.c_str()); + return false; + } + + m_materialTypeSourceData = materialTypeOutcome.TakeValue(); + return true; + } + + bool MaterialDocument::LoadMaterialTypeSourceData() + { + // A material document can be created or loaded from material or material type source data. If we are attempting to load + // material type source data then the material source data object can be created just by referencing the document path as the + // material type path. + auto materialTypeOutcome = AZ::RPI::MaterialUtils::LoadMaterialTypeSourceData(m_absolutePath); + if (!materialTypeOutcome.IsSuccess()) + { + AZ_Error("MaterialDocument", false, "Material type source data could not be loaded: '%s'.", m_absolutePath.c_str()); + return false; + } + + m_materialTypeSourceData = materialTypeOutcome.TakeValue(); + + // We are storing absolute paths in the loaded version of the source data so that the files can be resolved at all times. + m_materialSourceData.m_materialType = m_absolutePath; + m_materialSourceData.m_parentMaterial.clear(); + return true; } void MaterialDocument::RestorePropertyValues(const PropertyValueMap& propertyValues) @@ -743,60 +738,186 @@ namespace MaterialEditor } } - MaterialDocument::EditorMaterialFunctorResult MaterialDocument::RunEditorMaterialFunctors(AZ::RPI::MaterialPropertyFlags dirtyFlags) + bool MaterialDocument::AddEditorMaterialFunctors( + const AZStd::vector>& functorSourceDataHolders) { - EditorMaterialFunctorResult result; + const AZ::RPI::MaterialFunctorSourceData::EditorContext editorContext = AZ::RPI::MaterialFunctorSourceData::EditorContext( + m_materialSourceData.m_materialType, m_materialAsset->GetMaterialPropertiesLayout()); - AZStd::unordered_map propertyDynamicMetadata; - AZStd::unordered_map propertyGroupDynamicMetadata; - for (auto& propertyPair : m_properties) - { - AtomToolsFramework::DynamicProperty& property = propertyPair.second; - AtomToolsFramework::ConvertToPropertyMetaData(propertyDynamicMetadata[property.GetId()], property.GetConfig()); - } - for (auto& groupPair : m_propertyGroupVisibility) + for (AZ::RPI::Ptr functorData : functorSourceDataHolders) { - AZ::RPI::MaterialPropertyGroupDynamicMetadata& metadata = propertyGroupDynamicMetadata[AZ::Name{groupPair.first}]; + AZ::RPI::MaterialFunctorSourceData::FunctorResult result = functorData->CreateFunctor(editorContext); - bool visible = groupPair.second; - metadata.m_visibility = visible ? - AZ::RPI::MaterialPropertyGroupVisibility::Enabled : AZ::RPI::MaterialPropertyGroupVisibility::Hidden; + if (result.IsSuccess()) + { + AZ::RPI::Ptr& functor = result.GetValue(); + if (functor != nullptr) + { + m_editorFunctors.push_back(functor); + } + } + else + { + AZ_Error("MaterialDocument", false, "Material functors were not created: '%s'.", m_absolutePath.c_str()); + return false; + } } - + + return true; + } + + void MaterialDocument::RunEditorMaterialFunctors(AZ::RPI::MaterialPropertyFlags dirtyFlags) + { + AZStd::unordered_map propertyDynamicMetadata; + AZStd::unordered_map propertyGroupDynamicMetadata; + + TraverseGroups(m_groups, [&](auto& group) { + AZ::RPI::MaterialPropertyGroupDynamicMetadata& metadata = propertyGroupDynamicMetadata[AZ::Name{ group->m_name }]; + metadata.m_visibility = group->m_visible ? AZ::RPI::MaterialPropertyGroupVisibility::Enabled : AZ::RPI::MaterialPropertyGroupVisibility::Hidden; + + for (auto& property : group->m_properties) + { + AtomToolsFramework::ConvertToPropertyMetaData(propertyDynamicMetadata[property.GetId()], property.GetConfig()); + } + return true; + }); + + AZStd::unordered_set updatedProperties; + AZStd::unordered_set updatedPropertyGroups; + for (AZ::RPI::Ptr& functor : m_editorFunctors) { const AZ::RPI::MaterialPropertyFlags& materialPropertyDependencies = functor->GetMaterialPropertyDependencies(); + // None also covers case that the client code doesn't register material properties to dependencies, // which will later get caught in Process() when trying to access a property. if (materialPropertyDependencies.none() || functor->NeedsProcess(dirtyFlags)) { AZ::RPI::MaterialFunctor::EditorContext context = AZ::RPI::MaterialFunctor::EditorContext( - m_materialInstance->GetPropertyValues(), - m_materialInstance->GetMaterialPropertiesLayout(), - propertyDynamicMetadata, - propertyGroupDynamicMetadata, - result.m_updatedProperties, - result.m_updatedPropertyGroups, - &materialPropertyDependencies - ); + m_materialInstance->GetPropertyValues(), m_materialInstance->GetMaterialPropertiesLayout(), propertyDynamicMetadata, + propertyGroupDynamicMetadata, updatedProperties, updatedPropertyGroups, + &materialPropertyDependencies); functor->Process(context); } } - for (auto& propertyPair : m_properties) + TraverseGroups(m_groups, [&](auto& group) { + bool groupChange = false; + bool groupRebuilt = false; + if (updatedPropertyGroups.find(AZ::Name(group->m_name)) != updatedPropertyGroups.end()) + { + AZ::RPI::MaterialPropertyGroupDynamicMetadata& metadata = propertyGroupDynamicMetadata[AZ::Name{ group->m_name }]; + group->m_visible = metadata.m_visibility != AZ::RPI::MaterialPropertyGroupVisibility::Hidden; + groupChange = true; + } + + for (auto& property : group->m_properties) + { + if (updatedProperties.find(AZ::Name(property.GetId())) != updatedProperties.end()) + { + const bool visibleBefore = property.GetConfig().m_visible; + AtomToolsFramework::DynamicPropertyConfig propertyConfig = property.GetConfig(); + AtomToolsFramework::ConvertToPropertyConfig(propertyConfig, propertyDynamicMetadata[property.GetId()]); + property.SetConfig(propertyConfig); + groupChange = true; + groupRebuilt |= visibleBefore != property.GetConfig().m_visible; + } + } + + if (groupChange || groupRebuilt) + { + AtomToolsFramework::AtomToolsDocumentNotificationBus::Broadcast( + &AtomToolsFramework::AtomToolsDocumentNotificationBus::Events::OnDocumentObjectInfoChanged, m_id, + GetObjectInfoFromDynamicPropertyGroup(group.get()), groupRebuilt); + } + return true; + }); + } + + AtomToolsFramework::DocumentObjectInfo MaterialDocument::GetObjectInfoFromDynamicPropertyGroup( + const AtomToolsFramework::DynamicPropertyGroup* group) const + { + AtomToolsFramework::DocumentObjectInfo objectInfo; + objectInfo.m_visible = group->m_visible; + objectInfo.m_name = group->m_name; + objectInfo.m_displayName = group->m_displayName; + objectInfo.m_description = group->m_description; + objectInfo.m_objectType = azrtti_typeid(); + objectInfo.m_objectPtr = const_cast(group); + return objectInfo; + } + + bool MaterialDocument::TraverseGroups( + AZStd::vector>& groups, + AZStd::function&)> callback) + { + if (!callback) { - AtomToolsFramework::DynamicProperty& property = propertyPair.second; - AtomToolsFramework::DynamicPropertyConfig propertyConfig = property.GetConfig(); - AtomToolsFramework::ConvertToPropertyConfig(propertyConfig, propertyDynamicMetadata[property.GetId()]); - property.SetConfig(propertyConfig); + return false; + } + + for (auto& group : groups) + { + if (!callback(group) || !TraverseGroups(group->m_groups, callback)) + { + return false; + } + } + + return true; + } + + bool MaterialDocument::TraverseGroups( + const AZStd::vector>& groups, + AZStd::function&)> callback) const + { + if (!callback) + { + return false; } - for (auto& updatedPropertyGroup : result.m_updatedPropertyGroups) + for (auto& group : groups) { - bool visible = propertyGroupDynamicMetadata[updatedPropertyGroup].m_visibility == AZ::RPI::MaterialPropertyGroupVisibility::Enabled; - m_propertyGroupVisibility[updatedPropertyGroup] = visible; + if (!callback(group) || !TraverseGroups(group->m_groups, callback)) + { + return false; + } } + return true; + } + + AtomToolsFramework::DynamicProperty* MaterialDocument::FindProperty(const AZ::Name& propertyId) + { + AtomToolsFramework::DynamicProperty* result = nullptr; + TraverseGroups(m_groups, [&](auto& group) { + for (auto& property : group->m_properties) + { + if (property.GetId() == propertyId) + { + result = &property; + return false; + } + } + return true; + }); + return result; + } + + const AtomToolsFramework::DynamicProperty* MaterialDocument::FindProperty(const AZ::Name& propertyId) const + { + AtomToolsFramework::DynamicProperty* result = nullptr; + TraverseGroups(m_groups, [&](auto& group) { + for (auto& property : group->m_properties) + { + if (property.GetId() == propertyId) + { + result = &property; + return false; + } + } + return true; + }); return result; } } // namespace MaterialEditor diff --git a/Gems/Atom/Tools/MaterialEditor/Code/Source/Document/MaterialDocument.h b/Gems/Atom/Tools/MaterialEditor/Code/Source/Document/MaterialDocument.h index b03d0943fa..37b3e1922f 100644 --- a/Gems/Atom/Tools/MaterialEditor/Code/Source/Document/MaterialDocument.h +++ b/Gems/Atom/Tools/MaterialEditor/Code/Source/Document/MaterialDocument.h @@ -37,10 +37,7 @@ namespace MaterialEditor virtual ~MaterialDocument(); // AtomToolsFramework::AtomToolsDocument overrides... - const AZStd::any& GetPropertyValue(const AZ::Name& propertyId) const override; - const AtomToolsFramework::DynamicProperty& GetProperty(const AZ::Name& propertyId) const override; - bool IsPropertyGroupVisible(const AZ::Name& propertyGroupFullName) const override; - void SetPropertyValue(const AZ::Name& propertyId, const AZStd::any& value) override; + AZStd::vector GetObjectInfo() const override; bool Open(AZStd::string_view loadPath) override; bool Save() override; bool SaveAsCopy(AZStd::string_view savePath) override; @@ -56,20 +53,16 @@ namespace MaterialEditor AZ::Data::Instance GetInstance() const override; const AZ::RPI::MaterialSourceData* GetMaterialSourceData() const override; const AZ::RPI::MaterialTypeSourceData* GetMaterialTypeSourceData() const override; + void SetPropertyValue(const AZ::Name& propertyId, const AZStd::any& value) override; + const AZStd::any& GetPropertyValue(const AZ::Name& propertyId) const override; private: // Predicate for evaluating properties using PropertyFilterFunction = AZStd::function; - // Map of document's properties - using PropertyMap = AZStd::unordered_map; - // Map of raw property values for undo/redo comparison and storage using PropertyValueMap = AZStd::unordered_map; - - // Map of document's property group visibility flags - using PropertyGroupVisibilityMap = AZStd::unordered_map; // AZ::TickBus overrides... void OnTick(float deltaTime, AZ::ScriptTimePoint time) override; @@ -78,47 +71,60 @@ namespace MaterialEditor // AtomToolsFramework::AtomToolsDocument overrides... void Clear() override; - bool ReopenRecordState() override; bool ReopenRestoreState() override; void Recompile(); + bool LoadMaterialSourceData(); + bool LoadMaterialTypeSourceData(); + void RestorePropertyValues(const PropertyValueMap& propertyValues); - struct EditorMaterialFunctorResult - { - AZStd::unordered_set m_updatedProperties; - AZStd::unordered_set m_updatedPropertyGroups; - }; + bool AddEditorMaterialFunctors( + const AZStd::vector>& functorSourceDataHolders); // Run editor material functor to update editor metadata. // @param dirtyFlags indicates which properties have changed, and thus which MaterialFunctors need to be run. - // @return names for the set of properties and groups that have been changed or need update. - EditorMaterialFunctorResult RunEditorMaterialFunctors(AZ::RPI::MaterialPropertyFlags dirtyFlags); + void RunEditorMaterialFunctors(AZ::RPI::MaterialPropertyFlags dirtyFlags); + + // Convert a dynamic property group pointer into generic document object info used to populate the inspector + AtomToolsFramework::DocumentObjectInfo GetObjectInfoFromDynamicPropertyGroup( + const AtomToolsFramework::DynamicPropertyGroup* group) const; - // Underlying material asset + // In order traversal of dynamic property groups + bool TraverseGroups( + AZStd::vector>& groups, + AZStd::function&)> callback); + + // In order traversal of dynamic property groups + bool TraverseGroups( + const AZStd::vector>& groups, + AZStd::function&)> callback) const; + + // Traverses dynamic property groups to find a property with a specific ID + AtomToolsFramework::DynamicProperty* FindProperty(const AZ::Name& propertyId); + + // Traverses dynamic property groups to find a property with a specific ID + const AtomToolsFramework::DynamicProperty* FindProperty(const AZ::Name& propertyId) const; + + // Material asset generated from source data, used to get the final values for properties to be assigned to the document AZ::Data::Asset m_materialAsset; - // Material instance being edited + // Material instance is only needed to run editor functors and is assigned directly to the viewport model to reflect real time + // changes to material property values AZ::Data::Instance m_materialInstance; // If material instance value(s) were modified, do we need to recompile on next tick? bool m_compilePending = false; - // Collection of all material's properties - PropertyMap m_properties; - - // Collection of all material's property groups - PropertyGroupVisibilityMap m_propertyGroupVisibility; - // Material functors that run in editor. See MaterialFunctor.h for details. AZStd::vector> m_editorFunctors; - // Source data for material type + // Material type source data used to enumerate all properties and populate the document AZ::RPI::MaterialTypeSourceData m_materialTypeSourceData; - // Source data for material + // Material source data with property values that override the material type AZ::RPI::MaterialSourceData m_materialSourceData; // State of property values prior to an edit, used for restoration during undo @@ -126,5 +132,12 @@ namespace MaterialEditor // State of property values prior to reopen PropertyValueMap m_propertyValuesBeforeReopen; + + // A container of root level dynamic property groups that represents the reflected, editable data within the document. + // These groups will be mapped to document object info so they can populate and be edited directly in the inspector. + AZStd::vector> m_groups; + + // Dummy default value returned whenever a property cannot be located + AZStd::any m_invalidValue; }; } // namespace MaterialEditor diff --git a/Gems/Atom/Tools/MaterialEditor/Code/Source/Document/MaterialDocumentRequestBus.h b/Gems/Atom/Tools/MaterialEditor/Code/Source/Document/MaterialDocumentRequestBus.h index c95aa4f215..da47ace48e 100644 --- a/Gems/Atom/Tools/MaterialEditor/Code/Source/Document/MaterialDocumentRequestBus.h +++ b/Gems/Atom/Tools/MaterialEditor/Code/Source/Document/MaterialDocumentRequestBus.h @@ -45,7 +45,14 @@ namespace MaterialEditor //! Get the internal material type source data virtual const AZ::RPI::MaterialTypeSourceData* GetMaterialTypeSourceData() const = 0; - }; + + //! Modify property value + virtual void SetPropertyValue(const AZ::Name& propertyFullName, const AZStd::any& value) = 0; + + //! Return property value + //! If the document is not open or the id can't be found, an invalid value is returned instead. + virtual const AZStd::any& GetPropertyValue(const AZ::Name& propertyFullName) const = 0; + }; using MaterialDocumentRequestBus = AZ::EBus; } // namespace MaterialEditor diff --git a/Gems/Atom/Tools/MaterialEditor/Code/Source/MaterialEditorApplication.cpp b/Gems/Atom/Tools/MaterialEditor/Code/Source/MaterialEditorApplication.cpp index 2e64740057..686715017c 100644 --- a/Gems/Atom/Tools/MaterialEditor/Code/Source/MaterialEditorApplication.cpp +++ b/Gems/Atom/Tools/MaterialEditor/Code/Source/MaterialEditorApplication.cpp @@ -65,7 +65,8 @@ namespace MaterialEditor ->Attribute(AZ::Script::Attributes::Scope, AZ::Script::Attributes::ScopeFlags::Common) ->Attribute(AZ::Script::Attributes::Category, "Editor") ->Attribute(AZ::Script::Attributes::Module, "materialeditor") - ; + ->Event("SetPropertyValue", &MaterialDocumentRequestBus::Events::SetPropertyValue) + ->Event("GetPropertyValue", &MaterialDocumentRequestBus::Events::GetPropertyValue); } } diff --git a/Gems/Atom/Tools/MaterialEditor/Code/Source/Window/MaterialInspector/MaterialInspector.cpp b/Gems/Atom/Tools/MaterialEditor/Code/Source/Window/MaterialInspector/MaterialInspector.cpp index 1402ad9f24..e6e768a7fd 100644 --- a/Gems/Atom/Tools/MaterialEditor/Code/Source/Window/MaterialInspector/MaterialInspector.cpp +++ b/Gems/Atom/Tools/MaterialEditor/Code/Source/Window/MaterialInspector/MaterialInspector.cpp @@ -7,14 +7,10 @@ */ #include -#include -#include -#include #include #include #include #include -#include #include namespace MaterialEditor @@ -38,7 +34,7 @@ namespace MaterialEditor { m_documentPath.clear(); m_documentId = AZ::Uuid::CreateNull(); - m_groups = {}; + m_activeProperty = {}; AtomToolsFramework::InspectorRequestBus::Handler::BusDisconnect(); AtomToolsFramework::InspectorWidget::Reset(); @@ -67,18 +63,31 @@ namespace MaterialEditor m_documentId = documentId; bool isOpen = false; - AtomToolsFramework::AtomToolsDocumentRequestBus::EventResult(isOpen, m_documentId, &AtomToolsFramework::AtomToolsDocumentRequestBus::Events::IsOpen); + AtomToolsFramework::AtomToolsDocumentRequestBus::EventResult( + isOpen, m_documentId, &AtomToolsFramework::AtomToolsDocumentRequestBus::Events::IsOpen); - AtomToolsFramework::AtomToolsDocumentRequestBus::EventResult(m_documentPath, m_documentId, &AtomToolsFramework::AtomToolsDocumentRequestBus::Events::GetAbsolutePath); + AtomToolsFramework::AtomToolsDocumentRequestBus::EventResult( + m_documentPath, m_documentId, &AtomToolsFramework::AtomToolsDocumentRequestBus::Events::GetAbsolutePath); if (!m_documentId.IsNull() && isOpen) { - // Create the top group for displaying overview info about the material - AddOverviewGroup(); - // Create groups for displaying editable UV names - AddUvNamesGroup(); - // Create groups for displaying editable properties - AddPropertiesGroup(); + // This will automatically expose all document contents to an inspector with a collapsible group per object. In the case of the + // material editor, this will be one inspector group per property group. + AZStd::vector objects; + AtomToolsFramework::AtomToolsDocumentRequestBus::EventResult( + objects, m_documentId, &AtomToolsFramework::AtomToolsDocumentRequestBus::Events::GetObjectInfo); + + for (auto& objectInfo : objects) + { + // Passing in same main and comparison instance to enable custom value comparison for highlighting modified properties + auto propertyGroupWidget = new AtomToolsFramework::InspectorPropertyGroupWidget( + objectInfo.m_objectPtr, objectInfo.m_objectPtr, objectInfo.m_objectType, this, this, + GetGroupSaveStateKey(objectInfo.m_name), {}, + [this](const auto node) { return GetInstanceNodePropertyIndicator(node); }, 0); + + AddGroup(objectInfo.m_name, objectInfo.m_displayName, objectInfo.m_description, propertyGroupWidget); + SetGroupVisible(objectInfo.m_name, objectInfo.m_visible); + } AtomToolsFramework::InspectorRequestBus::Handler::BusConnect(m_documentId); } @@ -106,198 +115,42 @@ namespace MaterialEditor return ":/Icons/blank.png"; } - void MaterialInspector::AddOverviewGroup() - { - const AZ::RPI::MaterialTypeSourceData* materialTypeSourceData = nullptr; - MaterialDocumentRequestBus::EventResult( - materialTypeSourceData, m_documentId, &MaterialDocumentRequestBus::Events::GetMaterialTypeSourceData); - - const AZStd::string groupName = "overview"; - const AZStd::string groupDisplayName = "Overview"; - const AZStd::string groupDescription = materialTypeSourceData->m_description; - auto& group = m_groups[groupName]; - - AtomToolsFramework::DynamicProperty property; - AtomToolsFramework::AtomToolsDocumentRequestBus::EventResult( - property, m_documentId, &AtomToolsFramework::AtomToolsDocumentRequestBus::Events::GetProperty, AZ::Name("overview.materialType")); - group.m_properties.push_back(property); - - property = {}; - AtomToolsFramework::AtomToolsDocumentRequestBus::EventResult( - property, m_documentId, &AtomToolsFramework::AtomToolsDocumentRequestBus::Events::GetProperty, AZ::Name("overview.parentMaterial")); - group.m_properties.push_back(property); - - // Passing in same group as main and comparison instance to enable custom value comparison for highlighting modified properties - auto propertyGroupWidget = new AtomToolsFramework::InspectorPropertyGroupWidget( - &group, &group, group.TYPEINFO_Uuid(), this, this, GetGroupSaveStateKey(groupName), {}, - [this](const auto node) { return GetInstanceNodePropertyIndicator(node); }, 0); - AddGroup(groupName, groupDisplayName, groupDescription, propertyGroupWidget); - } - - void MaterialInspector::AddUvNamesGroup() - { - AZ::Data::Asset materialAsset; - MaterialDocumentRequestBus::EventResult(materialAsset, m_documentId, &MaterialDocumentRequestBus::Events::GetAsset); - - const AZStd::string groupName = UvGroupName; - const AZStd::string groupDisplayName = "UV Sets"; - const AZStd::string groupDescription = "UV set names in this material, which can be renamed to match those in the model."; - auto& group = m_groups[groupName]; - - const auto& uvNameMap = materialAsset->GetMaterialTypeAsset()->GetUvNameMap(); - group.m_properties.reserve(uvNameMap.size()); - - for (const auto& uvNamePair : uvNameMap) - { - AtomToolsFramework::DynamicProperty property; - AtomToolsFramework::AtomToolsDocumentRequestBus::EventResult( - property, m_documentId, &AtomToolsFramework::AtomToolsDocumentRequestBus::Events::GetProperty, - AZ::RPI::MaterialPropertyId(groupName, uvNamePair.m_shaderInput.ToString())); - group.m_properties.push_back(property); - - property.SetValue(property.GetConfig().m_parentValue); - } - - // Passing in same group as main and comparison instance to enable custom value comparison for highlighting modified properties - auto propertyGroupWidget = new AtomToolsFramework::InspectorPropertyGroupWidget( - &group, &group, group.TYPEINFO_Uuid(), this, this, GetGroupSaveStateKey(groupName), {}, - [this](const auto node) { return GetInstanceNodePropertyIndicator(node); }, 0); - AddGroup(groupName, groupDisplayName, groupDescription, propertyGroupWidget); - } - - void MaterialInspector::AddPropertiesGroup() - { - const AZ::RPI::MaterialTypeSourceData* materialTypeSourceData = nullptr; - MaterialDocumentRequestBus::EventResult( - materialTypeSourceData, m_documentId, &MaterialDocumentRequestBus::Events::GetMaterialTypeSourceData); - - // TODO: Support populating the Material Editor with nested property groups, not just the top level. - for (const AZStd::unique_ptr& propertyGroup : materialTypeSourceData->GetPropertyLayout().m_propertyGroups) - { - const AZStd::string& groupName = propertyGroup->GetName(); - const AZStd::string& groupDisplayName = !propertyGroup->GetDisplayName().empty() ? propertyGroup->GetDisplayName() : groupName; - const AZStd::string& groupDescription = !propertyGroup->GetDescription().empty() ? propertyGroup->GetDescription() : groupDisplayName; - auto& group = m_groups[groupName]; - - group.m_properties.reserve(propertyGroup->GetProperties().size()); - for (const auto& propertyDefinition : propertyGroup->GetProperties()) - { - AtomToolsFramework::DynamicProperty property; - AtomToolsFramework::AtomToolsDocumentRequestBus::EventResult( - property, m_documentId, &AtomToolsFramework::AtomToolsDocumentRequestBus::Events::GetProperty, - AZ::RPI::MaterialPropertyId(groupName, propertyDefinition->GetName())); - group.m_properties.push_back(property); - } - - // Passing in same group as main and comparison instance to enable custom value comparison for highlighting modified properties - auto propertyGroupWidget = new AtomToolsFramework::InspectorPropertyGroupWidget( - &group, &group, group.TYPEINFO_Uuid(), this, this, GetGroupSaveStateKey(groupName), {}, - [this](const auto node) { return GetInstanceNodePropertyIndicator(node); }, 0); - AddGroup(groupName, groupDisplayName, groupDescription, propertyGroupWidget); - - bool isGroupVisible = false; - AtomToolsFramework::AtomToolsDocumentRequestBus::EventResult( - isGroupVisible, m_documentId, &AtomToolsFramework::AtomToolsDocumentRequestBus::Events::IsPropertyGroupVisible, AZ::Name{groupName}); - SetGroupVisible(groupName, isGroupVisible); - } - } - - void MaterialInspector::OnDocumentPropertyValueModified(const AZ::Uuid& documentId, const AtomToolsFramework::DynamicProperty& property) + void MaterialInspector::OnDocumentObjectInfoChanged( + [[maybe_unused]] const AZ::Uuid& documentId, const AtomToolsFramework::DocumentObjectInfo& objectInfo, bool rebuilt) { - for (auto& groupPair : m_groups) + SetGroupVisible(objectInfo.m_name, objectInfo.m_visible); + if (rebuilt) { - for (auto& reflectedProperty : groupPair.second.m_properties) - { - if (reflectedProperty.GetId() == property.GetId()) - { - if (!AtomToolsFramework::ArePropertyValuesEqual(reflectedProperty.GetValue(), property.GetValue())) - { - reflectedProperty.SetValue(property.GetValue()); - AtomToolsFramework::InspectorRequestBus::Event( - documentId, &AtomToolsFramework::InspectorRequestBus::Events::RefreshGroup, groupPair.first); - } - return; - } - } + RebuildGroup(objectInfo.m_name); } - } - - void MaterialInspector::OnDocumentPropertyConfigModified(const AZ::Uuid&, const AtomToolsFramework::DynamicProperty& property) - { - for (auto& groupPair : m_groups) + else { - for (auto& reflectedProperty : groupPair.second.m_properties) - { - if (reflectedProperty.GetId() == property.GetId()) - { - // Visibility changes require the entire reflected property editor tree for this group to be rebuilt - if (reflectedProperty.GetVisibility() != property.GetVisibility()) - { - reflectedProperty.SetConfig(property.GetConfig()); - RebuildGroup(groupPair.first); - } - else - { - reflectedProperty.SetConfig(property.GetConfig()); - RefreshGroup(groupPair.first); - } - return; - } - } + RefreshGroup(objectInfo.m_name); } } - - void MaterialInspector::OnDocumentPropertyGroupVisibilityChanged(const AZ::Uuid&, const AZ::Name& groupId, bool visible) - { - SetGroupVisible(groupId.GetStringView(), visible); - } void MaterialInspector::BeforePropertyModified(AzToolsFramework::InstanceDataNode* pNode) { - // For some reason the reflected property editor notifications are not symmetrical - // This function is called continuously anytime a property changes until the edit has completed - // Because of that, we have to track whether or not we are continuing to edit the same property to know when editing has started and - // ended - const AtomToolsFramework::DynamicProperty* property = AtomToolsFramework::FindDynamicPropertyForInstanceDataNode(pNode); - if (property) - { - if (m_activeProperty != property) - { - m_activeProperty = property; - AtomToolsFramework::AtomToolsDocumentRequestBus::Event(m_documentId, &AtomToolsFramework::AtomToolsDocumentRequestBus::Events::BeginEdit); - } - } - } - - void MaterialInspector::AfterPropertyModified(AzToolsFramework::InstanceDataNode* pNode) - { + // This function is called before every single property change whether it's a button click or dragging a slider. We only want to + // begin tracking undo state for the first change in the sequence, when the user begins to drag the slider. const AtomToolsFramework::DynamicProperty* property = AtomToolsFramework::FindDynamicPropertyForInstanceDataNode(pNode); - if (property) + if (!m_activeProperty && property) { - if (m_activeProperty == property) - { - AtomToolsFramework::AtomToolsDocumentRequestBus::Event( - m_documentId, &AtomToolsFramework::AtomToolsDocumentRequestBus::Events::SetPropertyValue, property->GetId(), property->GetValue()); - } + m_activeProperty = property; + AtomToolsFramework::AtomToolsDocumentRequestBus::Event( + m_documentId, &AtomToolsFramework::AtomToolsDocumentRequestBus::Events::BeginEdit); } } void MaterialInspector::SetPropertyEditingComplete(AzToolsFramework::InstanceDataNode* pNode) { - // As above, there are symmetrical functions on the notification interface for when editing begins and ends and has been completed - // but they are not being called following that pattern. when this function executes the changes to the property are ready to be - // committed or reverted + // If tracking has started and editing has completed then we can stop tracking undue state for this sequence of changes. const AtomToolsFramework::DynamicProperty* property = AtomToolsFramework::FindDynamicPropertyForInstanceDataNode(pNode); - if (property) + if (m_activeProperty && m_activeProperty == property) { - if (m_activeProperty == property) - { - AtomToolsFramework::AtomToolsDocumentRequestBus::Event( - m_documentId, &AtomToolsFramework::AtomToolsDocumentRequestBus::Events::SetPropertyValue, property->GetId(), property->GetValue()); - - AtomToolsFramework::AtomToolsDocumentRequestBus::Event(m_documentId, &AtomToolsFramework::AtomToolsDocumentRequestBus::Events::EndEdit); - m_activeProperty = nullptr; - } + AtomToolsFramework::AtomToolsDocumentRequestBus::Event( + m_documentId, &AtomToolsFramework::AtomToolsDocumentRequestBus::Events::EndEdit); + m_activeProperty = {}; } } } // namespace MaterialEditor diff --git a/Gems/Atom/Tools/MaterialEditor/Code/Source/Window/MaterialInspector/MaterialInspector.h b/Gems/Atom/Tools/MaterialEditor/Code/Source/Window/MaterialInspector/MaterialInspector.h index 690e8add86..fe688e3ad5 100644 --- a/Gems/Atom/Tools/MaterialEditor/Code/Source/Window/MaterialInspector/MaterialInspector.h +++ b/Gems/Atom/Tools/MaterialEditor/Code/Source/Window/MaterialInspector/MaterialInspector.h @@ -45,31 +45,25 @@ namespace MaterialEditor bool IsInstanceNodePropertyModifed(const AzToolsFramework::InstanceDataNode* node) const; const char* GetInstanceNodePropertyIndicator(const AzToolsFramework::InstanceDataNode* node) const; - void AddOverviewGroup(); - void AddUvNamesGroup(); - void AddPropertiesGroup(); - // AtomToolsDocumentNotificationBus::Handler implementation void OnDocumentOpened(const AZ::Uuid& documentId) override; - void OnDocumentPropertyValueModified(const AZ::Uuid& documentId, const AtomToolsFramework::DynamicProperty& property) override; - void OnDocumentPropertyConfigModified(const AZ::Uuid& documentId, const AtomToolsFramework::DynamicProperty& property) override; - void OnDocumentPropertyGroupVisibilityChanged(const AZ::Uuid& documentId, const AZ::Name& groupId, bool visible) override; + void OnDocumentObjectInfoChanged( + const AZ::Uuid& documentId, const AtomToolsFramework::DocumentObjectInfo& objectInfo, bool rebuilt) override; // AzToolsFramework::IPropertyEditorNotify overrides... void BeforePropertyModified(AzToolsFramework::InstanceDataNode* pNode) override; - void AfterPropertyModified(AzToolsFramework::InstanceDataNode* pNode) override; + void AfterPropertyModified([[maybe_unused]] AzToolsFramework::InstanceDataNode* pNode) override {} void SetPropertyEditingActive([[maybe_unused]] AzToolsFramework::InstanceDataNode* pNode) override {} void SetPropertyEditingComplete(AzToolsFramework::InstanceDataNode* pNode) override; void SealUndoStack() override {} - void RequestPropertyContextMenu(AzToolsFramework::InstanceDataNode*, const QPoint&) override {} - void PropertySelectionChanged(AzToolsFramework::InstanceDataNode*, bool) override {} + void RequestPropertyContextMenu([[maybe_unused]] AzToolsFramework::InstanceDataNode* pNode, const QPoint&) override {} + void PropertySelectionChanged([[maybe_unused]] AzToolsFramework::InstanceDataNode* pNode, bool) override {} // Tracking the property that is activiley being edited in the inspector - const AtomToolsFramework::DynamicProperty* m_activeProperty = nullptr; + const AtomToolsFramework::DynamicProperty* m_activeProperty = {}; AZ::Uuid m_documentId = AZ::Uuid::CreateNull(); AZStd::string m_documentPath; - AZStd::unordered_map m_groups; AZStd::intrusive_ptr m_windowSettings; }; } // namespace MaterialEditor diff --git a/Gems/Atom/Tools/ShaderManagementConsole/Code/Source/Document/ShaderManagementConsoleDocument.cpp b/Gems/Atom/Tools/ShaderManagementConsole/Code/Source/Document/ShaderManagementConsoleDocument.cpp index 99a3aea347..5698e33cec 100644 --- a/Gems/Atom/Tools/ShaderManagementConsole/Code/Source/Document/ShaderManagementConsoleDocument.cpp +++ b/Gems/Atom/Tools/ShaderManagementConsole/Code/Source/Document/ShaderManagementConsoleDocument.cpp @@ -78,6 +78,28 @@ namespace ShaderManagementConsole return m_invalidDescriptor; } + AZStd::vector ShaderManagementConsoleDocument::GetObjectInfo() const + { + if (!IsOpen()) + { + AZ_Error("ShaderManagementConsoleDocument", false, "Document is not open."); + return {}; + } + + AZStd::vector objects; + + AtomToolsFramework::DocumentObjectInfo objectInfo; + objectInfo.m_visible = true; + objectInfo.m_name = "Shader Variant List"; + objectInfo.m_displayName = "Shader Variant List"; + objectInfo.m_description = "Shader Variant List"; + objectInfo.m_objectType = azrtti_typeid(); + objectInfo.m_objectPtr = const_cast(&m_shaderVariantListSourceData); + objects.push_back(AZStd::move(objectInfo)); + + return objects; + } + bool ShaderManagementConsoleDocument::Open(AZStd::string_view loadPath) { if (!AtomToolsDocument::Open(loadPath)) diff --git a/Gems/Atom/Tools/ShaderManagementConsole/Code/Source/Document/ShaderManagementConsoleDocument.h b/Gems/Atom/Tools/ShaderManagementConsole/Code/Source/Document/ShaderManagementConsoleDocument.h index 4ad951e463..5c3d66b0a9 100644 --- a/Gems/Atom/Tools/ShaderManagementConsole/Code/Source/Document/ShaderManagementConsoleDocument.h +++ b/Gems/Atom/Tools/ShaderManagementConsole/Code/Source/Document/ShaderManagementConsoleDocument.h @@ -32,6 +32,7 @@ namespace ShaderManagementConsole ~ShaderManagementConsoleDocument(); // AtomToolsFramework::AtomToolsDocument overrides... + AZStd::vector GetObjectInfo() const override; bool Open(AZStd::string_view loadPath) override; bool Save() override; bool SaveAsCopy(AZStd::string_view savePath) override; diff --git a/Gems/Atom/Utils/Code/Include/Atom/Utils/MaterialUtils.h b/Gems/Atom/Utils/Code/Include/Atom/Utils/MaterialUtils.h new file mode 100644 index 0000000000..5c89b63182 --- /dev/null +++ b/Gems/Atom/Utils/Code/Include/Atom/Utils/MaterialUtils.h @@ -0,0 +1,46 @@ +/* + * Copyright (c) Contributors to the Open 3D Engine Project. + * For complete copyright and license terms please see the LICENSE at the root of this distribution. + * + * SPDX-License-Identifier: Apache-2.0 OR MIT + * + */ + +#pragma once + +#include +#include +#include +#include + +//! This file holds useful material related utility functions. + +namespace AZ +{ + namespace Render + { + enum class TransformType + { + Invalid, + Scale, + Rotate, + Translate + }; + + struct UvTransformDescriptor + { + Vector2 m_center{ Vector2::CreateZero() }; + float m_scale{ 1.0f }; + float m_scaleX{ 1.0f }; + float m_scaleY{ 1.0f }; + float m_translateX{ 0.0f }; + float m_translateY{ 0.0f }; + float m_rotateDegrees{ 0.0f }; + }; + + // Create a 3x3 uv transform matrix from a set of input properties. + Matrix3x3 CreateUvTransformMatrix(const UvTransformDescriptor& desc, const AZStd::span transformOrder); + } + + AZ_TYPE_INFO_SPECIALIZE(Render::TransformType, "{D8C15D33-CE3D-4297-A646-030B0625BF84}"); +} diff --git a/Gems/Atom/Utils/Code/Source/MaterialUtils.cpp b/Gems/Atom/Utils/Code/Source/MaterialUtils.cpp new file mode 100644 index 0000000000..6ce9ed5629 --- /dev/null +++ b/Gems/Atom/Utils/Code/Source/MaterialUtils.cpp @@ -0,0 +1,62 @@ +/* + * Copyright (c) Contributors to the Open 3D Engine Project. + * For complete copyright and license terms please see the LICENSE at the root of this distribution. + * + * SPDX-License-Identifier: Apache-2.0 OR MIT + * + */ + +#include + +namespace AZ::Render +{ + + Matrix3x3 CreateUvTransformMatrix(const UvTransformDescriptor& desc, AZStd::span transformOrder) + { + float translateX = desc.m_translateX; + float translateY = desc.m_translateY; + + if (desc.m_scaleX != 0.0f) + { + translateX *= (1.0f / desc.m_scaleX); + } + + if (desc.m_scaleY != 0.0f) + { + translateY *= (1.0f / desc.m_scaleY); + } + + Matrix3x3 translateCenter2D = Matrix3x3::CreateIdentity(); + translateCenter2D.SetBasisZ(-desc.m_center.GetX(), -desc.m_center.GetY(), 1.0f); + + Matrix3x3 translateCenterInv2D = Matrix3x3::CreateIdentity(); + translateCenterInv2D.SetBasisZ(desc.m_center.GetX(), desc.m_center.GetY(), 1.0f); + + Matrix3x3 scale2D = Matrix3x3::CreateDiagonal(AZ::Vector3(desc.m_scaleX * desc.m_scale, desc.m_scaleY * desc.m_scale, 1.0f)); + + Matrix3x3 translate2D = Matrix3x3::CreateIdentity(); + translate2D.SetBasisZ(translateX, translateY, 1.0f); + + Matrix3x3 rotate2D = Matrix3x3::CreateRotationZ(AZ::DegToRad(desc.m_rotateDegrees)); + + Matrix3x3 transform = translateCenter2D; + for (auto transformType : transformOrder) + { + switch (transformType) + { + case TransformType::Scale: + transform = scale2D * transform; + break; + case TransformType::Rotate: + transform = rotate2D * transform; + break; + case TransformType::Translate: + transform = translate2D * transform; + break; + } + } + transform = translateCenterInv2D * transform; + return transform; + } + +} diff --git a/Gems/Atom/Utils/Code/atom_utils_files.cmake b/Gems/Atom/Utils/Code/atom_utils_files.cmake index c11c2e294d..31529c93be 100644 --- a/Gems/Atom/Utils/Code/atom_utils_files.cmake +++ b/Gems/Atom/Utils/Code/atom_utils_files.cmake @@ -21,6 +21,7 @@ set(FILES Include/Atom/Utils/ImGuiShaderMetrics.inl Include/Atom/Utils/ImGuiTransientAttachmentProfiler.h Include/Atom/Utils/ImGuiTransientAttachmentProfiler.inl + Include/Atom/Utils/MaterialUtils.h Include/Atom/Utils/PngFile.h Include/Atom/Utils/PpmFile.h Include/Atom/Utils/StableDynamicArray.h @@ -30,6 +31,7 @@ set(FILES Include/Atom/Utils/AssetCollectionAsyncLoader.h Source/DdsFile.cpp Source/ImageComparison.cpp + Source/MaterialUtils.cpp Source/PngFile.cpp Source/PpmFile.cpp Source/Utils.cpp diff --git a/Gems/AtomLyIntegration/CommonFeatures/Code/Source/SurfaceData/SurfaceDataMeshComponent.cpp b/Gems/AtomLyIntegration/CommonFeatures/Code/Source/SurfaceData/SurfaceDataMeshComponent.cpp index 71e880fdef..2686ca8a16 100644 --- a/Gems/AtomLyIntegration/CommonFeatures/Code/Source/SurfaceData/SurfaceDataMeshComponent.cpp +++ b/Gems/AtomLyIntegration/CommonFeatures/Code/Source/SurfaceData/SurfaceDataMeshComponent.cpp @@ -95,7 +95,7 @@ namespace SurfaceData m_refresh = false; // Update the cached mesh data and bounds, then register the surface data provider - AssignSurfaceTagWeights(m_configuration.m_tags, 1.0f, m_newPointWeights); + m_newPointWeights.AssignSurfaceTagWeights(m_configuration.m_tags, 1.0f); UpdateMeshData(); } @@ -178,12 +178,7 @@ namespace SurfaceData AZ::Vector3 hitNormal; if (DoRayTrace(inPosition, hitPosition, hitNormal)) { - SurfacePoint point; - point.m_entityId = GetEntityId(); - point.m_position = hitPosition; - point.m_normal = hitNormal; - point.m_masks = m_newPointWeights; - surfacePointList.push_back(AZStd::move(point)); + surfacePointList.AddSurfacePoint(GetEntityId(), hitPosition, hitNormal, m_newPointWeights); } } diff --git a/Gems/AtomLyIntegration/CommonFeatures/Code/Source/SurfaceData/SurfaceDataMeshComponent.h b/Gems/AtomLyIntegration/CommonFeatures/Code/Source/SurfaceData/SurfaceDataMeshComponent.h index 758bb1ee99..4a8d3cf427 100644 --- a/Gems/AtomLyIntegration/CommonFeatures/Code/Source/SurfaceData/SurfaceDataMeshComponent.h +++ b/Gems/AtomLyIntegration/CommonFeatures/Code/Source/SurfaceData/SurfaceDataMeshComponent.h @@ -103,6 +103,6 @@ namespace SurfaceData AZ::Transform m_meshWorldTMInverse = AZ::Transform::CreateIdentity(); AZ::Vector3 m_meshNonUniformScale = AZ::Vector3::CreateOne(); AZ::Aabb m_meshBounds = AZ::Aabb::CreateNull(); - SurfaceTagWeightMap m_newPointWeights; + SurfaceTagWeights m_newPointWeights; }; } diff --git a/Gems/AtomLyIntegration/CommonFeatures/Editor/Scripts/Materials/assign_material_to_all_entities.py b/Gems/AtomLyIntegration/CommonFeatures/Editor/Scripts/Materials/assign_material_to_all_entities.py new file mode 100644 index 0000000000..8523145f54 --- /dev/null +++ b/Gems/AtomLyIntegration/CommonFeatures/Editor/Scripts/Materials/assign_material_to_all_entities.py @@ -0,0 +1,63 @@ +# coding:utf-8 +#!/usr/bin/python +# +# Copyright (c) Contributors to the Open 3D Engine Project. +# For complete copyright and license terms please see the LICENSE at the root of this distribution. +# +# SPDX-License-Identifier: Apache-2.0 OR MIT +# +# +""" + Apply a hard-coded material to all meshes in the level +""" + +import os + +import azlmbr.asset as asset +import azlmbr.bus as bus +import azlmbr.entity as entity +import azlmbr.legacy.general as general +import azlmbr.math as math +import azlmbr.editor as editor +import azlmbr.render as render + +########################################################################### +# Main Code Block, runs this script as main (testing) +# ------------------------------------------------------------------------- +if __name__ == '__main__': + """Run this file as main""" + + + # Get the material we want to assign + material_asset_path = os.path.join("materials", "special", "debugvertexstreams.azmaterial") + material_asset_id = asset.AssetCatalogRequestBus( + bus.Broadcast, "GetAssetIdByPath", material_asset_path, math.Uuid(), False) + general.log(f"Assigning {material_asset_path} to all mesh and actor components in the level.") + + type_ids_list = editor.EditorComponentAPIBus(bus.Broadcast, 'FindComponentTypeIdsByEntityType', ["Mesh", "Actor", "Material"], 0) + + mesh_component_type_id = type_ids_list[0] + actor_component_type_id = type_ids_list[1] + material_component_type_id = type_ids_list[2] + + # For each entity + search_filter = entity.SearchFilter() + all_entities = entity.SearchBus(bus.Broadcast, "SearchEntities", search_filter) + + for current_entity_id in all_entities: + # If entity has Mesh or Actor component + has_mesh_component = editor.EditorComponentAPIBus(bus.Broadcast, 'HasComponentOfType', current_entity_id, mesh_component_type_id) + has_actor_component = editor.EditorComponentAPIBus(bus.Broadcast, 'HasComponentOfType', current_entity_id, actor_component_type_id) + if has_mesh_component or has_actor_component: + # If entity does not have Material component + has_material_component = editor.EditorComponentAPIBus(bus.Broadcast, 'HasComponentOfType', current_entity_id, material_component_type_id) + if not has_material_component: + # Add material component + editor.EditorComponentAPIBus(bus.Broadcast, 'AddComponentsOfType', current_entity_id, [material_component_type_id]) + + # Clear all material overrides + render.MaterialComponentRequestBus(bus.Event, 'ClearAllMaterialOverrides', current_entity_id) + + # Set the default material to the one we want, which will apply it to every slot since we've cleared all overrides + render.MaterialComponentRequestBus(bus.Event, 'SetDefaultMaterialOverride', current_entity_id, material_asset_id) + diff --git a/Gems/EMotionFX/Code/EMotionFX/Tools/EMotionStudio/EMStudioSDK/Source/Workspace.cpp b/Gems/EMotionFX/Code/EMotionFX/Tools/EMotionStudio/EMStudioSDK/Source/Workspace.cpp index c8ee9be995..6196c86205 100644 --- a/Gems/EMotionFX/Code/EMotionFX/Tools/EMotionStudio/EMStudioSDK/Source/Workspace.cpp +++ b/Gems/EMotionFX/Code/EMotionFX/Tools/EMotionStudio/EMStudioSDK/Source/Workspace.cpp @@ -344,8 +344,9 @@ namespace EMStudio if (itActivationIndices->second.m_animGraphCommandIndex != -1 && itActivationIndices->second.m_motionSetCommandIndex != -1) { - commandString = AZStd::string::format("ActivateAnimGraph -actorInstanceID %%LASTRESULT%d%% -animGraphID %%LASTRESULT%d%% -motionSetID %%LASTRESULT%d%% -visualizeScale %f\n", - (commandIndex - itActivationIndices->second.m_actorInstanceCommandIndex), + // Since the actor instance will be created by the component, we pass in -1 as the actor instance id so the activate anim graph command + // will pick up the first available actor instance. + commandString = AZStd::string::format("ActivateAnimGraph -actorInstanceID -1 -animGraphID %%LASTRESULT%d%% -motionSetID %%LASTRESULT%d%% -visualizeScale %f\n", (commandIndex - itActivationIndices->second.m_animGraphCommandIndex), (commandIndex - itActivationIndices->second.m_motionSetCommandIndex), animGraphInstance->GetVisualizeScale()); diff --git a/Gems/EditorPythonBindings/Code/Source/PythonSystemComponent.cpp b/Gems/EditorPythonBindings/Code/Source/PythonSystemComponent.cpp index fe9156013f..e6564ea7af 100644 --- a/Gems/EditorPythonBindings/Code/Source/PythonSystemComponent.cpp +++ b/Gems/EditorPythonBindings/Code/Source/PythonSystemComponent.cpp @@ -414,10 +414,10 @@ namespace EditorPythonBindings EditorPythonBindingsNotificationBus::Broadcast(&EditorPythonBindingsNotificationBus::Events::OnPreInitialize); if (StartPythonInterpreter(pythonPathStack)) { - EditorPythonBindingsNotificationBus::Broadcast(&EditorPythonBindingsNotificationBus::Events::OnPostInitialize); // initialize internal base module and bootstrap scripts ExecuteByString("import azlmbr", false); ExecuteBootstrapScripts(pythonPathStack); + EditorPythonBindingsNotificationBus::Broadcast(&EditorPythonBindingsNotificationBus::Events::OnPostInitialize); return true; } return false; diff --git a/Gems/GradientSignal/Code/Include/GradientSignal/Components/SurfaceAltitudeGradientComponent.h b/Gems/GradientSignal/Code/Include/GradientSignal/Components/SurfaceAltitudeGradientComponent.h index 6843be8a0e..d8e902a0d5 100644 --- a/Gems/GradientSignal/Code/Include/GradientSignal/Components/SurfaceAltitudeGradientComponent.h +++ b/Gems/GradientSignal/Code/Include/GradientSignal/Components/SurfaceAltitudeGradientComponent.h @@ -109,14 +109,14 @@ namespace GradientSignal private: static float CalculateAltitudeRatio(const SurfaceData::SurfacePointList& points, float altitudeMin, float altitudeMax) { - if (points.empty()) + if (points.IsEmpty()) { return 0.0f; } // GetSurfacePoints (which was used to populate the points list) always returns points in decreasing height order, so the // first point in the list contains the highest altitude. - const float highestAltitude = points.front().m_position.GetZ(); + const float highestAltitude = points.GetHighestSurfacePoint().m_position.GetZ(); // Turn the absolute altitude value into a 0-1 value by returning the % of the given altitude range that it falls at. return GetRatio(altitudeMin, altitudeMax, highestAltitude); diff --git a/Gems/GradientSignal/Code/Include/GradientSignal/Components/SurfaceMaskGradientComponent.h b/Gems/GradientSignal/Code/Include/GradientSignal/Components/SurfaceMaskGradientComponent.h index 2580da10a0..eb009e6b92 100644 --- a/Gems/GradientSignal/Code/Include/GradientSignal/Components/SurfaceMaskGradientComponent.h +++ b/Gems/GradientSignal/Code/Include/GradientSignal/Components/SurfaceMaskGradientComponent.h @@ -85,13 +85,18 @@ namespace GradientSignal { float result = 0.0f; - for (const auto& point : points) + points.EnumeratePoints([&result]( + [[maybe_unused]] const AZ::Vector3& position, [[maybe_unused]] const AZ::Vector3& normal, + const SurfaceData::SurfaceTagWeights& masks) -> bool { - for (const auto& [maskId, weight] : point.m_masks) - { - result = AZ::GetMax(AZ::GetClamp(weight, 0.0f, 1.0f), result); - } - } + masks.EnumerateWeights( + [&result]([[maybe_unused]] AZ::Crc32 surfaceType, float weight) -> bool + { + result = AZ::GetMax(AZ::GetClamp(weight, 0.0f, 1.0f), result); + return true; + }); + return true; + }); return result; } diff --git a/Gems/GradientSignal/Code/Include/GradientSignal/Components/SurfaceSlopeGradientComponent.h b/Gems/GradientSignal/Code/Include/GradientSignal/Components/SurfaceSlopeGradientComponent.h index bdfbcd2b7f..e7a55a2bbc 100644 --- a/Gems/GradientSignal/Code/Include/GradientSignal/Components/SurfaceSlopeGradientComponent.h +++ b/Gems/GradientSignal/Code/Include/GradientSignal/Components/SurfaceSlopeGradientComponent.h @@ -125,7 +125,7 @@ namespace GradientSignal private: float GetSlopeRatio(const SurfaceData::SurfacePointList& points, float angleMin, float angleMax) const { - if (points.empty()) + if (points.IsEmpty()) { return 0.0f; } @@ -133,9 +133,9 @@ namespace GradientSignal // Assuming our surface normal vector is actually normalized, we can get the slope // by just grabbing the Z value. It's the same thing as normal.Dot(AZ::Vector3::CreateAxisZ()). AZ_Assert( - points.front().m_normal.GetNormalized().IsClose(points.front().m_normal), + points.GetHighestSurfacePoint().m_normal.GetNormalized().IsClose(points.GetHighestSurfacePoint().m_normal), "Surface normals are expected to be normalized"); - const float slope = points.front().m_normal.GetZ(); + const float slope = points.GetHighestSurfacePoint().m_normal.GetZ(); // Convert slope back to an angle so that we can lerp in "angular space", not "slope value space". // (We want our 0-1 range to be linear across the range of angles) const float slopeAngle = acosf(slope); diff --git a/Gems/GradientSignal/Code/Source/Components/GradientSurfaceDataComponent.cpp b/Gems/GradientSignal/Code/Source/Components/GradientSurfaceDataComponent.cpp index 5a0555fe33..cd87e3044c 100644 --- a/Gems/GradientSignal/Code/Source/Components/GradientSurfaceDataComponent.cpp +++ b/Gems/GradientSignal/Code/Source/Components/GradientSurfaceDataComponent.cpp @@ -224,10 +224,9 @@ namespace GradientSignal validShapeBounds = m_cachedShapeConstraintBounds.IsValid(); } - const AZ::EntityId entityId = GetEntityId(); - for (auto& point : surfacePointList) - { - if (point.m_entityId != entityId) + surfacePointList.ModifySurfaceWeights( + GetEntityId(), + [this, validShapeBounds, shapeConstraintBounds](const AZ::Vector3& position, SurfaceData::SurfaceTagWeights& weights) { bool inBounds = true; @@ -236,28 +235,26 @@ namespace GradientSignal if (validShapeBounds) { inBounds = false; - if (shapeConstraintBounds.Contains(point.m_position)) + if (shapeConstraintBounds.Contains(position)) { - LmbrCentral::ShapeComponentRequestsBus::EventResult(inBounds, m_configuration.m_shapeConstraintEntityId, - &LmbrCentral::ShapeComponentRequestsBus::Events::IsPointInside, point.m_position); + LmbrCentral::ShapeComponentRequestsBus::EventResult( + inBounds, m_configuration.m_shapeConstraintEntityId, + &LmbrCentral::ShapeComponentRequestsBus::Events::IsPointInside, position); } } // If the point is within our allowed shape bounds, verify that it meets the gradient thresholds. - // If so, then add the value to the surface tags. + // If so, then return the value to add to the surface tags. if (inBounds) { - const GradientSampleParams sampleParams = { point.m_position }; + const GradientSampleParams sampleParams = { position }; const float value = m_gradientSampler.GetValue(sampleParams); - if (value >= m_configuration.m_thresholdMin && - value <= m_configuration.m_thresholdMax) + if (value >= m_configuration.m_thresholdMin && value <= m_configuration.m_thresholdMax) { - SurfaceData::AddMaxValueForMasks(point.m_masks, m_configuration.m_modifierTags, value); + weights.AddSurfaceWeightsIfGreater(m_configuration.m_modifierTags, value); } } - - } - } + }); } } diff --git a/Gems/GradientSignal/Code/Source/Components/SurfaceAltitudeGradientComponent.cpp b/Gems/GradientSignal/Code/Source/Components/SurfaceAltitudeGradientComponent.cpp index 1670483131..b79606818b 100644 --- a/Gems/GradientSignal/Code/Source/Components/SurfaceAltitudeGradientComponent.cpp +++ b/Gems/GradientSignal/Code/Source/Components/SurfaceAltitudeGradientComponent.cpp @@ -234,7 +234,7 @@ namespace GradientSignal // For each position, call GetSurfacePoints() and turn the height into a 0-1 value based on our min/max altitudes. for (size_t index = 0; index < positions.size(); index++) { - points.clear(); + points.Clear(); surfaceDataRequests->GetSurfacePoints(positions[index], m_configuration.m_surfaceTagsToSample, points); outValues[index] = CalculateAltitudeRatio(points, m_configuration.m_altitudeMin, m_configuration.m_altitudeMax); } diff --git a/Gems/GradientSignal/Code/Source/Components/SurfaceMaskGradientComponent.cpp b/Gems/GradientSignal/Code/Source/Components/SurfaceMaskGradientComponent.cpp index ea72971818..56bb846ca4 100644 --- a/Gems/GradientSignal/Code/Source/Components/SurfaceMaskGradientComponent.cpp +++ b/Gems/GradientSignal/Code/Source/Components/SurfaceMaskGradientComponent.cpp @@ -198,7 +198,7 @@ namespace GradientSignal for (size_t index = 0; index < positions.size(); index++) { - points.clear(); + points.Clear(); surfaceDataRequests->GetSurfacePoints(positions[index], m_configuration.m_surfaceTagList, points); outValues[index] = GetMaxSurfaceWeight(points); } diff --git a/Gems/GradientSignal/Code/Source/Components/SurfaceSlopeGradientComponent.cpp b/Gems/GradientSignal/Code/Source/Components/SurfaceSlopeGradientComponent.cpp index e557785509..fdfa9dd5f8 100644 --- a/Gems/GradientSignal/Code/Source/Components/SurfaceSlopeGradientComponent.cpp +++ b/Gems/GradientSignal/Code/Source/Components/SurfaceSlopeGradientComponent.cpp @@ -239,7 +239,7 @@ namespace GradientSignal for (size_t index = 0; index < positions.size(); index++) { - points.clear(); + points.Clear(); surfaceDataRequests->GetSurfacePoints(positions[index], m_configuration.m_surfaceTagsToSample, points); outValues[index] = GetSlopeRatio(points, angleMin, angleMax); } diff --git a/Gems/GradientSignal/Code/Source/Editor/EditorGradientSurfaceDataComponent.cpp b/Gems/GradientSignal/Code/Source/Editor/EditorGradientSurfaceDataComponent.cpp index b715df1f92..e318e0fdf6 100644 --- a/Gems/GradientSignal/Code/Source/Editor/EditorGradientSurfaceDataComponent.cpp +++ b/Gems/GradientSignal/Code/Source/Editor/EditorGradientSurfaceDataComponent.cpp @@ -98,10 +98,9 @@ namespace GradientSignal return [this]([[maybe_unused]] float sampleValue, const GradientSampleParams& params) { // Create a fake surface point with the position we're sampling. - SurfaceData::SurfacePoint point; + AzFramework::SurfaceData::SurfacePoint point; point.m_position = params.m_position; - SurfaceData::SurfacePointList pointList; - pointList.emplace_back(point); + SurfaceData::SurfacePointList pointList = { { point } }; // Send it into the component, see what emerges m_component.ModifySurfacePoints(pointList); @@ -110,10 +109,18 @@ namespace GradientSignal // Technically, they should all have the same value, but we'll grab the max from all of them in case // the underlying logic ever changes to allow separate ranges per tag. float result = 0.0f; - for (auto& mask : pointList[0].m_masks) + pointList.EnumeratePoints([&result]( + [[maybe_unused]] const AZ::Vector3& position, [[maybe_unused]] const AZ::Vector3& normal, + const SurfaceData::SurfaceTagWeights& masks) -> bool { - result = AZ::GetMax(result, mask.second); - } + masks.EnumerateWeights( + [&result]([[maybe_unused]] AZ::Crc32 surfaceType, float weight) -> bool + { + result = AZ::GetMax(result, weight); + return true; + }); + return true; + }); return result; }; } diff --git a/Gems/GradientSignal/Code/Tests/GradientSignalReferencesTests.cpp b/Gems/GradientSignal/Code/Tests/GradientSignalReferencesTests.cpp index 72bdfa202e..6f90c5022f 100644 --- a/Gems/GradientSignal/Code/Tests/GradientSignalReferencesTests.cpp +++ b/Gems/GradientSignal/Code/Tests/GradientSignalReferencesTests.cpp @@ -66,7 +66,7 @@ namespace UnitTest float falloffMidpoint, float falloffRange, float falloffStrength) { MockSurfaceDataSystem mockSurfaceDataSystem; - SurfaceData::SurfacePoint point; + AzFramework::SurfaceData::SurfacePoint point; // Fill our mock surface with the correct normal value for each point based on our test angle set. for (int y = 0; y < dataSize; y++) @@ -539,10 +539,10 @@ namespace UnitTest // Set a different altitude for each point we're going to test. We'll use 0, 2, 5, 10 to test various points along the range. MockSurfaceDataSystem mockSurfaceDataSystem; - mockSurfaceDataSystem.m_GetSurfacePoints[AZStd::make_pair(0.0f, 0.0f)] = { { entityShape->GetId(), AZ::Vector3(0.0f, 0.0f, 0.0f), AZ::Vector3::CreateZero() } }; - mockSurfaceDataSystem.m_GetSurfacePoints[AZStd::make_pair(1.0f, 0.0f)] = { { entityShape->GetId(), AZ::Vector3(0.0f, 0.0f, 2.0f), AZ::Vector3::CreateZero() } }; - mockSurfaceDataSystem.m_GetSurfacePoints[AZStd::make_pair(0.0f, 1.0f)] = { { entityShape->GetId(), AZ::Vector3(0.0f, 0.0f, 5.0f), AZ::Vector3::CreateZero() } }; - mockSurfaceDataSystem.m_GetSurfacePoints[AZStd::make_pair(1.0f, 1.0f)] = { { entityShape->GetId(), AZ::Vector3(0.0f, 0.0f, 10.0f), AZ::Vector3::CreateZero() } }; + mockSurfaceDataSystem.m_GetSurfacePoints[AZStd::make_pair(0.0f, 0.0f)] = { { AZ::Vector3(0.0f, 0.0f, 0.0f), AZ::Vector3::CreateZero() } }; + mockSurfaceDataSystem.m_GetSurfacePoints[AZStd::make_pair(1.0f, 0.0f)] = { { AZ::Vector3(0.0f, 0.0f, 2.0f), AZ::Vector3::CreateZero() } }; + mockSurfaceDataSystem.m_GetSurfacePoints[AZStd::make_pair(0.0f, 1.0f)] = { { AZ::Vector3(0.0f, 0.0f, 5.0f), AZ::Vector3::CreateZero() } }; + mockSurfaceDataSystem.m_GetSurfacePoints[AZStd::make_pair(1.0f, 1.0f)] = { { AZ::Vector3(0.0f, 0.0f, 10.0f), AZ::Vector3::CreateZero() } }; // We set the min/max to values other than 0-10 to help validate that they aren't used in the case of the pinned shape. GradientSignal::SurfaceAltitudeGradientConfig config; @@ -573,10 +573,10 @@ namespace UnitTest // Set a different altitude for each point we're going to test. We'll use 0, 2, 5, 10 to test various points along the range. MockSurfaceDataSystem mockSurfaceDataSystem; - mockSurfaceDataSystem.m_GetSurfacePoints[AZStd::make_pair(0.0f, 0.0f)] = { { entityShape->GetId(), AZ::Vector3(0.0f, 0.0f, 0.0f), AZ::Vector3::CreateZero() } }; - mockSurfaceDataSystem.m_GetSurfacePoints[AZStd::make_pair(1.0f, 0.0f)] = { { entityShape->GetId(), AZ::Vector3(0.0f, 0.0f, 2.0f), AZ::Vector3::CreateZero() } }; - mockSurfaceDataSystem.m_GetSurfacePoints[AZStd::make_pair(0.0f, 1.0f)] = { { entityShape->GetId(), AZ::Vector3(0.0f, 0.0f, 5.0f), AZ::Vector3::CreateZero() } }; - mockSurfaceDataSystem.m_GetSurfacePoints[AZStd::make_pair(1.0f, 1.0f)] = { { entityShape->GetId(), AZ::Vector3(0.0f, 0.0f, 10.0f), AZ::Vector3::CreateZero() } }; + mockSurfaceDataSystem.m_GetSurfacePoints[AZStd::make_pair(0.0f, 0.0f)] = { { AZ::Vector3(0.0f, 0.0f, 0.0f), AZ::Vector3::CreateZero() } }; + mockSurfaceDataSystem.m_GetSurfacePoints[AZStd::make_pair(1.0f, 0.0f)] = { { AZ::Vector3(0.0f, 0.0f, 2.0f), AZ::Vector3::CreateZero() } }; + mockSurfaceDataSystem.m_GetSurfacePoints[AZStd::make_pair(0.0f, 1.0f)] = { { AZ::Vector3(0.0f, 0.0f, 5.0f), AZ::Vector3::CreateZero() } }; + mockSurfaceDataSystem.m_GetSurfacePoints[AZStd::make_pair(1.0f, 1.0f)] = { { AZ::Vector3(0.0f, 0.0f, 10.0f), AZ::Vector3::CreateZero() } }; // We set the min/max to 0-10, but don't set a shape. GradientSignal::SurfaceAltitudeGradientConfig config; @@ -634,13 +634,13 @@ namespace UnitTest MockSurfaceDataSystem mockSurfaceDataSystem; // Altitude value below min - should result in 0.0f. - mockSurfaceDataSystem.m_GetSurfacePoints[AZStd::make_pair(0.0f, 0.0f)] = { { entityShape->GetId(), AZ::Vector3(0.0f, 0.0f, -10.0f), AZ::Vector3::CreateZero() } }; + mockSurfaceDataSystem.m_GetSurfacePoints[AZStd::make_pair(0.0f, 0.0f)] = { { AZ::Vector3(0.0f, 0.0f, -10.0f), AZ::Vector3::CreateZero() } }; // Altitude value at exactly min - should result in 0.0f. - mockSurfaceDataSystem.m_GetSurfacePoints[AZStd::make_pair(1.0f, 0.0f)] = { { entityShape->GetId(), AZ::Vector3(0.0f, 0.0f, -5.0f), AZ::Vector3::CreateZero() } }; + mockSurfaceDataSystem.m_GetSurfacePoints[AZStd::make_pair(1.0f, 0.0f)] = { { AZ::Vector3(0.0f, 0.0f, -5.0f), AZ::Vector3::CreateZero() } }; // Altitude value at exactly max - should result in 1.0f. - mockSurfaceDataSystem.m_GetSurfacePoints[AZStd::make_pair(0.0f, 1.0f)] = { { entityShape->GetId(), AZ::Vector3(0.0f, 0.0f, 15.0f), AZ::Vector3::CreateZero() } }; + mockSurfaceDataSystem.m_GetSurfacePoints[AZStd::make_pair(0.0f, 1.0f)] = { { AZ::Vector3(0.0f, 0.0f, 15.0f), AZ::Vector3::CreateZero() } }; // Altitude value above max - should result in 1.0f. - mockSurfaceDataSystem.m_GetSurfacePoints[AZStd::make_pair(1.0f, 1.0f)] = { { entityShape->GetId(), AZ::Vector3(0.0f, 0.0f, 20.0f), AZ::Vector3::CreateZero() } }; + mockSurfaceDataSystem.m_GetSurfacePoints[AZStd::make_pair(1.0f, 1.0f)] = { { AZ::Vector3(0.0f, 0.0f, 20.0f), AZ::Vector3::CreateZero() } }; // We set the min/max to -5 - 15. By using a range without 0 at either end, and not having 0 as the midpoint, // it should be easier to verify that we're successfully clamping to 0 and 1. @@ -668,14 +668,15 @@ namespace UnitTest }; MockSurfaceDataSystem mockSurfaceDataSystem; - SurfaceData::SurfacePoint point; + AzFramework::SurfaceData::SurfacePoint point; // Fill our mock surface with the test_mask set and the expected gradient value at each point. for (int y = 0; y < dataSize; y++) { for (int x = 0; x < dataSize; x++) { - point.m_masks[AZ_CRC("test_mask", 0x7a16e9ff)] = expectedOutput[(y * dataSize) + x]; + point.m_surfaceTags.clear(); + point.m_surfaceTags.emplace_back(AZ_CRC_CE("test_mask"), expectedOutput[(y * dataSize) + x]); mockSurfaceDataSystem.m_GetSurfacePoints[AZStd::make_pair(static_cast(x), static_cast(y))] = { { point } }; } } diff --git a/Gems/GradientSignal/Code/Tests/GradientSignalSurfaceTests.cpp b/Gems/GradientSignal/Code/Tests/GradientSignalSurfaceTests.cpp index a716fc79b8..9f4346e09e 100644 --- a/Gems/GradientSignal/Code/Tests/GradientSignalSurfaceTests.cpp +++ b/Gems/GradientSignal/Code/Tests/GradientSignalSurfaceTests.cpp @@ -19,27 +19,53 @@ namespace UnitTest struct GradientSignalSurfaceTestsFixture : public GradientSignalTest { - void SetSurfacePoint(SurfaceData::SurfacePoint& point, AZ::EntityId id, AZ::Vector3 position, AZ::Vector3 normal, AZStd::vector> tags) + void SetSurfacePoint(AzFramework::SurfaceData::SurfacePoint& point, AZ::Vector3 position, AZ::Vector3 normal, AZStd::vector> tags) { - point.m_entityId = id; point.m_position = position; point.m_normal = normal; for (auto& tag : tags) { - point.m_masks[SurfaceData::SurfaceTag(tag.first)] = tag.second; + point.m_surfaceTags.emplace_back(SurfaceData::SurfaceTag(tag.first), tag.second); } } - bool SurfacePointsAreEqual(const SurfaceData::SurfacePoint& lhs, const SurfaceData::SurfacePoint& rhs) + bool SurfacePointsAreEqual(const AzFramework::SurfaceData::SurfacePoint& lhs, const AzFramework::SurfaceData::SurfacePoint& rhs) { - return (lhs.m_entityId == rhs.m_entityId) - && (lhs.m_position == rhs.m_position) - && (lhs.m_normal == rhs.m_normal) - && (lhs.m_masks == rhs.m_masks); + if ((lhs.m_position != rhs.m_position) || (lhs.m_normal != rhs.m_normal) + || (lhs.m_surfaceTags.size() != rhs.m_surfaceTags.size())) + { + return false; + } + + for (auto& mask : lhs.m_surfaceTags) + { + auto maskEntry = AZStd::find_if( + rhs.m_surfaceTags.begin(), rhs.m_surfaceTags.end(), + [mask](const AzFramework::SurfaceData::SurfaceTagWeight& weight) -> bool + { + return (mask.m_surfaceType == weight.m_surfaceType) && (mask.m_weight == weight.m_weight); + }); + if (maskEntry == rhs.m_surfaceTags.end()) + { + return false; + } + } + + return true; + } + + bool SurfacePointsAreEqual( + const AZ::Vector3& lhsPosition, const AZ::Vector3& lhsNormal, const SurfaceData::SurfaceTagWeights& lhsWeights, + const AzFramework::SurfaceData::SurfacePoint& rhs) + { + return ((lhsPosition == rhs.m_position) + && (lhsNormal == rhs.m_normal) + && (lhsWeights.SurfaceWeightsAreEqual(rhs.m_surfaceTags))); } void TestGradientSurfaceDataComponent(float gradientValue, float thresholdMin, float thresholdMax, AZStd::vector tags, bool usesShape, - const SurfaceData::SurfacePoint& input, const SurfaceData::SurfacePoint& expectedOutput) + const AzFramework::SurfaceData::SurfacePoint& input, + const AzFramework::SurfaceData::SurfacePoint& expectedOutput) { // This lets our component register with surfaceData successfully. MockSurfaceDataSystem mockSurfaceDataSystem; @@ -83,10 +109,17 @@ namespace UnitTest EXPECT_TRUE(modifierHandle != SurfaceData::InvalidSurfaceDataRegistryHandle); // Call ModifySurfacePoints and verify the results - SurfaceData::SurfacePointList pointList; - pointList.emplace_back(input); + SurfaceData::SurfacePointList pointList = { { input } }; SurfaceData::SurfaceDataModifierRequestBus::Event(modifierHandle, &SurfaceData::SurfaceDataModifierRequestBus::Events::ModifySurfacePoints, pointList); - EXPECT_TRUE(SurfacePointsAreEqual(pointList[0],expectedOutput)); + ASSERT_EQ(pointList.GetSize(), 1); + pointList.EnumeratePoints( + [this, expectedOutput]( + const AZ::Vector3& position, const AZ::Vector3& normal, + const SurfaceData::SurfaceTagWeights& masks) + { + EXPECT_TRUE(SurfacePointsAreEqual(position, normal, masks, expectedOutput)); + return true; + }); } @@ -97,17 +130,17 @@ namespace UnitTest // Verify that for a gradient value within the threshold, the output point contains the // correct tag and gradient value. - SurfaceData::SurfacePoint input; - SurfaceData::SurfacePoint expectedOutput; + AzFramework::SurfaceData::SurfacePoint input; + AzFramework::SurfaceData::SurfacePoint expectedOutput; const char* tag = "test_mask"; // Select a gradient value within the threshold range below float gradientValue = 0.5f; // Set arbitrary input data - SetSurfacePoint(input, AZ::EntityId(0x12345678), AZ::Vector3(1.0f), AZ::Vector3(0.0f), {}); + SetSurfacePoint(input, AZ::Vector3(1.0f), AZ::Vector3(0.0f), {}); // Output should match the input, but with an added tag / value - SetSurfacePoint(expectedOutput, input.m_entityId, input.m_position, input.m_normal, { AZStd::make_pair(tag, gradientValue) }); + SetSurfacePoint(expectedOutput, input.m_position, input.m_normal, { AZStd::make_pair(tag, gradientValue) }); TestGradientSurfaceDataComponent( gradientValue, // constant gradient value @@ -123,17 +156,17 @@ namespace UnitTest { // Verify that for a gradient value outside the threshold, the output point contains no tags / values. - SurfaceData::SurfacePoint input; - SurfaceData::SurfacePoint expectedOutput; + AzFramework::SurfaceData::SurfacePoint input; + AzFramework::SurfaceData::SurfacePoint expectedOutput; const char* tag = "test_mask"; // Choose a value outside the threshold range float gradientValue = 0.05f; // Set arbitrary input data - SetSurfacePoint(input, AZ::EntityId(0x12345678), AZ::Vector3(1.0f), AZ::Vector3(0.0f), {}); + SetSurfacePoint(input, AZ::Vector3(1.0f), AZ::Vector3(0.0f), {}); // Output should match the input - no extra tags / values should be added. - SetSurfacePoint(expectedOutput, input.m_entityId, input.m_position, input.m_normal, {}); + SetSurfacePoint(expectedOutput, input.m_position, input.m_normal, {}); TestGradientSurfaceDataComponent( gradientValue, // constant gradient value @@ -149,8 +182,8 @@ namespace UnitTest { // Verify that if the component has multiple tags, all of them get put on the output with the same gradient value. - SurfaceData::SurfacePoint input; - SurfaceData::SurfacePoint expectedOutput; + AzFramework::SurfaceData::SurfacePoint input; + AzFramework::SurfaceData::SurfacePoint expectedOutput; const char* tag1 = "test_mask1"; const char* tag2 = "test_mask2"; @@ -158,9 +191,9 @@ namespace UnitTest float gradientValue = 0.5f; // Set arbitrary input data - SetSurfacePoint(input, AZ::EntityId(0x12345678), AZ::Vector3(1.0f), AZ::Vector3(0.0f), {}); + SetSurfacePoint(input, AZ::Vector3(1.0f), AZ::Vector3(0.0f), {}); // Output should match the input, but with two added tags - SetSurfacePoint(expectedOutput, input.m_entityId, input.m_position, input.m_normal, + SetSurfacePoint(expectedOutput, input.m_position, input.m_normal, { AZStd::make_pair(tag1, gradientValue), AZStd::make_pair(tag2, gradientValue) }); TestGradientSurfaceDataComponent( @@ -178,8 +211,8 @@ namespace UnitTest // Verify that the output contains input tags that are NOT on the modification list and adds any // new tags that weren't in the input - SurfaceData::SurfacePoint input; - SurfaceData::SurfacePoint expectedOutput; + AzFramework::SurfaceData::SurfacePoint input; + AzFramework::SurfaceData::SurfacePoint expectedOutput; const char* preservedTag = "preserved_tag"; const char* modifierTag = "modifier_tag"; @@ -187,9 +220,9 @@ namespace UnitTest float gradientValue = 0.5f; // Set arbitrary input data - SetSurfacePoint(input, AZ::EntityId(0x12345678), AZ::Vector3(1.0f), AZ::Vector3(0.0f), { AZStd::make_pair(preservedTag, 1.0f) }); + SetSurfacePoint(input, AZ::Vector3(1.0f), AZ::Vector3(0.0f), { AZStd::make_pair(preservedTag, 1.0f) }); // Output should match the input, but with two added tags - SetSurfacePoint(expectedOutput, input.m_entityId, input.m_position, input.m_normal, + SetSurfacePoint(expectedOutput, input.m_position, input.m_normal, { AZStd::make_pair(preservedTag, 1.0f), AZStd::make_pair(modifierTag, gradientValue) }); TestGradientSurfaceDataComponent( @@ -206,8 +239,8 @@ namespace UnitTest { // Verify that if the input has a higher value on the tag than the modifier, it keeps the higher value. - SurfaceData::SurfacePoint input; - SurfaceData::SurfacePoint expectedOutput; + AzFramework::SurfaceData::SurfacePoint input; + AzFramework::SurfaceData::SurfacePoint expectedOutput; const char* tag = "test_mask"; // Select a gradient value within the threshold range below @@ -216,9 +249,9 @@ namespace UnitTest float inputValue = 0.75f; // Set arbitrary input data - SetSurfacePoint(input, AZ::EntityId(0x12345678), AZ::Vector3(1.0f), AZ::Vector3(0.0f), { AZStd::make_pair(tag, inputValue) }); + SetSurfacePoint(input, AZ::Vector3(1.0f), AZ::Vector3(0.0f), { AZStd::make_pair(tag, inputValue) }); // Output should match the input - the higher input value on the tag is preserved - SetSurfacePoint(expectedOutput, input.m_entityId, input.m_position, input.m_normal, + SetSurfacePoint(expectedOutput, input.m_position, input.m_normal, { AZStd::make_pair(tag, inputValue) }); TestGradientSurfaceDataComponent( @@ -235,8 +268,8 @@ namespace UnitTest { // Verify that if the input has a lower value on the tag than the modifier, it keeps the higher value. - SurfaceData::SurfacePoint input; - SurfaceData::SurfacePoint expectedOutput; + AzFramework::SurfaceData::SurfacePoint input; + AzFramework::SurfaceData::SurfacePoint expectedOutput; const char* tag = "test_mask"; // Select a gradient value within the threshold range below @@ -245,9 +278,9 @@ namespace UnitTest float inputValue = 0.25f; // Set arbitrary input data - SetSurfacePoint(input, AZ::EntityId(0x12345678), AZ::Vector3(1.0f), AZ::Vector3(0.0f), { AZStd::make_pair(tag, inputValue) }); + SetSurfacePoint(input, AZ::Vector3(1.0f), AZ::Vector3(0.0f), { AZStd::make_pair(tag, inputValue) }); // Output should match the input, except that the value on the tag gets the higher modifier value - SetSurfacePoint(expectedOutput, input.m_entityId, input.m_position, input.m_normal, + SetSurfacePoint(expectedOutput, input.m_position, input.m_normal, { AZStd::make_pair(tag, gradientValue) }); TestGradientSurfaceDataComponent( @@ -264,17 +297,17 @@ namespace UnitTest { // Verify that if no shape has been added, the component modifies points in unbounded space - SurfaceData::SurfacePoint input; - SurfaceData::SurfacePoint expectedOutput; + AzFramework::SurfaceData::SurfacePoint input; + AzFramework::SurfaceData::SurfacePoint expectedOutput; const char* tag = "test_mask"; // Select a gradient value within the threshold range below float gradientValue = 0.5f; // Set arbitrary input data, but with a point that's extremely far away in space - SetSurfacePoint(input, AZ::EntityId(0x12345678), AZ::Vector3(-100000000.0f), AZ::Vector3(0.0f), {}); + SetSurfacePoint(input, AZ::Vector3(-100000000.0f), AZ::Vector3(0.0f), {}); // Output should match the input but with the tag added, even though the point was far away. - SetSurfacePoint(expectedOutput, input.m_entityId, input.m_position, input.m_normal, + SetSurfacePoint(expectedOutput, input.m_position, input.m_normal, { AZStd::make_pair(tag, gradientValue) }); TestGradientSurfaceDataComponent( @@ -292,17 +325,17 @@ namespace UnitTest // Verify that if a shape constraint is added, points within the shape are still modified. // Our default mock shape is a cube that exists from -0.5 to 0.5 in space. - SurfaceData::SurfacePoint input; - SurfaceData::SurfacePoint expectedOutput; + AzFramework::SurfaceData::SurfacePoint input; + AzFramework::SurfaceData::SurfacePoint expectedOutput; const char* tag = "test_mask"; // Select a gradient value within the threshold range below float gradientValue = 0.5f; // Set arbitrary input data, but with a point that's within the mock shape cube (0.25 vs -0.5 to 0.5) - SetSurfacePoint(input, AZ::EntityId(0x12345678), AZ::Vector3(0.25f), AZ::Vector3(0.0f), {}); + SetSurfacePoint(input, AZ::Vector3(0.25f), AZ::Vector3(0.0f), {}); // Output should match the input but with the tag added, since the point is within the shape constraint. - SetSurfacePoint(expectedOutput, input.m_entityId, input.m_position, input.m_normal, + SetSurfacePoint(expectedOutput, input.m_position, input.m_normal, { AZStd::make_pair(tag, gradientValue) }); TestGradientSurfaceDataComponent( @@ -320,17 +353,17 @@ namespace UnitTest // Verify that if a shape constraint is added, points outside the shape are not modified. // Our default mock shape is a cube that exists from -0.5 to 0.5 in space. - SurfaceData::SurfacePoint input; - SurfaceData::SurfacePoint expectedOutput; + AzFramework::SurfaceData::SurfacePoint input; + AzFramework::SurfaceData::SurfacePoint expectedOutput; const char* tag = "test_mask"; // Select a gradient value within the threshold range below float gradientValue = 0.5f; // Set arbitrary input data, but with a point that's outside the mock shape cube (10.0 vs -0.5 to 0.5) - SetSurfacePoint(input, AZ::EntityId(0x12345678), AZ::Vector3(10.0f), AZ::Vector3(0.0f), {}); + SetSurfacePoint(input, AZ::Vector3(10.0f), AZ::Vector3(0.0f), {}); // Output should match the input with no tag added, since the point is outside the shape constraint - SetSurfacePoint(expectedOutput, input.m_entityId, input.m_position, input.m_normal, {}); + SetSurfacePoint(expectedOutput, input.m_position, input.m_normal, {}); TestGradientSurfaceDataComponent( gradientValue, // constant gradient value diff --git a/Gems/GradientSignal/Code/Tests/GradientSignalTestFixtures.cpp b/Gems/GradientSignal/Code/Tests/GradientSignalTestFixtures.cpp index d81370f6a8..402438ee88 100644 --- a/Gems/GradientSignal/Code/Tests/GradientSignalTestFixtures.cpp +++ b/Gems/GradientSignal/Code/Tests/GradientSignalTestFixtures.cpp @@ -84,7 +84,7 @@ namespace UnitTest AZStd::unique_ptr GradientSignalBaseFixture::CreateMockSurfaceDataSystem(const AZ::Aabb& spawnerBox) { - SurfaceData::SurfacePoint point; + AzFramework::SurfaceData::SurfacePoint point; AZStd::unique_ptr mockSurfaceDataSystem = AZStd::make_unique(); // Give the mock surface data a bunch of fake point values to return. @@ -101,7 +101,8 @@ namespace UnitTest // Create an arbitrary normal value. point.m_normal = point.m_position.GetNormalized(); // Create an arbitrary surface value. - point.m_masks[AZ_CRC_CE("test_mask")] = arbitraryPercentage; + point.m_surfaceTags.clear(); + point.m_surfaceTags.emplace_back(AZ_CRC_CE("test_mask"), arbitraryPercentage); mockSurfaceDataSystem->m_GetSurfacePoints[AZStd::make_pair(x, y)] = { { point } }; } diff --git a/Code/Framework/AzFramework/AzFramework/Matchmaking/IMatchmakingRequests.h b/Gems/Multiplayer/Code/Include/Multiplayer/Session/IMatchmakingRequests.h similarity index 97% rename from Code/Framework/AzFramework/AzFramework/Matchmaking/IMatchmakingRequests.h rename to Gems/Multiplayer/Code/Include/Multiplayer/Session/IMatchmakingRequests.h index ccf9acdf8b..fff1c2f0af 100644 --- a/Code/Framework/AzFramework/AzFramework/Matchmaking/IMatchmakingRequests.h +++ b/Gems/Multiplayer/Code/Include/Multiplayer/Session/IMatchmakingRequests.h @@ -10,9 +10,9 @@ #include #include -#include +#include -namespace AzFramework +namespace Multiplayer { //! IMatchmakingRequests //! Pure virtual session interface class to abstract the details of session handling from application code. @@ -87,4 +87,4 @@ namespace AzFramework virtual void OnStopMatchmakingAsyncComplete() = 0; }; using MatchmakingAsyncRequestNotificationBus = AZ::EBus; -} // namespace AzFramework +} // namespace Multiplayer diff --git a/Code/Framework/AzFramework/AzFramework/Session/ISessionHandlingRequests.h b/Gems/Multiplayer/Code/Include/Multiplayer/Session/ISessionHandlingRequests.h similarity index 98% rename from Code/Framework/AzFramework/AzFramework/Session/ISessionHandlingRequests.h rename to Gems/Multiplayer/Code/Include/Multiplayer/Session/ISessionHandlingRequests.h index 188ea7b994..022d1743b3 100644 --- a/Code/Framework/AzFramework/AzFramework/Session/ISessionHandlingRequests.h +++ b/Gems/Multiplayer/Code/Include/Multiplayer/Session/ISessionHandlingRequests.h @@ -12,7 +12,7 @@ #include #include -namespace AzFramework +namespace Multiplayer { //! SessionConnectionConfig //! The properties for handling join session request. @@ -91,4 +91,4 @@ namespace AzFramework //! empty string. virtual AZ::IO::Path GetInternalSessionCertificate() = 0; }; -} // namespace AzFramework +} // namespace Multiplayer diff --git a/Code/Framework/AzFramework/AzFramework/Session/ISessionRequests.h b/Gems/Multiplayer/Code/Include/Multiplayer/Session/ISessionRequests.h similarity index 97% rename from Code/Framework/AzFramework/AzFramework/Session/ISessionRequests.h rename to Gems/Multiplayer/Code/Include/Multiplayer/Session/ISessionRequests.h index 8b985a3187..d4a5737546 100644 --- a/Code/Framework/AzFramework/AzFramework/Session/ISessionRequests.h +++ b/Gems/Multiplayer/Code/Include/Multiplayer/Session/ISessionRequests.h @@ -11,9 +11,9 @@ #include #include #include -#include +#include -namespace AzFramework +namespace Multiplayer { //! ISessionRequests //! Pure virtual session interface class to abstract the details of session handling from application code. @@ -101,4 +101,4 @@ namespace AzFramework virtual void OnLeaveSessionAsyncComplete() = 0; }; using SessionAsyncRequestNotificationBus = AZ::EBus; -} // namespace AzFramework +} // namespace Multiplayer diff --git a/Code/Framework/AzFramework/AzFramework/Matchmaking/MatchmakingNotifications.h b/Gems/Multiplayer/Code/Include/Multiplayer/Session/MatchmakingNotifications.h similarity index 97% rename from Code/Framework/AzFramework/AzFramework/Matchmaking/MatchmakingNotifications.h rename to Gems/Multiplayer/Code/Include/Multiplayer/Session/MatchmakingNotifications.h index 0ec52c7215..70ff67ff21 100644 --- a/Code/Framework/AzFramework/AzFramework/Matchmaking/MatchmakingNotifications.h +++ b/Gems/Multiplayer/Code/Include/Multiplayer/Session/MatchmakingNotifications.h @@ -11,7 +11,7 @@ #include #include -namespace AzFramework +namespace Multiplayer { //! MatchmakingNotifications //! The matchmaking notifications to listen for performing required operations @@ -43,4 +43,4 @@ namespace AzFramework virtual void OnMatchFailure() = 0; }; using MatchmakingNotificationBus = AZ::EBus; -} // namespace AzFramework +} // namespace Multiplayer diff --git a/Code/Framework/AzFramework/AzFramework/Matchmaking/MatchmakingRequests.h b/Gems/Multiplayer/Code/Include/Multiplayer/Session/MatchmakingRequests.h similarity index 97% rename from Code/Framework/AzFramework/AzFramework/Matchmaking/MatchmakingRequests.h rename to Gems/Multiplayer/Code/Include/Multiplayer/Session/MatchmakingRequests.h index 5f5dcc0643..b07b7a55f8 100644 --- a/Code/Framework/AzFramework/AzFramework/Matchmaking/MatchmakingRequests.h +++ b/Gems/Multiplayer/Code/Include/Multiplayer/Session/MatchmakingRequests.h @@ -17,7 +17,7 @@ namespace AZ class ReflectContext; } -namespace AzFramework +namespace Multiplayer { //! AcceptMatchRequest //! The container for AcceptMatch request parameters. @@ -64,4 +64,4 @@ namespace AzFramework //! A unique identifier for a matchmaking ticket AZStd::string m_ticketId; }; -} // namespace AzFramework +} // namespace Multiplayer diff --git a/Code/Framework/AzFramework/AzFramework/Session/SessionConfig.h b/Gems/Multiplayer/Code/Include/Multiplayer/Session/SessionConfig.h similarity index 97% rename from Code/Framework/AzFramework/AzFramework/Session/SessionConfig.h rename to Gems/Multiplayer/Code/Include/Multiplayer/Session/SessionConfig.h index f951cf58fa..3ed5ab891a 100644 --- a/Code/Framework/AzFramework/AzFramework/Session/SessionConfig.h +++ b/Gems/Multiplayer/Code/Include/Multiplayer/Session/SessionConfig.h @@ -12,7 +12,7 @@ #include #include -namespace AzFramework +namespace Multiplayer { //! SessionConfig //! Properties describing a session. @@ -66,4 +66,4 @@ namespace AzFramework //! Provides additional information about session status. AZStd::string m_statusReason; }; -} // namespace AzFramework +} // namespace Multiplayer diff --git a/Code/Framework/AzFramework/AzFramework/Session/SessionNotifications.h b/Gems/Multiplayer/Code/Include/Multiplayer/Session/SessionNotifications.h similarity index 98% rename from Code/Framework/AzFramework/AzFramework/Session/SessionNotifications.h rename to Gems/Multiplayer/Code/Include/Multiplayer/Session/SessionNotifications.h index cf1382aeba..90abfaded5 100644 --- a/Code/Framework/AzFramework/AzFramework/Session/SessionNotifications.h +++ b/Gems/Multiplayer/Code/Include/Multiplayer/Session/SessionNotifications.h @@ -10,7 +10,7 @@ #include -namespace AzFramework +namespace Multiplayer { struct SessionConfig; @@ -68,4 +68,4 @@ namespace AzFramework virtual void OnUpdateSessionEnd() = 0; }; using SessionNotificationBus = AZ::EBus; -} // namespace AzFramework +} // namespace Multiplayer diff --git a/Code/Framework/AzFramework/AzFramework/Session/SessionRequests.h b/Gems/Multiplayer/Code/Include/Multiplayer/Session/SessionRequests.h similarity index 98% rename from Code/Framework/AzFramework/AzFramework/Session/SessionRequests.h rename to Gems/Multiplayer/Code/Include/Multiplayer/Session/SessionRequests.h index d806e6fefa..75abd52f29 100644 --- a/Code/Framework/AzFramework/AzFramework/Session/SessionRequests.h +++ b/Gems/Multiplayer/Code/Include/Multiplayer/Session/SessionRequests.h @@ -17,7 +17,7 @@ namespace AZ class ReflectContext; } -namespace AzFramework +namespace Multiplayer { struct SessionConfig; @@ -104,4 +104,4 @@ namespace AzFramework //! Developer-defined information related to a player. AZStd::string m_playerData; }; -} // namespace AzFramework +} // namespace Multiplayer diff --git a/Gems/Multiplayer/Code/Source/MultiplayerSystemComponent.cpp b/Gems/Multiplayer/Code/Source/MultiplayerSystemComponent.cpp index dcad230f71..dad584d3e8 100644 --- a/Gems/Multiplayer/Code/Source/MultiplayerSystemComponent.cpp +++ b/Gems/Multiplayer/Code/Source/MultiplayerSystemComponent.cpp @@ -17,6 +17,8 @@ #include #include #include +#include +#include #include #include @@ -30,8 +32,6 @@ #include #include #include -#include -#include #include #include #include @@ -184,13 +184,13 @@ namespace Multiplayer void MultiplayerSystemComponent::Activate() { AZ::TickBus::Handler::BusConnect(); - AzFramework::SessionNotificationBus::Handler::BusConnect(); + SessionNotificationBus::Handler::BusConnect(); m_networkInterface = AZ::Interface::Get()->CreateNetworkInterface(AZ::Name(MpNetworkInterfaceName), sv_protocol, TrustZone::ExternalClientToServer, *this); if (AZ::Interface::Get()) { m_consoleCommandHandler.Connect(AZ::Interface::Get()->GetConsoleCommandInvokedEvent()); } - AZ::Interface::Register(this); + AZ::Interface::Register(this); //! Register our gems multiplayer components to assign NetComponentIds RegisterMultiplayerComponents(); @@ -198,10 +198,10 @@ namespace Multiplayer void MultiplayerSystemComponent::Deactivate() { - AZ::Interface::Unregister(this); + AZ::Interface::Unregister(this); m_consoleCommandHandler.Disconnect(); AZ::Interface::Get()->DestroyNetworkInterface(AZ::Name(MpNetworkInterfaceName)); - AzFramework::SessionNotificationBus::Handler::BusDisconnect(); + SessionNotificationBus::Handler::BusDisconnect(); AZ::TickBus::Handler::BusDisconnect(); m_networkEntityManager.Reset(); @@ -251,14 +251,14 @@ namespace Multiplayer // Signal session management, do this after uninitializing state if (agentType == MultiplayerAgentType::DedicatedServer || agentType == MultiplayerAgentType::ClientServer) { - if (AZ::Interface::Get() != nullptr) + if (AZ::Interface::Get() != nullptr) { - AZ::Interface::Get()->HandleDestroySession(); + AZ::Interface::Get()->HandleDestroySession(); } } } - bool MultiplayerSystemComponent::RequestPlayerJoinSession(const AzFramework::SessionConnectionConfig& config) + bool MultiplayerSystemComponent::RequestPlayerJoinSession(const SessionConnectionConfig& config) { m_pendingConnectionTickets.push(config.m_playerSessionId); AZStd::string hostname = config.m_dnsName.empty() ? config.m_ipAddress : config.m_dnsName; @@ -280,13 +280,13 @@ namespace Multiplayer return true; } - bool MultiplayerSystemComponent::OnCreateSessionBegin(const AzFramework::SessionConfig& sessionConfig) + bool MultiplayerSystemComponent::OnCreateSessionBegin(const SessionConfig& sessionConfig) { // Check if session manager has a certificate for us and pass it along if so - if (AZ::Interface::Get() != nullptr) + if (AZ::Interface::Get() != nullptr) { AZ::CVarFixedString externalCertPath = AZ::CVarFixedString( - AZ::Interface::Get()->GetExternalSessionCertificate().c_str()); + AZ::Interface::Get()->GetExternalSessionCertificate().c_str()); if (!externalCertPath.empty()) { AZ::CVarFixedString commandString = "net_SslExternalCertificateFile " + externalCertPath; @@ -294,7 +294,7 @@ namespace Multiplayer } AZ::CVarFixedString internalCertPath = AZ::CVarFixedString( - AZ::Interface::Get()->GetInternalSessionCertificate().c_str()); + AZ::Interface::Get()->GetInternalSessionCertificate().c_str()); if (!internalCertPath.empty()) { AZ::CVarFixedString commandString = "net_SslInternalCertificateFile " + internalCertPath; @@ -335,7 +335,7 @@ namespace Multiplayer { } - void MultiplayerSystemComponent::OnUpdateSessionBegin(const AzFramework::SessionConfig& sessionConfig, const AZStd::string& updateReason) + void MultiplayerSystemComponent::OnUpdateSessionBegin(const SessionConfig& sessionConfig, const AZStd::string& updateReason) { AZ_UNUSED(sessionConfig); AZ_UNUSED(updateReason); @@ -496,12 +496,12 @@ namespace Multiplayer ) { // Validate our session with the provider if any - if (AZ::Interface::Get() != nullptr) + if (AZ::Interface::Get() != nullptr) { - AzFramework::PlayerConnectionConfig config; + PlayerConnectionConfig config; config.m_playerConnectionId = aznumeric_cast(connection->GetConnectionId()); config.m_playerSessionId = packet.GetTicket(); - if (!AZ::Interface::Get()->ValidatePlayerJoinSession(config)) + if (!AZ::Interface::Get()->ValidatePlayerJoinSession(config)) { auto visitor = [](IConnection& connection) { connection.Disconnect(DisconnectReason::TerminatedByUser, TerminationEndpoint::Local); }; m_networkInterface->GetConnectionSet().VisitConnections(visitor); @@ -780,13 +780,13 @@ namespace Multiplayer else if (m_agentType == MultiplayerAgentType::DedicatedServer || m_agentType == MultiplayerAgentType::ClientServer) { // Signal to session management that a user has left the server - if (AZ::Interface::Get() != nullptr && + if (AZ::Interface::Get() != nullptr && connection->GetConnectionRole() == ConnectionRole::Acceptor) { - AzFramework::PlayerConnectionConfig config; + PlayerConnectionConfig config; config.m_playerConnectionId = aznumeric_cast(connection->GetConnectionId()); config.m_playerSessionId = reinterpret_cast(connection->GetUserData())->GetProviderTicket(); - AZ::Interface::Get()->HandlePlayerLeaveSession(config); + AZ::Interface::Get()->HandlePlayerLeaveSession(config); } } diff --git a/Gems/Multiplayer/Code/Source/MultiplayerSystemComponent.h b/Gems/Multiplayer/Code/Source/MultiplayerSystemComponent.h index 47238cc729..990ff86bbc 100644 --- a/Gems/Multiplayer/Code/Source/MultiplayerSystemComponent.h +++ b/Gems/Multiplayer/Code/Source/MultiplayerSystemComponent.h @@ -9,6 +9,8 @@ #pragma once #include +#include +#include #include #include #include @@ -21,8 +23,6 @@ #include #include #include -#include -#include #include namespace AzFramework @@ -41,8 +41,8 @@ namespace Multiplayer class MultiplayerSystemComponent final : public AZ::Component , public AZ::TickBus::Handler - , public AzFramework::SessionNotificationBus::Handler - , public AzFramework::ISessionHandlingClientRequests + , public SessionNotificationBus::Handler + , public ISessionHandlingClientRequests , public AzNetworking::IConnectionListener , public IMultiplayer { @@ -63,14 +63,14 @@ namespace Multiplayer void Deactivate() override; //! @} - //! AzFramework::SessionNotificationBus::Handler overrides. + //! SessionNotificationBus::Handler overrides. //! @{ bool OnSessionHealthCheck() override; - bool OnCreateSessionBegin(const AzFramework::SessionConfig& sessionConfig) override; + bool OnCreateSessionBegin(const SessionConfig& sessionConfig) override; void OnCreateSessionEnd() override; bool OnDestroySessionBegin() override; void OnDestroySessionEnd() override; - void OnUpdateSessionBegin(const AzFramework::SessionConfig& sessionConfig, const AZStd::string& updateReason) override; + void OnUpdateSessionBegin(const SessionConfig& sessionConfig, const AZStd::string& updateReason) override; void OnUpdateSessionEnd() override; //! @} @@ -101,7 +101,7 @@ namespace Multiplayer //! ISessionHandlingClientRequests interface //! @{ - bool RequestPlayerJoinSession(const AzFramework::SessionConnectionConfig& sessionConnectionConfig) override; + bool RequestPlayerJoinSession(const SessionConnectionConfig& sessionConnectionConfig) override; void RequestPlayerLeaveSession() override; //! @} diff --git a/Code/Framework/AzFramework/AzFramework/Matchmaking/MatchmakingRequests.cpp b/Gems/Multiplayer/Code/Source/Session/MatchmakingRequests.cpp similarity index 97% rename from Code/Framework/AzFramework/AzFramework/Matchmaking/MatchmakingRequests.cpp rename to Gems/Multiplayer/Code/Source/Session/MatchmakingRequests.cpp index b6c8c55fa4..4da2d7749e 100644 --- a/Code/Framework/AzFramework/AzFramework/Matchmaking/MatchmakingRequests.cpp +++ b/Gems/Multiplayer/Code/Source/Session/MatchmakingRequests.cpp @@ -9,9 +9,9 @@ #include #include #include -#include +#include -namespace AzFramework +namespace Multiplayer { void AcceptMatchRequest::Reflect(AZ::ReflectContext* context) { @@ -75,4 +75,4 @@ namespace AzFramework } } } -} // namespace AzFramework +} // namespace Multiplayer diff --git a/Code/Framework/AzFramework/AzFramework/Session/SessionConfig.cpp b/Gems/Multiplayer/Code/Source/Session/SessionConfig.cpp similarity index 85% rename from Code/Framework/AzFramework/AzFramework/Session/SessionConfig.cpp rename to Gems/Multiplayer/Code/Source/Session/SessionConfig.cpp index 0856ddeed6..87a220d34a 100644 --- a/Code/Framework/AzFramework/AzFramework/Session/SessionConfig.cpp +++ b/Gems/Multiplayer/Code/Source/Session/SessionConfig.cpp @@ -8,9 +8,9 @@ #include #include -#include +#include -namespace AzFramework +namespace Multiplayer { void SessionConfig::Reflect(AZ::ReflectContext* context) { @@ -39,35 +39,35 @@ namespace AzFramework editContext->Class("SessionConfig", "Properties describing a session") ->ClassElement(AZ::Edit::ClassElements::EditorData, "") ->Attribute(AZ::Edit::Attributes::Visibility, AZ::Edit::PropertyVisibility::ShowChildrenOnly) - ->DataElement(AZ::Edit::UIHandlers::Default, &AzFramework::SessionConfig::m_creationTime, + ->DataElement(AZ::Edit::UIHandlers::Default, &Multiplayer::SessionConfig::m_creationTime, "CreationTime", "A time stamp indicating when this session was created. Format is a number expressed in Unix time as milliseconds.") - ->DataElement(AZ::Edit::UIHandlers::Default, &AzFramework::SessionConfig::m_terminationTime, + ->DataElement(AZ::Edit::UIHandlers::Default, &Multiplayer::SessionConfig::m_terminationTime, "TerminationTime", "A time stamp indicating when this data object was terminated. Same format as creation time.") - ->DataElement(AZ::Edit::UIHandlers::Default, &AzFramework::SessionConfig::m_creatorId, + ->DataElement(AZ::Edit::UIHandlers::Default, &Multiplayer::SessionConfig::m_creatorId, "CreatorId", "A unique identifier for a player or entity creating the session.") - ->DataElement(AZ::Edit::UIHandlers::Default, &AzFramework::SessionConfig::m_sessionProperties, + ->DataElement(AZ::Edit::UIHandlers::Default, &Multiplayer::SessionConfig::m_sessionProperties, "SessionProperties", "A collection of custom properties for a session.") - ->DataElement(AZ::Edit::UIHandlers::Default, &AzFramework::SessionConfig::m_matchmakingData, + ->DataElement(AZ::Edit::UIHandlers::Default, &Multiplayer::SessionConfig::m_matchmakingData, "MatchmakingData", "The matchmaking process information that was used to create the session.") - ->DataElement(AZ::Edit::UIHandlers::Default, &AzFramework::SessionConfig::m_sessionId, + ->DataElement(AZ::Edit::UIHandlers::Default, &Multiplayer::SessionConfig::m_sessionId, "SessionId", "A unique identifier for the session.") - ->DataElement(AZ::Edit::UIHandlers::Default, &AzFramework::SessionConfig::m_sessionName, + ->DataElement(AZ::Edit::UIHandlers::Default, &Multiplayer::SessionConfig::m_sessionName, "SessionName", "A descriptive label that is associated with a session.") - ->DataElement(AZ::Edit::UIHandlers::Default, &AzFramework::SessionConfig::m_dnsName, + ->DataElement(AZ::Edit::UIHandlers::Default, &Multiplayer::SessionConfig::m_dnsName, "DnsName", "The DNS identifier assigned to the instance that is running the session.") - ->DataElement(AZ::Edit::UIHandlers::Default, &AzFramework::SessionConfig::m_ipAddress, + ->DataElement(AZ::Edit::UIHandlers::Default, &Multiplayer::SessionConfig::m_ipAddress, "IpAddress", "The IP address of the session.") - ->DataElement(AZ::Edit::UIHandlers::Default, &AzFramework::SessionConfig::m_port, + ->DataElement(AZ::Edit::UIHandlers::Default, &Multiplayer::SessionConfig::m_port, "Port", "The port number for the session.") - ->DataElement(AZ::Edit::UIHandlers::Default, &AzFramework::SessionConfig::m_maxPlayer, + ->DataElement(AZ::Edit::UIHandlers::Default, &Multiplayer::SessionConfig::m_maxPlayer, "MaxPlayer", "The maximum number of players that can be connected simultaneously to the session.") - ->DataElement(AZ::Edit::UIHandlers::Default, &AzFramework::SessionConfig::m_currentPlayer, + ->DataElement(AZ::Edit::UIHandlers::Default, &Multiplayer::SessionConfig::m_currentPlayer, "CurrentPlayer", "Number of players currently in the session.") - ->DataElement(AZ::Edit::UIHandlers::Default, &AzFramework::SessionConfig::m_status, + ->DataElement(AZ::Edit::UIHandlers::Default, &Multiplayer::SessionConfig::m_status, "Status", "Current status of the session.") - ->DataElement(AZ::Edit::UIHandlers::Default, &AzFramework::SessionConfig::m_statusReason, + ->DataElement(AZ::Edit::UIHandlers::Default, &Multiplayer::SessionConfig::m_statusReason, "StatusReason", "Provides additional information about session status."); } } } -} // namespace AzFramework +} // namespace Multiplayer diff --git a/Code/Framework/AzFramework/AzFramework/Session/SessionRequests.cpp b/Gems/Multiplayer/Code/Source/Session/SessionRequests.cpp similarity index 97% rename from Code/Framework/AzFramework/AzFramework/Session/SessionRequests.cpp rename to Gems/Multiplayer/Code/Source/Session/SessionRequests.cpp index a7ffaa2491..895078daa8 100644 --- a/Code/Framework/AzFramework/AzFramework/Session/SessionRequests.cpp +++ b/Gems/Multiplayer/Code/Source/Session/SessionRequests.cpp @@ -9,10 +9,10 @@ #include #include #include -#include -#include +#include +#include -namespace AzFramework +namespace Multiplayer { void CreateSessionRequest::Reflect(AZ::ReflectContext* context) { @@ -124,4 +124,4 @@ namespace AzFramework } } } -} // namespace AzFramework +} // namespace Multiplayer diff --git a/Gems/Multiplayer/Code/multiplayer_files.cmake b/Gems/Multiplayer/Code/multiplayer_files.cmake index 9c83af49a3..35a75797b6 100644 --- a/Gems/Multiplayer/Code/multiplayer_files.cmake +++ b/Gems/Multiplayer/Code/multiplayer_files.cmake @@ -58,6 +58,14 @@ set(FILES Include/Multiplayer/NetworkTime/RewindableObject.h Include/Multiplayer/NetworkTime/RewindableObject.inl Include/Multiplayer/ReplicationWindows/IReplicationWindow.h + Include/Multiplayer/Session/IMatchmakingRequests.h + Include/Multiplayer/Session/ISessionHandlingRequests.h + Include/Multiplayer/Session/ISessionRequests.h + Include/Multiplayer/Session/MatchmakingRequests.h + Include/Multiplayer/Session/MatchmakingNotifications.h + Include/Multiplayer/Session/SessionRequests.h + Include/Multiplayer/Session/SessionConfig.h + Include/Multiplayer/Session/SessionNotifications.h Include/Multiplayer/AutoGen/AutoComponentTypes_Header.jinja Include/Multiplayer/AutoGen/AutoComponentTypes_Source.jinja Include/Multiplayer/AutoGen/AutoComponent_Common.jinja @@ -131,4 +139,7 @@ set(FILES Source/ReplicationWindows/NullReplicationWindow.h Source/ReplicationWindows/ServerToClientReplicationWindow.cpp Source/ReplicationWindows/ServerToClientReplicationWindow.h + Source/Session/MatchmakingRequests.cpp + Source/Session/SessionRequests.cpp + Source/Session/SessionConfig.cpp ) diff --git a/Gems/SceneProcessing/Code/Source/Generation/Components/TangentGenerator/TangentGenerateComponent.cpp b/Gems/SceneProcessing/Code/Source/Generation/Components/TangentGenerator/TangentGenerateComponent.cpp index 144638a351..a7804dda85 100644 --- a/Gems/SceneProcessing/Code/Source/Generation/Components/TangentGenerator/TangentGenerateComponent.cpp +++ b/Gems/SceneProcessing/Code/Source/Generation/Components/TangentGenerator/TangentGenerateComponent.cpp @@ -28,11 +28,15 @@ #include #include +#include #include namespace AZ::SceneGenerationComponents { + static constexpr AZStd::string_view DefaultTangentGenerationKey{ "/O3DE/SceneAPI/TangentGenerateComponent/DefaultGenerationMethod" }; + static constexpr AZStd::string_view DebugBitangentFlipKey{ "/O3DE/SceneAPI/TangentGenerateComponent/DebugBitangentFlip" }; + TangentGenerateComponent::TangentGenerateComponent() { BindToCall(&TangentGenerateComponent::GenerateTangentData); @@ -44,7 +48,7 @@ namespace AZ::SceneGenerationComponents AZ::SerializeContext* serializeContext = azrtti_cast(context); if (serializeContext) { - serializeContext->Class()->Version(1); + serializeContext->Class()->Version(2); } } @@ -66,8 +70,47 @@ namespace AZ::SceneGenerationComponents return nullptr; } + void TangentGenerateComponent::GetRegistrySettings( + AZ::SceneAPI::DataTypes::TangentGenerationMethod& defaultGenerationMethod, bool& debugBitangentFlip) const + { + if (auto settingsRegistry = AZ::SettingsRegistry::Get(); settingsRegistry != nullptr) + { + AZStd::string defaultTangentGenerationMethodString; + if (settingsRegistry->Get(defaultTangentGenerationMethodString, DefaultTangentGenerationKey)) + { + const bool isCaseSensitive = false; + if (AZ::StringFunc::Equal(defaultTangentGenerationMethodString, "MikkT", isCaseSensitive)) + { + defaultGenerationMethod = AZ::SceneAPI::DataTypes::TangentGenerationMethod::MikkT; + } + else + { + AZ_Warning( + AZ::SceneAPI::Utilities::WarningWindow, + AZ::StringFunc::Equal(defaultTangentGenerationMethodString, "FromSourceScene", isCaseSensitive), + "'" AZ_STRING_FORMAT "' is not a valid default tangent generation method. Check the value of %s in your settings registry, and change " + "it to 'FromSourceScene' or 'MikkT'", + defaultTangentGenerationMethodString.c_str(), AZ_STRING_ARG(DefaultTangentGenerationKey)); + } + } + + settingsRegistry->Get(debugBitangentFlip, DebugBitangentFlipKey); + } + } + AZ::SceneAPI::Events::ProcessingResult TangentGenerateComponent::GenerateTangentData(TangentGenerateContext& context) { + // Get any tangent related settings from the settings registry + AZ::SceneAPI::DataTypes::TangentGenerationMethod defaultGenerationMethod = + AZ::SceneAPI::DataTypes::TangentGenerationMethod::FromSourceScene; + bool debugBitangentFlip = false; + GetRegistrySettings(defaultGenerationMethod, debugBitangentFlip); + + // Get the generation setting for this scene + const AZ::SceneAPI::SceneData::TangentsRule* tangentsRule = GetTangentRule(context.GetScene()); + const AZ::SceneAPI::DataTypes::TangentGenerationMethod generationMethod = + tangentsRule ? tangentsRule->GetGenerationMethod() : defaultGenerationMethod; + // Iterate over all graph content and filter out all meshes. AZ::SceneAPI::Containers::SceneGraph& graph = context.GetScene().GetGraph(); AZ::SceneAPI::Containers::SceneGraph::ContentStorageData graphContent = graph.GetContentStorage(); @@ -92,19 +135,31 @@ namespace AZ::SceneGenerationComponents for (auto& [mesh, nodeIndex] : meshes) { // Generate tangents for the mesh (if this is desired or needed). - if (!GenerateTangentsForMesh(context.GetScene(), nodeIndex, mesh)) + if (!GenerateTangentsForMesh(context.GetScene(), nodeIndex, mesh, generationMethod)) { return AZ::SceneAPI::Events::ProcessingResult::Failure; } // Now that we have the tangents and bitangents, calculate the tangent w values for the ones that we imported from the scene file, as they only have xyz. - UpdateFbxTangentWValues(graph, nodeIndex, mesh); + // But only do this if we are getting tangents from the source scene, because MikkT will provide us with a correct tangent.w already + if (generationMethod == SceneAPI::DataTypes::TangentGenerationMethod::FromSourceScene) + { + if (!UpdateFbxTangentWValues(graph, nodeIndex, mesh, debugBitangentFlip)) + { + return AZ::SceneAPI::Events::ProcessingResult::Failure; + } + } + } return AZ::SceneAPI::Events::ProcessingResult::Success; } - void TangentGenerateComponent::UpdateFbxTangentWValues(AZ::SceneAPI::Containers::SceneGraph& graph, const AZ::SceneAPI::Containers::SceneGraph::NodeIndex& nodeIndex, const AZ::SceneAPI::DataTypes::IMeshData* meshData) + bool TangentGenerateComponent::UpdateFbxTangentWValues( + AZ::SceneAPI::Containers::SceneGraph& graph, + const AZ::SceneAPI::Containers::SceneGraph::NodeIndex& nodeIndex, + const AZ::SceneAPI::DataTypes::IMeshData* meshData, + bool debugBitangentFlip) { // Iterate over all UV sets. AZ::SceneAPI::DataTypes::IMeshVertexUVData* uvData = FindUvData(graph, nodeIndex, 0); @@ -145,6 +200,26 @@ namespace AZ::SceneGenerationComponents tangent = fbxTangentData->GetTangent(i); tangent.SetW(1.0f); } + + if (debugBitangentFlip) + { + AZ::Vector4 originalTangent = fbxTangentData->GetTangent(i); + + if (originalTangent.GetW() > 0.0f) + { + // If the tangent has a positive w value, the fix for GHI-7125 is going to flip the bitangent + // compared to the original behavior. Report an error and fail to process as an indication + // that this asset will be impacted by GHI-7125 + + AZ_Error( + AZ::SceneAPI::Utilities::ErrorWindow, false, + "Tangent w is positive for at least one vertex in the mesh. This model will be impacted by GHI-7125. " + "See https://github.com/o3de/o3de/issues/7125 for details."); + return false; + } + } + + // Update the tangent.w in the scene fbxTangentData->SetTangent(i, tangent); } } @@ -152,6 +227,8 @@ namespace AZ::SceneGenerationComponents // Find the next UV set. uvData = FindUvData(graph, nodeIndex, ++uvSetIndex); } + + return true; } void TangentGenerateComponent::FindBlendShapes( @@ -173,7 +250,11 @@ namespace AZ::SceneGenerationComponents } } - bool TangentGenerateComponent::GenerateTangentsForMesh(AZ::SceneAPI::Containers::Scene& scene, const AZ::SceneAPI::Containers::SceneGraph::NodeIndex& nodeIndex, AZ::SceneAPI::DataTypes::IMeshData* meshData) + bool TangentGenerateComponent::GenerateTangentsForMesh( + AZ::SceneAPI::Containers::Scene& scene, + const AZ::SceneAPI::Containers::SceneGraph::NodeIndex& nodeIndex, + AZ::SceneAPI::DataTypes::IMeshData* meshData, + AZ::SceneAPI::DataTypes::TangentGenerationMethod ruleGenerationMethod) { AZ::SceneAPI::Containers::SceneGraph& graph = scene.GetGraph(); @@ -186,7 +267,6 @@ namespace AZ::SceneGenerationComponents } const AZ::SceneAPI::SceneData::TangentsRule* tangentsRule = GetTangentRule(scene); - const AZ::SceneAPI::DataTypes::TangentGenerationMethod ruleGenerationMethod = tangentsRule ? tangentsRule->GetGenerationMethod() : AZ::SceneAPI::DataTypes::TangentGenerationMethod::FromSourceScene; // Find all blend shape data under the mesh. We need to generate the tangent and bitangent for blend shape as well. AZStd::vector blendShapes; diff --git a/Gems/SceneProcessing/Code/Source/Generation/Components/TangentGenerator/TangentGenerateComponent.h b/Gems/SceneProcessing/Code/Source/Generation/Components/TangentGenerator/TangentGenerateComponent.h index d2aa59b549..8b797177e2 100644 --- a/Gems/SceneProcessing/Code/Source/Generation/Components/TangentGenerator/TangentGenerateComponent.h +++ b/Gems/SceneProcessing/Code/Source/Generation/Components/TangentGenerator/TangentGenerateComponent.h @@ -58,9 +58,19 @@ namespace AZ::SceneGenerationComponents void FindBlendShapes( AZ::SceneAPI::Containers::SceneGraph& graph, const AZ::SceneAPI::Containers::SceneGraph::NodeIndex& nodeIndex, AZStd::vector& outBlendShapes) const; - bool GenerateTangentsForMesh(AZ::SceneAPI::Containers::Scene& scene, const AZ::SceneAPI::Containers::SceneGraph::NodeIndex& nodeIndex, AZ::SceneAPI::DataTypes::IMeshData* meshData); - void UpdateFbxTangentWValues(AZ::SceneAPI::Containers::SceneGraph& graph, const AZ::SceneAPI::Containers::SceneGraph::NodeIndex& nodeIndex, const AZ::SceneAPI::DataTypes::IMeshData* meshData); + bool GenerateTangentsForMesh( + AZ::SceneAPI::Containers::Scene& scene, + const AZ::SceneAPI::Containers::SceneGraph::NodeIndex& nodeIndex, + AZ::SceneAPI::DataTypes::IMeshData* meshData, + AZ::SceneAPI::DataTypes::TangentGenerationMethod defaultGenerationMethod); + bool UpdateFbxTangentWValues( + AZ::SceneAPI::Containers::SceneGraph& graph, + const AZ::SceneAPI::Containers::SceneGraph::NodeIndex& nodeIndex, + const AZ::SceneAPI::DataTypes::IMeshData* meshData, + bool deubgBitangentFlip); const AZ::SceneAPI::SceneData::TangentsRule* GetTangentRule(const AZ::SceneAPI::Containers::Scene& scene) const; + void GetRegistrySettings( + AZ::SceneAPI::DataTypes::TangentGenerationMethod& defaultTangentGenrationMethod, bool& debugBitangentFlip) const; size_t CalcUvSetCount(AZ::SceneAPI::Containers::SceneGraph& graph, const AZ::SceneAPI::Containers::SceneGraph::NodeIndex& nodeIndex) const; AZ::SceneAPI::DataTypes::IMeshVertexUVData* FindUvData(AZ::SceneAPI::Containers::SceneGraph& graph, const AZ::SceneAPI::Containers::SceneGraph::NodeIndex& nodeIndex, AZ::u64 uvSet) const; diff --git a/Gems/SceneProcessing/Code/Source/Generation/Components/TangentGenerator/TangentPreExportComponent.cpp b/Gems/SceneProcessing/Code/Source/Generation/Components/TangentGenerator/TangentPreExportComponent.cpp index 6ab9c44c8e..8848c365cb 100644 --- a/Gems/SceneProcessing/Code/Source/Generation/Components/TangentGenerator/TangentPreExportComponent.cpp +++ b/Gems/SceneProcessing/Code/Source/Generation/Components/TangentGenerator/TangentPreExportComponent.cpp @@ -35,6 +35,6 @@ namespace AZ::SceneGenerationComponents SceneEvents::ProcessingResultCombiner result; TangentGenerateContext tangentGenerateContext(context.GetScene()); result += SceneEvents::Process(tangentGenerateContext); - return SceneEvents::ProcessingResult::Success; + return result.GetResult(); } } // namespace AZ::SceneGenerationComponents diff --git a/Gems/SurfaceData/Code/CMakeLists.txt b/Gems/SurfaceData/Code/CMakeLists.txt index 6cef8b6e25..cb75be2de4 100644 --- a/Gems/SurfaceData/Code/CMakeLists.txt +++ b/Gems/SurfaceData/Code/CMakeLists.txt @@ -37,7 +37,7 @@ ly_add_target( PUBLIC Include BUILD_DEPENDENCIES - PRIVATE + PUBLIC Gem::SurfaceData.Static Gem::LmbrCentral RUNTIME_DEPENDENCIES diff --git a/Gems/SurfaceData/Code/Include/SurfaceData/SurfaceDataTypes.h b/Gems/SurfaceData/Code/Include/SurfaceData/SurfaceDataTypes.h index 6d39efaa9f..c892bc8c09 100644 --- a/Gems/SurfaceData/Code/Include/SurfaceData/SurfaceDataTypes.h +++ b/Gems/SurfaceData/Code/Include/SurfaceData/SurfaceDataTypes.h @@ -9,31 +9,215 @@ #pragma once #include +#include #include #include #include #include +#include #include namespace SurfaceData { //map of id or crc to contribution factor - using SurfaceTagWeightMap = AZStd::unordered_map; using SurfaceTagNameSet = AZStd::unordered_set; using SurfaceTagVector = AZStd::vector; - struct SurfacePoint final + //! SurfaceTagWeights stores a collection of surface tags and weights. + class SurfaceTagWeights { - AZ_CLASS_ALLOCATOR(SurfacePoint, AZ::SystemAllocator, 0); - AZ_TYPE_INFO(SurfacePoint, "{0DC7E720-68D6-47D4-BB6D-B89EF23C5A5C}"); + public: + SurfaceTagWeights() = default; - AZ::EntityId m_entityId; - AZ::Vector3 m_position; - AZ::Vector3 m_normal; - SurfaceTagWeightMap m_masks; + //! Construct a collection of SurfaceTagWeights from the given SurfaceTagWeightList. + //! @param weights - The list of weights to assign to the new instance. + SurfaceTagWeights(const AzFramework::SurfaceData::SurfaceTagWeightList& weights) + { + AssignSurfaceTagWeights(weights); + } + + //! Replace the existing surface tag weights with the given set. + //! @param weights - The list of weights to assign to this instance. + void AssignSurfaceTagWeights(const AzFramework::SurfaceData::SurfaceTagWeightList& weights); + + //! Replace the existing surface tag weights with the given set. + //! @param tags - The list of tags to assign to this instance. + //! @param weight - The weight to assign to each tag. + void AssignSurfaceTagWeights(const SurfaceTagVector& tags, float weight); + + //! Add a surface tag weight to this collection. + //! @param tag - The surface tag. + //! @param weight - The surface tag weight. + void AddSurfaceTagWeight(const AZ::Crc32 tag, const float weight); + + //! Replace the surface tag weight with the new one if it's higher, or add it if the tag isn't found. + //! (This method is intentionally inlined for its performance impact) + //! @param tag - The surface tag. + //! @param weight - The surface tag weight. + void AddSurfaceWeightIfGreater(const AZ::Crc32 tag, const float weight) + { + const auto maskItr = m_weights.find(tag); + const float previousValue = maskItr != m_weights.end() ? maskItr->second : 0.0f; + m_weights[tag] = AZ::GetMax(weight, previousValue); + } + + //! Replace the surface tag weight with the new one if it's higher, or add it if the tag isn't found. + //! (This method is intentionally inlined for its performance impact) + //! @param tags - The surface tags to replace/add. + //! @param weight - The surface tag weight to use for each tag. + void AddSurfaceWeightsIfGreater(const SurfaceTagVector& tags, const float weight) + { + for (const auto& tag : tags) + { + AddSurfaceWeightIfGreater(tag, weight); + } + } + + //! Replace the surface tag weight with the new one if it's higher, or add it if the tag isn't found. + //! (This method is intentionally inlined for its performance impact) + //! @param weights - The surface tags and weights to replace/add. + void AddSurfaceWeightsIfGreater(const SurfaceTagWeights& weights) + { + for (const auto& [tag, weight] : weights.m_weights) + { + AddSurfaceWeightIfGreater(tag, weight); + } + } + + //! Equality comparison operator for SurfaceTagWeights. + bool operator==(const SurfaceTagWeights& rhs) const; + + //! Inequality comparison operator for SurfaceTagWeights. + bool operator!=(const SurfaceTagWeights& rhs) const + { + return !(*this == rhs); + } + + //! Compares a SurfaceTagWeightList with a SurfaceTagWeights instance to look for equality. + //! They will be equal if they have the exact same set of tags and weights. + //! @param compareWeights - the set of weights to compare against. + bool SurfaceWeightsAreEqual(const AzFramework::SurfaceData::SurfaceTagWeightList& compareWeights) const; + + //! Clear the surface tag weight collection. + void Clear(); + + //! Get the size of the surface tag weight collection. + //! @return The size of the collection. + size_t GetSize() const; + + //! Get the collection of surface tag weights as a SurfaceTagWeightList. + //! @return SurfaceTagWeightList containing the same tags and weights as this collection. + AzFramework::SurfaceData::SurfaceTagWeightList GetSurfaceTagWeightList() const; + + //! Enumerate every tag and weight and call a callback for each one found. + //! Callback params: + //! AZ::Crc32 - The surface tag. + //! float - The surface tag weight. + //! return - true to keep enumerating, false to stop. + //! @param weightCallback - the callback to use for each surface tag / weight found. + void EnumerateWeights(AZStd::function weightCallback) const; + + //! Check to see if the collection has any valid tags stored within it. + //! A tag of "Unassigned" is considered an invalid tag. + //! @return True if there is at least one valid tag, false if there isn't. + bool HasValidTags() const; + + //! Check to see if the collection contains the given tag. + //! @param sampleTag - The tag to look for. + //! @return True if the tag is found, false if it isn't. + bool HasMatchingTag(const AZ::Crc32& sampleTag) const; + + //! Check to see if the collection contains the given tag with the given weight range. + //! The range check is inclusive on both sides of the range: [weightMin, weightMax] + //! @param sampleTag - The tag to look for. + //! @param weightMin - The minimum weight for this tag. + //! @param weightMax - The maximum weight for this tag. + //! @return True if the tag is found, false if it isn't. + bool HasMatchingTag(const AZ::Crc32& sampleTag, float weightMin, float weightMax) const; + + //! Check to see if the collection contains any of the given tags. + //! @param sampleTags - The tags to look for. + //! @return True if any of the tags is found, false if none are found. + bool HasAnyMatchingTags(const SurfaceTagVector& sampleTags) const; + + //! Check to see if the collection contains the given tag with the given weight range. + //! The range check is inclusive on both sides of the range: [weightMin, weightMax] + //! @param sampleTags - The tags to look for. + //! @param weightMin - The minimum weight for this tag. + //! @param weightMax - The maximum weight for this tag. + //! @return True if any of the tags is found, false if none are found. + bool HasAnyMatchingTags(const SurfaceTagVector& sampleTags, float weightMin, float weightMax) const; + + private: + AZStd::unordered_map m_weights; + }; + + //! SurfacePointList stores a collection of surface point data, which consists of positions, normals, and surface tag weights. + class SurfacePointList + { + public: + AZ_CLASS_ALLOCATOR(SurfacePointList, AZ::SystemAllocator, 0); + AZ_TYPE_INFO(SurfacePointList, "{DBA02848-2131-4279-BDEF-3581B76AB736}"); + + SurfacePointList() = default; + ~SurfacePointList() = default; + + //! Constructor for creating a SurfacePointList from a list of SurfacePoint data. + //! Primarily used as a convenience for unit tests. + //! @param surfacePoints - An initial set of SurfacePoint points to store in the SurfacePointList. + SurfacePointList(AZStd::initializer_list surfacePoints); + + //! Add a surface point to the list. + //! @param entityId - The entity creating the surface point. + //! @param position - The position of the surface point. + //! @param normal - The normal for the surface point. + //! @param weights - The surface tags and weights for this surface point. + void AddSurfacePoint(const AZ::EntityId& entityId, + const AZ::Vector3& position, const AZ::Vector3& normal, const SurfaceTagWeights& weights); + + //! Clear the surface point list. + void Clear(); + + //! Preallocate space in the list based on the maximum number of output points per input point we can generate. + //! @param maxPointsPerInput - The maximum number of output points per input point. + void ReserveSpace(size_t maxPointsPerInput); + + //! Check if the surface point list is empty. + //! @return - true if empty, false if it contains points. + bool IsEmpty() const; + + //! Get the size of the surface point list. + //! @return - The number of valid points in the list. + size_t GetSize() const; + + //! Enumerate every surface point and call a callback for each point found. + void EnumeratePoints(AZStd::function< + bool(const AZ::Vector3& position, const AZ::Vector3& normal, const SurfaceTagWeights& surfaceWeights)> pointCallback) const; + + //! Modify the surface weights for each surface point in the list. + void ModifySurfaceWeights( + const AZ::EntityId& currentEntityId, + AZStd::function modificationWeightCallback); + + //! Get the surface point with the highest Z value. + AzFramework::SurfaceData::SurfacePoint GetHighestSurfacePoint() const; + + //! Remove any points that don't contain any of the provided surface tags. + void FilterPoints(const SurfaceTagVector& desiredTags); + + protected: + // These are kept in separate parallel vectors instead of a single struct so that it's possible to pass just specific data + // "channels" into other methods as span<> without having to pass the full struct into the span<>. Specifically, we want to be + // able to pass spans of the positions down through nesting gradient/surface calls. + // A side benefit is that profiling showed the data access to be faster than packing all the fields into a single struct. + AZStd::vector m_surfaceCreatorIdList; + AZStd::vector m_surfacePositionList; + AZStd::vector m_surfaceNormalList; + AZStd::vector m_surfaceWeightsList; + + AZ::Aabb m_pointBounds = AZ::Aabb::CreateNull(); }; - using SurfacePointList = AZStd::vector; using SurfacePointLists = AZStd::vector; struct SurfaceDataRegistryEntry diff --git a/Gems/SurfaceData/Code/Include/SurfaceData/Utility/SurfaceDataUtility.h b/Gems/SurfaceData/Code/Include/SurfaceData/Utility/SurfaceDataUtility.h index 2a4a39ee3b..be053db5b9 100644 --- a/Gems/SurfaceData/Code/Include/SurfaceData/Utility/SurfaceDataUtility.h +++ b/Gems/SurfaceData/Code/Include/SurfaceData/Utility/SurfaceDataUtility.h @@ -88,48 +88,6 @@ namespace SurfaceData const AZ::Vector3& rayStart, const AZ::Vector3& rayEnd, AZ::Vector3& outPosition, AZ::Vector3& outNormal); - AZ_INLINE void AssignSurfaceTagWeights(const SurfaceTagVector& tags, float weight, SurfaceTagWeightMap& weights) - { - weights.clear(); - weights.reserve(tags.size()); - for (auto& tag : tags) - { - weights[tag] = weight; - } - } - - AZ_INLINE void AddMaxValueForMasks(SurfaceTagWeightMap& masks, const AZ::Crc32 tag, const float value) - { - const auto maskItr = masks.find(tag); - const float valueOld = maskItr != masks.end() ? maskItr->second : 0.0f; - masks[tag] = AZ::GetMax(value, valueOld); - } - - AZ_INLINE void AddMaxValueForMasks(SurfaceTagWeightMap& masks, const SurfaceTagVector& tags, const float value) - { - for (const auto& tag : tags) - { - AddMaxValueForMasks(masks, tag, value); - } - } - - AZ_INLINE void AddMaxValueForMasks(SurfaceTagWeightMap& outMasks, const SurfaceTagWeightMap& inMasks) - { - for (const auto& inMask : inMasks) - { - AddMaxValueForMasks(outMasks, inMask.first, inMask.second); - } - } - - template - AZ_INLINE void AddItemIfNotFound(Container& container, const Element& element) - { - if (AZStd::find(container.begin(), container.end(), element) == container.end()) - { - container.insert(container.end(), element); - } - } - template AZ_INLINE bool HasMatchingTag(const SourceContainer& sourceTags, const AZ::Crc32& sampleTag) { @@ -137,26 +95,7 @@ namespace SurfaceData } template - AZ_INLINE bool HasMatchingTags(const SourceContainer& sourceTags, const SampleContainer& sampleTags) - { - for (const auto& sampleTag : sampleTags) - { - if (HasMatchingTag(sourceTags, sampleTag)) - { - return true; - } - } - - return false; - } - - AZ_INLINE bool HasMatchingTag(const SurfaceTagWeightMap& sourceTags, const AZ::Crc32& sampleTag) - { - return sourceTags.find(sampleTag) != sourceTags.end(); - } - - template - AZ_INLINE bool HasMatchingTags(const SurfaceTagWeightMap& sourceTags, const SampleContainer& sampleTags) + AZ_INLINE bool HasAnyMatchingTags(const SourceContainer& sourceTags, const SampleContainer& sampleTags) { for (const auto& sampleTag : sampleTags) { @@ -168,36 +107,8 @@ namespace SurfaceData return false; } - - AZ_INLINE bool HasMatchingTag(const SurfaceTagWeightMap& sourceTags, const AZ::Crc32& sampleTag, float valueMin, float valueMax) - { - auto maskItr = sourceTags.find(sampleTag); - return maskItr != sourceTags.end() && valueMin <= maskItr->second && valueMax >= maskItr->second; - } - - template - AZ_INLINE bool HasMatchingTags( - const SurfaceTagWeightMap& sourceTags, const SampleContainer& sampleTags, float valueMin, float valueMax) - { - for (const auto& sampleTag : sampleTags) - { - if (HasMatchingTag(sourceTags, sampleTag, valueMin, valueMax)) - { - return true; - } - } - - return false; - } - - template - AZ_INLINE void RemoveUnassignedTags(const SourceContainer& sourceTags) - { - sourceTags.erase(AZStd::remove(sourceTags.begin(), sourceTags.end(), Constants::s_unassignedTagCrc), sourceTags.end()); - } - - template - AZ_INLINE bool HasValidTags(const SourceContainer& sourceTags) + + AZ_INLINE bool HasValidTags(const SurfaceTagVector& sourceTags) { for (const auto& sourceTag : sourceTags) { @@ -209,18 +120,6 @@ namespace SurfaceData return false; } - AZ_INLINE bool HasValidTags(const SurfaceTagWeightMap& sourceTags) - { - for (const auto& sourceTag : sourceTags) - { - if (sourceTag.first != Constants::s_unassignedTagCrc) - { - return true; - } - } - return false; - } - // Utility method to compare two AABBs for overlapping XY coordinates while ignoring the Z coordinates. AZ_INLINE bool AabbOverlaps2D(const AZ::Aabb& box1, const AZ::Aabb& box2) { diff --git a/Gems/SurfaceData/Code/Source/Components/SurfaceDataColliderComponent.cpp b/Gems/SurfaceData/Code/Source/Components/SurfaceDataColliderComponent.cpp index dc4e5e6e74..e51fbc09b2 100644 --- a/Gems/SurfaceData/Code/Source/Components/SurfaceDataColliderComponent.cpp +++ b/Gems/SurfaceData/Code/Source/Components/SurfaceDataColliderComponent.cpp @@ -132,7 +132,7 @@ namespace SurfaceData Physics::ColliderComponentEventBus::Handler::BusConnect(GetEntityId()); // Update the cached collider data and bounds, then register the surface data provider / modifier - AssignSurfaceTagWeights(m_configuration.m_providerTags, 1.0f, m_newPointWeights); + m_newPointWeights.AssignSurfaceTagWeights(m_configuration.m_providerTags, 1.0f); UpdateColliderData(); } @@ -237,12 +237,7 @@ namespace SurfaceData if (DoRayTrace(inPosition, queryPointOnly, hitPosition, hitNormal)) { - SurfacePoint point; - point.m_entityId = GetEntityId(); - point.m_position = hitPosition; - point.m_normal = hitNormal; - point.m_masks = m_newPointWeights; - surfacePointList.push_back(AZStd::move(point)); + surfacePointList.AddSurfacePoint(GetEntityId(), hitPosition, hitNormal, m_newPointWeights); } } @@ -252,20 +247,22 @@ namespace SurfaceData if (m_colliderBounds.IsValid() && !m_configuration.m_modifierTags.empty()) { - const AZ::EntityId entityId = GetEntityId(); - for (auto& point : surfacePointList) - { - if (point.m_entityId != entityId && m_colliderBounds.Contains(point.m_position)) + surfacePointList.ModifySurfaceWeights( + GetEntityId(), + [this](const AZ::Vector3& position, SurfaceData::SurfaceTagWeights& weights) { - AZ::Vector3 hitPosition; - AZ::Vector3 hitNormal; - constexpr bool queryPointOnly = true; - if (DoRayTrace(point.m_position, queryPointOnly, hitPosition, hitNormal)) + if (m_colliderBounds.Contains(position)) { - AddMaxValueForMasks(point.m_masks, m_configuration.m_modifierTags, 1.0f); + AZ::Vector3 hitPosition; + AZ::Vector3 hitNormal; + constexpr bool queryPointOnly = true; + if (DoRayTrace(position, queryPointOnly, hitPosition, hitNormal)) + { + // If the query point collides with the volume, add all our modifier tags with a weight of 1.0f. + weights.AddSurfaceWeightsIfGreater(m_configuration.m_modifierTags, 1.0f); + } } - } - } + }); } } diff --git a/Gems/SurfaceData/Code/Source/Components/SurfaceDataColliderComponent.h b/Gems/SurfaceData/Code/Source/Components/SurfaceDataColliderComponent.h index 50c84f9519..2ef25774aa 100644 --- a/Gems/SurfaceData/Code/Source/Components/SurfaceDataColliderComponent.h +++ b/Gems/SurfaceData/Code/Source/Components/SurfaceDataColliderComponent.h @@ -101,6 +101,6 @@ namespace SurfaceData AZStd::atomic_bool m_refresh{ false }; mutable AZStd::shared_mutex m_cacheMutex; AZ::Aabb m_colliderBounds = AZ::Aabb::CreateNull(); - SurfaceTagWeightMap m_newPointWeights; + SurfaceTagWeights m_newPointWeights; }; } diff --git a/Gems/SurfaceData/Code/Source/Components/SurfaceDataShapeComponent.cpp b/Gems/SurfaceData/Code/Source/Components/SurfaceDataShapeComponent.cpp index 682bac150a..b84607782e 100644 --- a/Gems/SurfaceData/Code/Source/Components/SurfaceDataShapeComponent.cpp +++ b/Gems/SurfaceData/Code/Source/Components/SurfaceDataShapeComponent.cpp @@ -89,7 +89,7 @@ namespace SurfaceData LmbrCentral::ShapeComponentNotificationsBus::Handler::BusConnect(GetEntityId()); // Update the cached shape data and bounds, then register the surface data provider / modifier - AssignSurfaceTagWeights(m_configuration.m_providerTags, 1.0f, m_newPointWeights); + m_newPointWeights.AssignSurfaceTagWeights(m_configuration.m_providerTags, 1.0f); UpdateShapeData(); } @@ -155,12 +155,8 @@ namespace SurfaceData LmbrCentral::ShapeComponentRequestsBus::EventResult(hitShape, GetEntityId(), &LmbrCentral::ShapeComponentRequestsBus::Events::IntersectRay, rayOrigin, rayDirection, intersectionDistance); if (hitShape) { - SurfacePoint point; - point.m_entityId = GetEntityId(); - point.m_position = rayOrigin + intersectionDistance * rayDirection; - point.m_normal = AZ::Vector3::CreateAxisZ(); - point.m_masks = m_newPointWeights; - surfacePointList.push_back(AZStd::move(point)); + AZ::Vector3 position = rayOrigin + intersectionDistance * rayDirection; + surfacePointList.AddSurfacePoint(GetEntityId(), position, AZ::Vector3::CreateAxisZ(), m_newPointWeights); } } } @@ -173,20 +169,19 @@ namespace SurfaceData { const AZ::EntityId entityId = GetEntityId(); LmbrCentral::ShapeComponentRequestsBus::Event( - GetEntityId(), + entityId, [entityId, this, &surfacePointList](LmbrCentral::ShapeComponentRequestsBus::Events* shape) { - for (auto& point : surfacePointList) + surfacePointList.ModifySurfaceWeights( + entityId, + [this, shape](const AZ::Vector3& position, SurfaceData::SurfaceTagWeights& weights) { - if (point.m_entityId != entityId && m_shapeBounds.Contains(point.m_position)) + if (m_shapeBounds.Contains(position) && shape->IsPointInside(position)) { - bool inside = shape->IsPointInside(point.m_position); - if (inside) - { - AddMaxValueForMasks(point.m_masks, m_configuration.m_modifierTags, 1.0f); - } + // If the point is inside our shape, add all our modifier tags with a weight of 1.0f. + weights.AddSurfaceWeightsIfGreater(m_configuration.m_modifierTags, 1.0f); } - } + }); }); } } diff --git a/Gems/SurfaceData/Code/Source/Components/SurfaceDataShapeComponent.h b/Gems/SurfaceData/Code/Source/Components/SurfaceDataShapeComponent.h index 59b7950412..25ac491809 100644 --- a/Gems/SurfaceData/Code/Source/Components/SurfaceDataShapeComponent.h +++ b/Gems/SurfaceData/Code/Source/Components/SurfaceDataShapeComponent.h @@ -97,6 +97,6 @@ namespace SurfaceData AZ::Aabb m_shapeBounds = AZ::Aabb::CreateNull(); bool m_shapeBoundsIsValid = false; static const float s_rayAABBHeightPadding; - SurfaceTagWeightMap m_newPointWeights; + SurfaceTagWeights m_newPointWeights; }; } diff --git a/Gems/SurfaceData/Code/Source/SurfaceDataSystemComponent.cpp b/Gems/SurfaceData/Code/Source/SurfaceDataSystemComponent.cpp index 66f282d12b..66b8c83a58 100644 --- a/Gems/SurfaceData/Code/Source/SurfaceDataSystemComponent.cpp +++ b/Gems/SurfaceData/Code/Source/SurfaceDataSystemComponent.cpp @@ -45,14 +45,10 @@ namespace SurfaceData if (auto behaviorContext = azrtti_cast(context)) { - behaviorContext->Class() + behaviorContext->Class() ->Constructor() ->Attribute(AZ::Script::Attributes::Category, "Vegetation") ->Attribute(AZ::Script::Attributes::Module, "surface_data") - ->Property("entityId", BehaviorValueProperty(&SurfacePoint::m_entityId)) - ->Property("position", BehaviorValueProperty(&SurfacePoint::m_position)) - ->Property("normal", BehaviorValueProperty(&SurfacePoint::m_normal)) - ->Property("masks", BehaviorValueProperty(&SurfacePoint::m_masks)) ; behaviorContext->Class() @@ -182,11 +178,12 @@ namespace SurfaceData void SurfaceDataSystemComponent::GetSurfacePoints(const AZ::Vector3& inPosition, const SurfaceTagVector& desiredTags, SurfacePointList& surfacePointList) const { const bool useTagFilters = HasValidTags(desiredTags); - const bool hasModifierTags = useTagFilters && HasMatchingTags(desiredTags, m_registeredModifierTags); + const bool hasModifierTags = useTagFilters && HasAnyMatchingTags(desiredTags, m_registeredModifierTags); AZStd::shared_lock registrationLock(m_registrationMutex); - surfacePointList.clear(); + surfacePointList.Clear(); + surfacePointList.ReserveSpace(m_registeredSurfaceDataProviders.size()); //gather all intersecting points for (const auto& entryPair : m_registeredSurfaceDataProviders) @@ -195,14 +192,14 @@ namespace SurfaceData const SurfaceDataRegistryEntry& entry = entryPair.second; if (!entry.m_bounds.IsValid() || AabbContains2D(entry.m_bounds, inPosition)) { - if (!useTagFilters || hasModifierTags || HasMatchingTags(desiredTags, entry.m_tags)) + if (!useTagFilters || hasModifierTags || HasAnyMatchingTags(desiredTags, entry.m_tags)) { SurfaceDataProviderRequestBus::Event(entryAddress, &SurfaceDataProviderRequestBus::Events::GetSurfacePoints, inPosition, surfacePointList); } } } - if (!surfacePointList.empty()) + if (!surfacePointList.IsEmpty()) { //modify or annotate reported points for (const auto& entryPair : m_registeredSurfaceDataModifiers) @@ -221,10 +218,8 @@ namespace SurfaceData // doesn't add a desired tag, and a surface modifier has the *potential* to add it, but then doesn't. if (useTagFilters) { - FilterPoints(surfacePointList, desiredTags); + surfacePointList.FilterPoints(desiredTags); } - - CombineAndSortNeighboringPoints(surfacePointList); } } @@ -260,8 +255,13 @@ namespace SurfaceData surfacePointLists.clear(); surfacePointLists.resize(totalQueryPositions); + for (auto& surfacePointList : surfacePointLists) + { + surfacePointList.ReserveSpace(m_registeredSurfaceDataProviders.size()); + } + const bool useTagFilters = HasValidTags(desiredTags); - const bool hasModifierTags = useTagFilters && HasMatchingTags(desiredTags, m_registeredModifierTags); + const bool hasModifierTags = useTagFilters && HasAnyMatchingTags(desiredTags, m_registeredModifierTags); // Loop through each data provider, and query all the points for each one. This allows us to check the tags and the overall // AABB bounds just once per provider, instead of once per point. It also allows for an eventual optimization in which we could @@ -270,7 +270,7 @@ namespace SurfaceData { bool hasInfiniteBounds = !provider.m_bounds.IsValid(); - if (!useTagFilters || hasModifierTags || HasMatchingTags(desiredTags, provider.m_tags)) + if (!useTagFilters || hasModifierTags || HasAnyMatchingTags(desiredTags, provider.m_tags)) { for (size_t index = 0; index < totalQueryPositions; index++) { @@ -299,7 +299,7 @@ namespace SurfaceData { const auto& inPosition = inPositions[index]; SurfacePointList& surfacePointList = surfacePointLists[index]; - if (!surfacePointList.empty()) + if (!surfacePointList.IsEmpty()) { if (hasInfiniteBounds || AabbContains2D(entry.m_bounds, inPosition)) { @@ -315,82 +315,14 @@ namespace SurfaceData // same XY coordinates and extremely similar Z values. This produces results that are sorted in decreasing Z order. // Also, this filters out any remaining points that don't match the desired tag list. This can happen when a surface provider // doesn't add a desired tag, and a surface modifier has the *potential* to add it, but then doesn't. - for (auto& surfacePointList : surfacePointLists) + if (useTagFilters) { - if (useTagFilters) + for (auto& surfacePointList : surfacePointLists) { - FilterPoints(surfacePointList, desiredTags); + surfacePointList.FilterPoints(desiredTags); } - CombineAndSortNeighboringPoints(surfacePointList); - } - - } - - void SurfaceDataSystemComponent::FilterPoints(SurfacePointList& sourcePointList, const SurfaceTagVector& desiredTags) const - { - // Before sorting and combining, filter out any points that don't match our search tags. - sourcePointList.erase( - AZStd::remove_if( - sourcePointList.begin(), sourcePointList.end(), - [desiredTags](SurfacePoint& point) -> bool - { - return !HasMatchingTags(point.m_masks, desiredTags); - }), - sourcePointList.end()); - } - - void SurfaceDataSystemComponent::CombineAndSortNeighboringPoints(SurfacePointList& sourcePointList) const - { - // If there's only 0 or 1 point, there is no sorting or combining that needs to happen, so just return. - if (sourcePointList.size() <= 1) - { - return; } - // Efficient point consolidation requires the points to be pre-sorted so we are only comparing/combining neighbors. - // Sort XY points together, with decreasing Z. - AZStd::sort(sourcePointList.begin(), sourcePointList.end(), [](const SurfacePoint& a, const SurfacePoint& b) - { - // Our goal is to have identical XY values sorted adjacent to each other with decreasing Z. - // We sort increasing Y, then increasing X, then decreasing Z, because we need to compare all 3 values for a - // stable sort. The choice of increasing Y first is because we'll often generate the points as ranges of X values within - // ranges of Y values, so this will produce the most usable and expected output sort. - if (a.m_position.GetY() != b.m_position.GetY()) - { - return a.m_position.GetY() < b.m_position.GetY(); - } - if (a.m_position.GetX() != b.m_position.GetX()) - { - return a.m_position.GetX() < b.m_position.GetX(); - } - if (a.m_position.GetZ() != b.m_position.GetZ()) - { - return a.m_position.GetZ() > b.m_position.GetZ(); - } - - // If we somehow ended up with two points with identical positions getting generated, use the entity ID as the tiebreaker - // to guarantee a stable sort. We should never have two identical positions generated from the same entity. - return a.m_entityId < b.m_entityId; - }); - - // iterate over subsequent source points for comparison and consolidation with the last added target/unique point - for (auto pointItr = sourcePointList.begin() + 1; pointItr < sourcePointList.end();) - { - auto prevPointItr = pointItr - 1; - - // (Someday we should add a configurable tolerance for comparison) - if (pointItr->m_position.IsClose(prevPointItr->m_position) && pointItr->m_normal.IsClose(prevPointItr->m_normal)) - { - // consolidate points with similar attributes by adding masks/weights to the previous point and deleting this point. - AddMaxValueForMasks(prevPointItr->m_masks, pointItr->m_masks); - - pointItr = sourcePointList.erase(pointItr); - } - else - { - pointItr++; - } - } } SurfaceDataRegistryHandle SurfaceDataSystemComponent::RegisterSurfaceDataProviderInternal(const SurfaceDataRegistryEntry& entry) diff --git a/Gems/SurfaceData/Code/Source/SurfaceDataSystemComponent.h b/Gems/SurfaceData/Code/Source/SurfaceDataSystemComponent.h index 6ec2cab4eb..bb554cec78 100644 --- a/Gems/SurfaceData/Code/Source/SurfaceDataSystemComponent.h +++ b/Gems/SurfaceData/Code/Source/SurfaceDataSystemComponent.h @@ -58,9 +58,6 @@ namespace SurfaceData void RefreshSurfaceData(const AZ::Aabb& dirtyArea) override; private: - void FilterPoints(SurfacePointList& sourcePointList, const SurfaceTagVector& desiredTags) const; - void CombineAndSortNeighboringPoints(SurfacePointList& sourcePointList) const; - SurfaceDataRegistryHandle RegisterSurfaceDataProviderInternal(const SurfaceDataRegistryEntry& entry); SurfaceDataRegistryEntry UnregisterSurfaceDataProviderInternal(const SurfaceDataRegistryHandle& handle); bool UpdateSurfaceDataProviderInternal(const SurfaceDataRegistryHandle& handle, const SurfaceDataRegistryEntry& entry, AZ::Aabb& oldBounds); diff --git a/Gems/SurfaceData/Code/Source/SurfaceDataTypes.cpp b/Gems/SurfaceData/Code/Source/SurfaceDataTypes.cpp new file mode 100644 index 0000000000..3071fd02ee --- /dev/null +++ b/Gems/SurfaceData/Code/Source/SurfaceDataTypes.cpp @@ -0,0 +1,319 @@ +/* + * Copyright (c) Contributors to the Open 3D Engine Project. + * For complete copyright and license terms please see the LICENSE at the root of this distribution. + * + * SPDX-License-Identifier: Apache-2.0 OR MIT + * + */ + +#include +#include + +namespace SurfaceData +{ + void SurfaceTagWeights::AssignSurfaceTagWeights(const AzFramework::SurfaceData::SurfaceTagWeightList& weights) + { + m_weights.clear(); + m_weights.reserve(weights.size()); + for (auto& weight : weights) + { + m_weights.emplace(weight.m_surfaceType, weight.m_weight); + } + } + + void SurfaceTagWeights::AssignSurfaceTagWeights(const SurfaceTagVector& tags, float weight) + { + m_weights.clear(); + m_weights.reserve(tags.size()); + for (auto& tag : tags) + { + m_weights[tag] = weight; + } + } + + void SurfaceTagWeights::AddSurfaceTagWeight(const AZ::Crc32 tag, const float value) + { + m_weights[tag] = value; + } + + void SurfaceTagWeights::Clear() + { + m_weights.clear(); + } + + size_t SurfaceTagWeights::GetSize() const + { + return m_weights.size(); + } + + AzFramework::SurfaceData::SurfaceTagWeightList SurfaceTagWeights::GetSurfaceTagWeightList() const + { + AzFramework::SurfaceData::SurfaceTagWeightList weights; + weights.reserve(m_weights.size()); + for (auto& weight : m_weights) + { + weights.emplace_back(weight.first, weight.second); + } + return weights; + } + + bool SurfaceTagWeights::operator==(const SurfaceTagWeights& rhs) const + { + // If the lists are different sizes, they're not equal. + if (m_weights.size() != rhs.m_weights.size()) + { + return false; + } + + for (auto& weight : m_weights) + { + auto rhsWeight = rhs.m_weights.find(weight.first); + if ((rhsWeight == rhs.m_weights.end()) || (rhsWeight->second != weight.second)) + { + return false; + } + } + + // All the entries matched, and the lists are the same size, so they're equal. + return true; + } + + bool SurfaceTagWeights::SurfaceWeightsAreEqual(const AzFramework::SurfaceData::SurfaceTagWeightList& compareWeights) const + { + // If the lists are different sizes, they're not equal. + if (m_weights.size() != compareWeights.size()) + { + return false; + } + + for (auto& weight : m_weights) + { + auto maskEntry = AZStd::find_if( + compareWeights.begin(), compareWeights.end(), + [weight](const AzFramework::SurfaceData::SurfaceTagWeight& compareWeight) -> bool + { + return (weight.first == compareWeight.m_surfaceType) && (weight.second == compareWeight.m_weight); + }); + + // If we didn't find a match, they're not equal. + if (maskEntry == compareWeights.end()) + { + return false; + } + } + + // All the entries matched, and the lists are the same size, so they're equal. + return true; + } + + void SurfaceTagWeights::EnumerateWeights(AZStd::function weightCallback) const + { + for (auto& [tag, weight] : m_weights) + { + if (!weightCallback(tag, weight)) + { + break; + } + } + } + + bool SurfaceTagWeights::HasValidTags() const + { + for (const auto& sourceTag : m_weights) + { + if (sourceTag.first != Constants::s_unassignedTagCrc) + { + return true; + } + } + return false; + } + + bool SurfaceTagWeights::HasMatchingTag(const AZ::Crc32& sampleTag) const + { + return m_weights.find(sampleTag) != m_weights.end(); + } + + bool SurfaceTagWeights::HasAnyMatchingTags(const SurfaceTagVector& sampleTags) const + { + for (const auto& sampleTag : sampleTags) + { + if (HasMatchingTag(sampleTag)) + { + return true; + } + } + + return false; + } + + bool SurfaceTagWeights::HasMatchingTag(const AZ::Crc32& sampleTag, float weightMin, float weightMax) const + { + auto maskItr = m_weights.find(sampleTag); + return maskItr != m_weights.end() && weightMin <= maskItr->second && weightMax >= maskItr->second; + } + + bool SurfaceTagWeights::HasAnyMatchingTags(const SurfaceTagVector& sampleTags, float weightMin, float weightMax) const + { + for (const auto& sampleTag : sampleTags) + { + if (HasMatchingTag(sampleTag, weightMin, weightMax)) + { + return true; + } + } + + return false; + } + + + + + SurfacePointList::SurfacePointList(AZStd::initializer_list surfacePoints) + { + ReserveSpace(surfacePoints.size()); + + for (auto& point : surfacePoints) + { + SurfaceTagWeights weights(point.m_surfaceTags); + AddSurfacePoint(AZ::EntityId(), point.m_position, point.m_normal, weights); + } + } + + void SurfacePointList::AddSurfacePoint(const AZ::EntityId& entityId, + const AZ::Vector3& position, const AZ::Vector3& normal, const SurfaceTagWeights& masks) + { + // When adding a surface point, we'll either merge it with a similar existing point, or else add it in order of + // decreasing Z, so that our final results are sorted. + + for (size_t index = 0; index < m_surfacePositionList.size(); ++index) + { + // (Someday we should add a configurable tolerance for comparison) + if (m_surfacePositionList[index].IsClose(position) && m_surfaceNormalList[index].IsClose(normal)) + { + // consolidate points with similar attributes by adding masks/weights to the similar point instead of adding a new one. + m_surfaceWeightsList[index].AddSurfaceWeightsIfGreater(masks); + return; + } + else if (m_surfacePositionList[index].GetZ() < position.GetZ()) + { + m_pointBounds.AddPoint(position); + m_surfacePositionList.insert(m_surfacePositionList.begin() + index, position); + m_surfaceNormalList.insert(m_surfaceNormalList.begin() + index, normal); + m_surfaceWeightsList.insert(m_surfaceWeightsList.begin() + index, masks); + m_surfaceCreatorIdList.insert(m_surfaceCreatorIdList.begin() + index, entityId); + return; + } + } + + // The point wasn't merged and the sort puts it at the end, so just add the point to the end of the list. + m_pointBounds.AddPoint(position); + m_surfacePositionList.emplace_back(position); + m_surfaceNormalList.emplace_back(normal); + m_surfaceWeightsList.emplace_back(masks); + m_surfaceCreatorIdList.emplace_back(entityId); + } + + void SurfacePointList::Clear() + { + m_surfacePositionList.clear(); + m_surfaceNormalList.clear(); + m_surfaceWeightsList.clear(); + m_surfaceCreatorIdList.clear(); + } + + void SurfacePointList::ReserveSpace(size_t maxPointsPerInput) + { + AZ_Assert( + m_surfacePositionList.size() < maxPointsPerInput, + "Trying to reserve space on a list that is already using more points than requested."); + + m_surfaceCreatorIdList.reserve(maxPointsPerInput); + m_surfacePositionList.reserve(maxPointsPerInput); + m_surfaceNormalList.reserve(maxPointsPerInput); + m_surfaceWeightsList.reserve(maxPointsPerInput); + } + + bool SurfacePointList::IsEmpty() const + { + return m_surfacePositionList.empty(); + } + + size_t SurfacePointList::GetSize() const + { + return m_surfacePositionList.size(); + } + + void SurfacePointList::EnumeratePoints( + AZStd::function + pointCallback) const + { + for (size_t index = 0; index < m_surfacePositionList.size(); index++) + { + if (!pointCallback(m_surfacePositionList[index], m_surfaceNormalList[index], m_surfaceWeightsList[index])) + { + break; + } + } + } + + void SurfacePointList::ModifySurfaceWeights( + const AZ::EntityId& currentEntityId, + AZStd::function modificationWeightCallback) + { + for (size_t index = 0; index < m_surfacePositionList.size(); index++) + { + if (m_surfaceCreatorIdList[index] != currentEntityId) + { + modificationWeightCallback(m_surfacePositionList[index], m_surfaceWeightsList[index]); + } + } + } + + AzFramework::SurfaceData::SurfacePoint SurfacePointList::GetHighestSurfacePoint() const + { + AzFramework::SurfaceData::SurfacePoint point; + point.m_position = m_surfacePositionList.front(); + point.m_normal = m_surfaceNormalList.front(); + point.m_surfaceTags = m_surfaceWeightsList.front().GetSurfaceTagWeightList(); + + return point; + } + + void SurfacePointList::FilterPoints(const SurfaceTagVector& desiredTags) + { + // Filter out any points that don't match our search tags. + // This has to be done after the Surface Modifiers have processed the points, not at point insertion time, because + // Surface Modifiers add tags to existing points. + size_t listSize = m_surfacePositionList.size(); + size_t index = 0; + for (; index < listSize; index++) + { + if (!m_surfaceWeightsList[index].HasAnyMatchingTags(desiredTags)) + { + break; + } + } + + if (index != listSize) + { + size_t next = index + 1; + for (; next < listSize; ++next) + { + if (m_surfaceWeightsList[index].HasAnyMatchingTags(desiredTags)) + { + m_surfaceCreatorIdList[index] = m_surfaceCreatorIdList[next]; + m_surfacePositionList[index] = m_surfacePositionList[next]; + m_surfaceNormalList[index] = m_surfaceNormalList[next]; + m_surfaceWeightsList[index] = m_surfaceWeightsList[next]; + ++index; + } + } + + m_surfaceCreatorIdList.resize(index); + m_surfacePositionList.resize(index); + m_surfaceNormalList.resize(index); + m_surfaceWeightsList.resize(index); + } + } +} diff --git a/Gems/SurfaceData/Code/Tests/SurfaceDataBenchmarks.cpp b/Gems/SurfaceData/Code/Tests/SurfaceDataBenchmarks.cpp index 65487c155b..226a711cff 100644 --- a/Gems/SurfaceData/Code/Tests/SurfaceDataBenchmarks.cpp +++ b/Gems/SurfaceData/Code/Tests/SurfaceDataBenchmarks.cpp @@ -190,7 +190,7 @@ namespace UnitTest for (float x = 0.0f; x < worldSize; x += 1.0f) { AZ::Vector3 queryPosition(x, y, 0.0f); - points.clear(); + points.Clear(); SurfaceData::SurfaceDataSystemRequestBus::Broadcast( &SurfaceData::SurfaceDataSystemRequestBus::Events::GetSurfacePoints, queryPosition, filterTags, points); diff --git a/Gems/SurfaceData/Code/Tests/SurfaceDataColliderComponentTest.cpp b/Gems/SurfaceData/Code/Tests/SurfaceDataColliderComponentTest.cpp index c51ea49f14..884c831393 100644 --- a/Gems/SurfaceData/Code/Tests/SurfaceDataColliderComponentTest.cpp +++ b/Gems/SurfaceData/Code/Tests/SurfaceDataColliderComponentTest.cpp @@ -26,7 +26,8 @@ namespace UnitTest : public AzPhysics::SimulatedBodyComponentRequestsBus::Handler { public: - MockPhysicsWorldBusProvider(const AZ::EntityId& id, AZ::Vector3 inPosition, bool setHitResult, const SurfaceData::SurfacePoint& hitResult) + MockPhysicsWorldBusProvider( + const AZ::EntityId& id, AZ::Vector3 inPosition, bool setHitResult, const AzFramework::SurfaceData::SurfacePoint& hitResult) { AzPhysics::SimulatedBodyComponentRequestsBus::Handler::BusConnect(id); @@ -77,51 +78,36 @@ namespace UnitTest { protected: // Create a new SurfacePoint with the given fields. - SurfaceData::SurfacePoint CreateSurfacePoint(AZ::EntityId id, AZ::Vector3 position, AZ::Vector3 normal, AZStd::vector> tags) + AzFramework::SurfaceData::SurfacePoint CreateSurfacePoint( + AZ::Vector3 position, AZ::Vector3 normal, AZStd::vector> tags) { - SurfaceData::SurfacePoint point; - point.m_entityId = id; + AzFramework::SurfaceData::SurfacePoint point; point.m_position = position; point.m_normal = normal; for (auto& tag : tags) { - point.m_masks[SurfaceData::SurfaceTag(tag.first)] = tag.second; + point.m_surfaceTags.emplace_back(SurfaceData::SurfaceTag(tag.first), tag.second); } return point; } // Compare two surface points. - bool SurfacePointsAreEqual(const SurfaceData::SurfacePoint& lhs, const SurfaceData::SurfacePoint& rhs) + bool SurfacePointsAreEqual( + const AZ::Vector3& lhsPosition, + const AZ::Vector3& lhsNormal, + const SurfaceData::SurfaceTagWeights& lhsMasks, + const AzFramework::SurfaceData::SurfacePoint& rhs) { - if ((lhs.m_entityId != rhs.m_entityId) - || (lhs.m_position != rhs.m_position) - || (lhs.m_normal != rhs.m_normal) - || (lhs.m_masks.size() != rhs.m_masks.size())) - { - return false; - } - - for (auto& mask : lhs.m_masks) - { - auto maskEntry = rhs.m_masks.find(mask.first); - if (maskEntry == rhs.m_masks.end()) - { - return false; - } - if (maskEntry->second != mask.second) - { - return false; - } - } - - return true; + return ((lhsPosition == rhs.m_position) + && (lhsNormal == rhs.m_normal) + && (lhsMasks.SurfaceWeightsAreEqual(rhs.m_surfaceTags))); } // Common test function for testing the "Provider" functionality of the component. // Given a set of tags and an expected output, check to see if the component provides the // expected output point. void TestSurfaceDataColliderProvider(AZStd::vector providerTags, bool pointOnProvider, - AZ::Vector3 queryPoint, const SurfaceData::SurfacePoint& expectedOutput) + AZ::Vector3 queryPoint, const AzFramework::SurfaceData::SurfacePoint& expectedOutput) { // This lets our component register with surfaceData successfully. MockSurfaceDataSystem mockSurfaceDataSystem; @@ -135,8 +121,6 @@ namespace UnitTest // Create the test entity with the SurfaceDataCollider component and the required physics collider dependency auto entity = CreateEntity(); - // Initialize our Entity ID to the one passed in on the expectedOutput - entity->SetId(expectedOutput.m_entityId); // Create the components CreateComponent(entity.get()); CreateComponent(entity.get(), config); @@ -155,17 +139,25 @@ namespace UnitTest queryPoint, pointList); if (pointOnProvider) { - ASSERT_TRUE(pointList.size() == 1); - EXPECT_TRUE(SurfacePointsAreEqual(pointList[0], expectedOutput)); + ASSERT_EQ(pointList.GetSize(), 1); + pointList.EnumeratePoints( + [this, expectedOutput]( + const AZ::Vector3& position, const AZ::Vector3& normal, const SurfaceData::SurfaceTagWeights& masks) -> bool + { + EXPECT_TRUE(SurfacePointsAreEqual(position, normal, masks, expectedOutput)); + return true; + }); } else { - EXPECT_TRUE(pointList.empty()); + EXPECT_TRUE(pointList.IsEmpty()); } } void TestSurfaceDataColliderModifier(AZStd::vector modifierTags, - const SurfaceData::SurfacePoint& input, bool pointInCollider, const SurfaceData::SurfacePoint& expectedOutput) + const AzFramework::SurfaceData::SurfacePoint& input, + bool pointInCollider, + const AzFramework::SurfaceData::SurfacePoint& expectedOutput) { // This lets our component register with surfaceData successfully. MockSurfaceDataSystem mockSurfaceDataSystem; @@ -191,11 +183,18 @@ namespace UnitTest EXPECT_TRUE(modifierHandle != SurfaceData::InvalidSurfaceDataRegistryHandle); // Call ModifySurfacePoints and verify the results - SurfaceData::SurfacePointList pointList; - pointList.emplace_back(input); + // Add the surface point with a different entity ID than the entity doing the modification, so that the point doesn't get + // filtered out. + SurfaceData::SurfacePointList pointList = { input }; SurfaceData::SurfaceDataModifierRequestBus::Event(modifierHandle, &SurfaceData::SurfaceDataModifierRequestBus::Events::ModifySurfacePoints, pointList); - ASSERT_TRUE(pointList.size() == 1); - EXPECT_TRUE(SurfacePointsAreEqual(pointList[0], expectedOutput)); + ASSERT_EQ(pointList.GetSize(), 1); + pointList.EnumeratePoints( + [this, expectedOutput]( + const AZ::Vector3& position, const AZ::Vector3& normal, const SurfaceData::SurfaceTagWeights& masks) -> bool + { + EXPECT_TRUE(SurfacePointsAreEqual(position, normal, masks, expectedOutput)); + return true; + }); } }; @@ -232,7 +231,8 @@ namespace UnitTest // Set the expected output to an arbitrary entity ID, position, and normal. // We'll use this to initialize the mock physics, so the output of the query should match. const char* tag = "test_mask"; - SurfaceData::SurfacePoint expectedOutput = CreateSurfacePoint(AZ::EntityId(0x12345678), AZ::Vector3(1.0f), AZ::Vector3::CreateAxisZ(), + AzFramework::SurfaceData::SurfacePoint expectedOutput = + CreateSurfacePoint(AZ::Vector3(1.0f), AZ::Vector3::CreateAxisZ(), { AZStd::make_pair(tag, 1.0f) }); // Query from the same XY, but one unit higher on Z, just so we can verify that the output returns the collision @@ -248,7 +248,8 @@ namespace UnitTest // Set the expected output to an arbitrary entity ID, position, and normal. // We'll use this to initialize the mock physics. const char* tag = "test_mask"; - SurfaceData::SurfacePoint expectedOutput = CreateSurfacePoint(AZ::EntityId(0x12345678), AZ::Vector3(1.0f), AZ::Vector3::CreateAxisZ(), + AzFramework::SurfaceData::SurfacePoint expectedOutput = + CreateSurfacePoint(AZ::Vector3(1.0f), AZ::Vector3::CreateAxisZ(), { AZStd::make_pair(tag, 1.0f) }); // Query from the same XY, but one unit higher on Z. However, we're also telling our test to provide @@ -266,9 +267,9 @@ namespace UnitTest // We'll use this to initialize the mock physics. const char* tag1 = "test_mask1"; const char* tag2 = "test_mask2"; - SurfaceData::SurfacePoint expectedOutput = CreateSurfacePoint(AZ::EntityId(0x12345678), AZ::Vector3(1.0f), AZ::Vector3::CreateAxisZ(), - { AZStd::make_pair(tag1, 1.0f), - AZStd::make_pair(tag2, 1.0f) }); + AzFramework::SurfaceData::SurfacePoint expectedOutput = CreateSurfacePoint( + AZ::Vector3(1.0f), AZ::Vector3::CreateAxisZ(), + { AZStd::make_pair(tag1, 1.0f), AZStd::make_pair(tag2, 1.0f) }); // Query from the same XY, but one unit higher on Z, just so we can verify that the output returns the collision // result, not the input point. @@ -281,11 +282,12 @@ namespace UnitTest // Verify that for a point inside the collider, the output point contains the correct tag and value. // Set arbitrary input data - SurfaceData::SurfacePoint input = CreateSurfacePoint(AZ::EntityId(0x12345678), AZ::Vector3(1.0f), AZ::Vector3(0.0f), {}); + AzFramework::SurfaceData::SurfacePoint input = CreateSurfacePoint(AZ::Vector3(1.0f), AZ::Vector3(0.0f), {}); // Output should match the input, but with an added tag / value const char* tag = "test_mask"; - SurfaceData::SurfacePoint expectedOutput = CreateSurfacePoint(input.m_entityId, input.m_position, input.m_normal, - { AZStd::make_pair(tag, 1.0f) }); + AzFramework::SurfaceData::SurfacePoint expectedOutput = + CreateSurfacePoint(input.m_position, input.m_normal, + { AZStd::make_pair(tag, 1.0f) }); constexpr bool pointInCollider = true; TestSurfaceDataColliderModifier({ tag }, input, pointInCollider, expectedOutput); @@ -296,10 +298,10 @@ namespace UnitTest // Verify that for a point outside the collider, the output point contains no tags / values. // Set arbitrary input data - SurfaceData::SurfacePoint input = CreateSurfacePoint(AZ::EntityId(0x12345678), AZ::Vector3(1.0f), AZ::Vector3(0.0f), {}); + AzFramework::SurfaceData::SurfacePoint input = CreateSurfacePoint(AZ::Vector3(1.0f), AZ::Vector3(0.0f), {}); // Output should match the input - no extra tags / values should be added. const char* tag = "test_mask"; - SurfaceData::SurfacePoint expectedOutput = CreateSurfacePoint(input.m_entityId, input.m_position, input.m_normal, {}); + AzFramework::SurfaceData::SurfacePoint expectedOutput = CreateSurfacePoint(input.m_position, input.m_normal, {}); constexpr bool pointInCollider = true; TestSurfaceDataColliderModifier({ tag }, input, !pointInCollider, expectedOutput); @@ -310,11 +312,12 @@ namespace UnitTest // Verify that if the component has multiple tags, all of them get put on the output with the same value. // Set arbitrary input data - SurfaceData::SurfacePoint input = CreateSurfacePoint(AZ::EntityId(0x12345678), AZ::Vector3(1.0f), AZ::Vector3(0.0f), {}); + AzFramework::SurfaceData::SurfacePoint input = CreateSurfacePoint(AZ::Vector3(1.0f), AZ::Vector3(0.0f), {}); // Output should match the input, but with two added tags const char* tag1 = "test_mask1"; const char* tag2 = "test_mask2"; - SurfaceData::SurfacePoint expectedOutput = CreateSurfacePoint(input.m_entityId, input.m_position, input.m_normal, + AzFramework::SurfaceData::SurfacePoint expectedOutput = CreateSurfacePoint( + input.m_position, input.m_normal, { AZStd::make_pair(tag1, 1.0f), AZStd::make_pair(tag2, 1.0f) }); constexpr bool pointInCollider = true; @@ -328,11 +331,13 @@ namespace UnitTest // Set arbitrary input data const char* preservedTag = "preserved_tag"; - SurfaceData::SurfacePoint input = CreateSurfacePoint(AZ::EntityId(0x12345678), AZ::Vector3(1.0f), AZ::Vector3(0.0f), + AzFramework::SurfaceData::SurfacePoint input = + CreateSurfacePoint(AZ::Vector3(1.0f), AZ::Vector3(0.0f), { AZStd::make_pair(preservedTag, 1.0f) }); // Output should match the input, but with two added tags const char* modifierTag = "modifier_tag"; - SurfaceData::SurfacePoint expectedOutput = CreateSurfacePoint(input.m_entityId, input.m_position, input.m_normal, + AzFramework::SurfaceData::SurfacePoint expectedOutput = CreateSurfacePoint( + input.m_position, input.m_normal, { AZStd::make_pair(preservedTag, 1.0f), AZStd::make_pair(modifierTag, 1.0f) }); constexpr bool pointInCollider = true; @@ -349,10 +354,12 @@ namespace UnitTest float inputValue = 0.25f; // Set arbitrary input data - SurfaceData::SurfacePoint input = CreateSurfacePoint(AZ::EntityId(0x12345678), AZ::Vector3(1.0f), AZ::Vector3(0.0f), + AzFramework::SurfaceData::SurfacePoint input = + CreateSurfacePoint(AZ::Vector3(1.0f), AZ::Vector3(0.0f), { AZStd::make_pair(tag, inputValue) }); // Output should match the input, except that the value on the tag gets the higher modifier value - SurfaceData::SurfacePoint expectedOutput = CreateSurfacePoint(input.m_entityId, input.m_position, input.m_normal, + AzFramework::SurfaceData::SurfacePoint expectedOutput = + CreateSurfacePoint(input.m_position, input.m_normal, { AZStd::make_pair(tag, 1.0f) }); constexpr bool pointInCollider = true; diff --git a/Gems/SurfaceData/Code/Tests/SurfaceDataTest.cpp b/Gems/SurfaceData/Code/Tests/SurfaceDataTest.cpp index 2d6d64f65d..39659313f5 100644 --- a/Gems/SurfaceData/Code/Tests/SurfaceDataTest.cpp +++ b/Gems/SurfaceData/Code/Tests/SurfaceDataTest.cpp @@ -54,7 +54,7 @@ class MockSurfaceProvider } private: - AZStd::unordered_map, SurfaceData::SurfacePointList> m_GetSurfacePoints; + AZStd::unordered_map, AZStd::vector> m_GetSurfacePoints; SurfaceData::SurfaceTagVector m_tags; ProviderType m_providerType; AZ::EntityId m_id; @@ -71,15 +71,16 @@ class MockSurfaceProvider { for (float x = start.GetX(); x < end.GetX(); x += stepSize.GetX()) { - SurfaceData::SurfacePointList points; + AZStd::vector points; for (float z = start.GetZ(); z < end.GetZ(); z += stepSize.GetZ()) { - SurfaceData::SurfacePoint point; - point.m_entityId = m_id; + AzFramework::SurfaceData::SurfacePoint point; point.m_position = AZ::Vector3(x, y, z); point.m_normal = AZ::Vector3::CreateAxisZ(); - AddMaxValueForMasks(point.m_masks, m_tags, 1.0f); - + for (auto& tag : m_tags) + { + point.m_surfaceTags.emplace_back(tag, 1.0f); + } points.push_back(point); } m_GetSurfacePoints[AZStd::pair(x, y)] = points; @@ -150,7 +151,8 @@ class MockSurfaceProvider { for (auto& point : surfacePoints->second) { - surfacePointList.push_back(point); + SurfaceData::SurfaceTagWeights weights(point.m_surfaceTags); + surfacePointList.AddSurfacePoint(m_id, point.m_position, point.m_normal, weights); } } } @@ -159,16 +161,17 @@ class MockSurfaceProvider // SurfaceDataModifierRequestBus void ModifySurfacePoints(SurfaceData::SurfacePointList& surfacePointList) const override { - for (auto& point : surfacePointList) - { - auto surfacePoints = m_GetSurfacePoints.find(AZStd::make_pair(point.m_position.GetX(), point.m_position.GetY())); - - if (surfacePoints != m_GetSurfacePoints.end()) + surfacePointList.ModifySurfaceWeights( + AZ::EntityId(), + [this](const AZ::Vector3& position, SurfaceData::SurfaceTagWeights& weights) { - AddMaxValueForMasks(point.m_masks, m_tags, 1.0f); - } - } + auto surfacePoints = m_GetSurfacePoints.find(AZStd::make_pair(position.GetX(), position.GetY())); + if (surfacePoints != m_GetSurfacePoints.end()) + { + weights.AddSurfaceWeightsIfGreater(m_tags, 1.0f); + } + }); } SurfaceData::SurfaceDataRegistryHandle m_providerHandle = SurfaceData::InvalidSurfaceDataRegistryHandle; @@ -205,42 +208,49 @@ public: } void CompareSurfacePointListWithGetSurfacePoints( - const AZStd::vector& queryPositions, SurfaceData::SurfacePointLists surfacePointLists, + const AZStd::vector& queryPositions, SurfaceData::SurfacePointLists& surfacePointLists, const SurfaceData::SurfaceTagVector& testTags) { - SurfaceData::SurfacePointLists singleQueryPointLists; + AZStd::vector singleQueryResults; for (auto& queryPosition : queryPositions) { SurfaceData::SurfacePointList tempSingleQueryPointList; SurfaceData::SurfaceDataSystemRequestBus::Broadcast( &SurfaceData::SurfaceDataSystemRequestBus::Events::GetSurfacePoints, queryPosition, testTags, tempSingleQueryPointList); - singleQueryPointLists.push_back(tempSingleQueryPointList); + tempSingleQueryPointList.EnumeratePoints( + [&singleQueryResults]( + const AZ::Vector3& position, const AZ::Vector3& normal, const SurfaceData::SurfaceTagWeights& masks) -> bool + { + AzFramework::SurfaceData::SurfacePoint point; + point.m_position = position; + point.m_normal = normal; + point.m_surfaceTags = masks.GetSurfaceTagWeightList(); + singleQueryResults.emplace_back(AZStd::move(point)); + return true; + }); } - // Verify the two point lists are the same size, then verify that each point in each list is equal. - ASSERT_EQ(singleQueryPointLists.size(), surfacePointLists.size()); + // Verify that each point in each list is equal. + AzFramework::SurfaceData::SurfacePoint* singleQueryPoint = singleQueryResults.begin(); for (size_t listIndex = 0; listIndex < surfacePointLists.size(); listIndex++) { auto& surfacePointList = surfacePointLists[listIndex]; - auto& singleQueryPointList = singleQueryPointLists[listIndex]; - - ASSERT_EQ(singleQueryPointList.size(), surfacePointList.size()); - for (size_t index = 0; index < surfacePointList.size(); index++) - { - SurfaceData::SurfacePoint& point1 = surfacePointList[index]; - SurfaceData::SurfacePoint& point2 = singleQueryPointList[index]; - - EXPECT_EQ(point1.m_entityId, point2.m_entityId); - EXPECT_EQ(point1.m_position, point2.m_position); - EXPECT_EQ(point1.m_normal, point2.m_normal); - ASSERT_EQ(point1.m_masks.size(), point2.m_masks.size()); - for (auto& mask : point1.m_masks) + surfacePointList.EnumeratePoints( + [&singleQueryPoint, singleQueryResults]( + const AZ::Vector3& position, const AZ::Vector3& normal, const SurfaceData::SurfaceTagWeights& masks) -> bool { - EXPECT_EQ(mask.second, point2.m_masks[mask.first]); - } - } + EXPECT_NE(singleQueryPoint, singleQueryResults.end()); + + EXPECT_EQ(position, singleQueryPoint->m_position); + EXPECT_EQ(normal, singleQueryPoint->m_normal); + EXPECT_TRUE(masks.SurfaceWeightsAreEqual(singleQueryPoint->m_surfaceTags)); + ++singleQueryPoint; + return true; + }); } + + EXPECT_EQ(singleQueryPoint, singleQueryResults.end()); } @@ -488,13 +498,18 @@ TEST_F(SurfaceDataTestApp, SurfaceData_TestSurfacePointsFromRegion) // We *could* check every mask as well for completeness, but that seems like overkill. for (auto& pointList : availablePointsPerPosition) { - EXPECT_EQ(pointList.size(), 2); - EXPECT_EQ(pointList[0].m_position.GetZ(), 4.0f); - EXPECT_EQ(pointList[1].m_position.GetZ(), 0.0f); - for (auto& point : pointList) - { - EXPECT_EQ(point.m_masks.size(), providerTags.size()); - } + EXPECT_EQ(pointList.GetSize(), 2); + float expectedZ = 4.0f; + pointList.EnumeratePoints( + [providerTags, + &expectedZ](const AZ::Vector3& position, [[maybe_unused]] const AZ::Vector3& normal, + const SurfaceData::SurfaceTagWeights& masks) -> bool + { + EXPECT_EQ(position.GetZ(), expectedZ); + EXPECT_EQ(masks.GetSize(), providerTags.size()); + expectedZ = (expectedZ == 4.0f) ? 0.0f : 4.0f; + return true; + }); } } @@ -523,7 +538,7 @@ TEST_F(SurfaceDataTestApp, SurfaceData_TestSurfacePointsFromRegion_NoMatchingMas // any of the masks from our mock surface provider. for (auto& queryPosition : availablePointsPerPosition) { - EXPECT_TRUE(queryPosition.empty()); + EXPECT_TRUE(queryPosition.IsEmpty()); } } @@ -551,7 +566,7 @@ TEST_F(SurfaceDataTestApp, SurfaceData_TestSurfacePointsFromRegion_NoMatchingReg // our surface provider. for (auto& pointList : availablePointsPerPosition) { - EXPECT_TRUE(pointList.empty()); + EXPECT_TRUE(pointList.IsEmpty()); } } @@ -601,14 +616,17 @@ TEST_F(SurfaceDataTestApp, SurfaceData_TestSurfacePointsFromRegion_ProviderModif // and each point should have both the "test_surface1" and "test_surface2" tag. for (auto& pointList : availablePointsPerPosition) { - EXPECT_EQ(pointList.size(), 2); + EXPECT_EQ(pointList.GetSize(), 2); float expectedZ = 4.0f; - for (auto& point : pointList) - { - EXPECT_EQ(point.m_position.GetZ(), expectedZ); - EXPECT_EQ(point.m_masks.size(), 2); - expectedZ = (expectedZ == 4.0f) ? 0.0f : 4.0f; - } + pointList.EnumeratePoints( + [&expectedZ](const AZ::Vector3& position, + [[maybe_unused]] const AZ::Vector3& normal, const SurfaceData::SurfaceTagWeights& masks) -> bool + { + EXPECT_EQ(position.GetZ(), expectedZ); + EXPECT_EQ(masks.GetSize(), 2); + expectedZ = (expectedZ == 4.0f) ? 0.0f : 4.0f; + return true; + }); } } } @@ -648,14 +666,20 @@ TEST_F(SurfaceDataTestApp, SurfaceData_TestSurfacePointsFromRegion_SimilarPoints // should have both surface tags on them. for (auto& pointList : availablePointsPerPosition) { - EXPECT_EQ(pointList.size(), 2); - float expectedZ = 4.0005f; - for (auto& point : pointList) - { - EXPECT_EQ(point.m_position.GetZ(), expectedZ); - EXPECT_EQ(point.m_masks.size(), 2); - expectedZ = (expectedZ == 4.0005f) ? 0.0005f : 4.0005f; - } + EXPECT_EQ(pointList.GetSize(), 2); + float expectedZ = 4.0f; + pointList.EnumeratePoints( + [&expectedZ]( + const AZ::Vector3& position, [[maybe_unused]] const AZ::Vector3& normal, + const SurfaceData::SurfaceTagWeights& masks) -> bool + { + // Similar points get merged, but there's no guarantee which value will be kept, so we set our comparison tolerance + // high enough to allow both x.0 and x.0005 to pass. + EXPECT_NEAR(position.GetZ(), expectedZ, 0.001f); + EXPECT_EQ(masks.GetSize(), 2); + expectedZ = (expectedZ == 4.0f) ? 0.0f : 4.0f; + return true; + }); } } @@ -693,11 +717,14 @@ TEST_F(SurfaceDataTestApp, SurfaceData_TestSurfacePointsFromRegion_DissimilarPoi // because the points are far enough apart that they won't merge. for (auto& pointList : availablePointsPerPosition) { - EXPECT_EQ(pointList.size(), 4); - for (auto& point : pointList) - { - EXPECT_EQ(point.m_masks.size(), 1); - } + EXPECT_EQ(pointList.GetSize(), 4); + pointList.EnumeratePoints( + []([[maybe_unused]] const AZ::Vector3& position, [[maybe_unused]] const AZ::Vector3& normal, + const SurfaceData::SurfaceTagWeights& masks) -> bool + { + EXPECT_EQ(masks.GetSize(), 1); + return true; + }); } } diff --git a/Gems/SurfaceData/Code/surfacedata_files.cmake b/Gems/SurfaceData/Code/surfacedata_files.cmake index 4b8ac914d7..1c36ca43a0 100644 --- a/Gems/SurfaceData/Code/surfacedata_files.cmake +++ b/Gems/SurfaceData/Code/surfacedata_files.cmake @@ -19,6 +19,7 @@ set(FILES Include/SurfaceData/Utility/SurfaceDataUtility.h Source/SurfaceDataSystemComponent.cpp Source/SurfaceDataSystemComponent.h + Source/SurfaceDataTypes.cpp Source/SurfaceTag.cpp Source/Components/SurfaceDataColliderComponent.cpp Source/Components/SurfaceDataColliderComponent.h diff --git a/Gems/Terrain/Assets/Shaders/Terrain/TerrainDetailHelpers.azsli b/Gems/Terrain/Assets/Shaders/Terrain/TerrainDetailHelpers.azsli index b566b727ff..9794eec4a3 100644 --- a/Gems/Terrain/Assets/Shaders/Terrain/TerrainDetailHelpers.azsli +++ b/Gems/Terrain/Assets/Shaders/Terrain/TerrainDetailHelpers.azsli @@ -204,16 +204,33 @@ void GetDetailSurfaceForMaterial(inout DetailSurface surface, uint materialId, f { TerrainSrg::DetailMaterialData detailMaterialData = TerrainSrg::m_detailMaterialData[materialId]; + float3x3 uvTransform = (float3x3)detailMaterialData.m_uvTransform; + float2 transformedUv = mul(uvTransform, float3(uv, 1.0)).xy; + + // With different materials in the quad, we can't rely on ddx/ddy of the transformed uv because + // the materials may have different uv transforms. This would create visible seams where the wrong + // mip was being used. Instead, manually calculate the transformed ddx/ddy using the ddx/ddy of the + // original uv. + float2 uvDdx = ddx(uv); float2 uvDdy = ddy(uv); - surface.m_color = GetDetailColor(detailMaterialData, uv, uvDdx, uvDdy); - surface.m_normal = GetDetailNormal(detailMaterialData, uv, uvDdx, uvDdy); - surface.m_roughness = GetDetailRoughness(detailMaterialData, uv, uvDdx, uvDdy); - surface.m_specularF0 = GetDetailSpecularF0(detailMaterialData, uv, uvDdx, uvDdy); - surface.m_metalness = GetDetailMetalness(detailMaterialData, uv, uvDdx, uvDdy); - surface.m_occlusion = GetDetailOcclusion(detailMaterialData, uv, uvDdx, uvDdy); - surface.m_height = GetDetailHeight(detailMaterialData, uv, uvDdx, uvDdy); + float2 uvX = uv + uvDdx; + float2 uvY = uv + uvDdy; + + float2 transformedUvX = mul(uvTransform, float3(uvX, 1.0)).xy; + float2 transformedUvY = mul(uvTransform, float3(uvY, 1.0)).xy; + + float2 transformedUvDdx = transformedUvX - transformedUv; + float2 transformedUvDdy = transformedUvY - transformedUv; + + surface.m_color = GetDetailColor(detailMaterialData, transformedUv, transformedUvDdx, transformedUvDdy); + surface.m_normal = GetDetailNormal(detailMaterialData, transformedUv, transformedUvDdx, transformedUvDdy); + surface.m_roughness = GetDetailRoughness(detailMaterialData, transformedUv, transformedUvDdx, transformedUvDdy); + surface.m_specularF0 = GetDetailSpecularF0(detailMaterialData, transformedUv, transformedUvDdx, transformedUvDdy); + surface.m_metalness = GetDetailMetalness(detailMaterialData, transformedUv, transformedUvDdx, transformedUvDdy); + surface.m_occlusion = GetDetailOcclusion(detailMaterialData, transformedUv, transformedUvDdx, transformedUvDdy); + surface.m_height = GetDetailHeight(detailMaterialData, transformedUv, transformedUvDdx, transformedUvDdy); } // Debugs the detail material by choosing a random color per material ID and rendering it without blending. @@ -279,7 +296,7 @@ bool GetDetailSurface(inout DetailSurface surface, float2 detailMaterialIdCoord, float2 textureSize; TerrainSrg::m_detailMaterialIdImage.GetDimensions(textureSize.x, textureSize.y); - // The detail material id texture wraps since the "center" point can be anywhere in the texture, so mod by texturesize + // The detail material id texture wraps since the "center" point can be anywhere in the texture, so mod by textureSize int2 detailMaterialIdTopLeft = ((int2(detailMaterialIdCoord) % textureSize) + textureSize) % textureSize; int2 detailMaterialIdBottomRight = (detailMaterialIdTopLeft + 1) % textureSize; diff --git a/Gems/Terrain/Code/Source/Components/TerrainSurfaceDataSystemComponent.cpp b/Gems/Terrain/Code/Source/Components/TerrainSurfaceDataSystemComponent.cpp index 9a9cb24e4c..3092f7c000 100644 --- a/Gems/Terrain/Code/Source/Components/TerrainSurfaceDataSystemComponent.cpp +++ b/Gems/Terrain/Code/Source/Components/TerrainSurfaceDataSystemComponent.cpp @@ -159,25 +159,13 @@ namespace Terrain const bool isHole = !isTerrainValidAtPoint; - SurfaceData::SurfacePoint point; - point.m_entityId = GetEntityId(); - point.m_position = terrainSurfacePoint.m_position; - point.m_normal = terrainSurfacePoint.m_normal; - - // Preallocate enough space for all of our terrain's surface tags, plus the default "terrain" / "terrainHole" tag. - point.m_masks.reserve(terrainSurfacePoint.m_surfaceTags.size() + 1); - - // Add all of the surface tags that the terrain has at this point. - for (auto& tag : terrainSurfacePoint.m_surfaceTags) - { - point.m_masks[tag.m_surfaceType] = tag.m_weight; - } + SurfaceData::SurfaceTagWeights weights(terrainSurfacePoint.m_surfaceTags); // Always add a "terrain" or "terrainHole" tag. const AZ::Crc32 terrainTag = isHole ? Constants::s_terrainHoleTagCrc : Constants::s_terrainTagCrc; - point.m_masks[terrainTag] = 1.0f; + weights.AddSurfaceTagWeight(terrainTag, 1.0f); - surfacePointList.push_back(AZStd::move(point)); + surfacePointList.AddSurfacePoint(GetEntityId(), terrainSurfacePoint.m_position, terrainSurfacePoint.m_normal, weights); } AZ::Aabb TerrainSurfaceDataSystemComponent::GetSurfaceAabb() const diff --git a/Gems/Terrain/Code/Source/TerrainRenderer/TerrainDetailMaterialManager.cpp b/Gems/Terrain/Code/Source/TerrainRenderer/TerrainDetailMaterialManager.cpp index 96b363d8c6..a00d2efe59 100644 --- a/Gems/Terrain/Code/Source/TerrainRenderer/TerrainDetailMaterialManager.cpp +++ b/Gems/Terrain/Code/Source/TerrainRenderer/TerrainDetailMaterialManager.cpp @@ -15,6 +15,8 @@ #include #include +#include + #include namespace Terrain @@ -56,6 +58,13 @@ namespace Terrain static const char* const HeightFactor("parallax.factor"); static const char* const HeightOffset("parallax.offset"); static const char* const HeightBlendFactor("parallax.blendFactor"); + static const char* const UvCenter("uv.center"); + static const char* const UvScale("uv.scale"); + static const char* const UvTileU("uv.tileU"); + static const char* const UvTileV("uv.tileV"); + static const char* const UvOffsetU("uv.offsetU"); + static const char* const UvOffsetV("uv.offsetV"); + static const char* const UvRotateDegrees("uv.rotateDegrees"); } namespace TerrainSrgInputs @@ -548,6 +557,36 @@ namespace Terrain applyProperty(HeightOffset, shaderData.m_heightOffset); applyProperty(HeightBlendFactor, shaderData.m_heightBlendFactor); + AZ::Render::UvTransformDescriptor transformDescriptor; + applyProperty(UvCenter, transformDescriptor.m_center); + applyProperty(UvScale, transformDescriptor.m_scale); + applyProperty(UvTileU, transformDescriptor.m_scaleX); + applyProperty(UvTileV, transformDescriptor.m_scaleY); + applyProperty(UvOffsetU, transformDescriptor.m_translateX); + applyProperty(UvOffsetV, transformDescriptor.m_translateY); + applyProperty(UvRotateDegrees, transformDescriptor.m_rotateDegrees); + + AZStd::array order = + { + AZ::Render::TransformType::Rotate, + AZ::Render::TransformType::Translate, + AZ::Render::TransformType::Scale, + }; + + AZ::Matrix3x3 uvTransformMatrix = AZ::Render::CreateUvTransformMatrix(transformDescriptor, order); + uvTransformMatrix.GetRow(0).StoreToFloat3(&shaderData.m_uvTransform[0]); + uvTransformMatrix.GetRow(1).StoreToFloat3(&shaderData.m_uvTransform[4]); + uvTransformMatrix.GetRow(2).StoreToFloat3(&shaderData.m_uvTransform[8]); + + // Store a hash of the matrix in element in an unused portion for quick comparisons in the shader + size_t hash64 = 0; + for (float value : shaderData.m_uvTransform) + { + AZStd::hash_combine(hash64, value); + } + uint32_t hash32 = uint32_t((hash64 ^ (hash64 >> 32)) & 0xFFFFFFFF); + shaderData.m_uvTransform[3] = *reinterpret_cast(&hash32); + m_detailMaterialBufferNeedsUpdate = true; } diff --git a/Gems/Terrain/Code/Source/TerrainRenderer/TerrainDetailMaterialManager.h b/Gems/Terrain/Code/Source/TerrainRenderer/TerrainDetailMaterialManager.h index 667b1b2e85..3f63812e47 100644 --- a/Gems/Terrain/Code/Source/TerrainRenderer/TerrainDetailMaterialManager.h +++ b/Gems/Terrain/Code/Source/TerrainRenderer/TerrainDetailMaterialManager.h @@ -77,7 +77,7 @@ namespace Terrain struct DetailMaterialShaderData { - // Uv + // Uv (data is 3x3, padding each row for explicit alignment) AZStd::array m_uvTransform { 1.0, 0.0, 0.0, 0.0, diff --git a/Gems/Vegetation/Code/Include/Vegetation/Ebuses/AreaRequestBus.h b/Gems/Vegetation/Code/Include/Vegetation/Ebuses/AreaRequestBus.h index 3323e2a805..605369671d 100644 --- a/Gems/Vegetation/Code/Include/Vegetation/Ebuses/AreaRequestBus.h +++ b/Gems/Vegetation/Code/Include/Vegetation/Ebuses/AreaRequestBus.h @@ -56,12 +56,12 @@ namespace Vegetation ClaimHandle m_handle; AZ::Vector3 m_position; AZ::Vector3 m_normal; - SurfaceData::SurfaceTagWeightMap m_masks; + SurfaceData::SurfaceTagWeights m_masks; }; struct ClaimContext { - SurfaceData::SurfaceTagWeightMap m_masks; + SurfaceData::SurfaceTagWeights m_masks; AZStd::vector m_availablePoints; AZStd::function m_existedCallback; AZStd::function m_createdCallback; diff --git a/Gems/Vegetation/Code/Include/Vegetation/InstanceData.h b/Gems/Vegetation/Code/Include/Vegetation/InstanceData.h index 7e685105f7..b13bef5ae7 100644 --- a/Gems/Vegetation/Code/Include/Vegetation/InstanceData.h +++ b/Gems/Vegetation/Code/Include/Vegetation/InstanceData.h @@ -34,7 +34,7 @@ namespace Vegetation AZ::Quaternion m_rotation = AZ::Quaternion::CreateIdentity(); AZ::Quaternion m_alignment = AZ::Quaternion::CreateIdentity(); float m_scale = 1.0f; - SurfaceData::SurfaceTagWeightMap m_masks; //[LY-90908] remove when surface mask filtering is done in area + SurfaceData::SurfaceTagWeights m_masks; //[LY-90908] remove when surface mask filtering is done in area DescriptorPtr m_descriptorPtr; // Determine if two different sets of instance data are similar enough to be considered the same when placing diff --git a/Gems/Vegetation/Code/Source/AreaSystemComponent.cpp b/Gems/Vegetation/Code/Source/AreaSystemComponent.cpp index 9cd9c1a7cb..e575480ff4 100644 --- a/Gems/Vegetation/Code/Source/AreaSystemComponent.cpp +++ b/Gems/Vegetation/Code/Source/AreaSystemComponent.cpp @@ -1091,7 +1091,7 @@ namespace Vegetation const float vegStep = sectorSizeInMeters / static_cast(sectorDensity); //build a free list of all points in the sector for areas to consume - sectorInfo.m_baseContext.m_masks.clear(); + sectorInfo.m_baseContext.m_masks.Clear(); sectorInfo.m_baseContext.m_availablePoints.clear(); sectorInfo.m_baseContext.m_availablePoints.reserve(sectorDensity * sectorDensity); @@ -1127,16 +1127,19 @@ namespace Vegetation uint claimIndex = 0; for (auto& availablePoints : availablePointsPerPosition) { - for (auto& surfacePoint : availablePoints) - { - sectorInfo.m_baseContext.m_availablePoints.push_back(); - ClaimPoint& claimPoint = sectorInfo.m_baseContext.m_availablePoints.back(); - claimPoint.m_handle = CreateClaimHandle(sectorInfo, ++claimIndex); - claimPoint.m_position = surfacePoint.m_position; - claimPoint.m_normal = surfacePoint.m_normal; - claimPoint.m_masks = surfacePoint.m_masks; - SurfaceData::AddMaxValueForMasks(sectorInfo.m_baseContext.m_masks, surfacePoint.m_masks); - } + availablePoints.EnumeratePoints( + [this, §orInfo, + &claimIndex](const AZ::Vector3& position, const AZ::Vector3& normal, const SurfaceData::SurfaceTagWeights& masks) -> bool + { + sectorInfo.m_baseContext.m_availablePoints.push_back(); + ClaimPoint& claimPoint = sectorInfo.m_baseContext.m_availablePoints.back(); + claimPoint.m_handle = CreateClaimHandle(sectorInfo, ++claimIndex); + claimPoint.m_position = position; + claimPoint.m_normal = normal; + claimPoint.m_masks = masks; + sectorInfo.m_baseContext.m_masks.AddSurfaceWeightsIfGreater(masks); + return true; + }); } } diff --git a/Gems/Vegetation/Code/Source/Components/PositionModifierComponent.cpp b/Gems/Vegetation/Code/Source/Components/PositionModifierComponent.cpp index 17457786f2..ed81ebae87 100644 --- a/Gems/Vegetation/Code/Source/Components/PositionModifierComponent.cpp +++ b/Gems/Vegetation/Code/Source/Components/PositionModifierComponent.cpp @@ -306,31 +306,40 @@ namespace Vegetation m_surfaceTagsToSnapToCombined.clear(); m_surfaceTagsToSnapToCombined.reserve( m_configuration.m_surfaceTagsToSnapTo.size() + - instanceData.m_masks.size()); + instanceData.m_masks.GetSize()); m_surfaceTagsToSnapToCombined.insert(m_surfaceTagsToSnapToCombined.end(), m_configuration.m_surfaceTagsToSnapTo.begin(), m_configuration.m_surfaceTagsToSnapTo.end()); - for (const auto& maskPair : instanceData.m_masks) - { - m_surfaceTagsToSnapToCombined.push_back(maskPair.first); - } + instanceData.m_masks.EnumerateWeights( + [this](AZ::Crc32 surfaceType, [[maybe_unused]] float weight) + { + m_surfaceTagsToSnapToCombined.push_back(surfaceType); + return true; + }); //get the intersection data at the new position - m_points.clear(); + m_points.Clear(); SurfaceData::SurfaceDataSystemRequestBus::Broadcast(&SurfaceData::SurfaceDataSystemRequestBus::Events::GetSurfacePoints, instanceData.m_position, m_surfaceTagsToSnapToCombined, m_points); - if (!m_points.empty()) - { - //sort the intersection data by distance from the new position in case there are multiple intersections at different or unrelated heights - AZStd::sort(m_points.begin(), m_points.end(), [&instanceData](const SurfaceData::SurfacePoint& a, const SurfaceData::SurfacePoint& b) + + // Get the point with the closest distance from the new position in case there are multiple intersections at different or + // unrelated heights + float closestPointDistanceSq = AZStd::numeric_limits::max(); + AZ::Vector3 originalInstanceDataPosition = instanceData.m_position; + m_points.EnumeratePoints( + [&instanceData, originalInstanceDataPosition, &closestPointDistanceSq]( + const AZ::Vector3& position, const AZ::Vector3& normal, const SurfaceData::SurfaceTagWeights& masks) -> bool { - return a.m_position.GetDistanceSq(instanceData.m_position) < b.m_position.GetDistanceSq(instanceData.m_position); + float distanceSq = position.GetDistanceSq(originalInstanceDataPosition); + if (distanceSq < closestPointDistanceSq) + { + instanceData.m_position = position; + instanceData.m_normal = normal; + instanceData.m_masks = masks; + closestPointDistanceSq = distanceSq; + } + return true; }); - - instanceData.m_position = m_points[0].m_position; - instanceData.m_normal = m_points[0].m_normal; - instanceData.m_masks = m_points[0].m_masks; - } } instanceData.m_position.SetZ(instanceData.m_position.GetZ() + delta.GetZ()); diff --git a/Gems/Vegetation/Code/Source/Components/SpawnerComponent.cpp b/Gems/Vegetation/Code/Source/Components/SpawnerComponent.cpp index 404e425489..cc7b75f867 100644 --- a/Gems/Vegetation/Code/Source/Components/SpawnerComponent.cpp +++ b/Gems/Vegetation/Code/Source/Components/SpawnerComponent.cpp @@ -416,9 +416,9 @@ namespace Vegetation AZ_PROFILE_FUNCTION(Entity); //reject entire spawner if there are inclusion tags to consider that don't exist in the context - if (SurfaceData::HasValidTags(context.m_masks) && + if (context.m_masks.HasValidTags() && SurfaceData::HasValidTags(m_inclusiveTagsToConsider) && - !SurfaceData::HasMatchingTags(context.m_masks, m_inclusiveTagsToConsider)) + !context.m_masks.HasAnyMatchingTags(m_inclusiveTagsToConsider)) { VEG_PROFILE_METHOD(DebugNotificationBus::TryQueueBroadcast(&DebugNotificationBus::Events::MarkAreaRejectedByMask, GetEntityId())); return; diff --git a/Gems/Vegetation/Code/Source/Components/SurfaceMaskDepthFilterComponent.cpp b/Gems/Vegetation/Code/Source/Components/SurfaceMaskDepthFilterComponent.cpp index b4e65beb3f..aa6c3a8440 100644 --- a/Gems/Vegetation/Code/Source/Components/SurfaceMaskDepthFilterComponent.cpp +++ b/Gems/Vegetation/Code/Source/Components/SurfaceMaskDepthFilterComponent.cpp @@ -210,26 +210,38 @@ namespace Vegetation float lowerZDistanceRange = useOverrides ? instanceData.m_descriptorPtr->m_surfaceTagDistance.m_lowerDistanceInMeters : m_configuration.m_lowerDistance; float upperZDistanceRange = useOverrides ? instanceData.m_descriptorPtr->m_surfaceTagDistance.m_upperDistanceInMeters : m_configuration.m_upperDistance; + bool passesFilter = false; + if (!surfaceTagsToCompare.empty()) { - m_points.clear(); + m_points.Clear(); SurfaceData::SurfaceDataSystemRequestBus::Broadcast(&SurfaceData::SurfaceDataSystemRequestBus::Events::GetSurfacePoints, instanceData.m_position, surfaceTagsToCompare, m_points); float instanceZ = instanceData.m_position.GetZ(); - for (auto& point : m_points) - { - float pointZ = point.m_position.GetZ(); - float zDistance = instanceZ - pointZ; - if (lowerZDistanceRange <= zDistance && zDistance <= upperZDistanceRange) + m_points.EnumeratePoints( + [instanceZ, lowerZDistanceRange, upperZDistanceRange, &passesFilter]( + const AZ::Vector3& position, + [[maybe_unused]] const AZ::Vector3& normal, [[maybe_unused]] const SurfaceData::SurfaceTagWeights& masks) -> bool { + float pointZ = position.GetZ(); + float zDistance = instanceZ - pointZ; + if (lowerZDistanceRange <= zDistance && zDistance <= upperZDistanceRange) + { + passesFilter = true; + return false; + } return true; - } - } + }); } - // if we get here instance is marked filtered - VEG_PROFILE_METHOD(DebugNotificationBus::TryQueueBroadcast(&DebugNotificationBus::Events::FilterInstance, instanceData.m_id, AZStd::string_view("SurfaceDepthMaskFilter"))); - return false; + if (!passesFilter) + { + // if we get here instance is marked filtered + VEG_PROFILE_METHOD(DebugNotificationBus::TryQueueBroadcast( + &DebugNotificationBus::Events::FilterInstance, instanceData.m_id, AZStd::string_view("SurfaceDepthMaskFilter"))); + } + + return passesFilter; } FilterStage SurfaceMaskDepthFilterComponent::GetFilterStage() const diff --git a/Gems/Vegetation/Code/Source/Components/SurfaceMaskFilterComponent.cpp b/Gems/Vegetation/Code/Source/Components/SurfaceMaskFilterComponent.cpp index 9be6764460..23ef5ab3cb 100644 --- a/Gems/Vegetation/Code/Source/Components/SurfaceMaskFilterComponent.cpp +++ b/Gems/Vegetation/Code/Source/Components/SurfaceMaskFilterComponent.cpp @@ -281,14 +281,15 @@ namespace Vegetation const float exclusiveWeightMax = AZ::GetMax(m_configuration.m_exclusiveWeightMin, m_configuration.m_exclusiveWeightMax); if (useCompTags && - SurfaceData::HasMatchingTags(instanceData.m_masks, m_configuration.m_exclusiveSurfaceMasks, exclusiveWeightMin, exclusiveWeightMax)) + instanceData.m_masks.HasAnyMatchingTags(m_configuration.m_exclusiveSurfaceMasks, exclusiveWeightMin, exclusiveWeightMax)) { VEG_PROFILE_METHOD(DebugNotificationBus::TryQueueBroadcast(&DebugNotificationBus::Events::FilterInstance, instanceData.m_id, AZStd::string_view("SurfaceMaskFilter"))); return false; } if (useDescTags && - SurfaceData::HasMatchingTags(instanceData.m_masks, instanceData.m_descriptorPtr->m_exclusiveSurfaceFilterTags, exclusiveWeightMin, exclusiveWeightMax)) + instanceData.m_masks.HasAnyMatchingTags( + instanceData.m_descriptorPtr->m_exclusiveSurfaceFilterTags, exclusiveWeightMin, exclusiveWeightMax)) { VEG_PROFILE_METHOD(DebugNotificationBus::TryQueueBroadcast(&DebugNotificationBus::Events::FilterInstance, instanceData.m_id, AZStd::string_view("SurfaceMaskFilter"))); return false; @@ -299,13 +300,14 @@ namespace Vegetation const float inclusiveWeightMax = AZ::GetMax(m_configuration.m_inclusiveWeightMin, m_configuration.m_inclusiveWeightMax); if (useCompTags && - SurfaceData::HasMatchingTags(instanceData.m_masks, m_configuration.m_inclusiveSurfaceMasks, inclusiveWeightMin, inclusiveWeightMax)) + instanceData.m_masks.HasAnyMatchingTags(m_configuration.m_inclusiveSurfaceMasks, inclusiveWeightMin, inclusiveWeightMax)) { return true; } if (useDescTags && - SurfaceData::HasMatchingTags(instanceData.m_masks, instanceData.m_descriptorPtr->m_inclusiveSurfaceFilterTags, inclusiveWeightMin, inclusiveWeightMax)) + instanceData.m_masks.HasAnyMatchingTags( + instanceData.m_descriptorPtr->m_inclusiveSurfaceFilterTags, inclusiveWeightMin, inclusiveWeightMax)) { return true; } diff --git a/Gems/Vegetation/Code/Source/Debugger/DebugComponent.cpp b/Gems/Vegetation/Code/Source/Debugger/DebugComponent.cpp index b415a7c41c..abb577acfc 100644 --- a/Gems/Vegetation/Code/Source/Debugger/DebugComponent.cpp +++ b/Gems/Vegetation/Code/Source/Debugger/DebugComponent.cpp @@ -862,7 +862,7 @@ void DebugComponent::PrepareNextReport() SurfaceData::SurfacePointList points; SurfaceData::SurfaceDataSystemRequestBus::Broadcast(&SurfaceData::SurfaceDataSystemRequestBus::Events::GetSurfacePoints, pos, SurfaceData::SurfaceTagVector(), points); - timing.m_worldPosition = points.empty() ? pos : points.front().m_position; + timing.m_worldPosition = points.IsEmpty() ? pos : points.GetHighestSurfacePoint().m_position; return timing; }, [](const SectorTracker& sectorTracker, SectorTiming& sectorTiming) diff --git a/Gems/Vegetation/Code/Tests/VegetationComponentFilterTests.cpp b/Gems/Vegetation/Code/Tests/VegetationComponentFilterTests.cpp index bb1efb5ebd..377ed31890 100644 --- a/Gems/Vegetation/Code/Tests/VegetationComponentFilterTests.cpp +++ b/Gems/Vegetation/Code/Tests/VegetationComponentFilterTests.cpp @@ -80,7 +80,7 @@ namespace UnitTest }); Vegetation::InstanceData vegInstance; - vegInstance.m_masks[maskValue] = 1.0f; + vegInstance.m_masks.AddSurfaceTagWeight(maskValue, 1.0f); // passes { @@ -119,8 +119,7 @@ namespace UnitTest MockSurfaceHandler mockSurfaceHandler; mockSurfaceHandler.m_outPosition = AZ::Vector3::CreateZero(); mockSurfaceHandler.m_outNormal = AZ::Vector3::CreateAxisZ(); - mockSurfaceHandler.m_outMasks.clear(); - mockSurfaceHandler.m_outMasks[SurfaceData::Constants::s_unassignedTagCrc] = 1.0f; + mockSurfaceHandler.m_outMasks.AddSurfaceTagWeight(SurfaceData::Constants::s_unassignedTagCrc, 1.0f); // passes { diff --git a/Gems/Vegetation/Code/Tests/VegetationComponentModifierTests.cpp b/Gems/Vegetation/Code/Tests/VegetationComponentModifierTests.cpp index e60a681512..f9ee408140 100644 --- a/Gems/Vegetation/Code/Tests/VegetationComponentModifierTests.cpp +++ b/Gems/Vegetation/Code/Tests/VegetationComponentModifierTests.cpp @@ -71,7 +71,7 @@ namespace UnitTest MockSurfaceHandler mockSurfaceHandler; mockSurfaceHandler.m_outPosition = AZ::Vector3(vegInstance.m_position.GetX(), vegInstance.m_position.GetY(), 6.0f); mockSurfaceHandler.m_outNormal = AZ::Vector3(0.0f, 0.0f, 1.0f); - mockSurfaceHandler.m_outMasks[crcMask] = 1.0f; + mockSurfaceHandler.m_outMasks.AddSurfaceTagWeight(crcMask, 1.0f); entity->Deactivate(); config.m_autoSnapToSurface = true; diff --git a/Gems/Vegetation/Code/Tests/VegetationMocks.h b/Gems/Vegetation/Code/Tests/VegetationMocks.h index c1d83fb68b..d77862d578 100644 --- a/Gems/Vegetation/Code/Tests/VegetationMocks.h +++ b/Gems/Vegetation/Code/Tests/VegetationMocks.h @@ -329,15 +329,11 @@ namespace UnitTest AZ::Vector3 m_outPosition = {}; AZ::Vector3 m_outNormal = {}; - SurfaceData::SurfaceTagWeightMap m_outMasks; + SurfaceData::SurfaceTagWeights m_outMasks; void GetSurfacePoints([[maybe_unused]] const AZ::Vector3& inPosition, [[maybe_unused]] const SurfaceData::SurfaceTagVector& masks, SurfaceData::SurfacePointList& surfacePointList) const override { ++m_count; - SurfaceData::SurfacePoint outPoint; - outPoint.m_position = m_outPosition; - outPoint.m_normal = m_outNormal; - SurfaceData::AddMaxValueForMasks(outPoint.m_masks, m_outMasks); - surfacePointList.push_back(outPoint); + surfacePointList.AddSurfacePoint(AZ::EntityId(), m_outPosition, m_outNormal, m_outMasks); } void GetSurfacePointsFromRegion([[maybe_unused]] const AZ::Aabb& inRegion, [[maybe_unused]] const AZ::Vector2 stepSize, [[maybe_unused]] const SurfaceData::SurfaceTagVector& desiredTags, diff --git a/Registry/sceneassetimporter.setreg b/Registry/sceneassetimporter.setreg index 6fef3a40dc..ea88dc90c2 100644 --- a/Registry/sceneassetimporter.setreg +++ b/Registry/sceneassetimporter.setreg @@ -15,6 +15,11 @@ { "Enable": true, "DefaultMaterial": "Materials/Presets/PBR/default_grid.material" + }, + "TangentGenerateComponent": + { + "DefaultGenerationMethod": "FromSourceScene", + "DebugBitangentFlip": false } } } diff --git a/cmake/3rdParty/Platform/Linux/BuiltInPackages_linux.cmake b/cmake/3rdParty/Platform/Linux/BuiltInPackages_linux.cmake index 742b4a0555..f20b67307b 100644 --- a/cmake/3rdParty/Platform/Linux/BuiltInPackages_linux.cmake +++ b/cmake/3rdParty/Platform/Linux/BuiltInPackages_linux.cmake @@ -38,7 +38,7 @@ ly_associate_package(PACKAGE_NAME OpenMesh-8.1-rev3-linux ly_associate_package(PACKAGE_NAME OpenSSL-1.1.1b-rev2-linux TARGETS OpenSSL PACKAGE_HASH b779426d1e9c5ddf71160d5ae2e639c3b956e0fb5e9fcaf9ce97c4526024e3bc) ly_associate_package(PACKAGE_NAME DirectXShaderCompilerDxc-1.6.2104-o3de-rev3-linux TARGETS DirectXShaderCompilerDxc PACKAGE_HASH 88c4a359325d749bc34090b9ac466424847f3b71ba0de15045cf355c17c07099) ly_associate_package(PACKAGE_NAME SPIRVCross-2021.04.29-rev1-linux TARGETS SPIRVCross PACKAGE_HASH 7889ee5460a688e9b910c0168b31445c0079d363affa07b25d4c8aeb608a0b80) -ly_associate_package(PACKAGE_NAME azslc-1.7.34-rev1-linux TARGETS azslc PACKAGE_HASH 6d7dc671936c34ff70d2632196107ca1b8b2b41acdd021bfbc69a9fd56215c22) +ly_associate_package(PACKAGE_NAME azslc-1.7.35-rev1-linux TARGETS azslc PACKAGE_HASH 273484be06dfc25e8da6a6e17937ae69a2efdb0b4c5f105efa83d6ad54d756e5) ly_associate_package(PACKAGE_NAME zlib-1.2.11-rev5-linux TARGETS ZLIB PACKAGE_HASH 9be5ea85722fc27a8645a9c8a812669d107c68e6baa2ca0740872eaeb6a8b0fc) ly_associate_package(PACKAGE_NAME squish-ccr-deb557d-rev1-linux TARGETS squish-ccr PACKAGE_HASH 85fecafbddc6a41a27c5f59ed4a5dfb123a94cb4666782cf26e63c0a4724c530) ly_associate_package(PACKAGE_NAME astc-encoder-3.2-rev2-linux TARGETS astc-encoder PACKAGE_HASH 71549d1ca9e4d48391b92a89ea23656d3393810e6777879f6f8a9def2db1610c) diff --git a/cmake/3rdParty/Platform/Mac/BuiltInPackages_mac.cmake b/cmake/3rdParty/Platform/Mac/BuiltInPackages_mac.cmake index 2ac3c49480..fba8f73ba1 100644 --- a/cmake/3rdParty/Platform/Mac/BuiltInPackages_mac.cmake +++ b/cmake/3rdParty/Platform/Mac/BuiltInPackages_mac.cmake @@ -41,6 +41,6 @@ ly_associate_package(PACKAGE_NAME squish-ccr-deb557d-rev1-mac ly_associate_package(PACKAGE_NAME astc-encoder-3.2-rev5-mac TARGETS astc-encoder PACKAGE_HASH bdb1146cc6bbacc07901564fe884529d7cacc9bb44895597327341d3b9833ab0) ly_associate_package(PACKAGE_NAME ISPCTexComp-36b80aa-rev1-mac TARGETS ISPCTexComp PACKAGE_HASH 8a4e93277b8face6ea2fd57c6d017bdb55643ed3d6387110bc5f6b3b884dd169) ly_associate_package(PACKAGE_NAME lz4-1.9.3-vcpkg-rev4-mac TARGETS lz4 PACKAGE_HASH 891ff630bf34f7ab1d8eaee2ea0a8f1fca89dbdc63fca41ee592703dd488a73b) -ly_associate_package(PACKAGE_NAME azslc-1.7.34-rev1-mac TARGETS azslc PACKAGE_HASH a9d81946b42ffa55c0d14d6a9249b3340e59a8fb8835e7a96c31df80f14723bc) +ly_associate_package(PACKAGE_NAME azslc-1.7.35-rev1-mac TARGETS azslc PACKAGE_HASH 03cb1ea8c47d4c80c893e2e88767272d5d377838f5ba94b777a45902dd85052e) ly_associate_package(PACKAGE_NAME SQLite-3.37.2-rev1-mac TARGETS SQLite PACKAGE_HASH f9101023f99cf32fc5867284ceb28c0761c23d2c5a4b1748349c69f976a2fbea) ly_associate_package(PACKAGE_NAME AwsIotDeviceSdkCpp-1.15.2-rev2-mac TARGETS AwsIotDeviceSdkCpp PACKAGE_HASH 4854edb7b88fa6437b4e69e87d0ee111a25313ac2a2db5bb2f8b674ba0974f95) diff --git a/cmake/3rdParty/Platform/Windows/BuiltInPackages_windows.cmake b/cmake/3rdParty/Platform/Windows/BuiltInPackages_windows.cmake index fb7fb18235..e24582a453 100644 --- a/cmake/3rdParty/Platform/Windows/BuiltInPackages_windows.cmake +++ b/cmake/3rdParty/Platform/Windows/BuiltInPackages_windows.cmake @@ -47,6 +47,6 @@ ly_associate_package(PACKAGE_NAME squish-ccr-deb557d-rev1-windows ly_associate_package(PACKAGE_NAME astc-encoder-3.2-rev2-windows TARGETS astc-encoder PACKAGE_HASH 17249bfa438afb34e21449865d9c9297471174ae0cea9b2f9def2ee206038295) ly_associate_package(PACKAGE_NAME ISPCTexComp-36b80aa-rev1-windows TARGETS ISPCTexComp PACKAGE_HASH b6fa6ea28a2808a9a5524c72c37789c525925e435770f2d94eb2d387360fa2d0) ly_associate_package(PACKAGE_NAME lz4-1.9.3-vcpkg-rev4-windows TARGETS lz4 PACKAGE_HASH 4ea457b833cd8cfaf8e8e06ed6df601d3e6783b606bdbc44a677f77e19e0db16) -ly_associate_package(PACKAGE_NAME azslc-1.7.34-rev1-windows TARGETS azslc PACKAGE_HASH 44eb2e0fc4b0f1c75d0fb6f24c93a5753655b84dbc3e6ad45389ed3b9cf7a4b0) +ly_associate_package(PACKAGE_NAME azslc-1.7.35-rev1-windows TARGETS azslc PACKAGE_HASH 606aea611f2f20afcd8467ddabeecd3661e946eac3c843756c7df2871c1fb8a0) ly_associate_package(PACKAGE_NAME SQLite-3.37.2-rev1-windows TARGETS SQLite PACKAGE_HASH c1658c8ed5cf0e45d4a5da940c6a6d770b76e0f4f57313b70d0fd306885f015e) ly_associate_package(PACKAGE_NAME AwsIotDeviceSdkCpp-1.15.2-rev1-windows TARGETS AwsIotDeviceSdkCpp PACKAGE_HASH b03475a9f0f7a7e7c90619fba35f1a74fb2b8f4cd33fa07af99f2ae9e0c079dd)