diff --git a/Assets/Engine/SeedAssetList.seed b/Assets/Engine/SeedAssetList.seed
index 77ec509721..579fd3c444 100644
--- a/Assets/Engine/SeedAssetList.seed
+++ b/Assets/Engine/SeedAssetList.seed
@@ -66,779 +66,75 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+
-
+
-
+
-
+
-
+
-
+
-
+
-
+
-
+
-
+
-
+
-
+
-
+
-
+
-
+
-
+
-
+
-
+
@@ -1384,166 +680,6 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
@@ -1632,46 +768,6 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
diff --git a/AutomatedTesting/AutomatedTesting_Dependencies.xml b/AutomatedTesting/AutomatedTesting_Dependencies.xml
index 50a5caea73..98e00a2914 100644
--- a/AutomatedTesting/AutomatedTesting_Dependencies.xml
+++ b/AutomatedTesting/AutomatedTesting_Dependencies.xml
@@ -1,5 +1,4 @@
-
\ No newline at end of file
diff --git a/AutomatedTesting/Gem/PythonTests/Atom/TestSuite_Main_GPU.py b/AutomatedTesting/Gem/PythonTests/Atom/TestSuite_Main_GPU.py
index 249b9c7096..3403d8e9b1 100644
--- a/AutomatedTesting/Gem/PythonTests/Atom/TestSuite_Main_GPU.py
+++ b/AutomatedTesting/Gem/PythonTests/Atom/TestSuite_Main_GPU.py
@@ -226,9 +226,9 @@ class TestMaterialEditor(object):
self, request, workspace, project, launcher_platform, generic_launcher, exe_file_name, cfg_args):
"""
Tests each valid RHI option (Null RHI excluded) can be launched with the MaterialEditor.
- Checks for the "Finished loading viewport configurtions." success message post lounch.
+ Checks for the "Finished loading viewport configurations." success message post launch.
"""
- expected_lines = ["Finished loading viewport configurtions."]
+ expected_lines = ["Finished loading viewport configurations."]
unexpected_lines = [
# "Trace::Assert",
# "Trace::Error",
@@ -241,7 +241,7 @@ class TestMaterialEditor(object):
generic_launcher,
editor_script="",
run_python="--runpython",
- timeout=30,
+ timeout=60,
expected_lines=expected_lines,
unexpected_lines=unexpected_lines,
halt_on_unexpected=False,
diff --git a/AutomatedTesting/Gem/PythonTests/largeworlds/CMakeLists.txt b/AutomatedTesting/Gem/PythonTests/largeworlds/CMakeLists.txt
index f1299ddc2d..d5c7fd5109 100644
--- a/AutomatedTesting/Gem/PythonTests/largeworlds/CMakeLists.txt
+++ b/AutomatedTesting/Gem/PythonTests/largeworlds/CMakeLists.txt
@@ -96,19 +96,6 @@ if(PAL_TRAIT_BUILD_TESTS_SUPPORTED AND PAL_TRAIT_BUILD_HOST_TOOLS AND PAL_TRAIT_
## GradientSignal ##
- ly_add_pytest(
- NAME AutomatedTesting::GradientSignalTests_Periodic
- TEST_SERIAL
- TEST_SUITE periodic
- PATH ${CMAKE_CURRENT_LIST_DIR}/gradient_signal/TestSuite_Periodic.py
- RUNTIME_DEPENDENCIES
- AZ::AssetProcessor
- Legacy::Editor
- AutomatedTesting.Assets
- COMPONENT
- LargeWorlds
- )
-
ly_add_pytest(
NAME AutomatedTesting::GradientSignalTests_Periodic_Optimized
TEST_SERIAL
diff --git a/AutomatedTesting/Gem/PythonTests/largeworlds/gradient_signal/TestSuite_Periodic_Optimized.py b/AutomatedTesting/Gem/PythonTests/largeworlds/gradient_signal/TestSuite_Periodic_Optimized.py
index f996a1f8c3..514504d324 100644
--- a/AutomatedTesting/Gem/PythonTests/largeworlds/gradient_signal/TestSuite_Periodic_Optimized.py
+++ b/AutomatedTesting/Gem/PythonTests/largeworlds/gradient_signal/TestSuite_Periodic_Optimized.py
@@ -10,7 +10,6 @@ import pytest
from ly_test_tools.o3de.editor_test import EditorSingleTest, EditorSharedTest, EditorParallelTest, EditorTestSuite
-@pytest.mark.xfail(reason="Optimized tests are experimental, we will enable xfail and monitor them temporarily.")
@pytest.mark.SUITE_periodic
@pytest.mark.parametrize("launcher_platform", ['windows_editor'])
@pytest.mark.parametrize("project", ["AutomatedTesting"])
diff --git a/AutomatedTesting/Gem/PythonTests/prefab/Prefab.py b/AutomatedTesting/Gem/PythonTests/prefab/Prefab.py
index 14a1ab62f0..9b4d2d1393 100644
--- a/AutomatedTesting/Gem/PythonTests/prefab/Prefab.py
+++ b/AutomatedTesting/Gem/PythonTests/prefab/Prefab.py
@@ -25,28 +25,39 @@ import prefab.Prefab_Test_Utils as prefab_test_utils
# This is a helper class which contains some of the useful information about a prefab instance.
class PrefabInstance:
- def __init__(self, name: str=None, prefab_file_name: str=None, container_entity: EditorEntity=EntityId()):
- self.name = name
+ def __init__(self, prefab_file_name: str=None, container_entity: EditorEntity=EntityId()):
self.prefab_file_name: str = prefab_file_name
self.container_entity: EditorEntity = container_entity
+ def __eq__(self, other):
+ return other and self.container_entity.id == other.container_entity.id
+
+ def __ne__(self, other):
+ return not self.__eq__(other)
+
+ def __hash__(self):
+ return hash(self.container_entity.id)
+
"""
See if this instance is valid to be used with other prefab operations.
:return: Whether the target instance is valid or not.
"""
def is_valid() -> bool:
- return self.container_entity.id.IsValid() and self.name is not None and self.prefab_file_name in Prefab.existing_prefabs
+ return self.container_entity.id.IsValid() and self.prefab_file_name in Prefab.existing_prefabs
-
"""
Reparent this instance to target parent entity.
The function will also check pop up dialog ui in editor to see if there's prefab cyclical dependency error while reparenting prefabs.
:param parent_entity_id: The id of the entity this instance should be a child of in the transform hierarchy next.
"""
async def ui_reparent_prefab_instance(self, parent_entity_id: EntityId):
- container_entity_name = self.container_entity.get_name()
- current_children_entity_ids_having_prefab_name = prefab_test_utils.get_children_ids_by_name(parent_entity_id, container_entity_name)
- Report.info(f'current_children_entity_ids_having_prefab_name: {current_children_entity_ids_having_prefab_name}')
+ container_entity_id_before_reparent = self.container_entity.id
+
+ original_parent = EditorEntity(self.container_entity.get_parent_id())
+ original_parent_before_reparent_children_ids = set(original_parent.get_children_ids())
+
+ new_parent = EditorEntity(parent_entity_id)
+ new_parent_before_reparent_children_ids = set(new_parent.get_children_ids())
pyside_utils.run_soon(lambda: self.container_entity.set_parent_entity(parent_entity_id))
pyside_utils.run_soon(lambda: prefab_test_utils.wait_for_propagation())
@@ -60,18 +71,23 @@ class PrefabInstance:
except pyside_utils.EventLoopTimeoutException:
pass
- updated_children_entity_ids_having_prefab_name = prefab_test_utils.get_children_ids_by_name(parent_entity_id, container_entity_name)
- Report.info(f'updated_children_entity_ids_having_prefab_name: {updated_children_entity_ids_having_prefab_name}')
- new_child_with_reparented_prefab_name_added = len(updated_children_entity_ids_having_prefab_name) == len(current_children_entity_ids_having_prefab_name) + 1
- assert new_child_with_reparented_prefab_name_added, "No entity with reparented prefab name become a child of target parent entity"
+ original_parent_after_reparent_children_ids = set(original_parent.get_children_ids())
+ assert len(original_parent_after_reparent_children_ids) == len(original_parent_before_reparent_children_ids) - 1, \
+ "The children count of the Prefab Instance's original parent should be decreased by 1."
+ assert not container_entity_id_before_reparent in original_parent_after_reparent_children_ids, \
+ "This Prefab Instance is still a child entity of its original parent entity."
+
+ new_parent_after_reparent_children_ids = set(new_parent.get_children_ids())
+ assert len(new_parent_after_reparent_children_ids) == len(new_parent_before_reparent_children_ids) + 1, \
+ "The children count of the Prefab Instance's new parent should be increased by 1."
- updated_container_entity_id = set(updated_children_entity_ids_having_prefab_name).difference(current_children_entity_ids_having_prefab_name).pop()
- updated_container_entity = EditorEntity(updated_container_entity_id)
- updated_container_entity_parent_id = updated_container_entity.get_parent_id()
- has_correct_parent = updated_container_entity_parent_id.ToString() == parent_entity_id.ToString()
- assert has_correct_parent, "Prefab reparented is *not* under the expected parent entity"
+ container_entity_id_after_reparent = set(new_parent_after_reparent_children_ids).difference(new_parent_before_reparent_children_ids).pop()
+ reparented_container_entity = EditorEntity(container_entity_id_after_reparent)
+ reparented_container_entity_parent_id = reparented_container_entity.get_parent_id()
+ has_correct_parent = reparented_container_entity_parent_id.ToString() == parent_entity_id.ToString()
+ assert has_correct_parent, "Prefab Instance reparented is *not* under the expected parent entity"
- self.container_entity = EditorEntity(updated_container_entity_id)
+ self.container_entity = reparented_container_entity
# This is a helper class which contains some of the useful information about a prefab template.
class Prefab:
@@ -81,7 +97,7 @@ class Prefab:
def __init__(self, file_name: str):
self.file_name:str = file_name
self.file_path: str = prefab_test_utils.get_prefab_file_path(file_name)
- self.instances: dict = {}
+ self.instances: set[PrefabInstance] = set()
"""
Check if a prefab is ready to be used to generate its instances.
@@ -122,10 +138,10 @@ class Prefab:
:param entities: The entities that should form the new prefab (along with their descendants).
:param file_name: A unique file name of new prefab.
:param prefab_instance_name: A name for the very first instance generated while prefab creation. The default instance name is the same as file_name.
- :return: An outcome object with an entityId of the new prefab's container entity; on failure, it comes with an error message detailing the cause of the error.
+ :return: Created Prefab object and the very first PrefabInstance object owned by the prefab.
"""
@classmethod
- def create_prefab(cls, entities: list[EditorEntity], file_name: str, prefab_instance_name: str=None) -> Prefab:
+ def create_prefab(cls, entities: list[EditorEntity], file_name: str, prefab_instance_name: str=None) -> (Prefab, PrefabInstance):
assert not Prefab.is_prefab_loaded(file_name), f"Can't create Prefab '{file_name}' since the prefab already exists"
new_prefab = Prefab(file_name)
@@ -133,18 +149,18 @@ class Prefab:
create_prefab_result = prefab.PrefabPublicRequestBus(bus.Broadcast, 'CreatePrefabInMemory', entity_ids, new_prefab.file_path)
assert create_prefab_result.IsSuccess(), f"Prefab operation 'CreatePrefab' failed. Error: {create_prefab_result.GetError()}"
- container_entity = EditorEntity(create_prefab_result.GetValue())
+ container_entity_id = create_prefab_result.GetValue()
+ container_entity = EditorEntity(container_entity_id)
if prefab_instance_name:
container_entity.set_name(prefab_instance_name)
- else:
- prefab_instance_name = file_name
prefab_test_utils.wait_for_propagation()
- container_entity_id = prefab_test_utils.find_entity_by_unique_name(prefab_instance_name)
- new_prefab.instances[prefab_instance_name] = PrefabInstance(prefab_instance_name, file_name, EditorEntity(container_entity_id))
+
+ new_prefab_instance = PrefabInstance(file_name, EditorEntity(container_entity_id))
+ new_prefab.instances.add(new_prefab_instance)
Prefab.existing_prefabs[file_name] = new_prefab
- return new_prefab
+ return new_prefab, new_prefab_instance
"""
Remove target prefab instances.
@@ -152,22 +168,15 @@ class Prefab:
"""
@classmethod
def remove_prefabs(cls, prefab_instances: list[PrefabInstance]):
- instances_to_remove_name_counts = Counter()
- instances_removed_expected_name_counts = Counter()
-
- entities_to_remove = [prefab_instance.container_entity for prefab_instance in prefab_instances]
- while entities_to_remove:
- entity = entities_to_remove.pop(-1)
- entity_name = entity.get_name()
- instances_to_remove_name_counts[entity_name] += 1
-
+ entity_ids_to_remove = []
+ entity_id_queue = [prefab_instance.container_entity for prefab_instance in prefab_instances]
+ while entity_id_queue:
+ entity = entity_id_queue.pop(0)
children_entity_ids = entity.get_children_ids()
for child_entity_id in children_entity_ids:
- entities_to_remove.append(EditorEntity(child_entity_id))
+ entity_id_queue.append(EditorEntity(child_entity_id))
- for entity_name, entity_count in instances_to_remove_name_counts.items():
- entities = prefab_test_utils.find_entities_by_name(entity_name)
- instances_removed_expected_name_counts[entity_name] = len(entities) - entity_count
+ entity_ids_to_remove.append(entity.id)
container_entity_ids = [prefab_instance.container_entity.id for prefab_instance in prefab_instances]
delete_prefab_result = prefab.PrefabPublicRequestBus(bus.Broadcast, 'DeleteEntitiesAndAllDescendantsInInstance', container_entity_ids)
@@ -175,28 +184,24 @@ class Prefab:
prefab_test_utils.wait_for_propagation()
- prefab_entities_deleted = True
- for entity_name, expected_entity_count in instances_removed_expected_name_counts.items():
- actual_entity_count = len(prefab_test_utils.find_entities_by_name(entity_name))
- if actual_entity_count is not expected_entity_count:
- prefab_entities_deleted = False
- break
-
- assert prefab_entities_deleted, "Not all entities and descendants in target prefabs are deleted."
+ entity_ids_after_delete = set(prefab_test_utils.get_all_entities())
+ for entity_id_removed in entity_ids_to_remove:
+ if entity_id_removed in entity_ids_after_delete:
+ assert prefab_entities_deleted, "Not all entities and descendants in target prefabs are deleted."
for instance in prefab_instances:
instance_deleted_prefab = Prefab.get_prefab(instance.prefab_file_name)
- instance_deleted_prefab.instances.pop(instance.name)
+ instance_deleted_prefab.instances.remove(instance)
instance = PrefabInstance()
"""
Instantiate an instance of this prefab.
- :param name: A name for newly instantiated prefab instance. The default instance name is the same as this prefab's file name.
:param parent_entity: The entity the prefab should be a child of in the transform hierarchy.
+ :param name: A name for newly instantiated prefab instance. The default instance name is the same as this prefab's file name.
:param prefab_position: The position in world space the prefab should be instantiated in.
- :return: An outcome object with an entityId of the new prefab's container entity; on failure, it comes with an error message detailing the cause of the error.
+ :return: Instantiated PrefabInstance object owned by this prefab.
"""
- def instantiate(self, name: str=None, parent_entity: EditorEntity=None, prefab_position: Vector3=Vector3()) -> PrefabInstance:
+ def instantiate(self, parent_entity: EditorEntity=None, name: str=None, prefab_position: Vector3=Vector3()) -> PrefabInstance:
parent_entity_id = parent_entity.id if parent_entity is not None else EntityId()
instantiate_prefab_result = prefab.PrefabPublicRequestBus(
@@ -209,13 +214,13 @@ class Prefab:
if name:
container_entity.set_name(name)
- else:
- name = self.file_name
prefab_test_utils.wait_for_propagation()
- container_entity_id = prefab_test_utils.find_entity_by_unique_name(name)
- self.instances[name] = PrefabInstance(name, self.file_name, EditorEntity(container_entity_id))
+
+ new_prefab_instance = PrefabInstance(self.file_name, EditorEntity(container_entity_id))
+ assert not new_prefab_instance in self.instances, "This prefab instance is already existed before this instantiation."
+ self.instances.add(new_prefab_instance)
prefab_test_utils.check_entity_at_position(container_entity_id, prefab_position)
- return container_entity_id
+ return new_prefab_instance
diff --git a/AutomatedTesting/Gem/PythonTests/prefab/Prefab_BasicWorkflow_CreateAndDeletePrefab.py b/AutomatedTesting/Gem/PythonTests/prefab/Prefab_BasicWorkflow_CreateAndDeletePrefab.py
index c6e0daa4dd..f3fbcfa6ad 100644
--- a/AutomatedTesting/Gem/PythonTests/prefab/Prefab_BasicWorkflow_CreateAndDeletePrefab.py
+++ b/AutomatedTesting/Gem/PythonTests/prefab/Prefab_BasicWorkflow_CreateAndDeletePrefab.py
@@ -22,11 +22,10 @@ def Prefab_BasicWorkflow_CreateAndDeletePrefab():
car_prefab_entities = [car_entity]
# Checks for prefab creation passed or not
- car_prefab = Prefab.create_prefab(
+ _, car = Prefab.create_prefab(
car_prefab_entities, CAR_PREFAB_FILE_NAME)
# Checks for prefab deletion passed or not
- car = car_prefab.instances[CAR_PREFAB_FILE_NAME]
Prefab.remove_prefabs([car])
if __name__ == "__main__":
diff --git a/AutomatedTesting/Gem/PythonTests/prefab/Prefab_BasicWorkflow_CreateAndReparentPrefab.py b/AutomatedTesting/Gem/PythonTests/prefab/Prefab_BasicWorkflow_CreateAndReparentPrefab.py
index 04f7b97628..e5a9d9930a 100644
--- a/AutomatedTesting/Gem/PythonTests/prefab/Prefab_BasicWorkflow_CreateAndReparentPrefab.py
+++ b/AutomatedTesting/Gem/PythonTests/prefab/Prefab_BasicWorkflow_CreateAndReparentPrefab.py
@@ -28,7 +28,7 @@ def Prefab_BasicWorkflow_CreateAndReparentPrefab():
car_prefab_entities = [car_entity]
# Checks for prefab creation passed or not
- car_prefab = Prefab.create_prefab(
+ _, car = Prefab.create_prefab(
car_prefab_entities, CAR_PREFAB_FILE_NAME)
# Creates another new Entity at the root level
@@ -36,12 +36,10 @@ def Prefab_BasicWorkflow_CreateAndReparentPrefab():
wheel_prefab_entities = [wheel_entity]
# Checks for wheel prefab creation passed or not
- wheel_prefab = Prefab.create_prefab(
+ _, wheel = Prefab.create_prefab(
wheel_prefab_entities, WHEEL_PREFAB_FILE_NAME)
# Checks for prefab reparenting passed or not
- car = car_prefab.instances[CAR_PREFAB_FILE_NAME]
- wheel = wheel_prefab.instances[WHEEL_PREFAB_FILE_NAME]
await wheel.ui_reparent_prefab_instance(car.container_entity.id)
run_test()
diff --git a/AutomatedTesting/Gem/PythonTests/prefab/Prefab_BasicWorkflow_InstantiatePrefab.py b/AutomatedTesting/Gem/PythonTests/prefab/Prefab_BasicWorkflow_InstantiatePrefab.py
index b9015ab556..46be669697 100644
--- a/AutomatedTesting/Gem/PythonTests/prefab/Prefab_BasicWorkflow_InstantiatePrefab.py
+++ b/AutomatedTesting/Gem/PythonTests/prefab/Prefab_BasicWorkflow_InstantiatePrefab.py
@@ -22,11 +22,11 @@ def Prefab_BasicWorkflow_InstantiatePrefab():
# Checks for prefab instantiation passed or not
test_prefab = Prefab.get_prefab(EXISTING_TEST_PREFAB_FILE_NAME)
- instantiated_test_container_entity_id = test_prefab.instantiate(
+ test_instance = test_prefab.instantiate(
prefab_position=INSTANTIATED_TEST_PREFAB_POSITION)
prefab_test_utils.check_entity_children_count(
- instantiated_test_container_entity_id,
+ test_instance.container_entity.id,
EXPECTED_TEST_PREFAB_CHILDREN_COUNT)
if __name__ == "__main__":
diff --git a/AutomatedTesting/Gem/PythonTests/prefab/Prefab_Test_Utils.py b/AutomatedTesting/Gem/PythonTests/prefab/Prefab_Test_Utils.py
index 8cd59ed077..3e19911449 100644
--- a/AutomatedTesting/Gem/PythonTests/prefab/Prefab_Test_Utils.py
+++ b/AutomatedTesting/Gem/PythonTests/prefab/Prefab_Test_Utils.py
@@ -29,20 +29,8 @@ def find_entities_by_name(entity_name):
searchFilter.names = [entity_name]
return entity.SearchBus(bus.Broadcast, 'SearchEntities', searchFilter)
-def find_entity_by_unique_name(entity_name):
- unique_name_entity_found_result = (
- "Entity with a unique name found",
- "Entity with a unique name *not* found")
-
- entities = find_entities_by_name(entity_name)
- unique_name_entity_found = len(entities) == 1
- Report.result(unique_name_entity_found_result, unique_name_entity_found)
-
- if unique_name_entity_found:
- return entities[0]
- else:
- Report.info(f"{len(entities)} entities with name '{entity_name}' found")
- return EntityId()
+def get_all_entities():
+ return entity.SearchBus(bus.Broadcast, 'SearchEntities', entity.SearchFilter())
def check_entity_at_position(entity_id, expected_entity_position):
entity_at_expected_position_result = (
diff --git a/AutomatedTesting/Gem/PythonTests/scripting/TestSuite_Periodic.py b/AutomatedTesting/Gem/PythonTests/scripting/TestSuite_Periodic.py
index 0862e03a79..b2001e6825 100755
--- a/AutomatedTesting/Gem/PythonTests/scripting/TestSuite_Periodic.py
+++ b/AutomatedTesting/Gem/PythonTests/scripting/TestSuite_Periodic.py
@@ -122,6 +122,7 @@ class TestAutomation(TestAutomationBase):
from . import Debugger_HappyPath_TargetMultipleEntities as test_module
self._run_test(request, workspace, editor, test_module)
+ @pytest.mark.xfail(reason="Test fails to find expected lines, it needs to be fixed.")
def test_EditMenu_Default_UndoRedo(self, request, workspace, editor, launcher_platform, project):
from . import EditMenu_Default_UndoRedo as test_module
self._run_test(request, workspace, editor, test_module)
@@ -181,6 +182,7 @@ class TestAutomation(TestAutomationBase):
from . import NodePalette_SearchText_Deletion as test_module
self._run_test(request, workspace, editor, test_module)
+ @pytest.mark.xfail(reason="Test fails to find expected lines, it needs to be fixed.")
def test_VariableManager_UnpinVariableType_Works(self, request, workspace, editor, launcher_platform):
from . import VariableManager_UnpinVariableType_Works as test_module
self._run_test(request, workspace, editor, test_module)
diff --git a/Code/Editor/Include/IDisplayViewport.h b/Code/Editor/Include/IDisplayViewport.h
index 813c54355b..c7dff33e50 100644
--- a/Code/Editor/Include/IDisplayViewport.h
+++ b/Code/Editor/Include/IDisplayViewport.h
@@ -35,8 +35,6 @@ struct IDisplayViewport
*/
virtual float GetDistanceToLine(const Vec3& lineP1, const Vec3& lineP2, const QPoint& point) const = 0;
- virtual CBaseObjectsCache* GetVisibleObjectsCache() = 0;
-
enum EAxis
{
AXIS_NONE,
diff --git a/Code/Editor/Objects/ObjectManager.cpp b/Code/Editor/Objects/ObjectManager.cpp
index 06aa8866b3..f67cf24553 100644
--- a/Code/Editor/Objects/ObjectManager.cpp
+++ b/Code/Editor/Objects/ObjectManager.cpp
@@ -33,10 +33,6 @@
AZ_CVAR_EXTERNED(bool, ed_visibility_logTiming);
-AZ_CVAR(
- bool, ed_visibility_use, true, nullptr, AZ::ConsoleFunctorFlags::Null,
- "Enable/disable using the new IVisibilitySystem for Entity visibility determination");
-
/*!
* Class Description used for object templates.
* This description filled from Xml template files.
@@ -76,17 +72,6 @@ public:
int GameCreationOrder() override { return superType->GameCreationOrder(); };
};
-void CBaseObjectsCache::AddObject(CBaseObject* object)
-{
- m_objects.push_back(object);
- if (object->GetType() == OBJTYPE_AZENTITY)
- {
- auto componentEntityObject = static_cast(object);
- m_entityIds.push_back(componentEntityObject->GetAssociatedEntityId());
- }
-}
-
-
//////////////////////////////////////////////////////////////////////////
// CObjectManager implementation.
//////////////////////////////////////////////////////////////////////////
@@ -1267,25 +1252,8 @@ void CObjectManager::Display(DisplayContext& dc)
UpdateVisibilityList();
}
- bool viewIsDirty = dc.settings->IsDisplayHelpers(); // displaying helpers require computing all the bound boxes and things anyway.
-
- if (!viewIsDirty)
+ if (dc.settings->IsDisplayHelpers())
{
- if (CBaseObjectsCache* cache = dc.view->GetVisibleObjectsCache())
- {
- // if the current rendering viewport has an out-of-date cache serial number, it needs to be refreshed too.
- // views set their cache empty when they indicate they need to force a refresh.
- if ((cache->GetObjectCount() == 0) || (cache->GetSerialNumber() != m_visibilitySerialNumber))
- {
- viewIsDirty = true;
- }
- }
- }
-
- if (viewIsDirty)
- {
- FindDisplayableObjects(dc, true); // this also actually draws the helpers.
-
// Also broadcast for anyone else that needs to draw global debug to do so now
AzFramework::DebugDisplayEventBus::Broadcast(&AzFramework::DebugDisplayEvents::DrawGlobalDebugInfo);
}
@@ -1296,94 +1264,14 @@ void CObjectManager::Display(DisplayContext& dc)
}
}
-void CObjectManager::ForceUpdateVisibleObjectCache(DisplayContext& dc)
+void CObjectManager::ForceUpdateVisibleObjectCache([[maybe_unused]] DisplayContext& dc)
{
- FindDisplayableObjects(dc, false);
+ AZ_Assert(false, "CObjectManager::ForceUpdateVisibleObjectCache is legacy/deprecated and should not be used.");
}
-void CObjectManager::FindDisplayableObjects(DisplayContext& dc, [[maybe_unused]] bool bDisplay)
+void CObjectManager::FindDisplayableObjects([[maybe_unused]] DisplayContext& dc, [[maybe_unused]] bool bDisplay)
{
- // if the new IVisibilitySystem is being used, do not run this logic
- if (ed_visibility_use)
- {
- return;
- }
-
- AZ_PROFILE_FUNCTION(Editor);
-
- auto start = std::chrono::steady_clock::now();
- CBaseObjectsCache* pDispayedViewObjects = dc.view->GetVisibleObjectsCache();
- if (!pDispayedViewObjects)
- {
- return;
- }
-
- pDispayedViewObjects->SetSerialNumber(m_visibilitySerialNumber); // update viewport to be latest serial number
-
- AABB bbox;
- bbox.min.zero();
- bbox.max.zero();
-
- pDispayedViewObjects->ClearObjects();
- pDispayedViewObjects->Reserve(static_cast(m_visibleObjects.size()));
-
- if (dc.flags & DISPLAY_2D)
- {
- int numVis = static_cast(m_visibleObjects.size());
- for (int i = 0; i < numVis; i++)
- {
- CBaseObject* obj = m_visibleObjects[i];
-
- obj->GetBoundBox(bbox);
- if (dc.box.IsIntersectBox(bbox))
- {
- pDispayedViewObjects->AddObject(obj);
- }
- }
- }
- else
- {
- CSelectionGroup* pSelection = GetSelection();
- if (pSelection && pSelection->GetCount() > 1)
- {
- AABB mergedAABB;
- mergedAABB.Reset();
- for (int i = 0, iCount(pSelection->GetCount()); i < iCount; ++i)
- {
- CBaseObject* pObj(pSelection->GetObject(i));
- if (pObj == nullptr)
- {
- continue;
- }
- AABB aabb;
- pObj->GetBoundBox(aabb);
- mergedAABB.Add(aabb);
- }
-
- pSelection->GetObject(0)->CBaseObject::DrawDimensions(dc, &mergedAABB);
- }
-
- int numVis = static_cast(m_visibleObjects.size());
- for (int i = 0; i < numVis; i++)
- {
- CBaseObject* obj = m_visibleObjects[i];
-
- if (obj)
- {
- if ((dc.flags & DISPLAY_SELECTION_HELPERS) || obj->IsSelected())
- {
- pDispayedViewObjects->AddObject(obj);
- }
- }
- }
- }
-
- if (ed_visibility_logTiming && !ed_visibility_use)
- {
- auto stop = std::chrono::steady_clock::now();
- std::chrono::duration diff = stop - start;
- AZ_Printf("Visibility", "FindDisplayableObjects (old) - Duration: %f", diff);
- }
+ AZ_Assert(false, "CObjectManager::FindDisplayableObjects is legacy/deprecated and should not be used.");
}
void CObjectManager::BeginEditParams(CBaseObject* obj, int flags)
@@ -1630,214 +1518,24 @@ bool CObjectManager::HitTestObject(CBaseObject* obj, HitContext& hc)
return (bSelectionHelperHit || obj->HitTest(hc));
}
-
//////////////////////////////////////////////////////////////////////////
-bool CObjectManager::HitTest(HitContext& hitInfo)
+bool CObjectManager::HitTest([[maybe_unused]] HitContext& hitInfo)
{
- AZ_PROFILE_FUNCTION(Editor);
-
- hitInfo.object = nullptr;
- hitInfo.dist = FLT_MAX;
- hitInfo.axis = 0;
- hitInfo.manipulatorMode = 0;
-
- HitContext hcOrg = hitInfo;
- if (hcOrg.view)
- {
- hcOrg.view->GetPerpendicularAxis(nullptr, &hcOrg.b2DViewport);
- }
- hcOrg.rayDir = hcOrg.rayDir.GetNormalized();
-
- HitContext hc = hcOrg;
-
- float mindist = FLT_MAX;
-
- if (!hitInfo.bIgnoreAxis && !hc.bUseSelectionHelpers)
- {
- // Test gizmos.
- if (m_gizmoManager->HitTest(hc))
- {
- if (hc.axis != 0)
- {
- hitInfo.object = hc.object;
- hitInfo.gizmo = hc.gizmo;
- hitInfo.axis = hc.axis;
- hitInfo.manipulatorMode = hc.manipulatorMode;
- hitInfo.dist = hc.dist;
- return true;
- }
- }
- }
-
- if (hitInfo.bOnlyGizmo)
- {
- return false;
- }
-
- // Only HitTest objects, that where previously Displayed.
- CBaseObjectsCache* pDispayedViewObjects = hitInfo.view->GetVisibleObjectsCache();
-
- const bool iconsPrioritized = true; // Force icons to always be prioritized over other things you hit. Can change to be a configurable option in the future.
-
- CBaseObject* selected = nullptr;
- const char* name = nullptr;
- bool iconHit = false;
- int numVis = pDispayedViewObjects->GetObjectCount();
- for (int i = 0; i < numVis; i++)
- {
- CBaseObject* obj = pDispayedViewObjects->GetObject(i);
-
- if (obj == hitInfo.pExcludedObject)
- {
- continue;
- }
-
- if (HitTestObject(obj, hc))
- {
- if (m_selectCallback && !m_selectCallback->CanSelectObject(obj))
- {
- continue;
- }
-
- // Check if this object is nearest.
- if (hc.axis != 0)
- {
- hitInfo.object = obj;
- hitInfo.axis = hc.axis;
- hitInfo.dist = hc.dist;
- return true;
- }
-
- // When prioritizing icons, we don't allow non-icon hits to beat icon hits
- if (iconsPrioritized && iconHit && !hc.iconHit)
- {
- continue;
- }
-
- if (hc.dist < mindist || (!iconHit && hc.iconHit))
- {
- if (hc.iconHit)
- {
- iconHit = true;
- }
-
- mindist = hc.dist;
- name = hc.name;
- selected = obj;
- }
-
- // Clear the object pointer if an object was hit, not just if the collision
- // was closer than any previous. Not all paths from HitTestObject set the object pointer and so you could get
- // an object from a previous (rejected) result but with collision information about a closer hit.
- hc.object = nullptr;
- hc.iconHit = false;
-
- // If use deep selection
- if (hitInfo.pDeepSelection)
- {
- hitInfo.pDeepSelection->AddObject(hc.dist, obj);
- }
- }
- }
-
- if (selected)
- {
- hitInfo.object = selected;
- hitInfo.dist = mindist;
- hitInfo.name = name;
- hitInfo.iconHit = iconHit;
- return true;
- }
+ AZ_Assert(false, "CObjectManager::HitTest is legacy/deprecated and should not be used.");
return false;
}
-void CObjectManager::FindObjectsInRect(CViewport* view, const QRect& rect, std::vector& guids)
-{
- AZ_PROFILE_FUNCTION(Editor);
-
- if (rect.width() < 1 || rect.height() < 1)
- {
- return;
- }
-
- HitContext hc;
- hc.view = view;
- hc.b2DViewport = view->GetType() != ET_ViewportCamera;
- hc.rect = rect;
- hc.bUseSelectionHelpers = view->GetAdvancedSelectModeFlag();
-
- guids.clear();
- CBaseObjectsCache* pDispayedViewObjects = view->GetVisibleObjectsCache();
-
- int numVis = pDispayedViewObjects->GetObjectCount();
- for (int i = 0; i < numVis; ++i)
- {
- CBaseObject* pObj = pDispayedViewObjects->GetObject(i);
-
- HitTestObjectAgainstRect(pObj, view, hc, guids);
- }
+void CObjectManager::FindObjectsInRect(
+ [[maybe_unused]] CViewport* view, [[maybe_unused]] const QRect& rect, [[maybe_unused]] std::vector& guids)
+{
+ AZ_Assert(false, "CObjectManager::FindObjectsInRect is legacy/deprecated and should not be used.");
}
//////////////////////////////////////////////////////////////////////////
-void CObjectManager::SelectObjectsInRect(CViewport* view, const QRect& rect, bool bSelect)
+void CObjectManager::SelectObjectsInRect(
+ [[maybe_unused]] CViewport* view, [[maybe_unused]] const QRect& rect, [[maybe_unused]] bool bSelect)
{
- AZ_PROFILE_FUNCTION(Editor);
-
- // Ignore too small rectangles.
- if (rect.width() < 1 || rect.height() < 1)
- {
- return;
- }
-
- CUndo undo("Select Object(s)");
-
- HitContext hc;
- hc.view = view;
- hc.b2DViewport = view->GetType() != ET_ViewportCamera;
- hc.rect = rect;
- hc.bUseSelectionHelpers = view->GetAdvancedSelectModeFlag();
-
- bool isUndoRecording = GetIEditor()->IsUndoRecording();
- if (isUndoRecording)
- {
- m_processingBulkSelect = true;
- }
-
- CBaseObjectsCache* displayedViewObjects = view->GetVisibleObjectsCache();
- int numVis = displayedViewObjects->GetObjectCount();
-
- // Tracking the previous selection allows proper undo/redo functionality of additional
- // selections (CTRL + drag select)
- AZStd::unordered_set previousSelection;
-
- for (int i = 0; i < numVis; ++i)
- {
- CBaseObject* object = displayedViewObjects->GetObject(i);
-
- if (object->IsSelected())
- {
- previousSelection.insert(object);
- }
- else
- {
- // This will update m_currSelection
- SelectObjectInRect(object, view, hc, bSelect);
-
- // Legacy undo/redo does not go through the Ebus system and must be done individually
- if (isUndoRecording && object->GetType() != OBJTYPE_AZENTITY)
- {
- GetIEditor()->RecordUndo(new CUndoBaseObjectSelect(object, true));
- }
- }
- }
-
- if (isUndoRecording && m_currSelection)
- {
- // Component Entities can handle undo/redo in bulk due to Ebuses
- GetIEditor()->RecordUndo(new CUndoBaseObjectBulkSelect(previousSelection, *m_currSelection));
- }
-
- m_processingBulkSelect = false;
+ AZ_Assert(false, "CObjectManager::SelectObjectsInRect is legacy/deprecated and should not be used.");
}
//////////////////////////////////////////////////////////////////////////
@@ -3011,6 +2709,4 @@ namespace AzToolsFramework
}
}
-}
-
-
+} // namespace AzToolsFramework
diff --git a/Code/Editor/Objects/ObjectManager.h b/Code/Editor/Objects/ObjectManager.h
index 4ffa5e9a07..0ad5d8323e 100644
--- a/Code/Editor/Objects/ObjectManager.h
+++ b/Code/Editor/Objects/ObjectManager.h
@@ -52,40 +52,6 @@ public:
}
};
-//////////////////////////////////////////////////////////////////////////
-// Array of editor objects.
-//////////////////////////////////////////////////////////////////////////
-class CBaseObjectsCache
-{
-public:
- int GetObjectCount() const { return static_cast(m_objects.size()); }
- CBaseObject* GetObject(int nIndex) const { return m_objects[nIndex]; }
- void AddObject(CBaseObject* object);
-
- void ClearObjects()
- {
- m_objects.clear();
- m_entityIds.clear();
- }
-
- void Reserve(int nCount)
- {
- m_objects.reserve(nCount);
- m_entityIds.reserve(nCount);
- }
-
- const AZStd::vector& GetEntityIdCache() const { return m_entityIds; }
-
- /// Checksum is used as a dirty flag.
- unsigned int GetSerialNumber() { return m_serialNumber; }
- void SetSerialNumber(unsigned int serialNumber) { m_serialNumber = serialNumber; }
-private:
- //! List of objects that was displayed at last frame.
- std::vector<_smart_ptr > m_objects;
- AZStd::vector m_entityIds;
- unsigned int m_serialNumber = 0;
-};
-
/*!
* CObjectManager is a singleton object that
* manages global set of objects in level.
diff --git a/Code/Editor/Plugins/ComponentEntityEditorPlugin/SandboxIntegration.cpp b/Code/Editor/Plugins/ComponentEntityEditorPlugin/SandboxIntegration.cpp
index 666700a874..b9e4878879 100644
--- a/Code/Editor/Plugins/ComponentEntityEditorPlugin/SandboxIntegration.cpp
+++ b/Code/Editor/Plugins/ComponentEntityEditorPlugin/SandboxIntegration.cpp
@@ -142,8 +142,7 @@ void GetSelectedEntitiesSetWithFlattenedHierarchy(AzToolsFramework::EntityIdSet&
}
SandboxIntegrationManager::SandboxIntegrationManager()
- : m_inObjectPickMode(false)
- , m_startedUndoRecordingNestingLevel(0)
+ : m_startedUndoRecordingNestingLevel(0)
, m_dc(nullptr)
, m_notificationWindowManager(new AzToolsFramework::SliceOverridesNotificationWindowManager())
{
@@ -1000,62 +999,6 @@ void SandboxIntegrationManager::SetupSliceContextMenu_Modify(QMenu* menu, const
revertAction->setEnabled(canRevert);
}
-void SandboxIntegrationManager::HandleObjectModeSelection(const AZ::Vector2& point, [[maybe_unused]] int flags, bool& handled)
-{
- // Todo - Use a custom "edit tool". This will eliminate the need for this bus message entirely, which technically
- // makes this feature less intrusive on Sandbox.
- // UPDATE: This is now provided by EditorPickEntitySelection when the new Viewport Interaction Model changes are enabled.
- if (m_inObjectPickMode)
- {
- CViewport* view = GetIEditor()->GetViewManager()->GetGameViewport();
- const QPoint viewPoint(static_cast(point.GetX()), static_cast(point.GetY()));
-
- HitContext hitInfo;
- hitInfo.view = view;
- if (view->HitTest(viewPoint, hitInfo))
- {
- if (hitInfo.object && (hitInfo.object->GetType() == OBJTYPE_AZENTITY))
- {
- CComponentEntityObject* entityObject = static_cast(hitInfo.object);
- AzToolsFramework::EditorPickModeRequestBus::Broadcast(
- &AzToolsFramework::EditorPickModeRequests::PickModeSelectEntity, entityObject->GetAssociatedEntityId());
- }
- }
-
- AzToolsFramework::EditorPickModeRequestBus::Broadcast(
- &AzToolsFramework::EditorPickModeRequests::StopEntityPickMode);
-
- handled = true;
- }
-}
-
-void SandboxIntegrationManager::UpdateObjectModeCursor(AZ::u32& cursorId, AZStd::string& cursorStr)
-{
- if (m_inObjectPickMode)
- {
- cursorId = static_cast(STD_CURSOR_HAND);
- cursorStr = "Pick an entity...";
- }
-}
-
-void SandboxIntegrationManager::OnEntityPickModeStarted()
-{
- m_inObjectPickMode = true;
-
- // Currently this object pick mode is activated only via PropertyEntityIdCtrl picker.
- // When the picker button is clicked, we transfer focus to the viewport so the
- // spacebar can still be used to activate selection helpers.
- if (CViewport* view = GetIEditor()->GetViewManager()->GetGameViewport())
- {
- view->SetFocus();
- }
-}
-
-void SandboxIntegrationManager::OnEntityPickModeStopped()
-{
- m_inObjectPickMode = false;
-}
-
void SandboxIntegrationManager::CreateEditorRepresentation(AZ::Entity* entity)
{
IEditor* editor = GetIEditor();
diff --git a/Code/Editor/Plugins/ComponentEntityEditorPlugin/SandboxIntegration.h b/Code/Editor/Plugins/ComponentEntityEditorPlugin/SandboxIntegration.h
index 617c5cb2c8..40962409a3 100644
--- a/Code/Editor/Plugins/ComponentEntityEditorPlugin/SandboxIntegration.h
+++ b/Code/Editor/Plugins/ComponentEntityEditorPlugin/SandboxIntegration.h
@@ -93,7 +93,6 @@ namespace AzToolsFramework
class SandboxIntegrationManager
: private AzToolsFramework::ToolsApplicationEvents::Bus::Handler
, private AzToolsFramework::EditorRequests::Bus::Handler
- , private AzToolsFramework::EditorPickModeNotificationBus::Handler
, private AzToolsFramework::EditorContextMenuBus::Handler
, private AzToolsFramework::EditorWindowRequests::Bus::Handler
, private AzFramework::AssetCatalogEventBus::Handler
@@ -140,8 +139,6 @@ private:
QDockWidget* InstanceViewPane(const char* paneName) override;
void CloseViewPane(const char* paneName) override;
void BrowseForAssets(AzToolsFramework::AssetBrowser::AssetSelectionModel& selection) override;
- void HandleObjectModeSelection(const AZ::Vector2& point, int flags, bool& handled) override;
- void UpdateObjectModeCursor(AZ::u32& cursorId, AZStd::string& cursorStr) override;
void CreateEditorRepresentation(AZ::Entity* entity) override;
bool DestroyEditorRepresentation(AZ::EntityId entityId, bool deleteAZEntity) override;
void CloneSelection(bool& handled) override;
@@ -175,10 +172,6 @@ private:
QWidget* GetAppMainWindow() override;
//////////////////////////////////////////////////////////////////////////
- // EditorPickModeNotificationBus
- void OnEntityPickModeStarted() override;
- void OnEntityPickModeStopped() override;
-
//////////////////////////////////////////////////////////////////////////
// AzToolsFramework::EditorContextMenu::Bus::Handler overrides
void PopulateEditorGlobalContextMenu(QMenu* menu, const AZ::Vector2& point, int flags) override;
@@ -281,7 +274,6 @@ private:
private:
AZ::Vector2 m_contextMenuViewPoint;
- int m_inObjectPickMode;
short m_startedUndoRecordingNestingLevel; // used in OnBegin/EndUndo to ensure we only accept undo's we started recording
AzToolsFramework::SliceOverridesNotificationWindowManager* m_notificationWindowManager;
diff --git a/Code/Editor/UndoDropDown.cpp b/Code/Editor/UndoDropDown.cpp
index 6bf807ebf4..4f346b57dd 100644
--- a/Code/Editor/UndoDropDown.cpp
+++ b/Code/Editor/UndoDropDown.cpp
@@ -101,13 +101,13 @@ public:
if (fresh.size() < m_stackNames.size())
{
- beginRemoveRows(createIndex(-1, -1), static_cast(fresh.size()), static_cast(m_stackNames.size() - 1));
+ beginRemoveRows(QModelIndex(), static_cast(fresh.size()), static_cast(m_stackNames.size() - 1));
m_stackNames = fresh;
endRemoveRows();
}
else
{
- beginInsertRows(createIndex(-1, -1), static_cast(m_stackNames.size()), static_cast(fresh.size() - 1));
+ beginInsertRows(QModelIndex(), static_cast(m_stackNames.size()), static_cast(fresh.size() - 1));
m_stackNames = fresh;
endInsertRows();
}
diff --git a/Code/Editor/Viewport.cpp b/Code/Editor/Viewport.cpp
index 2d41538d92..5b4f4a4df3 100644
--- a/Code/Editor/Viewport.cpp
+++ b/Code/Editor/Viewport.cpp
@@ -173,8 +173,6 @@ QtViewport::QtViewport(QWidget* parent)
m_bAdvancedSelectMode = false;
- m_pVisibleObjectsCache = new CBaseObjectsCache;
-
m_constructionPlane.SetPlane(Vec3_OneZ, Vec3_Zero);
m_constructionPlaneAxisX = Vec3_Zero;
m_constructionPlaneAxisY = Vec3_Zero;
@@ -204,8 +202,6 @@ QtViewport::QtViewport(QWidget* parent)
//////////////////////////////////////////////////////////////////////////
QtViewport::~QtViewport()
{
- delete m_pVisibleObjectsCache;
-
GetIEditor()->GetViewManager()->UnregisterViewport(this);
}
@@ -376,11 +372,6 @@ void QtViewport::OnDeactivate()
void QtViewport::ResetContent()
{
m_pMouseOverObject = nullptr;
-
- // Need to clear visual object cache.
- // Right after loading new level, some code(e.g. OnMouseMove) access invalid
- // previous level object before cache updated.
- GetVisibleObjectsCache()->ClearObjects();
}
//////////////////////////////////////////////////////////////////////////
@@ -398,11 +389,8 @@ void QtViewport::Update()
m_viewportUi.Update();
m_bAdvancedSelectMode = false;
- bool bSpaceClick = false;
- {
- bSpaceClick = CheckVirtualKey(Qt::Key_Space) & !CheckVirtualKey(Qt::Key_Shift) /*& !CheckVirtualKey(Qt::Key_Control)*/;
- }
- if (bSpaceClick && hasFocus())
+
+ if (CheckVirtualKey(Qt::Key_Space) && !CheckVirtualKey(Qt::Key_Shift) && hasFocus())
{
m_bAdvancedSelectMode = true;
}
diff --git a/Code/Editor/Viewport.h b/Code/Editor/Viewport.h
index 60c1306420..7f8ccc4c4f 100644
--- a/Code/Editor/Viewport.h
+++ b/Code/Editor/Viewport.h
@@ -157,7 +157,7 @@ public:
virtual Vec3 SnapToGrid(const Vec3& vec) = 0;
- //! Get selection procision tolerance.
+ //! Get selection precision tolerance.
virtual float GetSelectionTolerance() const = 0;
//////////////////////////////////////////////////////////////////////////
@@ -491,10 +491,6 @@ public:
void ResetCursor() override;
void SetSupplementaryCursorStr(const QString& str) override;
- //////////////////////////////////////////////////////////////////////////
- // Return visble objects cache.
- CBaseObjectsCache* GetVisibleObjectsCache() override { return m_pVisibleObjectsCache; };
-
void RegisterRenderListener(IRenderListener* piListener) override;
bool UnregisterRenderListener(IRenderListener* piListener) override;
bool IsRenderListenerRegistered(IRenderListener* piListener) override;
@@ -612,8 +608,6 @@ protected:
int m_nLastUpdateFrame;
int m_nLastMouseMoveFrame;
- CBaseObjectsCache* m_pVisibleObjectsCache;
-
QRect m_rcClient;
AZ_PUSH_DISABLE_DLL_EXPORT_MEMBER_WARNING
diff --git a/Code/Framework/AzCore/AzCore/Asset/AssetManager.cpp b/Code/Framework/AzCore/AzCore/Asset/AssetManager.cpp
index 8eb620f69e..06bb0b0cac 100644
--- a/Code/Framework/AzCore/AzCore/Asset/AssetManager.cpp
+++ b/Code/Framework/AzCore/AzCore/Asset/AssetManager.cpp
@@ -551,8 +551,6 @@ namespace AZ
{
PrepareShutDown();
- DispatchEvents();
-
// Acquire the asset lock to make sure nobody else is trying to do anything fancy with assets
AZStd::scoped_lock assetLock(m_assetMutex);
@@ -575,7 +573,10 @@ namespace AZ
{
AZ_PROFILE_FUNCTION(AzCore);
AssetManagerNotificationBus::Broadcast(&AssetManagerNotificationBus::Events::OnAssetEventsDispatchBegin);
- AssetBus::ExecuteQueuedEvents();
+ while (AssetBus::QueuedEventCount())
+ {
+ AssetBus::ExecuteQueuedEvents();
+ }
AssetManagerNotificationBus::Broadcast(&AssetManagerNotificationBus::Events::OnAssetEventsDispatchEnd);
}
diff --git a/Code/Framework/AzCore/AzCore/AzCoreModule.cpp b/Code/Framework/AzCore/AzCore/AzCoreModule.cpp
index c60ea1bd72..67123ed826 100644
--- a/Code/Framework/AzCore/AzCore/AzCoreModule.cpp
+++ b/Code/Framework/AzCore/AzCore/AzCoreModule.cpp
@@ -22,6 +22,8 @@
#include
#include
#include
+#include
+#include
namespace AZ
{
@@ -41,6 +43,11 @@ namespace AZ
TimeSystemComponent::CreateDescriptor(),
LoggerSystemComponent::CreateDescriptor(),
EventSchedulerSystemComponent::CreateDescriptor(),
+ TaskGraphSystemComponent::CreateDescriptor(),
+
+#if !defined(_RELEASE)
+ Statistics::StatisticalProfilerProxySystemComponent::CreateDescriptor(),
+#endif
#if !defined(AZCORE_EXCLUDE_LUA)
ScriptSystemComponent::CreateDescriptor(),
@@ -55,6 +62,11 @@ namespace AZ
azrtti_typeid(),
azrtti_typeid(),
azrtti_typeid(),
+ azrtti_typeid(),
+
+#if !defined(_RELEASE)
+ azrtti_typeid(),
+#endif
};
}
}
diff --git a/Code/Framework/AzCore/AzCore/Component/ComponentApplication.cpp b/Code/Framework/AzCore/AzCore/Component/ComponentApplication.cpp
index 168807cd97..7e9accffd7 100644
--- a/Code/Framework/AzCore/AzCore/Component/ComponentApplication.cpp
+++ b/Code/Framework/AzCore/AzCore/Component/ComponentApplication.cpp
@@ -1367,9 +1367,6 @@ namespace AZ
#endif
}
- //=========================================================================
- // Tick
- //=========================================================================
void ComponentApplication::Tick(float deltaOverride /*= -1.f*/)
{
{
@@ -1397,9 +1394,6 @@ namespace AZ
}
}
- //=========================================================================
- // Tick
- //=========================================================================
void ComponentApplication::TickSystem()
{
AZ_PROFILE_SCOPE(System, "Component application tick");
@@ -1547,5 +1541,4 @@ namespace AZ
AZ::SettingsRegistryScriptUtils::ReflectSettingsRegistryToBehaviorContext(*behaviorContext);
}
}
-
} // namespace AZ
diff --git a/Code/Framework/AzCore/AzCore/Component/ComponentApplication.h b/Code/Framework/AzCore/AzCore/Component/ComponentApplication.h
index bfc541ca09..8e95ff5fa3 100644
--- a/Code/Framework/AzCore/AzCore/Component/ComponentApplication.h
+++ b/Code/Framework/AzCore/AzCore/Component/ComponentApplication.h
@@ -5,6 +5,7 @@
* SPDX-License-Identifier: Apache-2.0 OR MIT
*
*/
+
#pragma once
#include
diff --git a/Code/Framework/AzCore/AzCore/Debug/Budget.cpp b/Code/Framework/AzCore/AzCore/Debug/Budget.cpp
index f9fe7e462a..4a6f3ed114 100644
--- a/Code/Framework/AzCore/AzCore/Debug/Budget.cpp
+++ b/Code/Framework/AzCore/AzCore/Debug/Budget.cpp
@@ -11,6 +11,7 @@
#include
#include
#include
+#include
AZ_DEFINE_BUDGET(Animation);
AZ_DEFINE_BUDGET(Audio);
@@ -30,8 +31,7 @@ namespace AZ::Debug
};
Budget::Budget(const char* name)
- : m_name{ name }
- , m_crc{ Crc32(name) }
+ : Budget( name, Crc32(name) )
{
}
@@ -40,6 +40,10 @@ namespace AZ::Debug
, m_crc{ crc }
{
m_impl = aznew BudgetImpl;
+ if (auto statsProfiler = Interface::Get(); statsProfiler)
+ {
+ statsProfiler->RegisterProfilerId(m_crc);
+ }
}
Budget::~Budget()
diff --git a/Code/Framework/AzCore/AzCore/Debug/Profiler.h b/Code/Framework/AzCore/AzCore/Debug/Profiler.h
index 56103e8314..6e86de2e93 100644
--- a/Code/Framework/AzCore/AzCore/Debug/Profiler.h
+++ b/Code/Framework/AzCore/AzCore/Debug/Profiler.h
@@ -8,6 +8,7 @@
#pragma once
#include
+#include
#ifdef USE_PIX
#include
@@ -44,7 +45,10 @@
#define AZ_PROFILE_INTERVAL_START(...)
#define AZ_PROFILE_INTERVAL_START_COLORED(...)
#define AZ_PROFILE_INTERVAL_END(...)
-#define AZ_PROFILE_INTERVAL_SCOPED(...)
+#define AZ_PROFILE_INTERVAL_SCOPED(budget, scopeNameId, ...) \
+ static constexpr AZ::Crc32 AZ_JOIN(blockId, __LINE__)(scopeNameId); \
+ AZ::Statistics::StatisticalProfilerProxy::TimedScope AZ_JOIN(scope, __LINE__)(AZ_CRC_CE(#budget), AZ_JOIN(blockId, __LINE__));
+
#endif
#ifndef AZ_PROFILE_DATAPOINT
diff --git a/Code/Framework/AzCore/AzCore/Debug/Trace.h b/Code/Framework/AzCore/AzCore/Debug/Trace.h
index a1334d334e..507ba48e53 100644
--- a/Code/Framework/AzCore/AzCore/Debug/Trace.h
+++ b/Code/Framework/AzCore/AzCore/Debug/Trace.h
@@ -262,17 +262,17 @@ namespace AZ
#else // !AZ_ENABLE_TRACING
- #define AZ_Assert(...) AZ_UNUSED(__VA_ARGS__);
- #define AZ_Error(...) AZ_UNUSED(__VA_ARGS__);
- #define AZ_ErrorOnce(...) AZ_UNUSED(__VA_ARGS__);
- #define AZ_Warning(...) AZ_UNUSED(__VA_ARGS__);
- #define AZ_WarningOnce(...) AZ_UNUSED(__VA_ARGS__);
- #define AZ_TracePrintf(...) AZ_UNUSED(__VA_ARGS__);
- #define AZ_TracePrintfOnce(...) AZ_UNUSED(__VA_ARGS__);
-
- #define AZ_Verify(...) AZ_UNUSED(__VA_ARGS__);
- #define AZ_VerifyError(...) AZ_UNUSED(__VA_ARGS__);
- #define AZ_VerifyWarning(...) AZ_UNUSED(__VA_ARGS__);
+ #define AZ_Assert(...)
+ #define AZ_Error(...)
+ #define AZ_ErrorOnce(...)
+ #define AZ_Warning(...)
+ #define AZ_WarningOnce(...)
+ #define AZ_TracePrintf(...)
+ #define AZ_TracePrintfOnce(...)
+
+ #define AZ_Verify(expression, ...) AZ_UNUSED(expression)
+ #define AZ_VerifyError(window, expression, ...) AZ_UNUSED(expression)
+ #define AZ_VerifyWarning(window, expression, ...) AZ_UNUSED(expression)
#endif // AZ_ENABLE_TRACING
diff --git a/Code/Framework/AzCore/AzCore/EBus/EBus.h b/Code/Framework/AzCore/AzCore/EBus/EBus.h
index ff8966e8e0..da8c880963 100644
--- a/Code/Framework/AzCore/AzCore/EBus/EBus.h
+++ b/Code/Framework/AzCore/AzCore/EBus/EBus.h
@@ -12,7 +12,7 @@
* that Open 3D Engine uses to dispatch notifications and receive requests.
* EBuses are configurable and support many different use cases.
* For more information about %EBuses, see AZ::EBus in this guide and
- * [Event Bus](http://docs.aws.amazon.com/lumberyard/latest/developerguide/asset-pipeline-ebus.html)
+ * [Event Bus](https://o3de.org/docs/user-guide/engine/ebus/)
* in the *Open 3D Engine Developer Guide*.
*/
@@ -62,7 +62,7 @@ namespace AZ
* @endcode
*
* For more information about %EBuses, see EBus in this guide and
- * [Event Bus](http://docs.aws.amazon.com/lumberyard/latest/developerguide/asset-pipeline-ebus.html)
+ * [Event Bus](https://o3de.org/docs/user-guide/engine/ebus/)
* in the *Open 3D Engine Developer Guide*.
*/
struct EBusTraits
@@ -259,8 +259,8 @@ namespace AZ
*
* EBuses are configurable and support many different use cases.
* For more information about EBuses, see
- * [Event Bus](http://docs.aws.amazon.com/lumberyard/latest/developerguide/asset-pipeline-ebus.html)
- * and [Components and EBuses: Best Practices ](http://docs.aws.amazon.com/lumberyard/latest/developerguide/component-entity-system-pg-components-ebuses-best-practices.html)
+ * [Event Bus](https://o3de.org/docs/user-guide/engine/ebus/)
+ * and [Components and EBuses: Best Practices ](https://o3de.org/docs/user-guide/components/development/entity-system-pg-components-ebuses-best-practices/)
* in the *Open 3D Engine Developer Guide*.
*
* ## How Components Use EBuses
diff --git a/Code/Framework/AzCore/AzCore/IO/Streamer/Scheduler.cpp b/Code/Framework/AzCore/AzCore/IO/Streamer/Scheduler.cpp
index 9b4996ad49..9ee0fefc99 100644
--- a/Code/Framework/AzCore/AzCore/IO/Streamer/Scheduler.cpp
+++ b/Code/Framework/AzCore/AzCore/IO/Streamer/Scheduler.cpp
@@ -43,10 +43,12 @@ namespace AZ::IO
m_mainLoopDesc = threadDesc;
m_mainLoopDesc.m_name = "IO Scheduler";
- m_mainLoop = AZStd::thread([this]()
- {
- Thread_MainLoop();
- }, &m_mainLoopDesc);
+ m_mainLoop = AZStd::thread(
+ m_mainLoopDesc,
+ [this]()
+ {
+ Thread_MainLoop();
+ });
}
}
diff --git a/Code/Framework/AzCore/AzCore/IO/SystemFile.cpp b/Code/Framework/AzCore/AzCore/IO/SystemFile.cpp
index 651abb89fe..ac12a59609 100644
--- a/Code/Framework/AzCore/AzCore/IO/SystemFile.cpp
+++ b/Code/Framework/AzCore/AzCore/IO/SystemFile.cpp
@@ -35,6 +35,7 @@ namespace Platform
SystemFile::SizeType Length(FileHandleType handle, const SystemFile* systemFile);
bool Exists(const char* fileName);
+ bool IsDirectory(const char* filePath);
void FindFiles(const char* filter, SystemFile::FindFileCB cb);
AZ::u64 ModificationTime(const char* fileName);
SystemFile::SizeType Length(const char* fileName);
@@ -235,6 +236,11 @@ bool SystemFile::Exists(const char* fileName)
return Platform::Exists(fileName);
}
+bool SystemFile::IsDirectory(const char* filePath)
+{
+ return Platform::IsDirectory(filePath);
+}
+
void SystemFile::FindFiles(const char* filter, FindFileCB cb)
{
Platform::FindFiles(filter, cb);
diff --git a/Code/Framework/AzCore/AzCore/IO/SystemFile.h b/Code/Framework/AzCore/AzCore/IO/SystemFile.h
index 551ce89ce7..39e44f86da 100644
--- a/Code/Framework/AzCore/AzCore/IO/SystemFile.h
+++ b/Code/Framework/AzCore/AzCore/IO/SystemFile.h
@@ -99,6 +99,8 @@ namespace AZ
// Utility functions
/// Check if a file or directory exists.
static bool Exists(const char* path);
+ /// Check if path is a directory
+ static bool IsDirectory(const char* path);
/// FindFiles
typedef AZStd::function FindFileCB;
static void FindFiles(const char* filter, FindFileCB cb);
diff --git a/Code/Framework/AzCore/AzCore/Jobs/Internal/JobManagerWorkStealing.cpp b/Code/Framework/AzCore/AzCore/Jobs/Internal/JobManagerWorkStealing.cpp
index f76946a667..230bf959f6 100644
--- a/Code/Framework/AzCore/AzCore/Jobs/Internal/JobManagerWorkStealing.cpp
+++ b/Code/Framework/AzCore/AzCore/Jobs/Internal/JobManagerWorkStealing.cpp
@@ -644,11 +644,11 @@ JobManagerWorkStealing::ThreadList JobManagerWorkStealing::CreateWorkerThreads(c
}
info->m_thread = AZStd::thread(
+ threadDesc,
[this, info]()
{
this->ProcessJobsWorker(info);
- },
- &threadDesc
+ }
);
info->m_threadId = info->m_thread.get_id();
diff --git a/Code/Framework/AzCore/AzCore/Math/Aabb.h b/Code/Framework/AzCore/AzCore/Math/Aabb.h
index 488808bc4c..438d95622e 100644
--- a/Code/Framework/AzCore/AzCore/Math/Aabb.h
+++ b/Code/Framework/AzCore/AzCore/Math/Aabb.h
@@ -5,7 +5,6 @@
* SPDX-License-Identifier: Apache-2.0 OR MIT
*
*/
-
#pragma once
#include
diff --git a/Code/Framework/AzCore/AzCore/Math/Vector2.h b/Code/Framework/AzCore/AzCore/Math/Vector2.h
index b2b1ceeb4d..7c37d74135 100644
--- a/Code/Framework/AzCore/AzCore/Math/Vector2.h
+++ b/Code/Framework/AzCore/AzCore/Math/Vector2.h
@@ -180,6 +180,13 @@ namespace AZ
bool IsGreaterEqualThan(const Vector2& v) const;
//! @}
+ //! Floor/Ceil/Round functions, operate on each component individually, result will be a new Vector2.
+ //! @{
+ Vector2 GetFloor() const;
+ Vector2 GetCeil() const;
+ Vector2 GetRound() const; // Ties to even (banker's rounding)
+ //! @}
+
//! Min/Max functions, operate on each component individually, result will be a new Vector2.
//! @{
Vector2 GetMin(const Vector2& v) const;
diff --git a/Code/Framework/AzCore/AzCore/Math/Vector2.inl b/Code/Framework/AzCore/AzCore/Math/Vector2.inl
index 80b2a43475..086be2bbc3 100644
--- a/Code/Framework/AzCore/AzCore/Math/Vector2.inl
+++ b/Code/Framework/AzCore/AzCore/Math/Vector2.inl
@@ -398,6 +398,24 @@ namespace AZ
}
+ AZ_MATH_INLINE Vector2 Vector2::GetFloor() const
+ {
+ return Vector2(Simd::Vec2::Floor(m_value));
+ }
+
+
+ AZ_MATH_INLINE Vector2 Vector2::GetCeil() const
+ {
+ return Vector2(Simd::Vec2::Ceil(m_value));
+ }
+
+
+ AZ_MATH_INLINE Vector2 Vector2::GetRound() const
+ {
+ return Vector2(Simd::Vec2::Round(m_value));
+ }
+
+
AZ_MATH_INLINE Vector2 Vector2::GetMin(const Vector2& v) const
{
#if AZ_TRAIT_USE_PLATFORM_SIMD_SCALAR
diff --git a/Code/Framework/AzCore/AzCore/Math/Vector3.h b/Code/Framework/AzCore/AzCore/Math/Vector3.h
index 4bf0a18894..821dc8292c 100644
--- a/Code/Framework/AzCore/AzCore/Math/Vector3.h
+++ b/Code/Framework/AzCore/AzCore/Math/Vector3.h
@@ -211,6 +211,13 @@ namespace AZ
bool IsGreaterEqualThan(const Vector3& rhs) const;
//! @}
+ //! Floor/Ceil/Round functions, operate on each component individually, result will be a new Vector3.
+ //! @{
+ Vector3 GetFloor() const;
+ Vector3 GetCeil() const;
+ Vector3 GetRound() const; // Ties to even (banker's rounding)
+ //! @}
+
//! Min/Max functions, operate on each component individually, result will be a new Vector3.
//! @{
Vector3 GetMin(const Vector3& v) const;
diff --git a/Code/Framework/AzCore/AzCore/Math/Vector3.inl b/Code/Framework/AzCore/AzCore/Math/Vector3.inl
index 56baac5aa1..879ade38cf 100644
--- a/Code/Framework/AzCore/AzCore/Math/Vector3.inl
+++ b/Code/Framework/AzCore/AzCore/Math/Vector3.inl
@@ -481,6 +481,24 @@ namespace AZ
}
+ AZ_MATH_INLINE Vector3 Vector3::GetFloor() const
+ {
+ return Vector3(Simd::Vec3::Floor(m_value));
+ }
+
+
+ AZ_MATH_INLINE Vector3 Vector3::GetCeil() const
+ {
+ return Vector3(Simd::Vec3::Ceil(m_value));
+ }
+
+
+ AZ_MATH_INLINE Vector3 Vector3::GetRound() const
+ {
+ return Vector3(Simd::Vec3::Round(m_value));
+ }
+
+
AZ_MATH_INLINE Vector3 Vector3::GetMin(const Vector3& v) const
{
#if AZ_TRAIT_USE_PLATFORM_SIMD_SCALAR
diff --git a/Code/Framework/AzCore/AzCore/Math/Vector4.h b/Code/Framework/AzCore/AzCore/Math/Vector4.h
index 6bd67e8831..eaa18bbaff 100644
--- a/Code/Framework/AzCore/AzCore/Math/Vector4.h
+++ b/Code/Framework/AzCore/AzCore/Math/Vector4.h
@@ -189,6 +189,13 @@ namespace AZ
bool IsGreaterEqualThan(const Vector4& rhs) const;
//! @}
+ //! Floor/Ceil/Round functions, operate on each component individually, result will be a new Vector4.
+ //! @{
+ Vector4 GetFloor() const;
+ Vector4 GetCeil() const;
+ Vector4 GetRound() const; // Ties to even (banker's rounding)
+ //! @}
+
//! Min/Max functions, operate on each component individually, result will be a new Vector4.
//! @{
Vector4 GetMin(const Vector4& v) const;
diff --git a/Code/Framework/AzCore/AzCore/Math/Vector4.inl b/Code/Framework/AzCore/AzCore/Math/Vector4.inl
index 4b4cf2f84f..001dfb6a4d 100644
--- a/Code/Framework/AzCore/AzCore/Math/Vector4.inl
+++ b/Code/Framework/AzCore/AzCore/Math/Vector4.inl
@@ -464,6 +464,24 @@ namespace AZ
}
+ AZ_MATH_INLINE Vector4 Vector4::GetFloor() const
+ {
+ return Vector4(Simd::Vec4::Floor(m_value));
+ }
+
+
+ AZ_MATH_INLINE Vector4 Vector4::GetCeil() const
+ {
+ return Vector4(Simd::Vec4::Ceil(m_value));
+ }
+
+
+ AZ_MATH_INLINE Vector4 Vector4::GetRound() const
+ {
+ return Vector4(Simd::Vec4::Round(m_value));
+ }
+
+
AZ_MATH_INLINE Vector4 Vector4::GetMin(const Vector4& v) const
{
#if AZ_TRAIT_USE_PLATFORM_SIMD_SCALAR
diff --git a/Code/Framework/AzCore/AzCore/Settings/SettingsRegistryMergeUtils.cpp b/Code/Framework/AzCore/AzCore/Settings/SettingsRegistryMergeUtils.cpp
index da7110e36e..e1bd717e7b 100644
--- a/Code/Framework/AzCore/AzCore/Settings/SettingsRegistryMergeUtils.cpp
+++ b/Code/Framework/AzCore/AzCore/Settings/SettingsRegistryMergeUtils.cpp
@@ -276,7 +276,9 @@ namespace AZ::SettingsRegistryMergeUtils
return engineRoot;
}
- return {};
+ // Fall back to using the project root as the engine root if the engine path could not be reconciled
+ // by checking the project.json "engine" string within o3de_manifest.json "engine_paths" object
+ return projectRoot;
}
AZ::IO::FixedMaxPath FindProjectRoot(SettingsRegistryInterface& settingsRegistry)
@@ -309,7 +311,13 @@ namespace AZ::SettingsRegistryMergeUtils
return projectRoot;
}
- return {};
+ // Step 3 Check for a "Cache" directory by scanning upwards from the executable directory
+ if (auto candidateRoot = Internal::ScanUpRootLocator("Cache");
+ !candidateRoot.empty() && AZ::IO::SystemFile::IsDirectory(candidateRoot.c_str()))
+ {
+ projectRoot = AZStd::move(candidateRoot);
+ }
+ return projectRoot;
}
AZStd::string_view ConfigParserSettings::DefaultCommentPrefixFilter(AZStd::string_view line)
@@ -717,7 +725,9 @@ namespace AZ::SettingsRegistryMergeUtils
if (registry.Get(cacheRootPath, FilePathKey_CacheRootFolder))
{
mergePath = AZStd::move(cacheRootPath);
- mergePath /= SettingsRegistryInterface::RegistryFolder;
+ AZStd::fixed_string<32> registryFolderLower(SettingsRegistryInterface::RegistryFolder);
+ AZStd::to_lower(registryFolderLower.begin(), registryFolderLower.end());
+ mergePath /= registryFolderLower;
registry.MergeSettingsFolder(mergePath.Native(), specializations, platform, "", scratchBuffer);
}
diff --git a/Code/Framework/AzCore/AzCore/Statistics/RunningStatisticsManager.cpp b/Code/Framework/AzCore/AzCore/Statistics/RunningStatisticsManager.cpp
deleted file mode 100644
index 52085d98e7..0000000000
--- a/Code/Framework/AzCore/AzCore/Statistics/RunningStatisticsManager.cpp
+++ /dev/null
@@ -1,106 +0,0 @@
-/*
- * 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 "RunningStatisticsManager.h"
-
-namespace AzFramework
-{
- namespace Statistics
- {
- bool RunningStatisticsManager::ContainsStatistic(const AZStd::string& name)
- {
- auto iterator = m_statisticsNamesToIndexMap.find(name);
- return iterator != m_statisticsNamesToIndexMap.end();
- }
-
- bool RunningStatisticsManager::AddStatistic(const AZStd::string& name, const AZStd::string& units)
- {
- if (ContainsStatistic(name))
- {
- return false;
- }
- AddStatisticValidated(name, units);
- return true;
- }
-
- void RunningStatisticsManager::RemoveStatistic(const AZStd::string& name)
- {
- auto iterator = m_statisticsNamesToIndexMap.find(name);
- if (iterator == m_statisticsNamesToIndexMap.end())
- {
- return;
- }
- AZ::u32 itemIndex = iterator->second;
- m_statistics.erase(m_statistics.begin() + itemIndex);
- m_statisticsNamesToIndexMap.erase(iterator);
- //Update the indices in m_statisticsNamesToIndexMap.
- while (itemIndex < m_statistics.size())
- {
- const AZStd::string& statName = m_statistics[itemIndex].GetName();
- m_statisticsNamesToIndexMap[statName] = itemIndex;
- ++itemIndex;
- }
- }
-
- void RunningStatisticsManager::ResetStatistic(const AZStd::string& name)
- {
- NamedRunningStatistic* stat = GetStatistic(name);
- if (!stat)
- {
- return;
- }
- stat->Reset();
- }
-
- void RunningStatisticsManager::ResetAllStatistics()
- {
- for (NamedRunningStatistic& stat : m_statistics)
- {
- stat.Reset();
- }
- }
-
- void RunningStatisticsManager::PushSampleForStatistic(const AZStd::string& name, double value)
- {
- NamedRunningStatistic* stat = GetStatistic(name);
- if (!stat)
- {
- return;
- }
- stat->PushSample(value);
- }
-
- NamedRunningStatistic* RunningStatisticsManager::GetStatistic(const AZStd::string& name, AZ::u32* indexOut)
- {
- auto iterator = m_statisticsNamesToIndexMap.find(name);
- if (iterator == m_statisticsNamesToIndexMap.end())
- {
- return nullptr;
- }
- const AZ::u32 index = iterator->second;
- if (indexOut)
- {
- *indexOut = index;
- }
- return &m_statistics[index];
- }
-
- const AZStd::vector& RunningStatisticsManager::GetAllStatistics() const
- {
- return m_statistics;
- }
-
- void RunningStatisticsManager::AddStatisticValidated(const AZStd::string& name, const AZStd::string& units)
- {
- m_statistics.emplace_back(NamedRunningStatistic(name, units));
- const AZ::u32 itemIndex = static_cast(m_statistics.size() - 1);
- m_statisticsNamesToIndexMap[name] = itemIndex;
- }
-
- }//namespace Statistics
-}//namespace AzFramework
diff --git a/Code/Framework/AzCore/AzCore/Statistics/StatisticalProfiler.h b/Code/Framework/AzCore/AzCore/Statistics/StatisticalProfiler.h
index 681635cd1c..876898f8ba 100644
--- a/Code/Framework/AzCore/AzCore/Statistics/StatisticalProfiler.h
+++ b/Code/Framework/AzCore/AzCore/Statistics/StatisticalProfiler.h
@@ -8,7 +8,6 @@
#pragma once
#include //Just to get AZ::NullMutex
-#include
#include
#include
#include
@@ -37,8 +36,7 @@ namespace AZ
//! are some things to consider when working with the StatisticalProfilerProxy:
//! The StatisticalProfilerProxy OWNS an array of StatisticalProfiler.
//! You can "manage" one of those StatisticalProfiler by getting a reference to it and
- //! add Running statistics etc. See The TerrainProfilers mentioned above to see concrete use
- //! cases on how to work with the StatisticalProfilerProxy.
+ //! add Running statistics etc.
template
class StatisticalProfiler
{
diff --git a/Code/Framework/AzCore/AzCore/Statistics/StatisticalProfilerProxy.h b/Code/Framework/AzCore/AzCore/Statistics/StatisticalProfilerProxy.h
index 33d835076f..278b2ecc98 100644
--- a/Code/Framework/AzCore/AzCore/Statistics/StatisticalProfilerProxy.h
+++ b/Code/Framework/AzCore/AzCore/Statistics/StatisticalProfilerProxy.h
@@ -7,27 +7,11 @@
*/
#pragma once
-#include
-#include
-#include
-#include
-#include
#include
#include
-#include
-
-
-#if defined(AZ_STATISTICAL_PROFILING_ENABLED)
-
-#if defined(AZ_PROFILE_SCOPE)
-#undef AZ_PROFILE_SCOPE
-#endif // #if defined(AZ_PROFILE_SCOPE)
-
-#define AZ_PROFILE_SCOPE(profiler, scopeNameId) \
- static const AZStd::string AZ_JOIN(blockName, __LINE__)(scopeNameId); \
- AZ::Statistics::StatisticalProfilerProxy::TimedScope AZ_JOIN(scope, __LINE__)(profiler, AZ_JOIN(blockName, __LINE__));
+#include
+#include
-#endif //#if defined(AZ_STATISTICAL_PROFILING_ENABLED)
namespace AZ::Statistics
{
@@ -65,7 +49,7 @@ namespace AZ::Statistics
public:
AZ_TYPE_INFO(StatisticalProfilerProxy, "{1103D0EB-1C32-4854-B9D9-40A2D65BDBD2}");
- using StatIdType = AZStd::string;
+ using StatIdType = AZ::Crc32;
using StatisticalProfilerType = StatisticalProfiler;
//! A Convenience class used to measure time performance of scopes of code
@@ -94,6 +78,7 @@ namespace AZ::Statistics
}
m_startTime = AZStd::chrono::high_resolution_clock::now();
}
+
~TimedScope()
{
if (!m_profilerProxy)
@@ -122,7 +107,6 @@ namespace AZ::Statistics
StatisticalProfilerProxy()
{
- // TODO:BUDGETS Query available budgets at registration time and create an associated profiler per type
AZ::Interface::Register(this);
}
@@ -135,30 +119,54 @@ namespace AZ::Statistics
StatisticalProfilerProxy(StatisticalProfilerProxy&&) = delete;
StatisticalProfilerProxy& operator=(StatisticalProfilerProxy&&) = delete;
+ void RegisterProfilerId(StatisticalProfilerId id)
+ {
+ m_profilers.try_emplace(id, ProfilerInfo());
+ }
+
bool IsProfilerActive(StatisticalProfilerId id) const
{
- return m_activeProfilersFlag[static_cast(id)];
+ auto iter = m_profilers.find(id);
+ return (iter != m_profilers.end()) ? iter->second.m_enabled : false;
}
StatisticalProfilerType& GetProfiler(StatisticalProfilerId id)
{
- return m_profilers[static_cast(id)];
+ auto iter = m_profilers.try_emplace(id, ProfilerInfo()).first;
+ return iter->second.m_profiler;
}
- void ActivateProfiler(StatisticalProfilerId id, bool activate)
+ void ActivateProfiler(StatisticalProfilerId id, bool activate, bool autoCreate = true)
{
- m_activeProfilersFlag[static_cast(id)] = activate;
+ if (autoCreate)
+ {
+ auto iter = m_profilers.try_emplace(id, ProfilerInfo()).first;
+ iter->second.m_enabled = activate;
+ }
+ else if (auto iter = m_profilers.find(id); iter != m_profilers.end())
+ {
+ iter->second.m_enabled = activate;
+ }
}
void PushSample(StatisticalProfilerId id, const StatIdType& statId, double value)
{
- m_profilers[static_cast(id)].PushSample(statId, value);
+ if (auto iter = m_profilers.find(id); iter != m_profilers.end())
+ {
+ iter->second.m_profiler.PushSample(statId, value);
+ }
}
private:
- // TODO:BUDGETS the number of bits allocated here must be based on the number of budgets available at profiler registration time
- AZStd::bitset<128> m_activeProfilersFlag;
- AZStd::vector m_profilers;
+ struct ProfilerInfo
+ {
+ StatisticalProfilerType m_profiler;
+ bool m_enabled{ false };
+ };
+
+ using ProfilerMap = AZStd::unordered_map;
+
+ ProfilerMap m_profilers;
}; // class StatisticalProfilerProxy
}; // namespace AZ::Statistics
diff --git a/Code/Framework/AzCore/AzCore/Task/TaskExecutor.cpp b/Code/Framework/AzCore/AzCore/Task/TaskExecutor.cpp
index 2bb88fbfa2..7da04d7301 100644
--- a/Code/Framework/AzCore/AzCore/Task/TaskExecutor.cpp
+++ b/Code/Framework/AzCore/AzCore/Task/TaskExecutor.cpp
@@ -190,11 +190,13 @@ namespace AZ
class TaskWorker
{
public:
- void Spawn(::AZ::TaskExecutor& executor, size_t id, AZStd::semaphore& initSemaphore, bool affinitize)
+ static thread_local TaskWorker* t_worker;
+
+ void Spawn(::AZ::TaskExecutor& executor, uint32_t id, AZStd::semaphore& initSemaphore, bool affinitize)
{
m_executor = &executor;
- AZStd::string threadName = AZStd::string::format("TaskWorker %zu", id);
+ AZStd::string threadName = AZStd::string::format("TaskWorker %u", id);
AZStd::thread_desc desc = {};
desc.m_name = threadName.c_str();
if (affinitize)
@@ -203,12 +205,29 @@ namespace AZ
}
m_active.store(true, AZStd::memory_order_release);
- m_thread = AZStd::thread{ [this, &initSemaphore]
+ m_thread = AZStd::thread{ desc,
+ [this, &initSemaphore]
{
+ t_worker = this;
initSemaphore.release();
Run();
- },
- &desc };
+ } };
+ }
+
+ // Threads that wait on a graph to complete are disqualified from receiving tasks until the wait finishes
+ void Disable()
+ {
+ m_enabled = false;
+ }
+
+ void Enable()
+ {
+ m_enabled = true;
+ }
+
+ bool Enabled() const
+ {
+ return m_enabled;
}
void Join()
@@ -222,11 +241,7 @@ namespace AZ
{
m_queue.Enqueue(task);
- if (!m_busy.exchange(true))
- {
- // The worker was idle prior to enqueueing the task, release the semaphore
- m_semaphore.release();
- }
+ m_semaphore.release();
}
private:
@@ -234,7 +249,6 @@ namespace AZ
{
while (m_active)
{
- m_busy = false;
m_semaphore.acquire();
if (!m_active)
@@ -242,8 +256,6 @@ namespace AZ
return;
}
- m_busy = true;
-
Task* task = m_queue.TryDequeue();
while (task)
{
@@ -271,12 +283,15 @@ namespace AZ
AZStd::thread m_thread;
AZStd::atomic m_active;
- AZStd::atomic m_busy;
+ AZStd::atomic m_enabled = true;
AZStd::binary_semaphore m_semaphore;
::AZ::TaskExecutor* m_executor;
TaskQueue m_queue;
+ friend class ::AZ::TaskExecutor;
};
+
+ thread_local TaskWorker* TaskWorker::t_worker = nullptr;
} // namespace Internal
static EnvironmentVariable s_executor;
@@ -291,13 +306,16 @@ namespace AZ
return **s_executor;
}
- // TODO: Create the default executor as part of a component (as in TaskManagerComponent)
void TaskExecutor::SetInstance(TaskExecutor* executor)
{
- AZ_Assert(!s_executor, "Attempting to set the global task executor more than once");
-
- s_executor = AZ::Environment::CreateVariable("GlobalTaskExecutor");
- s_executor.Set(executor);
+ if (!executor)
+ {
+ s_executor.Reset();
+ }
+ else if (!s_executor) // ignore any calls to set after the first (this happens in unit tests that create new system entities)
+ {
+ s_executor = AZ::Environment::CreateVariable(s_executorName, executor);
+ }
}
TaskExecutor::TaskExecutor(uint32_t threadCount)
@@ -307,14 +325,12 @@ namespace AZ
m_workers = reinterpret_cast(azmalloc(m_threadCount * sizeof(Internal::TaskWorker)));
- bool affinitize = m_threadCount == AZStd::thread::hardware_concurrency();
-
AZStd::semaphore initSemaphore;
- for (size_t i = 0; i != m_threadCount; ++i)
+ for (uint32_t i = 0; i != m_threadCount; ++i)
{
new (m_workers + i) Internal::TaskWorker{};
- m_workers[i].Spawn(*this, i, initSemaphore, affinitize);
+ m_workers[i].Spawn(*this, i, initSemaphore, false);
}
for (size_t i = 0; i != m_threadCount; ++i)
@@ -334,9 +350,21 @@ namespace AZ
azfree(m_workers);
}
- void TaskExecutor::Submit(Internal::CompiledTaskGraph& graph)
+ Internal::TaskWorker* TaskExecutor::GetTaskWorker()
+ {
+ if (Internal::TaskWorker::t_worker && Internal::TaskWorker::t_worker->m_executor == this)
+ {
+ return Internal::TaskWorker::t_worker;
+ }
+ return nullptr;
+ }
+
+ void TaskExecutor::Submit(Internal::CompiledTaskGraph& graph, TaskGraphEvent* event)
{
++m_graphsRemaining;
+
+ event->m_executor = this; // Used to validate event is not waited for inside a job
+
// Submit all tasks that have no inbound edges
for (Internal::Task& task : graph.Tasks())
{
@@ -352,11 +380,24 @@ namespace AZ
// TODO: Something more sophisticated is likely needed here.
// First, we are completely ignoring affinity.
// Second, some heuristics on core availability will help distribute work more effectively
- m_workers[++m_lastSubmission % m_threadCount].Enqueue(&task);
+ uint32_t nextWorker = ++m_lastSubmission % m_threadCount;
+ while (!m_workers[nextWorker].Enabled())
+ {
+ // Graphs that are waiting for the completion of a task graph cannot enqueue tasks onto
+ // the thread issuing the wait.
+ nextWorker = ++m_lastSubmission % m_threadCount;
+ }
+
+ m_workers[nextWorker].Enqueue(&task);
}
void TaskExecutor::ReleaseGraph()
{
--m_graphsRemaining;
}
+
+ void TaskExecutor::ReactivateTaskWorker()
+ {
+ GetTaskWorker()->Enable();
+ }
} // namespace AZ
diff --git a/Code/Framework/AzCore/AzCore/Task/TaskExecutor.h b/Code/Framework/AzCore/AzCore/Task/TaskExecutor.h
index dc2fa5a4c8..7e1ff80902 100644
--- a/Code/Framework/AzCore/AzCore/Task/TaskExecutor.h
+++ b/Code/Framework/AzCore/AzCore/Task/TaskExecutor.h
@@ -72,14 +72,19 @@ namespace AZ
explicit TaskExecutor(uint32_t threadCount = 0);
~TaskExecutor();
- void Submit(Internal::CompiledTaskGraph& graph);
+ // Submit a task graph for execution. Waitable task graphs cannot enqueue work on the task thread
+ // that is currently active
+ void Submit(Internal::CompiledTaskGraph& graph, TaskGraphEvent* event);
void Submit(Internal::Task& task);
private:
friend class Internal::TaskWorker;
+ friend class TaskGraphEvent;
+ Internal::TaskWorker* GetTaskWorker();
void ReleaseGraph();
+ void ReactivateTaskWorker();
Internal::TaskWorker* m_workers;
uint32_t m_threadCount = 0;
diff --git a/Code/Framework/AzCore/AzCore/Task/TaskGraph.cpp b/Code/Framework/AzCore/AzCore/Task/TaskGraph.cpp
index 3fb93903c9..f57b06890a 100644
--- a/Code/Framework/AzCore/AzCore/Task/TaskGraph.cpp
+++ b/Code/Framework/AzCore/AzCore/Task/TaskGraph.cpp
@@ -14,6 +14,12 @@ namespace AZ
{
using Internal::CompiledTaskGraph;
+ void TaskGraphEvent::Wait()
+ {
+ AZ_Assert(m_executor->GetTaskWorker() == nullptr, "Waiting in a task is unsupported");
+ m_semaphore.acquire();
+ }
+
void TaskToken::PrecedesInternal(TaskToken& comesAfter)
{
AZ_Assert(!m_parent.m_submitted, "Cannot mutate a TaskGraph that was previously submitted.");
@@ -71,7 +77,7 @@ namespace AZ
m_compiledTaskGraph->m_tasks[i].Init();
}
- executor.Submit(*m_compiledTaskGraph);
+ executor.Submit(*m_compiledTaskGraph, waitEvent);
if (m_retained)
{
diff --git a/Code/Framework/AzCore/AzCore/Task/TaskGraph.h b/Code/Framework/AzCore/AzCore/Task/TaskGraph.h
index 4b454c63de..9553013a4b 100644
--- a/Code/Framework/AzCore/AzCore/Task/TaskGraph.h
+++ b/Code/Framework/AzCore/AzCore/Task/TaskGraph.h
@@ -22,10 +22,19 @@ namespace AZ
namespace Internal
{
class CompiledTaskGraph;
+ class TaskWorker;
}
class TaskExecutor;
class TaskGraph;
+ class TaskGraphActiveInterface
+ {
+ public:
+ AZ_RTTI(TaskGraphActiveInterface, "{08118074-B139-4EF9-B8FD-29F1D6DC9233}");
+
+ virtual bool IsTaskGraphActive() const = 0;
+ };
+
// A TaskToken is returned each time a Task is added to the TaskGraph. TaskTokens are used to
// express dependencies between tasks within the graph, and have no purpose after the graph
// is submitted (simply let them go out of scope)
@@ -70,9 +79,12 @@ namespace AZ
private:
friend class ::AZ::Internal::CompiledTaskGraph;
friend class TaskGraph;
+ friend class TaskExecutor;
+
void Signal();
AZStd::binary_semaphore m_semaphore;
+ TaskExecutor* m_executor = nullptr;
};
// The TaskGraph encapsulates a set of tasks and their interdependencies. After adding
@@ -89,6 +101,9 @@ namespace AZ
// Reset the state of the task graph to begin recording tasks and edges again
// NOTE: Graph must be in a "settled" state (cannot be in-flight)
void Reset();
+
+ // Returns false if 1 or more tasks have been added to the graph
+ bool IsEmpty();
// Add a task to the graph, retrieiving a token that can be used to express dependencies
// between tasks. The first argument specifies the TaskKind, used for tracking the task.
diff --git a/Code/Framework/AzCore/AzCore/Task/TaskGraph.inl b/Code/Framework/AzCore/AzCore/Task/TaskGraph.inl
index e0ac74ba9d..7b2f0cefdc 100644
--- a/Code/Framework/AzCore/AzCore/Task/TaskGraph.inl
+++ b/Code/Framework/AzCore/AzCore/Task/TaskGraph.inl
@@ -33,11 +33,6 @@ namespace AZ
return m_semaphore.try_acquire_for(AZStd::chrono::milliseconds{ 0 });
}
- inline void TaskGraphEvent::Wait()
- {
- m_semaphore.acquire();
- }
-
inline void TaskGraphEvent::Signal()
{
m_semaphore.release();
@@ -59,6 +54,11 @@ namespace AZ
return { AddTask(descriptor, AZStd::forward(lambdas))... };
}
+ inline bool TaskGraph::IsEmpty()
+ {
+ return m_tasks.empty();
+ }
+
inline void TaskGraph::Detach()
{
m_retained = false;
diff --git a/Code/Framework/AzCore/AzCore/Task/TaskGraphSystemComponent.cpp b/Code/Framework/AzCore/AzCore/Task/TaskGraphSystemComponent.cpp
new file mode 100644
index 0000000000..eed461ecb4
--- /dev/null
+++ b/Code/Framework/AzCore/AzCore/Task/TaskGraphSystemComponent.cpp
@@ -0,0 +1,88 @@
+/*
+ * 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
+#include
+#include
+#include
+
+// Create a cvar as a central location for experimentation with switching from the Job system to TaskGraph system.
+AZ_CVAR(bool, cl_activateTaskGraph, false, nullptr, AZ::ConsoleFunctorFlags::Null, "Flag clients of TaskGraph to switch between jobs/taskgraph (Note does not disable task graph system)");
+static constexpr uint32_t TaskExecutorServiceCrc = AZ_CRC_CE("TaskExecutorService");
+
+namespace AZ
+{
+ void TaskGraphSystemComponent::Activate()
+ {
+ AZ_Assert(m_taskExecutor == nullptr, "Error multiple activation of the TaskGraphSystemComponent");
+
+ if (Interface::Get() == nullptr)
+ {
+ Interface::Register(this);
+ m_taskExecutor = aznew TaskExecutor();
+ TaskExecutor::SetInstance(m_taskExecutor);
+ }
+ }
+
+ void TaskGraphSystemComponent::Deactivate()
+ {
+ if (&TaskExecutor::Instance() == m_taskExecutor) // check that our instance is the global instance (not always true in unit tests)
+ {
+ m_taskExecutor->SetInstance(nullptr);
+ }
+ if (m_taskExecutor)
+ {
+ azdestroy(m_taskExecutor);
+ m_taskExecutor = nullptr;
+ }
+ if (Interface::Get() == this)
+ {
+ Interface::Unregister(this);
+ }
+ }
+
+ void TaskGraphSystemComponent::GetProvidedServices(ComponentDescriptor::DependencyArrayType& provided)
+ {
+ provided.push_back(TaskExecutorServiceCrc);
+ }
+
+ void TaskGraphSystemComponent::GetIncompatibleServices(ComponentDescriptor::DependencyArrayType& incompatible)
+ {
+ incompatible.push_back(TaskExecutorServiceCrc);
+ }
+
+ void TaskGraphSystemComponent::GetDependentServices([[maybe_unused]] ComponentDescriptor::DependencyArrayType& dependent)
+ {
+ }
+
+ void TaskGraphSystemComponent::Reflect(ReflectContext* context)
+ {
+ if (SerializeContext* serializeContext = azrtti_cast(context))
+ {
+ serializeContext->Class()
+ ->Version(1)
+ ;
+
+ if (AZ::EditContext* ec = serializeContext->GetEditContext())
+ {
+ ec->Class
+ ("TaskGraph", "System component to create the default executor")
+ ->ClassElement(AZ::Edit::ClassElements::EditorData, "")
+ ->Attribute(AZ::Edit::Attributes::Category, "Engine")
+ ->Attribute(AZ::Edit::Attributes::AppearsInAddComponentMenu, AZ_CRC_CE("System"))
+ ;
+ }
+ }
+ }
+
+ bool TaskGraphSystemComponent::IsTaskGraphActive() const
+ {
+ return cl_activateTaskGraph;
+ }
+} // namespace AZ
diff --git a/Code/Framework/AzCore/AzCore/Task/TaskGraphSystemComponent.h b/Code/Framework/AzCore/AzCore/Task/TaskGraphSystemComponent.h
new file mode 100644
index 0000000000..a4c6da9539
--- /dev/null
+++ b/Code/Framework/AzCore/AzCore/Task/TaskGraphSystemComponent.h
@@ -0,0 +1,47 @@
+/*
+ * 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
+
+namespace AZ
+{
+ class TaskGraphSystemComponent
+ : public Component
+ , public TaskGraphActiveInterface
+ {
+ public:
+ AZ_COMPONENT(AZ::TaskGraphSystemComponent, "{5D56B829-1FEB-43D5-A0BD-E33C0497EFE2}")
+
+ TaskGraphSystemComponent() = default;
+
+ // Implement TaskGraphActiveInterface
+ bool IsTaskGraphActive() const override;
+
+ private:
+ //////////////////////////////////////////////////////////////////////////
+ // Component base
+ void Activate() override;
+ void Deactivate() override;
+ //////////////////////////////////////////////////////////////////////////
+
+ /// \ref ComponentDescriptor::GetProvidedServices
+ static void GetProvidedServices(ComponentDescriptor::DependencyArrayType& provided);
+ /// \ref ComponentDescriptor::GetIncompatibleServices
+ static void GetIncompatibleServices(ComponentDescriptor::DependencyArrayType& incompatible);
+ /// \ref ComponentDescriptor::GetDependentServices
+ static void GetDependentServices(ComponentDescriptor::DependencyArrayType& dependent);
+ /// \red ComponentDescriptor::Reflect
+ static void Reflect(ReflectContext* reflection);
+
+ AZ::TaskExecutor* m_taskExecutor = nullptr;
+ };
+}
diff --git a/Code/Framework/AzCore/AzCore/Time/ITime.h b/Code/Framework/AzCore/AzCore/Time/ITime.h
index 845017bd14..a97ba2319a 100644
--- a/Code/Framework/AzCore/AzCore/Time/ITime.h
+++ b/Code/Framework/AzCore/AzCore/Time/ITime.h
@@ -13,14 +13,26 @@
#include
#include
#include
+#include
namespace AZ
{
//! This is a strong typedef for representing a millisecond value since application start.
AZ_TYPE_SAFE_INTEGRAL(TimeMs, int64_t);
+ //! This is a strong typedef for representing a microsecond value since application start.
+ //! Using int64_t as the underlying type, this is good to represent approximately 292,471 years
+ AZ_TYPE_SAFE_INTEGRAL(TimeUs, int64_t);
+
//! @class ITime
//! @brief This is an AZ::Interface<> for managing time related operations.
+ //! AZ::ITime and associated types may not operate in realtime. These abstractions are to allow our application
+ //! simulation to operate both slower and faster than realtime in a well defined and user controllable manner
+ //! The rate at which time passes for AZ::ITime is controlled by the cvar t_scale
+ //! t_scale == 0 means simulation time should halt
+ //! 0 < t_scale < 1 will cause time to pass slower than realtime, with t_scale 0.1 being roughly 1/10th realtime
+ //! t_scale == 1 will cause time to pass at roughly realtime
+ //! t_scale > 1 will cause time to pass faster than normal, with t_scale 10 being roughly 10x realtime
class ITime
{
public:
@@ -33,6 +45,10 @@ namespace AZ
//! @return the number of milliseconds that have elapsed since application start
virtual TimeMs GetElapsedTimeMs() const = 0;
+ //! Returns the number of microseconds since application start.
+ //! @return the number of microseconds that have elapsed since application start
+ virtual TimeUs GetElapsedTimeUs() const = 0;
+
AZ_DISABLE_COPY_MOVE(ITime);
};
@@ -51,6 +67,53 @@ namespace AZ
{
return AZ::Interface::Get()->GetElapsedTimeMs();
}
-}
+
+ //! This is a simple convenience wrapper
+ inline TimeUs GetElapsedTimeUs()
+ {
+ return AZ::Interface::Get()->GetElapsedTimeUs();
+ }
+
+ //! Converts from milliseconds to microseconds
+ inline TimeUs TimeMsToUs(TimeMs value)
+ {
+ return static_cast(value * static_cast(1000));
+ }
+
+ //! Converts from microseconds to milliseconds
+ inline TimeMs TimeUsToMs(TimeUs value)
+ {
+ return static_cast(value / static_cast(1000));
+ }
+
+ //! Converts from milliseconds to seconds
+ inline float TimeMsToSeconds(TimeMs value)
+ {
+ return static_cast(value) / 1000.0f;
+ }
+
+ //! Converts from microseconds to seconds
+ inline float TimeUsToSeconds(TimeUs value)
+ {
+ return static_cast(value) / 1000000.0f;
+ }
+
+ //! Converts from milliseconds to AZStd::chrono::time_point
+ inline auto TimeMsToChrono(TimeMs value)
+ {
+ auto epoch = AZStd::chrono::time_point();
+ auto chronoValue = AZStd::chrono::milliseconds(aznumeric_cast(value));
+ return epoch + chronoValue;
+ }
+
+ //! Converts from microseconds to AZStd::chrono::time_point
+ inline auto TimeUsToChrono(TimeUs value)
+ {
+ auto epoch = AZStd::chrono::time_point();
+ auto chronoValue = AZStd::chrono::microseconds(aznumeric_cast(value));
+ return epoch + chronoValue;
+ }
+} // namespace AZ
AZ_TYPE_SAFE_INTEGRAL_SERIALIZEBINDING(AZ::TimeMs);
+AZ_TYPE_SAFE_INTEGRAL_SERIALIZEBINDING(AZ::TimeUs);
diff --git a/Code/Framework/AzCore/AzCore/Time/TimeSystemComponent.cpp b/Code/Framework/AzCore/AzCore/Time/TimeSystemComponent.cpp
index a2e7733222..99145d377a 100644
--- a/Code/Framework/AzCore/AzCore/Time/TimeSystemComponent.cpp
+++ b/Code/Framework/AzCore/AzCore/Time/TimeSystemComponent.cpp
@@ -35,7 +35,7 @@ namespace AZ
TimeSystemComponent::TimeSystemComponent()
{
- m_lastInvokedTimeMs = static_cast(AZStd::GetTimeNowMicroSecond() / 1000);
+ m_lastInvokedTimeUs = static_cast(AZStd::GetTimeNowMicroSecond());
AZ::Interface::Register(this);
ITimeRequestBus::Handler::BusConnect();
}
@@ -58,18 +58,23 @@ namespace AZ
TimeMs TimeSystemComponent::GetElapsedTimeMs() const
{
- TimeMs currentTime = static_cast(AZStd::GetTimeNowMicroSecond() / 1000);
- TimeMs deltaTime = currentTime - m_lastInvokedTimeMs;
+ return TimeUsToMs(GetElapsedTimeUs());
+ }
+
+ TimeUs TimeSystemComponent::GetElapsedTimeUs() const
+ {
+ TimeUs currentTime = static_cast(AZStd::GetTimeNowMicroSecond());
+ TimeUs deltaTime = currentTime - m_lastInvokedTimeUs;
if (t_scale != 1.0f)
{
float floatDelta = static_cast(deltaTime) * t_scale;
- deltaTime = static_cast(static_cast(floatDelta));
+ deltaTime = static_cast(static_cast(floatDelta));
}
- m_accumulatedTimeMs += deltaTime;
- m_lastInvokedTimeMs = currentTime;
+ m_accumulatedTimeUs += deltaTime;
+ m_lastInvokedTimeUs = currentTime;
- return m_accumulatedTimeMs;
+ return m_accumulatedTimeUs;
}
}
diff --git a/Code/Framework/AzCore/AzCore/Time/TimeSystemComponent.h b/Code/Framework/AzCore/AzCore/Time/TimeSystemComponent.h
index adf576becb..3ab3dbc234 100644
--- a/Code/Framework/AzCore/AzCore/Time/TimeSystemComponent.h
+++ b/Code/Framework/AzCore/AzCore/Time/TimeSystemComponent.h
@@ -39,11 +39,12 @@ namespace AZ
//! ITime overrides.
//! @{
TimeMs GetElapsedTimeMs() const override;
+ TimeUs GetElapsedTimeUs() const override;
//! @}
private:
- mutable TimeMs m_lastInvokedTimeMs = TimeMs{0};
- mutable TimeMs m_accumulatedTimeMs = TimeMs{0};
+ mutable TimeUs m_lastInvokedTimeUs = TimeUs{0};
+ mutable TimeUs m_accumulatedTimeUs = TimeUs{0};
};
}
diff --git a/Code/Framework/AzCore/AzCore/azcore_files.cmake b/Code/Framework/AzCore/AzCore/azcore_files.cmake
index aa07959997..14579cbf33 100644
--- a/Code/Framework/AzCore/AzCore/azcore_files.cmake
+++ b/Code/Framework/AzCore/AzCore/azcore_files.cmake
@@ -633,6 +633,8 @@ set(FILES
Task/TaskGraph.cpp
Task/TaskGraph.h
Task/TaskGraph.inl
+ Task/TaskGraphSystemComponent.h
+ Task/TaskGraphSystemComponent.cpp
Threading/ThreadSafeDeque.h
Threading/ThreadSafeDeque.inl
Threading/ThreadSafeObject.h
diff --git a/Code/Framework/AzCore/AzCore/std/parallel/thread.h b/Code/Framework/AzCore/AzCore/std/parallel/thread.h
index 15d8c9dc8e..eef269c8ac 100644
--- a/Code/Framework/AzCore/AzCore/std/parallel/thread.h
+++ b/Code/Framework/AzCore/AzCore/std/parallel/thread.h
@@ -87,12 +87,6 @@ namespace AZStd
// construct/copy/destroy:
thread();
- /**
- * \note thread_desc is AZStd extension.
- */
- template
- explicit thread(F&& f, const thread_desc* desc = 0);
-
~thread();
thread(thread&& rhs)
@@ -108,6 +102,15 @@ namespace AZStd
return *this;
}
+ template, thread_desc>>>
+ explicit thread(F&& f, Args&&... args);
+
+ /**
+ * \note thread_desc is AZStd extension.
+ */
+ template
+ thread(const thread_desc& desc, F&& f, Args&&... args);
+
// Till we fully have RVALUES
template
explicit thread(Internal::thread_move_t f);
@@ -138,8 +141,8 @@ namespace AZStd
//thread(AZStd::delegate d,const thread_desc* desc = 0);
private:
- thread(thread&);
- thread& operator=(thread&);
+ thread(const thread&) = delete;
+ thread& operator=(const thread&) = delete;
native_thread_data_type m_thread;
};
diff --git a/Code/Framework/AzCore/Platform/Android/AzCore/IO/SystemFile_Android.cpp b/Code/Framework/AzCore/Platform/Android/AzCore/IO/SystemFile_Android.cpp
index 001cd57ac5..b9a6cfef9a 100644
--- a/Code/Framework/AzCore/Platform/Android/AzCore/IO/SystemFile_Android.cpp
+++ b/Code/Framework/AzCore/Platform/Android/AzCore/IO/SystemFile_Android.cpp
@@ -368,6 +368,21 @@ namespace Platform
return access(fileName, F_OK) == 0;
}
}
+
+ bool IsDirectory(const char* filePath)
+ {
+ if (AZ::Android::Utils::IsApkPath(filePath))
+ {
+ return AZ::Android::APKFileHandler::IsDirectory(AZ::Android::Utils::StripApkPrefix(filePath).c_str());
+ }
+
+ struct stat result;
+ if (stat(filePath, &result) == 0)
+ {
+ return S_ISDIR(result.st_mode);
+ }
+ return false;
+ }
} // namespace AZ::IO::Platform
} // namespace AZ::IO
diff --git a/Code/Framework/AzCore/Platform/Common/UnixLike/AzCore/Debug/Trace_UnixLike.cpp b/Code/Framework/AzCore/Platform/Common/UnixLike/AzCore/Debug/Trace_UnixLike.cpp
index e9c0234ffa..f4d7db802b 100644
--- a/Code/Framework/AzCore/Platform/Common/UnixLike/AzCore/Debug/Trace_UnixLike.cpp
+++ b/Code/Framework/AzCore/Platform/Common/UnixLike/AzCore/Debug/Trace_UnixLike.cpp
@@ -38,7 +38,7 @@ namespace AZ
{
return false;
}
- for (size_t i = tracerPidOffset; i < numRead; ++i)
+ for (size_t i = tracerPidOffset + tracerPidString.length(); i < numRead; ++i)
{
if (!::isspace(processStatusView[i]))
{
diff --git a/Code/Framework/AzCore/Platform/Common/UnixLike/AzCore/std/parallel/internal/thread_UnixLike.h b/Code/Framework/AzCore/Platform/Common/UnixLike/AzCore/std/parallel/internal/thread_UnixLike.h
index 499caebac0..d9a4982a0a 100644
--- a/Code/Framework/AzCore/Platform/Common/UnixLike/AzCore/std/parallel/internal/thread_UnixLike.h
+++ b/Code/Framework/AzCore/Platform/Common/UnixLike/AzCore/std/parallel/internal/thread_UnixLike.h
@@ -10,6 +10,8 @@
#include
#include
+#include
+
namespace AZStd
{
namespace Internal
@@ -22,12 +24,20 @@ namespace AZStd
//////////////////////////////////////////////////////////////////////////
// thread
- template
- inline thread::thread(F&& f, const thread_desc* desc)
+ template
+ thread::thread(F&& f, Args&&... args)
+ : thread(thread_desc{}, AZStd::forward(f), AZStd::forward(args)...)
+ {}
+
+ template
+ thread::thread(const thread_desc& desc, F&& f, Args&&... args)
{
- Internal::thread_info* ti = Internal::create_thread_info(AZStd::forward(f));
- ti->m_name = desc ? desc->m_name : nullptr;
- m_thread = Internal::create_thread(desc, ti);
+ auto threadfunc = [fn = AZStd::forward(f), argsTuple = AZStd::make_tuple(AZStd::forward(args)...)]() mutable -> void
+ {
+ AZStd::apply(AZStd::move(fn), AZStd::move(argsTuple));
+ };
+ Internal::thread_info* ti = Internal::create_thread_info(AZStd::move(threadfunc));
+ m_thread = Internal::create_thread(&desc, ti);
}
inline bool thread::joinable() const
diff --git a/Code/Framework/AzCore/Platform/Common/UnixLikeDefault/AzCore/IO/SystemFile_UnixLikeDefault.cpp b/Code/Framework/AzCore/Platform/Common/UnixLikeDefault/AzCore/IO/SystemFile_UnixLikeDefault.cpp
index 3ca7a3fc76..88c47ed142 100644
--- a/Code/Framework/AzCore/Platform/Common/UnixLikeDefault/AzCore/IO/SystemFile_UnixLikeDefault.cpp
+++ b/Code/Framework/AzCore/Platform/Common/UnixLikeDefault/AzCore/IO/SystemFile_UnixLikeDefault.cpp
@@ -249,6 +249,16 @@ namespace Platform
{
return access(fileName, F_OK) == 0;
}
+
+ bool IsDirectory(const char* filePath)
+ {
+ struct stat result;
+ if (stat(filePath, &result) == 0)
+ {
+ return S_ISDIR(result.st_mode);
+ }
+ return false;
+ }
}
} // namespace AZ::IO
diff --git a/Code/Framework/AzCore/Platform/Common/WinAPI/AzCore/IO/SystemFile_WinAPI.cpp b/Code/Framework/AzCore/Platform/Common/WinAPI/AzCore/IO/SystemFile_WinAPI.cpp
index 15d779017d..0fe32dcd4a 100644
--- a/Code/Framework/AzCore/Platform/Common/WinAPI/AzCore/IO/SystemFile_WinAPI.cpp
+++ b/Code/Framework/AzCore/Platform/Common/WinAPI/AzCore/IO/SystemFile_WinAPI.cpp
@@ -10,6 +10,7 @@
#include
#include
#include
+#include
#include
#include
@@ -18,7 +19,7 @@
namespace AZ::IO
{
-
+ using FixedMaxPathWString = AZStd::fixed_wstring;
namespace
{
//=========================================================================
@@ -28,16 +29,9 @@ namespace
//=========================================================================
DWORD GetAttributes(const char* fileName)
{
- wchar_t fileNameW[AZ_MAX_PATH_LEN];
- size_t numCharsConverted;
- if (mbstowcs_s(&numCharsConverted, fileNameW, fileName, AZ_ARRAY_SIZE(fileNameW) - 1) == 0)
- {
- return GetFileAttributesW(fileNameW);
- }
- else
- {
- return INVALID_FILE_ATTRIBUTES;
- }
+ FixedMaxPathWString fileNameW;
+ AZStd::to_wstring(fileNameW, fileName);
+ return GetFileAttributesW(fileNameW.c_str());
}
//=========================================================================
@@ -47,16 +41,9 @@ namespace
//=========================================================================
BOOL SetAttributes(const char* fileName, DWORD fileAttributes)
{
- wchar_t fileNameW[AZ_MAX_PATH_LEN];
- size_t numCharsConverted;
- if (mbstowcs_s(&numCharsConverted, fileNameW, fileName, AZ_ARRAY_SIZE(fileNameW) - 1) == 0)
- {
- return SetFileAttributesW(fileNameW, fileAttributes);
- }
- else
- {
- return FALSE;
- }
+ FixedMaxPathWString fileNameW;
+ AZStd::to_wstring(fileNameW, fileName);
+ return SetFileAttributesW(fileNameW.c_str(), fileAttributes);
}
//=========================================================================
@@ -68,9 +55,9 @@ namespace
// * GetLastError() on Windows-like platforms
// * errno on Unix platforms
//=========================================================================
- bool CreateDirRecursive(wchar_t* dirPath)
+ bool CreateDirRecursive(AZ::IO::FixedMaxPathWString& dirPath)
{
- if (CreateDirectoryW(dirPath, nullptr))
+ if (CreateDirectoryW(dirPath.c_str(), nullptr))
{
return true; // Created without error
}
@@ -78,28 +65,24 @@ namespace
if (error == ERROR_PATH_NOT_FOUND)
{
// try to create our parent hierarchy
- for (size_t i = wcslen(dirPath); i > 0; --i)
+ if (size_t i = dirPath.find_last_of(LR"(/\)"); i != FixedMaxPathWString::npos)
{
- if (dirPath[i] == L'/' || dirPath[i] == L'\\')
+ wchar_t delimiter = dirPath[i];
+ dirPath[i] = 0; // null-terminate at the previous slash
+ const bool ret = CreateDirRecursive(dirPath);
+ dirPath[i] = delimiter; // restore slash
+ if (ret)
{
- wchar_t delimiter = dirPath[i];
- dirPath[i] = 0; // null-terminate at the previous slash
- bool ret = CreateDirRecursive(dirPath);
- dirPath[i] = delimiter; // restore slash
- if (ret)
- {
- // now that our parent is created, try to create again
- return CreateDirectoryW(dirPath, nullptr) != 0;
- }
- return false;
+ // now that our parent is created, try to create again
+ return CreateDirectoryW(dirPath.c_str(), nullptr) != 0;
}
}
// if we reach here then there was no parent folder to create, so we failed for other reasons
}
else if (error == ERROR_ALREADY_EXISTS)
{
- DWORD attributes = GetFileAttributesW(dirPath);
- return (attributes & FILE_ATTRIBUTE_DIRECTORY) != 0;
+ DWORD attributes = GetFileAttributesW(dirPath.c_str());
+ return attributes != INVALID_FILE_ATTRIBUTES && (attributes & FILE_ATTRIBUTE_DIRECTORY) != 0;
}
return false;
}
@@ -152,13 +135,10 @@ bool SystemFile::PlatformOpen(int mode, int platformFlags)
CreatePath(m_fileName.c_str());
}
- wchar_t fileNameW[AZ_MAX_PATH_LEN];
- size_t numCharsConverted;
+ AZ::IO::FixedMaxPathWString fileNameW;
+ AZStd::to_wstring(fileNameW, m_fileName);
m_handle = INVALID_HANDLE_VALUE;
- if (mbstowcs_s(&numCharsConverted, fileNameW, m_fileName.c_str(), AZ_ARRAY_SIZE(fileNameW) - 1) == 0)
- {
- m_handle = CreateFileW(fileNameW, dwDesiredAccess, dwShareMode, 0, dwCreationDisposition, dwFlagsAndAttributes, 0);
- }
+ m_handle = CreateFileW(fileNameW.c_str(), dwDesiredAccess, dwShareMode, 0, dwCreationDisposition, dwFlagsAndAttributes, 0);
if (m_handle == INVALID_HANDLE_VALUE)
{
@@ -350,6 +330,12 @@ namespace Platform
return GetAttributes(fileName) != INVALID_FILE_ATTRIBUTES;
}
+ bool IsDirectory(const char* filePath)
+ {
+ DWORD attributes = GetAttributes(filePath);
+ return attributes != INVALID_FILE_ATTRIBUTES && (attributes & FILE_ATTRIBUTE_DIRECTORY) != 0;
+ }
+
void FindFiles(const char* filter, SystemFile::FindFileCB cb)
{
@@ -357,35 +343,26 @@ namespace Platform
HANDLE hFile;
int lastError;
- wchar_t filterW[AZ_MAX_PATH_LEN];
- size_t numCharsConverted;
+ AZ::IO::FixedMaxPathWString filterW;
+ AZStd::to_wstring(filterW, filter);
hFile = INVALID_HANDLE_VALUE;
- if (mbstowcs_s(&numCharsConverted, filterW, filter, AZ_ARRAY_SIZE(filterW) - 1) == 0)
- {
- hFile = FindFirstFile(filterW, &fd);
- }
+ hFile = FindFirstFileW(filterW.c_str(), &fd);
if (hFile != INVALID_HANDLE_VALUE)
{
const char* fileName;
- char fileNameA[AZ_MAX_PATH_LEN];
- fileName = NULL;
- if (wcstombs_s(&numCharsConverted, fileNameA, fd.cFileName, AZ_ARRAY_SIZE(fileNameA) - 1) == 0)
- {
- fileName = fileNameA;
- }
+ AZ::IO::FixedMaxPathString fileNameUtf8;
+ AZStd::to_string(fileNameUtf8, fd.cFileName);
+ fileName = fileNameUtf8.c_str();
cb(fileName, (fd.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) == 0);
// List all the other files in the directory.
while (FindNextFileW(hFile, &fd) != 0)
{
- fileName = NULL;
- if (wcstombs_s(&numCharsConverted, fileNameA, fd.cFileName, AZ_ARRAY_SIZE(fileNameA) - 1) == 0)
- {
- fileName = fileNameA;
- }
+ AZStd::to_string(fileNameUtf8, fd.cFileName);
+ fileName = fileNameUtf8.c_str();
cb(fileName, (fd.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) == 0);
}
@@ -411,12 +388,9 @@ namespace Platform
{
HANDLE handle = nullptr;
- wchar_t fileNameW[AZ_MAX_PATH_LEN];
- size_t numCharsConverted;
- if (mbstowcs_s(&numCharsConverted, fileNameW, fileName, AZ_ARRAY_SIZE(fileNameW) - 1) == 0)
- {
- handle = CreateFileW(fileNameW, 0, FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, OPEN_EXISTING, 0, NULL);
- }
+ AZ::IO::FixedMaxPathWString fileNameW;
+ AZStd::to_wstring(fileNameW, fileName);
+ handle = CreateFileW(fileNameW.c_str(), 0, FILE_SHARE_READ | FILE_SHARE_WRITE, nullptr, OPEN_EXISTING, 0, nullptr);
if (handle == INVALID_HANDLE_VALUE)
{
@@ -448,12 +422,9 @@ namespace Platform
WIN32_FILE_ATTRIBUTE_DATA data = { 0 };
BOOL result = FALSE;
- wchar_t fileNameW[AZ_MAX_PATH_LEN];
- size_t numCharsConverted;
- if (mbstowcs_s(&numCharsConverted, fileNameW, fileName, AZ_ARRAY_SIZE(fileNameW) - 1) == 0)
- {
- result = GetFileAttributesExW(fileNameW, GetFileExInfoStandard, &data);
- }
+ AZ::IO::FixedMaxPathWString fileNameW;
+ AZStd::to_wstring(fileNameW, fileName);
+ result = GetFileAttributesExW(fileNameW.c_str(), GetFileExInfoStandard, &data);
if (result)
{
@@ -473,18 +444,11 @@ namespace Platform
bool Delete(const char* fileName)
{
- wchar_t fileNameW[AZ_MAX_PATH_LEN];
- size_t numCharsConverted;
- if (mbstowcs_s(&numCharsConverted, fileNameW, fileName, AZ_ARRAY_SIZE(fileNameW) - 1) == 0)
- {
- if (DeleteFileW(fileNameW) == 0)
- {
- EBUS_EVENT(FileIOEventBus, OnError, nullptr, fileName, (int)GetLastError());
- return false;
- }
- }
- else
+ AZ::IO::FixedMaxPathWString fileNameW;
+ AZStd::to_wstring(fileNameW, fileName);
+ if (DeleteFileW(fileNameW.c_str()) == 0)
{
+ EBUS_EVENT(FileIOEventBus, OnError, nullptr, fileName, (int)GetLastError());
return false;
}
@@ -493,20 +457,13 @@ namespace Platform
bool Rename(const char* sourceFileName, const char* targetFileName, bool overwrite)
{
- wchar_t sourceFileNameW[AZ_MAX_PATH_LEN];
- wchar_t targetFileNameW[AZ_MAX_PATH_LEN];
- size_t numCharsConverted;
- if (mbstowcs_s(&numCharsConverted, sourceFileNameW, sourceFileName, AZ_ARRAY_SIZE(sourceFileNameW) - 1) == 0 &&
- mbstowcs_s(&numCharsConverted, targetFileNameW, targetFileName, AZ_ARRAY_SIZE(targetFileNameW) - 1) == 0)
- {
- if (MoveFileExW(sourceFileNameW, targetFileNameW, overwrite ? MOVEFILE_REPLACE_EXISTING : 0) == 0)
- {
- EBUS_EVENT(FileIOEventBus, OnError, nullptr, sourceFileName, (int)GetLastError());
- return false;
- }
- }
- else
+ AZ::IO::FixedMaxPathWString sourceFileNameW;
+ AZStd::to_wstring(sourceFileNameW, sourceFileName);
+ AZ::IO::FixedMaxPathWString targetFileNameW;
+ AZStd::to_wstring(targetFileNameW, targetFileName);
+ if (MoveFileExW(sourceFileNameW.c_str(), targetFileNameW.c_str(), overwrite ? MOVEFILE_REPLACE_EXISTING : 0) == 0)
{
+ EBUS_EVENT(FileIOEventBus, OnError, nullptr, sourceFileName, (int)GetLastError());
return false;
}
@@ -543,17 +500,14 @@ namespace Platform
{
if (dirName)
{
- wchar_t dirPath[AZ_MAX_PATH_LEN];
- size_t numCharsConverted;
- if (mbstowcs_s(&numCharsConverted, dirPath, dirName, AZ_ARRAY_SIZE(dirPath) - 1) == 0)
+ AZ::IO::FixedMaxPathWString dirNameW;
+ AZStd::to_wstring(dirNameW, dirName);
+ bool success = CreateDirRecursive(dirNameW);
+ if (!success)
{
- bool success = CreateDirRecursive(dirPath);
- if (!success)
- {
- EBUS_EVENT(FileIOEventBus, OnError, nullptr, dirName, (int)GetLastError());
- }
- return success;
+ EBUS_EVENT(FileIOEventBus, OnError, nullptr, dirName, (int)GetLastError());
}
+ return success;
}
return false;
}
@@ -562,12 +516,9 @@ namespace Platform
{
if (dirName)
{
- wchar_t dirNameW[AZ_MAX_PATH_LEN];
- size_t numCharsConverted;
- if (mbstowcs_s(&numCharsConverted, dirNameW, dirName, AZ_ARRAY_SIZE(dirNameW) - 1) == 0)
- {
- return RemoveDirectory(dirNameW) != 0;
- }
+ AZ::IO::FixedMaxPathWString dirNameW;
+ AZStd::to_wstring(dirNameW, dirName);
+ return RemoveDirectory(dirNameW.c_str()) != 0;
}
return false;
diff --git a/Code/Framework/AzCore/Platform/Common/WinAPI/AzCore/std/parallel/internal/thread_WinAPI.h b/Code/Framework/AzCore/Platform/Common/WinAPI/AzCore/std/parallel/internal/thread_WinAPI.h
index 46986521e7..c79381a74a 100644
--- a/Code/Framework/AzCore/Platform/Common/WinAPI/AzCore/std/parallel/internal/thread_WinAPI.h
+++ b/Code/Framework/AzCore/Platform/Common/WinAPI/AzCore/std/parallel/internal/thread_WinAPI.h
@@ -18,6 +18,8 @@ extern "C"
AZ_DLL_IMPORT unsigned long __stdcall GetCurrentThreadId(void);
}
+#include
+
namespace AZStd
{
namespace Internal
@@ -30,11 +32,20 @@ namespace AZStd
//////////////////////////////////////////////////////////////////////////
// thread
- template
- inline thread::thread(F&& f, const thread_desc* desc)
+ template
+ thread::thread(F&& f, Args&&... args)
+ : thread(thread_desc{}, AZStd::forward(f), AZStd::forward(args)...)
+ {}
+
+ template
+ thread::thread(const thread_desc& desc, F&& f, Args&&... args)
{
- Internal::thread_info* ti = Internal::create_thread_info(AZStd::forward(f));
- m_thread.m_handle = Internal::create_thread(desc, ti, &m_thread.m_id);
+ auto threadfunc = [fn = AZStd::forward(f), argsTuple = AZStd::make_tuple(AZStd::forward(args)...)]() mutable -> void
+ {
+ AZStd::apply(AZStd::move(fn), AZStd::move(argsTuple));
+ };
+ Internal::thread_info* ti = Internal::create_thread_info(AZStd::move(threadfunc));
+ m_thread.m_handle = Internal::create_thread(&desc, ti, &m_thread.m_id);
}
inline bool thread::joinable() const
diff --git a/Code/Framework/AzCore/Tests/AZStd/Parallel.cpp b/Code/Framework/AzCore/Tests/AZStd/Parallel.cpp
index f3d4f58250..407cd3c258 100644
--- a/Code/Framework/AzCore/Tests/AZStd/Parallel.cpp
+++ b/Code/Framework/AzCore/Tests/AZStd/Parallel.cpp
@@ -195,18 +195,18 @@ namespace UnitTest
void test_thread_id_for_running_thread_is_not_default_constructed_id()
{
- const thread_desc* desc = m_numThreadDesc ? &m_desc[0] : nullptr;
- AZStd::thread t(AZStd::bind(&Parallel_Thread::do_nothing, this), desc);
+ const thread_desc desc = m_numThreadDesc ? m_desc[0] : thread_desc{};
+ AZStd::thread t(desc, AZStd::bind(&Parallel_Thread::do_nothing, this));
AZ_TEST_ASSERT(t.get_id() != AZStd::thread::id());
t.join();
}
void test_different_threads_have_different_ids()
{
- const thread_desc* desc1 = m_numThreadDesc ? &m_desc[0] : nullptr;
- const thread_desc* desc2 = m_numThreadDesc ? &m_desc[1] : nullptr;
- AZStd::thread t(AZStd::bind(&Parallel_Thread::do_nothing, this), desc1);
- AZStd::thread t2(AZStd::bind(&Parallel_Thread::do_nothing, this), desc2);
+ const thread_desc desc1 = m_numThreadDesc ? m_desc[0] : thread_desc{};
+ const thread_desc desc2 = m_numThreadDesc ? m_desc[1] : thread_desc{};
+ AZStd::thread t(desc1, AZStd::bind(&Parallel_Thread::do_nothing, this));
+ AZStd::thread t2(desc2, AZStd::bind(&Parallel_Thread::do_nothing, this));
AZ_TEST_ASSERT(t.get_id() != t2.get_id());
t.join();
t2.join();
@@ -214,13 +214,13 @@ namespace UnitTest
void test_thread_ids_have_a_total_order()
{
- const thread_desc* desc1 = m_numThreadDesc ? &m_desc[0] : nullptr;
- const thread_desc* desc2 = m_numThreadDesc ? &m_desc[1] : nullptr;
- const thread_desc* desc3 = m_numThreadDesc ? &m_desc[2] : nullptr;
+ const thread_desc desc1 = m_numThreadDesc ? m_desc[0] : thread_desc{};
+ const thread_desc desc2 = m_numThreadDesc ? m_desc[1] : thread_desc{};
+ const thread_desc desc3 = m_numThreadDesc ? m_desc[2] : thread_desc{};
- AZStd::thread t(AZStd::bind(&Parallel_Thread::do_nothing, this), desc1);
- AZStd::thread t2(AZStd::bind(&Parallel_Thread::do_nothing, this), desc2);
- AZStd::thread t3(AZStd::bind(&Parallel_Thread::do_nothing, this), desc3);
+ AZStd::thread t(desc1, AZStd::bind(&Parallel_Thread::do_nothing, this));
+ AZStd::thread t2(desc2, AZStd::bind(&Parallel_Thread::do_nothing, this));
+ AZStd::thread t3(desc3, AZStd::bind(&Parallel_Thread::do_nothing, this));
AZ_TEST_ASSERT(t.get_id() != t2.get_id());
AZ_TEST_ASSERT(t.get_id() != t3.get_id());
AZ_TEST_ASSERT(t2.get_id() != t3.get_id());
@@ -313,10 +313,10 @@ namespace UnitTest
void test_thread_id_of_running_thread_returned_by_this_thread_get_id()
{
- const thread_desc* desc1 = m_numThreadDesc ? &m_desc[0] : nullptr;
+ const thread_desc desc1 = m_numThreadDesc ? m_desc[0] : thread_desc{};
AZStd::thread::id id;
- AZStd::thread t(AZStd::bind(&Parallel_Thread::get_thread_id, this, &id), desc1);
+ AZStd::thread t(desc1, AZStd::bind(&Parallel_Thread::get_thread_id, this, &id));
AZStd::thread::id t_id = t.get_id();
t.join();
AZ_TEST_ASSERT(id == t_id);
@@ -366,10 +366,10 @@ namespace UnitTest
void test_move_on_construction()
{
- const thread_desc* desc1 = m_numThreadDesc ? &m_desc[0] : nullptr;
+ const thread_desc desc1 = m_numThreadDesc ? m_desc[0] : thread_desc{};
AZStd::thread::id the_id;
AZStd::thread x;
- x = AZStd::thread(AZStd::bind(&Parallel_Thread::do_nothing_id, this, &the_id), desc1);
+ x = AZStd::thread(desc1, AZStd::bind(&Parallel_Thread::do_nothing_id, this, &the_id));
AZStd::thread::id x_id = x.get_id();
x.join();
AZ_TEST_ASSERT(the_id == x_id);
@@ -377,8 +377,8 @@ namespace UnitTest
AZStd::thread make_thread(AZStd::thread::id* the_id)
{
- const thread_desc* desc1 = m_numThreadDesc ? &m_desc[0] : nullptr;
- return AZStd::thread(AZStd::bind(&Parallel_Thread::do_nothing_id, this, the_id), desc1);
+ const thread_desc desc1 = m_numThreadDesc ? m_desc[0] : thread_desc{};
+ return AZStd::thread(desc1, AZStd::bind(&Parallel_Thread::do_nothing_id, this, the_id));
}
void test_move_from_function_return()
@@ -430,9 +430,9 @@ namespace UnitTest
void do_test_creation()
{
- const thread_desc* desc1 = m_numThreadDesc ? &m_desc[0] : nullptr;
+ const thread_desc desc1 = m_numThreadDesc ? m_desc[0] : thread_desc{};
m_data = 0;
- AZStd::thread t(AZStd::bind(&Parallel_Thread::simple_thread, this), desc1);
+ AZStd::thread t(desc1, AZStd::bind(&Parallel_Thread::simple_thread, this));
t.join();
AZ_TEST_ASSERT(m_data == 999);
}
@@ -445,9 +445,9 @@ namespace UnitTest
void do_test_id_comparison()
{
- const thread_desc* desc1 = m_numThreadDesc ? &m_desc[0] : nullptr;
+ const thread_desc desc1 = m_numThreadDesc ? m_desc[0] : thread_desc{};
AZStd::thread::id self = this_thread::get_id();
- AZStd::thread thrd(AZStd::bind(&Parallel_Thread::comparison_thread, this, self), desc1);
+ AZStd::thread thrd(desc1, AZStd::bind(&Parallel_Thread::comparison_thread, this, self));
thrd.join();
}
@@ -476,10 +476,10 @@ namespace UnitTest
void do_test_creation_through_reference_wrapper()
{
- const thread_desc* desc1 = m_numThreadDesc ? &m_desc[0] : nullptr;
+ const thread_desc desc1 = m_numThreadDesc ? m_desc[0] : thread_desc{};
non_copyable_functor f;
- AZStd::thread thrd(AZStd::ref(f), desc1);
+ AZStd::thread thrd(desc1, AZStd::ref(f));
thrd.join();
AZ_TEST_ASSERT(f.value == 999);
}
@@ -491,10 +491,10 @@ namespace UnitTest
void test_swap()
{
- const thread_desc* desc1 = m_numThreadDesc ? &m_desc[0] : nullptr;
- const thread_desc* desc2 = m_numThreadDesc ? &m_desc[1] : nullptr;
- AZStd::thread t(AZStd::bind(&Parallel_Thread::simple_thread, this), desc1);
- AZStd::thread t2(AZStd::bind(&Parallel_Thread::simple_thread, this), desc2);
+ const thread_desc desc1 = m_numThreadDesc ? m_desc[0] : thread_desc{};
+ const thread_desc desc2 = m_numThreadDesc ? m_desc[1] : thread_desc{};
+ AZStd::thread t(desc1, AZStd::bind(&Parallel_Thread::simple_thread, this));
+ AZStd::thread t2(desc2, AZStd::bind(&Parallel_Thread::simple_thread, this));
AZStd::thread::id id1 = t.get_id();
AZStd::thread::id id2 = t2.get_id();
@@ -512,7 +512,7 @@ namespace UnitTest
void run()
{
- const thread_desc* desc1 = m_numThreadDesc ? &m_desc[0] : nullptr;
+ const thread_desc desc1 = m_numThreadDesc ? m_desc[0] : thread_desc{};
// We need to have at least one processor
AZ_TEST_ASSERT(AZStd::thread::hardware_concurrency() >= 1);
@@ -520,18 +520,18 @@ namespace UnitTest
// Create thread to increment data till we need to
m_data = 0;
m_dataMax = 10;
- AZStd::thread tr(AZStd::bind(&Parallel_Thread::increment_data, this), desc1);
+ AZStd::thread tr(desc1, AZStd::bind(&Parallel_Thread::increment_data, this));
tr.join();
AZ_TEST_ASSERT(m_data == m_dataMax);
m_data = 0;
- AZStd::thread trDel(make_delegate(this, &Parallel_Thread::increment_data), desc1);
+ AZStd::thread trDel(desc1, make_delegate(this, &Parallel_Thread::increment_data));
trDel.join();
AZ_TEST_ASSERT(m_data == m_dataMax);
chrono::system_clock::time_point startTime = chrono::system_clock::now();
{
- AZStd::thread tr1(AZStd::bind(&Parallel_Thread::sleep_thread, this, chrono::milliseconds(100)), desc1);
+ AZStd::thread tr1(desc1, AZStd::bind(&Parallel_Thread::sleep_thread, this, chrono::milliseconds(100)));
tr1.join();
}
auto sleepTime = chrono::system_clock::now() - startTime;
@@ -563,71 +563,71 @@ namespace UnitTest
{
MfTest x;
AZStd::function func = AZStd::bind(&MfTest::f0, &x);
- AZStd::thread(func, desc1).join();
+ AZStd::thread(desc1, func).join();
func = AZStd::bind(&MfTest::f0, AZStd::ref(x));
- AZStd::thread(func, desc1).join();
+ AZStd::thread(desc1, func).join();
func = AZStd::bind(&MfTest::g0, &x);
- AZStd::thread(func, desc1).join();
+ AZStd::thread(desc1, func).join();
func = AZStd::bind(&MfTest::g0, x);
- AZStd::thread(func, desc1).join();
+ AZStd::thread(desc1, func).join();
func = AZStd::bind(&MfTest::g0, AZStd::ref(x));
- AZStd::thread(func, desc1).join();
+ AZStd::thread(desc1, func).join();
//// 1
- //thread( AZStd::bind(&MfTest::f1, &x, 1) , desc1).join();
- //thread( AZStd::bind(&MfTest::f1, AZStd::ref(x), 1) , desc1).join();
- //thread( AZStd::bind(&MfTest::g1, &x, 1) , desc1).join();
- //thread( AZStd::bind(&MfTest::g1, x, 1) , desc1).join();
- //thread( AZStd::bind(&MfTest::g1, AZStd::ref(x), 1) , desc1).join();
+ //thread( AZStd::bind(desc1, &MfTest::f1, &x, 1)).join();
+ //thread( AZStd::bind(desc1, &MfTest::f1, AZStd::ref(x), 1)).join();
+ //thread( AZStd::bind(desc1, &MfTest::g1, &x, 1)).join();
+ //thread( AZStd::bind(desc1, &MfTest::g1, x, 1)).join();
+ //thread( AZStd::bind(desc1, &MfTest::g1, AZStd::ref(x), 1)).join();
//// 2
- //thread( AZStd::bind(&MfTest::f2, &x, 1, 2) , desc1).join();
- //thread( AZStd::bind(&MfTest::f2, AZStd::ref(x), 1, 2) , desc1).join();
- //thread( AZStd::bind(&MfTest::g2, &x, 1, 2) , desc1).join();
- //thread( AZStd::bind(&MfTest::g2, x, 1, 2) , desc1).join();
- //thread( AZStd::bind(&MfTest::g2, AZStd::ref(x), 1, 2) , desc1).join();
+ //thread( AZStd::bind(desc1, &MfTest::f2, &x, 1, 2)).join();
+ //thread( AZStd::bind(desc1, &MfTest::f2, AZStd::ref(x), 1, 2)).join();
+ //thread( AZStd::bind(desc1, &MfTest::g2, &x, 1, 2)).join();
+ //thread( AZStd::bind(desc1, &MfTest::g2, x, 1, 2)).join();
+ //thread( AZStd::bind(desc1, &MfTest::g2, AZStd::ref(x), 1, 2)).join();
//// 3
- //thread( AZStd::bind(&MfTest::f3, &x, 1, 2, 3) , desc1).join();
- //thread( AZStd::bind(&MfTest::f3, AZStd::ref(x), 1, 2, 3) , desc1).join();
- //thread( AZStd::bind(&MfTest::g3, &x, 1, 2, 3) , desc1).join();
- //thread( AZStd::bind(&MfTest::g3, x, 1, 2, 3) , desc1).join();
- //thread( AZStd::bind(&MfTest::g3, AZStd::ref(x), 1, 2, 3) , desc1).join();
+ //thread( AZStd::bind(desc1, &MfTest::f3, &x, 1, 2, 3)).join();
+ //thread( AZStd::bind(desc1, &MfTest::f3, AZStd::ref(x), 1, 2, 3)).join();
+ //thread( AZStd::bind(desc1, &MfTest::g3, &x, 1, 2, 3)).join();
+ //thread( AZStd::bind(desc1, &MfTest::g3, x, 1, 2, 3)).join();
+ //thread( AZStd::bind(desc1, &MfTest::g3, AZStd::ref(x), 1, 2, 3)).join();
//// 4
- //thread( AZStd::bind(&MfTest::f4, &x, 1, 2, 3, 4) , desc1).join();
- //thread( AZStd::bind(&MfTest::f4, AZStd::ref(x), 1, 2, 3, 4) , desc1).join();
- //thread( AZStd::bind(&MfTest::g4, &x, 1, 2, 3, 4) , desc1).join();
- //thread( AZStd::bind(&MfTest::g4, x, 1, 2, 3, 4) , desc1).join();
- //thread( AZStd::bind(&MfTest::g4, AZStd::ref(x), 1, 2, 3, 4) , desc1).join();
+ //thread( AZStd::bind(desc1, &MfTest::f4, &x, 1, 2, 3, 4)).join();
+ //thread( AZStd::bind(desc1, &MfTest::f4, AZStd::ref(x), 1, 2, 3, 4)).join();
+ //thread( AZStd::bind(desc1, &MfTest::g4, &x, 1, 2, 3, 4)).join();
+ //thread( AZStd::bind(desc1, &MfTest::g4, x, 1, 2, 3, 4)).join();
+ //thread( AZStd::bind(desc1, &MfTest::g4, AZStd::ref(x), 1, 2, 3, 4)).join();
//// 5
- //thread( AZStd::bind(&MfTest::f5, &x, 1, 2, 3, 4, 5) , desc1).join();
- //thread( AZStd::bind(&MfTest::f5, AZStd::ref(x), 1, 2, 3, 4, 5) , desc1).join();
- //thread( AZStd::bind(&MfTest::g5, &x, 1, 2, 3, 4, 5) , desc1).join();
- //thread( AZStd::bind(&MfTest::g5, x, 1, 2, 3, 4, 5) , desc1).join();
- //thread( AZStd::bind(&MfTest::g5, AZStd::ref(x), 1, 2, 3, 4, 5) , desc1).join();
+ //thread( AZStd::bind(desc1, &MfTest::f5, &x, 1, 2, 3, 4, 5)).join();
+ //thread( AZStd::bind(desc1, &MfTest::f5, AZStd::ref(x), 1, 2, 3, 4, 5)).join();
+ //thread( AZStd::bind(desc1, &MfTest::g5, &x, 1, 2, 3, 4, 5)).join();
+ //thread( AZStd::bind(desc1, &MfTest::g5, x, 1, 2, 3, 4, 5)).join();
+ //thread( AZStd::bind(desc1, &MfTest::g5, AZStd::ref(x), 1, 2, 3, 4, 5)).join();
//// 6
- //thread( AZStd::bind(&MfTest::f6, &x, 1, 2, 3, 4, 5, 6) , desc1).join();
- //thread( AZStd::bind(&MfTest::f6, AZStd::ref(x), 1, 2, 3, 4, 5, 6) , desc1).join();
- //thread( AZStd::bind(&MfTest::g6, &x, 1, 2, 3, 4, 5, 6) , desc1).join();
- //thread( AZStd::bind(&MfTest::g6, x, 1, 2, 3, 4, 5, 6) , desc1).join();
- //thread( AZStd::bind(&MfTest::g6, AZStd::ref(x), 1, 2, 3, 4, 5, 6) , desc1).join();
+ //thread( AZStd::bind(desc1, &MfTest::f6, &x, 1, 2, 3, 4, 5, 6)).join();
+ //thread( AZStd::bind(desc1, &MfTest::f6, AZStd::ref(x), 1, 2, 3, 4, 5, 6)).join();
+ //thread( AZStd::bind(desc1, &MfTest::g6, &x, 1, 2, 3, 4, 5, 6)).join();
+ //thread( AZStd::bind(desc1, &MfTest::g6, x, 1, 2, 3, 4, 5, 6)).join();
+ //thread( AZStd::bind(desc1, &MfTest::g6, AZStd::ref(x), 1, 2, 3, 4, 5, 6)).join();
//// 7
- //thread( AZStd::bind(&MfTest::f7, &x, 1, 2, 3, 4, 5, 6, 7), desc1).join();
- //thread( AZStd::bind(&MfTest::f7, AZStd::ref(x), 1, 2, 3, 4, 5, 6, 7), desc1).join();
- //thread( AZStd::bind(&MfTest::g7, &x, 1, 2, 3, 4, 5, 6, 7), desc1).join();
- //thread( AZStd::bind(&MfTest::g7, x, 1, 2, 3, 4, 5, 6, 7), desc1).join();
- //thread( AZStd::bind(&MfTest::g7, AZStd::ref(x), 1, 2, 3, 4, 5, 6, 7), desc1).join();
+ //thread( AZStd::bind(desc1, &MfTest::f7, &x, 1, 2, 3, 4, 5, 6, 7)).join();
+ //thread( AZStd::bind(desc1, &MfTest::f7, AZStd::ref(x), 1, 2, 3, 4, 5, 6, 7)).join();
+ //thread( AZStd::bind(desc1, &MfTest::g7, &x, 1, 2, 3, 4, 5, 6, 7)).join();
+ //thread( AZStd::bind(desc1, &MfTest::g7, x, 1, 2, 3, 4, 5, 6, 7)).join();
+ //thread( AZStd::bind(desc1, &MfTest::g7, AZStd::ref(x), 1, 2, 3, 4, 5, 6, 7)).join();
//// 8
- //thread( AZStd::bind(&MfTest::f8, &x, 1, 2, 3, 4, 5, 6, 7, 8) , desc1).join();
- //thread( AZStd::bind(&MfTest::f8, AZStd::ref(x), 1, 2, 3, 4, 5, 6, 7, 8) , desc1).join();
- //thread( AZStd::bind(&MfTest::g8, &x, 1, 2, 3, 4, 5, 6, 7, 8) , desc1).join();
- //thread( AZStd::bind(&MfTest::g8, x, 1, 2, 3, 4, 5, 6, 7, 8) , desc1).join();
- //thread( AZStd::bind(&MfTest::g8, AZStd::ref(x), 1, 2, 3, 4, 5, 6, 7, 8) , desc1).join();
+ //thread( AZStd::bind(desc1, &MfTest::f8, &x, 1, 2, 3, 4, 5, 6, 7, 8)).join();
+ //thread( AZStd::bind(desc1, &MfTest::f8, AZStd::ref(x), 1, 2, 3, 4, 5, 6, 7, 8)).join();
+ //thread( AZStd::bind(desc1, &MfTest::g8, &x, 1, 2, 3, 4, 5, 6, 7, 8)).join();
+ //thread( AZStd::bind(desc1, &MfTest::g8, x, 1, 2, 3, 4, 5, 6, 7, 8)).join();
+ //thread( AZStd::bind(desc1, &MfTest::g8, AZStd::ref(x), 1, 2, 3, 4, 5, 6, 7, 8)).join();
AZ_TEST_ASSERT(x.m_hash == 1366);
}
diff --git a/Code/Framework/AzCore/Tests/Memory.cpp b/Code/Framework/AzCore/Tests/Memory.cpp
index eb854050b6..5a483c1ed1 100644
--- a/Code/Framework/AzCore/Tests/Memory.cpp
+++ b/Code/Framework/AzCore/Tests/Memory.cpp
@@ -151,7 +151,7 @@ namespace UnitTest
AZStd::thread m_threads[m_maxNumThreads];
for (unsigned int i = 0; i < m_maxNumThreads; ++i)
{
- m_threads[i] = AZStd::thread(AZStd::bind(&SystemAllocatorTest::ThreadFunc, this), &m_desc[i]);
+ m_threads[i] = AZStd::thread(m_desc[i], AZStd::bind(&SystemAllocatorTest::ThreadFunc, this));
// give some time offset to the threads so we can test alloc and dealloc at the same time.
//AZStd::this_thread::sleep_for(AZStd::chrono::microseconds(500));
}
@@ -286,7 +286,7 @@ namespace UnitTest
AZStd::thread m_threads[m_maxNumThreads];
for (unsigned int i = 0; i < m_maxNumThreads; ++i)
{
- m_threads[i] = AZStd::thread(AZStd::bind(&SystemAllocatorTest::ThreadFunc, this), &m_desc[i]);
+ m_threads[i] = AZStd::thread(m_desc[i], AZStd::bind(&SystemAllocatorTest::ThreadFunc, this));
// give some time offset to the threads so we can test alloc and dealloc at the same time.
AZStd::this_thread::sleep_for(AZStd::chrono::microseconds(500));
}
@@ -724,7 +724,7 @@ namespace UnitTest
AZStd::thread m_threads[m_maxNumThreads];
for (unsigned int i = 0; i < m_maxNumThreads; ++i)
{
- m_threads[i] = AZStd::thread(AZStd::bind(&ThreadPoolAllocatorTest::AllocDeallocFunc, this), &m_desc[i]);
+ m_threads[i] = AZStd::thread(m_desc[i], AZStd::bind(&ThreadPoolAllocatorTest::AllocDeallocFunc, this));
}
for (unsigned int i = 0; i < m_maxNumThreads; ++i)
@@ -743,12 +743,12 @@ namespace UnitTest
for (unsigned int i = m_maxNumThreads/2; i profiler;
- const AZ::Crc32 statIdPerformance = AZ_CRC("PerformanceResult", 0xc1f29a10);
+ constexpr AZ::Crc32 statIdPerformance = AZ_CRC_CE("PerformanceResult");
const AZStd::string statNamePerformance("PerformanceResult");
- const AZ::Crc32 statIdBlock = AZ_CRC("Block", 0x831b9722);
+ constexpr AZ::Crc32 statIdBlock = AZ_CRC_CE("Block");
const AZStd::string statNameBlock("Block");
ASSERT_TRUE(profiler.GetStatsManager().AddStatistic(statIdPerformance, statNamePerformance, "us") != nullptr);
@@ -175,10 +177,10 @@ namespace UnitTest
AZ::Statistics::StatisticalProfiler profiler;
- const AZ::Crc32 statIdPerformance = AZ_CRC("PerformanceResult", 0xc1f29a10);
+ constexpr AZ::Crc32 statIdPerformance = AZ_CRC_CE("PerformanceResult");
const AZStd::string statNamePerformance("PerformanceResult");
- const AZ::Crc32 statIdBlock = AZ_CRC("Block", 0x831b9722);
+ constexpr AZ::Crc32 statIdBlock = AZ_CRC_CE("Block");
const AZStd::string statNameBlock("Block");
ASSERT_TRUE(profiler.GetStatsManager().AddStatistic(statIdPerformance, statNamePerformance, "us") != nullptr);
@@ -317,26 +319,26 @@ namespace UnitTest
AZ::Statistics::StatisticalProfilerProxy::TimedScope::ClearCachedProxy();
AZ::Statistics::StatisticalProfilerProxy profilerProxy;
AZ::Statistics::StatisticalProfilerProxy* proxy = AZ::Interface::Get();
- AZ::Statistics::StatisticalProfilerProxy::StatisticalProfilerType& profiler = proxy->GetProfiler(AZ::Debug::ProfileCategory::Terrain);
+ AZ::Statistics::StatisticalProfilerProxy::StatisticalProfilerType& profiler = proxy->GetProfiler(ProfilerProxyGroup);
- const AZ::Statistics::StatisticalProfilerProxy::StatIdType statIdPerformance = "PerformanceResult";
+ const AZ::Statistics::StatisticalProfilerProxy::StatIdType statIdPerformance("PerformanceResult");
const AZStd::string statNamePerformance("PerformanceResult");
- const AZ::Statistics::StatisticalProfilerProxy::StatIdType statIdBlock = "Block";
+ const AZ::Statistics::StatisticalProfilerProxy::StatIdType statIdBlock("Block");
const AZStd::string statNameBlock("Block");
ASSERT_TRUE(profiler.GetStatsManager().AddStatistic(statIdPerformance, statNamePerformance, "us") != nullptr);
ASSERT_TRUE(profiler.GetStatsManager().AddStatistic(statIdBlock, statNameBlock, "us") != nullptr);
- proxy->ActivateProfiler(AZ::Debug::ProfileCategory::Terrain, true);
+ proxy->ActivateProfiler(ProfilerProxyGroup, true);
const int iter_count = 10;
{
- CODE_PROFILER_PROXY_PUSH_TIME(AZ::Debug::ProfileCategory::Terrain, statIdPerformance)
+ CODE_PROFILER_PROXY_PUSH_TIME(ProfilerProxyGroup, statIdPerformance)
int counter = 0;
for (int i = 0; i < iter_count; i++)
{
- CODE_PROFILER_PROXY_PUSH_TIME(AZ::Debug::ProfileCategory::Terrain, statIdBlock)
+ CODE_PROFILER_PROXY_PUSH_TIME(ProfilerProxyGroup, statIdBlock)
counter++;
}
}
@@ -348,7 +350,7 @@ namespace UnitTest
EXPECT_EQ(profiler.GetStatistic(statIdBlock)->GetNumSamples(), iter_count);
//Clean Up
- proxy->ActivateProfiler(AZ::Debug::ProfileCategory::Terrain, false);
+ proxy->ActivateProfiler(ProfilerProxyGroup, false);
#undef CODE_PROFILER_PROXY_PUSH_TIME
@@ -362,12 +364,12 @@ namespace UnitTest
const AZ::Statistics::StatisticalProfilerProxy::StatIdType simple_thread1("simple_thread1");
const AZ::Statistics::StatisticalProfilerProxy::StatIdType simple_thread1_loop("simple_thread1_loop");
- CODE_PROFILER_PROXY_PUSH_TIME(AZ::Debug::ProfileCategory::Terrain, simple_thread1);
+ CODE_PROFILER_PROXY_PUSH_TIME(ProfilerProxyGroup, simple_thread1);
static int counter = 0;
for (int i = 0; i < loop_cnt; i++)
{
- CODE_PROFILER_PROXY_PUSH_TIME(AZ::Debug::ProfileCategory::Terrain, simple_thread1_loop);
+ CODE_PROFILER_PROXY_PUSH_TIME(ProfilerProxyGroup, simple_thread1_loop);
counter++;
}
}
@@ -377,12 +379,12 @@ namespace UnitTest
const AZ::Statistics::StatisticalProfilerProxy::StatIdType simple_thread2("simple_thread2");
const AZ::Statistics::StatisticalProfilerProxy::StatIdType simple_thread2_loop("simple_thread2_loop");
- CODE_PROFILER_PROXY_PUSH_TIME(AZ::Debug::ProfileCategory::Terrain, simple_thread2);
+ CODE_PROFILER_PROXY_PUSH_TIME(ProfilerProxyGroup, simple_thread2);
static int counter = 0;
for (int i = 0; i < loop_cnt; i++)
{
- CODE_PROFILER_PROXY_PUSH_TIME(AZ::Debug::ProfileCategory::Terrain, simple_thread2_loop);
+ CODE_PROFILER_PROXY_PUSH_TIME(ProfilerProxyGroup, simple_thread2_loop);
counter++;
}
}
@@ -392,12 +394,13 @@ namespace UnitTest
const AZ::Statistics::StatisticalProfilerProxy::StatIdType simple_thread3("simple_thread3");
const AZ::Statistics::StatisticalProfilerProxy::StatIdType simple_thread3_loop("simple_thread3_loop");
- CODE_PROFILER_PROXY_PUSH_TIME(AZ::Debug::ProfileCategory::Terrain, simple_thread3);
+ CODE_PROFILER_PROXY_PUSH_TIME(ProfilerProxyGroup, simple_thread3);
static int counter = 0;
for (int i = 0; i < loop_cnt; i++)
{
- CODE_PROFILER_PROXY_PUSH_TIME(AZ::Debug::ProfileCategory::Terrain, simple_thread3_loop);
+ CODE_PROFILER_PROXY_PUSH_TIME(ProfilerProxyGroup, simple_thread3_loop);
+ counter++;
}
}
@@ -408,21 +411,21 @@ namespace UnitTest
AZ::Statistics::StatisticalProfilerProxy::TimedScope::ClearCachedProxy();
AZ::Statistics::StatisticalProfilerProxy profilerProxy;
AZ::Statistics::StatisticalProfilerProxy* proxy = AZ::Interface::Get();
- AZ::Statistics::StatisticalProfilerProxy::StatisticalProfilerType& profiler = proxy->GetProfiler(AZ::Debug::ProfileCategory::Terrain);
+ AZ::Statistics::StatisticalProfilerProxy::StatisticalProfilerType& profiler = proxy->GetProfiler(ProfilerProxyGroup);
- const AZ::Statistics::StatisticalProfilerProxy::StatIdType statIdThread1 = "simple_thread1";
+ const AZ::Statistics::StatisticalProfilerProxy::StatIdType statIdThread1("simple_thread1");
const AZStd::string statNameThread1("simple_thread1");
- const AZ::Statistics::StatisticalProfilerProxy::StatIdType statIdThread1Loop = "simple_thread1_loop";
+ const AZ::Statistics::StatisticalProfilerProxy::StatIdType statIdThread1Loop("simple_thread1_loop");
const AZStd::string statNameThread1Loop("simple_thread1_loop");
- const AZ::Statistics::StatisticalProfilerProxy::StatIdType statIdThread2 = "simple_thread2";
+ const AZ::Statistics::StatisticalProfilerProxy::StatIdType statIdThread2("simple_thread2");
const AZStd::string statNameThread2("simple_thread2");
- const AZ::Statistics::StatisticalProfilerProxy::StatIdType statIdThread2Loop = "simple_thread2_loop";
+ const AZ::Statistics::StatisticalProfilerProxy::StatIdType statIdThread2Loop("simple_thread2_loop");
const AZStd::string statNameThread2Loop("simple_thread2_loop");
- const AZ::Statistics::StatisticalProfilerProxy::StatIdType statIdThread3 = "simple_thread3";
+ const AZ::Statistics::StatisticalProfilerProxy::StatIdType statIdThread3("simple_thread3");
const AZStd::string statNameThread3("simple_thread3");
- const AZ::Statistics::StatisticalProfilerProxy::StatIdType statIdThread3Loop = "simple_thread3_loop";
+ const AZ::Statistics::StatisticalProfilerProxy::StatIdType statIdThread3Loop("simple_thread3_loop");
const AZStd::string statNameThread3Loop("simple_thread3_loop");
ASSERT_TRUE(profiler.GetStatsManager().AddStatistic(statIdThread1, statNameThread1, "us"));
@@ -432,7 +435,7 @@ namespace UnitTest
ASSERT_TRUE(profiler.GetStatsManager().AddStatistic(statIdThread3, statNameThread3, "us"));
ASSERT_TRUE(profiler.GetStatsManager().AddStatistic(statIdThread3Loop, statNameThread3Loop, "us"));
- proxy->ActivateProfiler(AZ::Debug::ProfileCategory::Terrain, true);
+ proxy->ActivateProfiler(ProfilerProxyGroup, true);
//Let's kickoff the threads to see how much contention affects the profiler's performance.
const int iter_count = 10;
@@ -459,7 +462,7 @@ namespace UnitTest
EXPECT_EQ(profiler.GetStatistic(statIdThread3Loop)->GetNumSamples(), iter_count);
//Clean Up
- proxy->ActivateProfiler(AZ::Debug::ProfileCategory::Terrain, false);
+ proxy->ActivateProfiler(ProfilerProxyGroup, false);
}
/** Trace message handler to track messages during tests
@@ -566,10 +569,10 @@ namespace UnitTest
AZ::Statistics::StatisticalProfiler profiler;
- const AZ::Crc32 statIdPerformance = AZ_CRC("PerformanceResult", 0xc1f29a10);
+ constexpr AZ::Crc32 statIdPerformance = AZ_CRC_CE("PerformanceResult");
const AZStd::string statNamePerformance("PerformanceResult");
- const AZ::Crc32 statIdBlock = AZ_CRC("Block", 0x831b9722);
+ constexpr AZ::Crc32 statIdBlock = AZ_CRC_CE("Block");
const AZStd::string statNameBlock("Block");
ASSERT_TRUE(profiler.GetStatsManager().AddStatistic(statIdPerformance, statNamePerformance, "us") != nullptr);
@@ -647,10 +650,10 @@ namespace UnitTest
AZ::Statistics::StatisticalProfiler profiler;
- const AZ::Crc32 statIdPerformance = AZ_CRC("PerformanceResult", 0xc1f29a10);
+ constexpr AZ::Crc32 statIdPerformance = AZ_CRC_CE("PerformanceResult");
const AZStd::string statNamePerformance("PerformanceResult");
- const AZ::Crc32 statIdBlock = AZ_CRC("Block", 0x831b9722);
+ constexpr AZ::Crc32 statIdBlock = AZ_CRC_CE("Block");
const AZStd::string statNameBlock("Block");
ASSERT_TRUE(profiler.GetStatsManager().AddStatistic(statIdPerformance, statNamePerformance, "us") != nullptr);
@@ -745,26 +748,26 @@ namespace UnitTest
AZ::Statistics::StatisticalProfilerProxy::TimedScope::ClearCachedProxy();
AZ::Statistics::StatisticalProfilerProxy profilerProxy;
AZ::Statistics::StatisticalProfilerProxy* proxy = AZ::Interface::Get();
- AZ::Statistics::StatisticalProfilerProxy::StatisticalProfilerType& profiler = proxy->GetProfiler(AZ::Debug::ProfileCategory::Terrain);
+ AZ::Statistics::StatisticalProfilerProxy::StatisticalProfilerType& profiler = proxy->GetProfiler(ProfilerProxyGroup);
- const AZ::Statistics::StatisticalProfilerProxy::StatIdType statIdPerformance = "PerformanceResult";
+ const AZ::Statistics::StatisticalProfilerProxy::StatIdType statIdPerformance("PerformanceResult");
const AZStd::string statNamePerformance("PerformanceResult");
- const AZ::Statistics::StatisticalProfilerProxy::StatIdType statIdBlock = "Block";
+ const AZ::Statistics::StatisticalProfilerProxy::StatIdType statIdBlock("Block");
const AZStd::string statNameBlock("Block");
ASSERT_TRUE(profiler.GetStatsManager().AddStatistic(statIdPerformance, statNamePerformance, "us") != nullptr);
ASSERT_TRUE(profiler.GetStatsManager().AddStatistic(statIdBlock, statNameBlock, "us") != nullptr);
- proxy->ActivateProfiler(AZ::Debug::ProfileCategory::Terrain, true);
+ proxy->ActivateProfiler(ProfilerProxyGroup, true);
const int iter_count = 1000000;
{
- CODE_PROFILER_PROXY_PUSH_TIME(AZ::Debug::ProfileCategory::Terrain, statIdPerformance)
+ CODE_PROFILER_PROXY_PUSH_TIME(ProfilerProxyGroup, statIdPerformance)
int counter = 0;
for (int i = 0; i < iter_count; i++)
{
- CODE_PROFILER_PROXY_PUSH_TIME(AZ::Debug::ProfileCategory::Terrain, statIdBlock)
+ CODE_PROFILER_PROXY_PUSH_TIME(ProfilerProxyGroup, statIdBlock)
counter++;
}
}
@@ -778,7 +781,7 @@ namespace UnitTest
profiler.LogAndResetStats("StatisticalProfilerProxy");
//Clean Up
- proxy->ActivateProfiler(AZ::Debug::ProfileCategory::Terrain, false);
+ proxy->ActivateProfiler(ProfilerProxyGroup, false);
}
#undef CODE_PROFILER_PROXY_PUSH_TIME
@@ -788,21 +791,21 @@ namespace UnitTest
AZ::Statistics::StatisticalProfilerProxy::TimedScope::ClearCachedProxy();
AZ::Statistics::StatisticalProfilerProxy profilerProxy;
AZ::Statistics::StatisticalProfilerProxy* proxy = AZ::Interface::Get();
- AZ::Statistics::StatisticalProfilerProxy::StatisticalProfilerType& profiler = proxy->GetProfiler(AZ::Debug::ProfileCategory::Terrain);
+ AZ::Statistics::StatisticalProfilerProxy::StatisticalProfilerType& profiler = proxy->GetProfiler(ProfilerProxyGroup);
- const AZ::Statistics::StatisticalProfilerProxy::StatIdType statIdThread1 = "simple_thread1";
+ const AZ::Statistics::StatisticalProfilerProxy::StatIdType statIdThread1("simple_thread1");
const AZStd::string statNameThread1("simple_thread1");
- const AZ::Statistics::StatisticalProfilerProxy::StatIdType statIdThread1Loop = "simple_thread1_loop";
+ const AZ::Statistics::StatisticalProfilerProxy::StatIdType statIdThread1Loop("simple_thread1_loop");
const AZStd::string statNameThread1Loop("simple_thread1_loop");
- const AZ::Statistics::StatisticalProfilerProxy::StatIdType statIdThread2 = "simple_thread2";
+ const AZ::Statistics::StatisticalProfilerProxy::StatIdType statIdThread2("simple_thread2");
const AZStd::string statNameThread2("simple_thread2");
- const AZ::Statistics::StatisticalProfilerProxy::StatIdType statIdThread2Loop = "simple_thread2_loop";
+ const AZ::Statistics::StatisticalProfilerProxy::StatIdType statIdThread2Loop("simple_thread2_loop");
const AZStd::string statNameThread2Loop("simple_thread2_loop");
- const AZ::Statistics::StatisticalProfilerProxy::StatIdType statIdThread3 = "simple_thread3";
+ const AZ::Statistics::StatisticalProfilerProxy::StatIdType statIdThread3("simple_thread3");
const AZStd::string statNameThread3("simple_thread3");
- const AZ::Statistics::StatisticalProfilerProxy::StatIdType statIdThread3Loop = "simple_thread3_loop";
+ const AZ::Statistics::StatisticalProfilerProxy::StatIdType statIdThread3Loop("simple_thread3_loop");
const AZStd::string statNameThread3Loop("simple_thread3_loop");
ASSERT_TRUE(profiler.GetStatsManager().AddStatistic(statIdThread1, statNameThread1, "us"));
@@ -812,7 +815,7 @@ namespace UnitTest
ASSERT_TRUE(profiler.GetStatsManager().AddStatistic(statIdThread3, statNameThread3, "us"));
ASSERT_TRUE(profiler.GetStatsManager().AddStatistic(statIdThread3Loop, statNameThread3Loop, "us"));
- proxy->ActivateProfiler(AZ::Debug::ProfileCategory::Terrain, true);
+ proxy->ActivateProfiler(ProfilerProxyGroup, true);
//Let's kickoff the threads to see how much contention affects the profiler's performance.
const int iter_count = 1000000;
@@ -841,7 +844,7 @@ namespace UnitTest
profiler.LogAndResetStats("3_Threads_StatisticalProfilerProxy");
//Clean Up
- proxy->ActivateProfiler(AZ::Debug::ProfileCategory::Terrain, false);
+ proxy->ActivateProfiler(ProfilerProxyGroup, false);
}
}//namespace UnitTest
diff --git a/Code/Framework/AzCore/Tests/TaskTests.cpp b/Code/Framework/AzCore/Tests/TaskTests.cpp
index e743ab6643..9e839f60ee 100644
--- a/Code/Framework/AzCore/Tests/TaskTests.cpp
+++ b/Code/Framework/AzCore/Tests/TaskTests.cpp
@@ -34,7 +34,7 @@ namespace UnitTest
AZ::AllocatorInstance::Create();
AZ::AllocatorInstance::Create();
- m_executor = aznew TaskExecutor(4);
+ m_executor = aznew TaskExecutor();
}
void TearDown() override
@@ -236,6 +236,82 @@ namespace UnitTest
EXPECT_EQ(x, 1);
}
+ TEST_F(TaskGraphTestFixture, SingleTask)
+ {
+ AZStd::atomic_int32_t x = 0;
+
+ TaskGraph graph;
+ graph.AddTask(
+ defaultTD,
+ [&x]
+ {
+ x = 1;
+ });
+
+ TaskGraphEvent ev;
+ graph.SubmitOnExecutor(*m_executor, &ev);
+ ev.Wait();
+
+ EXPECT_EQ(1, x);
+ }
+
+
+ TEST_F(TaskGraphTestFixture, SingleTaskChain)
+ {
+ AZStd::atomic_int32_t x = 0;
+
+ TaskGraph graph;
+ auto a = graph.AddTask(
+ defaultTD,
+ [&x]
+ {
+ x += 1;
+ });
+ auto b = graph.AddTask(
+ defaultTD,
+ [&x]
+ {
+ x += 1;
+ });
+ b.Precedes(a);
+
+ TaskGraphEvent ev;
+ graph.SubmitOnExecutor(*m_executor, &ev);
+ ev.Wait();
+
+ EXPECT_EQ(2, x);
+ }
+
+ TEST_F(TaskGraphTestFixture, MultipleIndependentTaskChains)
+ {
+ AZStd::atomic_int32_t x = 0;
+ constexpr int numChains = 5;
+
+ TaskGraph graph;
+ for( int i = 0; i < numChains; ++i)
+ {
+ auto a = graph.AddTask(
+ defaultTD,
+ [&x]
+ {
+ x += 1;
+ });
+ auto b = graph.AddTask(
+ defaultTD,
+ [&x]
+ {
+ x += 1;
+ });
+ b.Precedes(a);
+ }
+
+ TaskGraphEvent ev;
+ graph.SubmitOnExecutor(*m_executor, &ev);
+ ev.Wait();
+
+ EXPECT_EQ(2*numChains, x);
+ }
+
TEST_F(TaskGraphTestFixture, VariadicInterface)
{
int x = 0;
@@ -388,6 +464,7 @@ namespace UnitTest
EXPECT_EQ(3, x);
}
+ // Waiting inside a task is disallowed , test that it fails correctly
TEST_F(TaskGraphTestFixture, SpawnSubgraph)
{
AZStd::atomic x = 0;
@@ -434,7 +511,10 @@ namespace UnitTest
f.Precedes(g);
TaskGraphEvent ev;
subgraph.SubmitOnExecutor(*m_executor, &ev);
+ // TaskGraphEvent::Wait asserts if called on a worker thread, suppress & validate assert
+ AZ_TEST_START_TRACE_SUPPRESSION;
ev.Wait();
+ AZ_TEST_STOP_TRACE_SUPPRESSION(1);
});
auto d = graph.AddTask(
defaultTD,
@@ -464,8 +544,6 @@ namespace UnitTest
TaskGraphEvent ev;
graph.SubmitOnExecutor(*m_executor, &ev);
ev.Wait();
-
- EXPECT_EQ(3 | 0b100000, x);
}
TEST_F(TaskGraphTestFixture, RetainedGraph)
diff --git a/Code/Framework/AzCore/Tests/Time/TimeTests.cpp b/Code/Framework/AzCore/Tests/Time/TimeTests.cpp
new file mode 100644
index 0000000000..6727ef1501
--- /dev/null
+++ b/Code/Framework/AzCore/Tests/Time/TimeTests.cpp
@@ -0,0 +1,56 @@
+/*
+ * 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 UnitTest
+{
+ class TimeTests
+ : public AllocatorsFixture
+ {
+ public:
+ void SetUp() override
+ {
+ SetupAllocator();
+ m_timeComponent = new AZ::TimeSystemComponent;
+ }
+
+ void TearDown() override
+ {
+ delete m_timeComponent;
+ TeardownAllocator();
+ }
+
+ AZ::TimeSystemComponent* m_timeComponent = nullptr;
+ };
+
+ TEST_F(TimeTests, TestConversionUsToMs)
+ {
+ AZ::TimeUs timeUs = AZ::TimeUs{ 1000 };
+ AZ::TimeMs timeMs = AZ::TimeUsToMs(timeUs);
+ EXPECT_EQ(timeMs, AZ::TimeMs{ 1 });
+ }
+
+ TEST_F(TimeTests, TestConversionMsToUs)
+ {
+ AZ::TimeMs timeMs = AZ::TimeMs{ 1000 };
+ AZ::TimeUs timeUs = AZ::TimeMsToUs(timeMs);
+ EXPECT_EQ(timeUs, AZ::TimeUs{ 1000000 });
+ }
+
+ TEST_F(TimeTests, TestClocks)
+ {
+ AZ::TimeUs timeUs = AZ::GetElapsedTimeUs();
+ AZ::TimeMs timeMs = AZ::GetElapsedTimeMs();
+
+ AZ::TimeMs timeUsToMs = AZ::TimeUsToMs(timeUs);
+ int64_t delta = static_cast(timeMs) - static_cast(timeUsToMs);
+ EXPECT_LT(abs(delta), 1);
+ }
+}
diff --git a/Code/Framework/AzCore/Tests/azcoretests_files.cmake b/Code/Framework/AzCore/Tests/azcoretests_files.cmake
index c36d37d874..e155594aa0 100644
--- a/Code/Framework/AzCore/Tests/azcoretests_files.cmake
+++ b/Code/Framework/AzCore/Tests/azcoretests_files.cmake
@@ -61,6 +61,7 @@ set(FILES
Slice.cpp
State.cpp
Statistics.cpp
+ StatisticalProfiler.cpp
StreamerTests.cpp
StringFunc.cpp
SystemFile.cpp
@@ -127,6 +128,7 @@ set(FILES
Serialization/Json/UnorderedSetSerializerTests.cpp
Serialization/Json/UnsupportedTypesSerializerTests.cpp
Serialization/Json/UuidSerializerTests.cpp
+ Time/TimeTests.cpp
Math/AabbTests.cpp
Math/ColorTests.cpp
Math/CrcTests.cpp
diff --git a/Code/Framework/AzFramework/AzFramework/Application/Application.cpp b/Code/Framework/AzFramework/AzFramework/Application/Application.cpp
index 12974d03cf..e72e2de472 100644
--- a/Code/Framework/AzFramework/AzFramework/Application/Application.cpp
+++ b/Code/Framework/AzFramework/AzFramework/Application/Application.cpp
@@ -28,6 +28,7 @@
#include
#include
#include
+#include
#include
#include
@@ -295,6 +296,7 @@ namespace AzFramework
azrtti_typeid(),
azrtti_typeid(),
azrtti_typeid(),
+ azrtti_typeid(),
azrtti_typeid(),
azrtti_typeid(),
@@ -477,14 +479,16 @@ namespace AzFramework
newThreadDesc.m_cpuId = AFFINITY_MASK_USERTHREADS;
newThreadDesc.m_name = newThreadName;
AZStd::binary_semaphore binarySemaphore;
- AZStd::thread newThread([&workForNewThread, &binarySemaphore, &newThreadName]
- {
- AZ_PROFILE_SCOPE(AzFramework,
- "Application::PumpSystemEventLoopWhileDoingWorkInNewThread:ThreadWorker %s", newThreadName);
+ AZStd::thread newThread(
+ newThreadDesc,
+ [&workForNewThread, &binarySemaphore, &newThreadName]
+ {
+ AZ_PROFILE_SCOPE(AzFramework,
+ "Application::PumpSystemEventLoopWhileDoingWorkInNewThread:ThreadWorker %s", newThreadName);
- workForNewThread();
- binarySemaphore.release();
- }, &newThreadDesc);
+ workForNewThread();
+ binarySemaphore.release();
+ });
while (!binarySemaphore.try_acquire_for(eventPumpFrequency))
{
PumpSystemEventLoopUntilEmpty();
diff --git a/Code/Framework/AzFramework/AzFramework/Archive/Archive.cpp b/Code/Framework/AzFramework/AzFramework/Archive/Archive.cpp
index d2a81102dc..8064ba6669 100644
--- a/Code/Framework/AzFramework/AzFramework/Archive/Archive.cpp
+++ b/Code/Framework/AzFramework/AzFramework/Archive/Archive.cpp
@@ -1631,7 +1631,20 @@ namespace AZ::IO
return nullptr;
}
- ZipDir::CacheFactory factory(ZipDir::ZD_INIT_FAST, nFactoryFlags);
+ ZipDir::InitMethod initType = ZipDir::InitMethod::Default;
+ if (!ZipDir::IsReleaseConfig)
+ {
+ if ((nFlags & INestedArchive::FLAGS_FULL_VALIDATE) != 0)
+ {
+ initType = ZipDir::InitMethod::FullValidation;
+ }
+ else if ((nFlags & INestedArchive::FLAGS_VALIDATE_HEADERS) != 0)
+ {
+ initType = ZipDir::InitMethod::ValidateHeaders;
+ }
+ }
+
+ ZipDir::CacheFactory factory(initType, nFactoryFlags);
ZipDir::CachePtr cache = factory.New(szFullPath->c_str());
if (cache)
diff --git a/Code/Framework/AzFramework/AzFramework/Archive/INestedArchive.h b/Code/Framework/AzFramework/AzFramework/Archive/INestedArchive.h
index f85fd273ce..e89d16ee5d 100644
--- a/Code/Framework/AzFramework/AzFramework/Archive/INestedArchive.h
+++ b/Code/Framework/AzFramework/AzFramework/Archive/INestedArchive.h
@@ -11,7 +11,9 @@
#include
#include
+#include
#include
+#include
#include
namespace AZ::IO
@@ -71,6 +73,13 @@ namespace AZ::IO
// multiple times
FLAGS_DONT_COMPACT = 1 << 5,
+ // if this is set, validate header data when opening the archive
+ FLAGS_VALIDATE_HEADERS = 1 << 9,
+
+ // if this is set, validate header data when opening the archive and validate CRCs when decompressing
+ // & reading files.
+ FLAGS_FULL_VALIDATE = 1 << 10,
+
// Disable a pak file without unloading it, this flag is used in combination with patches and multiplayer
// to ensure that specific paks stay in the position(to keep the same priority) but being disabled
// when running multiplayer
@@ -128,6 +137,10 @@ namespace AZ::IO
// Deletes all files and directories in the archive.
virtual int RemoveAll() = 0;
+ // Summary:
+ // Lists all the files in the archive.
+ virtual int ListAllFiles(AZStd::vector& outFileEntries) = 0;
+
// Summary:
// Finds the file; you don't have to close the returned handle.
// Returns:
diff --git a/Code/Framework/AzFramework/AzFramework/Archive/NestedArchive.cpp b/Code/Framework/AzFramework/AzFramework/Archive/NestedArchive.cpp
index 1e0f237df5..49a44b76fa 100644
--- a/Code/Framework/AzFramework/AzFramework/Archive/NestedArchive.cpp
+++ b/Code/Framework/AzFramework/AzFramework/Archive/NestedArchive.cpp
@@ -89,11 +89,51 @@ namespace AZ::IO
return m_pCache->RemoveDir(fullPath);
}
+ //////////////////////////////////////////////////////////////////////////
int NestedArchive::RemoveAll()
{
return m_pCache->RemoveAll();
}
+ //////////////////////////////////////////////////////////////////////////
+ // Helper for 'ListAllFiles' to recursively traverse the FileEntryTree and gather all the files
+ void EnumerateFilesRecursive(AZ::IO::Path currentPath, ZipDir::FileEntryTree* currentTree, AZStd::vector& fileList)
+ {
+ // Drill down directories first...
+ for (auto dirIter = currentTree->GetDirBegin(); dirIter != currentTree->GetDirEnd(); ++dirIter)
+ {
+ if (ZipDir::FileEntryTree* subTree = currentTree->GetDirEntry(dirIter);
+ subTree != nullptr)
+ {
+ EnumerateFilesRecursive(currentPath / currentTree->GetDirName(dirIter), subTree, fileList);
+ }
+ }
+
+ // Then enumerate the files in current directory...
+ for (auto fileIter = currentTree->GetFileBegin(); fileIter != currentTree->GetFileEnd(); ++fileIter)
+ {
+ fileList.emplace_back(currentPath / currentTree->GetFileName(fileIter));
+ }
+ }
+
+ //////////////////////////////////////////////////////////////////////////
+ // lists all files in the archive
+ int NestedArchive::ListAllFiles(AZStd::vector& outFileEntries)
+ {
+ AZStd::vector filesInArchive;
+
+ ZipDir::FileEntryTree* tree = m_pCache->GetRoot();
+ if (!tree)
+ {
+ return ZipDir::ZD_ERROR_UNEXPECTED;
+ }
+
+ EnumerateFilesRecursive(AZ::IO::Path{ AZ::IO::PosixPathSeparator }, tree, filesInArchive);
+
+ AZStd::swap(outFileEntries, filesInArchive);
+ return ZipDir::ZD_ERROR_SUCCESS;
+ }
+
//////////////////////////////////////////////////////////////////////////
// Adds a new file to the zip or update an existing one
// adds a directory (creates several nested directories if needed)
diff --git a/Code/Framework/AzFramework/AzFramework/Archive/NestedArchive.h b/Code/Framework/AzFramework/AzFramework/Archive/NestedArchive.h
index 34bbcdc201..59722703f2 100644
--- a/Code/Framework/AzFramework/AzFramework/Archive/NestedArchive.h
+++ b/Code/Framework/AzFramework/AzFramework/Archive/NestedArchive.h
@@ -39,7 +39,7 @@ namespace AZ::IO
NestedArchive(IArchive* pArchive, AZStd::string_view strBindRoot, ZipDir::CachePtr pCache, uint32_t nFlags = 0);
~NestedArchive() override;
-
+
auto GetRootFolderHandle() -> Handle override;
// Adds a new file to the zip or update an existing one
@@ -68,6 +68,9 @@ namespace AZ::IO
// deletes all files from the archive
int RemoveAll() override;
+ // lists all the files in the archive
+ int ListAllFiles(AZStd::vector& outFileEntries) override;
+
// finds the file; you don't have to close the returned handle
Handle FindFile(AZStd::string_view szRelativePath) override;
@@ -79,7 +82,6 @@ namespace AZ::IO
// returns the full path to the archive file
AZ::IO::PathView GetFullPath() const override;
- ZipDir::Cache* GetCache();
uint32_t GetFlags() const override;
bool SetFlags(uint32_t nFlagsToSet) override;
@@ -87,12 +89,15 @@ namespace AZ::IO
bool SetPackAccessible(bool bAccessible) override;
+ ZipDir::Cache* GetCache();
+
protected:
// returns the pointer to the relative file path to be passed
// to the underlying Cache pointer. Uses the given buffer to construct the path.
// returns nullptr if the file path is invalid
AZ::IO::FixedMaxPathString AdjustPath(AZStd::string_view szRelativePath);
+
ZipDir::CachePtr m_pCache;
// the binding root may be empty string - in this case, the absolute path binding won't work
AZ::IO::Path m_strBindRoot;
diff --git a/Code/Framework/AzFramework/AzFramework/Archive/ZipDirCache.cpp b/Code/Framework/AzFramework/AzFramework/Archive/ZipDirCache.cpp
index d17dbd0837..13d5b0f723 100644
--- a/Code/Framework/AzFramework/AzFramework/Archive/ZipDirCache.cpp
+++ b/Code/Framework/AzFramework/AzFramework/Archive/ZipDirCache.cpp
@@ -101,10 +101,11 @@ namespace AZ::IO::ZipDir
FileEntry* operator -> () { return m_pFileEntry; }
FileEntryTransactionAdd(Cache* pCache, AZStd::string_view szRelativePath)
: m_pCache(pCache)
+ , m_szRelativePath(AZ::IO::PosixPathSeparator)
, m_bCommitted(false)
{
// Update the cache string pool with the relative path to the file
- auto pathIt = m_pCache->m_relativePathPool.emplace(AZ::IO::PathView(szRelativePath).LexicallyNormal());
+ auto pathIt = m_pCache->m_relativePathPool.emplace(AZ::IO::PathView(szRelativePath, AZ::IO::PosixPathSeparator).LexicallyNormal());
m_szRelativePath = *pathIt.first;
// this is the name of the directory - create it or find it
m_pFileEntry = m_pCache->GetRoot()->Add(m_szRelativePath.Native());
@@ -740,6 +741,16 @@ namespace AZ::IO::ZipDir
{
return ZD_ERROR_CORRUPTED_DATA;
}
+ if (pFileEntry->bCheckCRCNextRead)
+ {
+ pFileEntry->bCheckCRCNextRead = false;
+ uLong uCRC32 = AZ::Crc32((Bytef*)pUncompressed, nSizeUncompressed);
+ if (uCRC32 != pFileEntry->desc.lCRC32)
+ {
+ AZ_Warning("Archive", false, "ZD_ERROR_CRC32_CHECK: Uncompressed stream CRC32 check failed");
+ return ZD_ERROR_CRC32_CHECK;
+ }
+ }
}
}
diff --git a/Code/Framework/AzFramework/AzFramework/Archive/ZipDirCacheFactory.cpp b/Code/Framework/AzFramework/AzFramework/Archive/ZipDirCacheFactory.cpp
index 5c5e93d441..d5bd4d2840 100644
--- a/Code/Framework/AzFramework/AzFramework/Archive/ZipDirCacheFactory.cpp
+++ b/Code/Framework/AzFramework/AzFramework/Archive/ZipDirCacheFactory.cpp
@@ -29,7 +29,7 @@ namespace AZ::IO::ZipDir
// this sets the window size of the blocks of data read from the end of the file to find the Central Directory Record
// since normally there are no
static constexpr size_t CDRSearchWindowSize = 0x100;
- CacheFactory::CacheFactory(InitMethodEnum nInitMethod, uint32_t nFlags)
+ CacheFactory::CacheFactory(InitMethod nInitMethod, uint32_t nFlags)
{
m_nCDREndPos = 0;
m_bBuildFileEntryMap = false; // we only need it for validation/debugging
@@ -448,7 +448,6 @@ namespace AZ::IO::ZipDir
// builds up the m_mapFileEntries
bool CacheFactory::BuildFileEntryMap()
{
-
Seek(m_CDREnd.lCDROffset);
if (m_CDREnd.lCDRSize == 0)
@@ -530,14 +529,6 @@ namespace AZ::IO::ZipDir
{
// Add this file entry.
char* str = reinterpret_cast(pFileName);
- for (int i = 0; i < pFile->nFileNameLength; i++)
- {
- str[i] = std::tolower(str[i], std::locale());
- if (str[i] == AZ_WRONG_FILESYSTEM_SEPARATOR)
- {
- str[i] = AZ_CORRECT_FILESYSTEM_SEPARATOR;
- }
- }
str[pFile->nFileNameLength] = 0; // Not standard!, may overwrite signature of the next memory record data in zip.
AddFileEntry(str, pFile, extra);
}
@@ -574,11 +565,7 @@ namespace AZ::IO::ZipDir
FileEntryBase fileEntry(*pFileHeader, extra);
- // when using encrypted headers we should always initialize data offsets from CDR
- if ((m_encryptedHeaders != ZipFile::HEADERS_NOT_ENCRYPTED || m_nInitMethod >= ZD_INIT_FULL) && pFileHeader->desc.lSizeCompressed)
- {
- InitDataOffset(fileEntry, pFileHeader);
- }
+ InitDataOffset(fileEntry, pFileHeader);
if (m_bBuildFileEntryMap)
{
@@ -606,142 +593,81 @@ namespace AZ::IO::ZipDir
{
Seek(pFileHeader->lLocalHeaderOffset);
- // read the local file header and the name (for validation) into the buffer
- AZStd::vectorpBuffer;
- uint32_t nBufferLength = sizeof(ZipFile::LocalFileHeader) + pFileHeader->nFileNameLength;
- pBuffer.resize(nBufferLength);
- Read(&pBuffer[0], nBufferLength);
-
- // validate the local file header (compare with the CDR file header - they should contain basically the same information)
- const auto* pLocalFileHeader = reinterpret_cast(&pBuffer[0]);
- if (pFileHeader->desc != pLocalFileHeader->desc
- || pFileHeader->nMethod != pLocalFileHeader->nMethod
- || pFileHeader->nFileNameLength != pLocalFileHeader->nFileNameLength
- // for a tough validation, we can compare the timestamps of the local and central directory entries
- // but we won't do that for backward compatibility with ZipDir
- //|| pFileHeader->nLastModDate != pLocalFileHeader->nLastModDate
- //|| pFileHeader->nLastModTime != pLocalFileHeader->nLastModTime
- )
- {
- AZ_Warning("Archive", false, "ZD_ERROR_VALIDATION_FAILED:"
- " The local file header descriptor doesn't match the basic parameters declared in the global file header in the file."
- " The archive content is misconsistent and may be damaged. Please try to repair the archive");
- return;
- }
+ // Read only the LocalFileHeader w/ no additional bytes ('name' or 'extra' fields)
+ AZStd::vector buffer;
+ uint32_t bufferLen = sizeof(ZipFile::LocalFileHeader);
+ buffer.resize_no_construct(bufferLen);
+ Read(buffer.data(), bufferLen);
- // now compare the local file name with the one recorded in CDR: they must match.
- auto CompareNoCase = [](const char lhs, const char rhs) { return std::tolower(lhs, std::locale()) == std::tolower(rhs, std::locale()); };
- auto zipFileDataBegin = pBuffer.begin() + sizeof(ZipFile::LocalFileHeader);
- auto zipFileDataEnd = zipFileDataBegin + pFileHeader->nFileNameLength;
- if (!AZStd::equal(zipFileDataBegin, zipFileDataEnd, reinterpret_cast(pFileHeader + 1), CompareNoCase))
- {
- // either file name, or the extra field do not match
- AZ_Warning("Archive", false, "ZD_ERROR_VALIDATION_FAILED:"
- " The local file header contains file name which does not match the file name of the global file header."
- " The archive content is misconsistent with its directory. Please repair the archive");
- return;
- }
+ const auto* localFileHeader = reinterpret_cast(buffer.data());
- fileEntry.nFileDataOffset = pFileHeader->lLocalHeaderOffset + sizeof(ZipFile::LocalFileHeader) + pLocalFileHeader->nFileNameLength + pLocalFileHeader->nExtraFieldLength;
- }
+ // set the correct file data offset...
+ fileEntry.nFileDataOffset = pFileHeader->lLocalHeaderOffset + sizeof(ZipFile::LocalFileHeader) +
+ localFileHeader->nFileNameLength + localFileHeader->nExtraFieldLength;
- // make sure it's the same file and the fileEntry structure is properly initialized
- AZ_Assert(fileEntry.nFileHeaderOffset == pFileHeader->lLocalHeaderOffset, "The file entry header offset doesn't match the file header local offst");
-
- fileEntry.nEOFOffset = fileEntry.nFileDataOffset + fileEntry.desc.lSizeCompressed;
-
- if (fileEntry.nFileDataOffset >= m_nCDREndPos)
- {
- AZ_Warning("Archive", false, "ZD_ERROR_VALIDATION_FAILED:"
- " The global file header declares the file which crosses the boundaries of the archive."
- " The archive is either corrupted or truncated, please try to repair it");
- return;
- }
+ fileEntry.nEOFOffset = fileEntry.nFileDataOffset + fileEntry.desc.lSizeCompressed;
- if (m_nInitMethod >= ZD_INIT_VALIDATE)
- {
- Validate(fileEntry);
- }
- }
+ if (m_nInitMethod != ZipDir::InitMethod::Default)
+ {
+ if (m_nInitMethod == ZipDir::InitMethod::FullValidation)
+ {
+ // Mark the FileEntry to check CRC when the next read occurs
+ fileEntry.bCheckCRCNextRead = true;
+ }
- //////////////////////////////////////////////////////////////////////////
- // reads the file pointed by the given header and entry (they must be coherent)
- // and decompresses it; then calculates and validates its CRC32
- void CacheFactory::Validate(const FileEntryBase& fileEntry)
- {
- AZStd::vector pBuffer;
- // validate the file contents
- // allocate memory for both the compressed data and uncompressed data
- pBuffer.resize(fileEntry.desc.lSizeCompressed + fileEntry.desc.lSizeUncompressed);
- char* pUncompressed = &pBuffer[fileEntry.desc.lSizeCompressed];
- char* pCompressed = &pBuffer[0];
+ // Timestamps
+ if (pFileHeader->nLastModDate != localFileHeader->nLastModDate
+ || pFileHeader->nLastModTime != localFileHeader->nLastModTime)
+ {
+ AZ_Warning("Archive", false, "ZD_ERROR_VALIDATION_FAILED: (%s)\n"
+ " The local file header's modification timestamps don't match that of the global file header in the archive."
+ " The archive timestamps are inconsistent and may be damaged. Check the archive file.", m_szFilename.c_str());
+ // don't return here, it may be ok.
+ }
- AZ_Assert(fileEntry.nFileDataOffset != FileEntry::INVALID_DATA_OFFSET, "File entry has invalid data offset of %" PRIx32, FileEntry::INVALID_DATA_OFFSET);
- Seek(fileEntry.nFileDataOffset);
+ // Validate data
+ if (pFileHeader->desc != localFileHeader->desc // this checks CRCs and compressed/uncompressed sizes
+ || pFileHeader->nMethod != localFileHeader->nMethod
+ || pFileHeader->nFileNameLength != localFileHeader->nFileNameLength)
+ {
+ AZ_Warning("Archive", false, "ZD_ERROR_VALIDATION_FAILED: (%s)\n"
+ " The local file header descriptor doesn't match basic parameters declared in the global file header in the file."
+ " The archive content is inconsistent and may be damaged. Please try to repair the archive.", m_szFilename.c_str());
+ // return here because further checks aren't worse than this.
+ return;
+ }
- Read(pCompressed, fileEntry.desc.lSizeCompressed);
+ // Read extra data
+ uint32_t extraDataLen = localFileHeader->nFileNameLength + localFileHeader->nExtraFieldLength;
+ buffer.resize_no_construct(buffer.size() + extraDataLen);
+ Read(buffer.data() + buffer.size(), extraDataLen);
- size_t nDestSize = fileEntry.desc.lSizeUncompressed;
- int nError = Z_OK;
- if (fileEntry.nMethod)
- {
- nError = ZipRawUncompress(pUncompressed, &nDestSize, pCompressed, fileEntry.desc.lSizeCompressed);
- }
- else
- {
- AZ_Assert(fileEntry.desc.lSizeCompressed == fileEntry.desc.lSizeUncompressed, "Uncompressed file does not have the same commpressed %u and uncompressed file sizes %u",
- fileEntry.desc.lSizeCompressed, fileEntry.desc.lSizeUncompressed);
- memcpy(pUncompressed, pCompressed, fileEntry.desc.lSizeUncompressed);
- }
- switch (nError)
- {
- case Z_OK:
- break;
- case Z_MEM_ERROR:
- AZ_Warning("Archive", false, "ZD_ERROR_ZLIB_NO_MEMORY: ZLib reported out-of-memory error");
- return;
- case Z_BUF_ERROR:
- AZ_Warning("Archive", false, "ZD_ERROR_ZLIB_CORRUPTED_DATA: ZLib reported compressed stream buffer error");
- return;
- case Z_DATA_ERROR:
- AZ_Warning("Archive", false, "ZD_ERROR_ZLIB_CORRUPTED_DATA: ZLib reported compressed stream data error");
- return;
- default:
- AZ_Warning("Archive", false, "ZD_ERROR_ZLIB_FAILED: ZLib reported an unexpected unknown error");
- return;
- }
+ // Compare local file name with the CDR file name, they should match
+ AZStd::string_view zipFileName{ buffer.data() + sizeof(ZipFile::LocalFileHeader), localFileHeader->nFileNameLength };
+ AZStd::string_view cdrFileName{ reinterpret_cast(pFileHeader + 1), pFileHeader->nFileNameLength };
+ if (zipFileName != cdrFileName)
+ {
+ AZ_Warning("Archive", false, "ZD_ERROR_VALIDATION_FAILED: (%s)\n"
+ " The file name in the local file header doesn't match the name in the global file header."
+ " The archive content is inconsisten with the directory. Please check the archive.", m_szFilename.c_str());
+ }
- if (nDestSize != fileEntry.desc.lSizeUncompressed)
- {
- AZ_Warning("Archive", false, "ZD_ERROR_CORRUPTED_DATA: Uncompressed stream doesn't match the size of uncompressed file stored in the archive file headers");
- return;
- }
+ // CDR and local "extra field" lengths may be different, should we compare them if they are equal?
- uLong uCRC32 = AZ::Crc32((Bytef*)pUncompressed, nDestSize);
- if (uCRC32 != fileEntry.desc.lCRC32)
- {
- AZ_Warning("Archive", false, "ZD_ERROR_CRC32_CHECK: Uncompressed stream CRC32 check failed");
- return;
- }
- }
+ // make sure it's the same file and the fileEntry structure is properly initialized
+ AZ_Assert(fileEntry.nFileHeaderOffset == pFileHeader->lLocalHeaderOffset,
+ "The file entry header offset doesn't match the file header local offst (%s)", m_szFilename.c_str());
+ if (fileEntry.nFileDataOffset >= m_nCDREndPos)
+ {
+ AZ_Warning("Archive", false, "ZD_ERROR_VALIDATION_FAILED: (%s)\n"
+ " The global file header declares the file which crosses the boundaries of the archive."
+ " The archive is either corrupted or truncated, please try to repair it", m_szFilename.c_str());
+ }
- //////////////////////////////////////////////////////////////////////////
- // extracts the file path from the file header with subsequent information
- // may, or may not, put all letters to lower-case (depending on whether the system is to be case-sensitive or not)
- // it's the responsibility of the caller to ensure that the file name is in readable valid memory
- char* CacheFactory::GetFilePath(const char* pFileName, uint16_t nFileNameLength)
- {
- static char strResult[AZ_MAX_PATH_LEN];
- AZ_Assert(nFileNameLength < AZ_MAX_PATH_LEN, "Only filenames shorter than %zu can be copied from filename parameter", AZ_MAX_PATH_LEN);
- memcpy(strResult, pFileName, nFileNameLength);
- strResult[nFileNameLength] = 0;
- for (int i = 0; i < nFileNameLength; i++)
- {
- strResult[i] = std::tolower(strResult[i], std::locale{});
+ // End Validation
+ }
}
-
- return strResult;
}
// seeks in the file relative to the starting position
diff --git a/Code/Framework/AzFramework/AzFramework/Archive/ZipDirCacheFactory.h b/Code/Framework/AzFramework/AzFramework/Archive/ZipDirCacheFactory.h
index c31d4d7dfd..1612829f13 100644
--- a/Code/Framework/AzFramework/AzFramework/Archive/ZipDirCacheFactory.h
+++ b/Code/Framework/AzFramework/AzFramework/Archive/ZipDirCacheFactory.h
@@ -39,7 +39,7 @@ namespace AZ::IO::ZipDir
// initializes the internal structures
// nFlags can have FLAGS_READ_ONLY flag, in this case the object will be opened only for reading
- CacheFactory(InitMethodEnum nInitMethod, uint32_t nFlags = 0);
+ CacheFactory(InitMethod nInitMethod, uint32_t nFlags = 0);
~CacheFactory();
// the new function creates a new cache
@@ -66,28 +66,6 @@ namespace AZ::IO::ZipDir
// This function can actually modify strFilePath variable, make sure you use a copy of the real path.
void AddFileEntry(char* strFilePath, const ZipFile::CDRFileHeader* pFileHeader, const SExtraZipFileData& extra);// throw (ErrorEnum);
- // extracts the file path from the file header with subsequent information
- // may, or may not, put all letters to lower-case (depending on whether the system is to be case-sensitive or not)
- // it's the responsibility of the caller to ensure that the file name is in readable valid memory
- char* GetFilePath(const ZipFile::CDRFileHeader* pFileHeader)
- {
- return GetFilePath((const char*)(pFileHeader + 1), pFileHeader->nFileNameLength);
- }
- // extracts the file path from the file header with subsequent information
- // may, or may not, put all letters to lower-case (depending on whether the system is to be case-sensitive or not)
- // it's the responsibility of the caller to ensure that the file name is in readable valid memory
- char* GetFilePath(const ZipFile::LocalFileHeader* pFileHeader)
- {
- return GetFilePath((const char*)(pFileHeader + 1), pFileHeader->nFileNameLength);
- }
- // extracts the file path from the file header with subsequent information
- // may, or may not, put all letters to lower-case (depending on whether the system is to be case-sensitive or not)
- // it's the responsibility of the caller to ensure that the file name is in readable valid memory
- char* GetFilePath(const char* pFileName, uint16_t nFileNameLength);
-
- // validates (if the init method has the corresponding value) the given file/header
- void Validate(const FileEntryBase& fileEntry);
-
// initializes the actual data offset in the file in the fileEntry structure
// searches to the local file header, reads it and calculates the actual offset in the file
void InitDataOffset(FileEntryBase& fileEntry, const ZipFile::CDRFileHeader* pFileHeader);
@@ -104,7 +82,7 @@ namespace AZ::IO::ZipDir
AZStd::string m_szFilename;
CZipFile m_fileExt;
- InitMethodEnum m_nInitMethod;
+ InitMethod m_nInitMethod;
uint32_t m_nFlags;
ZipFile::CDREnd m_CDREnd;
@@ -129,7 +107,7 @@ namespace AZ::IO::ZipDir
ZipFile::CryCustomEncryptionHeader m_headerEncryption;
ZipFile::CrySignedCDRHeader m_headerSignature;
ZipFile::CryCustomExtendedHeader m_headerExtended;
-
};
+
}
diff --git a/Code/Framework/AzFramework/AzFramework/Archive/ZipDirList.cpp b/Code/Framework/AzFramework/AzFramework/Archive/ZipDirList.cpp
index 729f394b9d..ab9c356d7f 100644
--- a/Code/Framework/AzFramework/AzFramework/Archive/ZipDirList.cpp
+++ b/Code/Framework/AzFramework/AzFramework/Archive/ZipDirList.cpp
@@ -68,14 +68,14 @@ namespace AZ::IO::ZipDir
{
for (FileEntryTree::SubdirMap::iterator it = pTree->GetDirBegin(); it != pTree->GetDirEnd(); ++it)
{
- AddAllFiles(it->second.get(), (AZ::IO::Path(strRoot) / it->first).Native());
+ AddAllFiles(it->second.get(), (AZ::IO::Path(strRoot, AZ::IO::PosixPathSeparator) / it->first).Native());
}
for (FileEntryTree::FileMap::iterator it = pTree->GetFileBegin(); it != pTree->GetFileEnd(); ++it)
{
FileRecord rec;
rec.pFileEntryBase = pTree->GetFileEntry(it);
- rec.strPath = (AZ::IO::Path(strRoot) / it->first).Native();
+ rec.strPath = (AZ::IO::Path(strRoot, AZ::IO::PosixPathSeparator) / it->first).Native();
push_back(rec);
}
}
diff --git a/Code/Framework/AzFramework/AzFramework/Archive/ZipDirStructures.h b/Code/Framework/AzFramework/AzFramework/Archive/ZipDirStructures.h
index 9295a7dd95..c890d498e4 100644
--- a/Code/Framework/AzFramework/AzFramework/Archive/ZipDirStructures.h
+++ b/Code/Framework/AzFramework/AzFramework/Archive/ZipDirStructures.h
@@ -119,19 +119,28 @@ namespace AZ::IO::ZipDir
const char* m_szDescription;
};
+#if defined(_RELEASE)
+ inline static constexpr bool IsReleaseConfig{ true };
+#else
+ inline static constexpr bool IsReleaseConfig{};
+#endif // _RELEASE
+
// possible initialization methods
- enum InitMethodEnum
+ enum class InitMethod
{
- // initialize as fast as possible, with minimal validation
- ZD_INIT_FAST,
- // after initialization, scan through all file headers, precache the actual file data offset values and validate the headers
- ZD_INIT_FULL,
- // scan all file headers and try to decompress the data, searching for corrupted files
- ZD_INIT_VALIDATE_IN_MEMORY,
- // store archive in memory
- ZD_INIT_VALIDATE,
- // maximum level of validation, checks for integrity of the archive
- ZD_INIT_VALIDATE_MAX = ZD_INIT_VALIDATE
+ // initializes without any sort of extra validation steps
+ Default,
+
+ // initializes with extra validation steps
+ // not available in RELEASE
+ // will check CDR and local headers data match
+ ValidateHeaders,
+
+ // initializes with extra validation steps
+ // not available in RELEASE
+ // will check CDR and local headers data match
+ // will check file data CRC matches (when file is read)
+ FullValidation,
};
// Uncompresses raw (without wrapping) data that is compressed with method 8 (deflated) in the Zip file
@@ -184,7 +193,11 @@ namespace AZ::IO::ZipDir
// the offset to the start of the next file's header - this
// can be used to calculate the available space in zip file
uint32_t nEOFOffset{};
+
+ // whether to check the CRC upon the next data read
+ bool bCheckCRCNextRead{};
};
+
// this is the record about the file in the Zip file.
struct FileEntry
: FileEntryBase
diff --git a/Code/Framework/AzFramework/AzFramework/IO/LocalFileIO.cpp b/Code/Framework/AzFramework/AzFramework/IO/LocalFileIO.cpp
index 4072c17ea0..49e16dcb90 100644
--- a/Code/Framework/AzFramework/AzFramework/IO/LocalFileIO.cpp
+++ b/Code/Framework/AzFramework/AzFramework/IO/LocalFileIO.cpp
@@ -281,6 +281,14 @@ namespace AZ
return SystemFile::Exists(resolvedPath);
}
+ bool LocalFileIO::IsDirectory(const char* filePath)
+ {
+ char resolvedPath[AZ_MAX_PATH_LEN];
+ ResolvePath(filePath, resolvedPath, AZ_MAX_PATH_LEN);
+
+ return SystemFile::IsDirectory(resolvedPath);
+ }
+
void LocalFileIO::CheckInvalidWrite([[maybe_unused]] const char* path)
{
#if defined(AZ_ENABLE_TRACING)
diff --git a/Code/Framework/AzFramework/AzFramework/Network/AssetProcessorConnection.cpp b/Code/Framework/AzFramework/AzFramework/Network/AssetProcessorConnection.cpp
index 2e1cde443c..74b92a5681 100644
--- a/Code/Framework/AzFramework/AzFramework/Network/AssetProcessorConnection.cpp
+++ b/Code/Framework/AzFramework/AzFramework/Network/AssetProcessorConnection.cpp
@@ -593,7 +593,7 @@ namespace AzFramework
DebugMessage("StartThread: Starting %s", thread.m_desc.m_name);
thread.m_join = false;
- thread.m_thread = AZStd::thread(thread.m_main, &thread.m_desc);
+ thread.m_thread = AZStd::thread(thread.m_desc, thread.m_main);
}
void AssetProcessorConnection::JoinThread(ThreadState& thread, AZStd::condition_variable* wakeUpCondition /* = nullptr */)
diff --git a/Code/Framework/AzFramework/AzFramework/TargetManagement/TargetManagementComponent.cpp b/Code/Framework/AzFramework/AzFramework/TargetManagement/TargetManagementComponent.cpp
index 1c26cbc744..8e6bacda2b 100644
--- a/Code/Framework/AzFramework/AzFramework/TargetManagement/TargetManagementComponent.cpp
+++ b/Code/Framework/AzFramework/AzFramework/TargetManagement/TargetManagementComponent.cpp
@@ -319,7 +319,7 @@ namespace AzFramework
AZStd::thread_desc td;
td.m_name = "TargetManager Thread";
td.m_cpuId = AFFINITY_MASK_USERTHREADS;
- m_threadHandle = AZStd::thread(AZStd::bind(&TargetManagementComponent::TickThread, this), &td);
+ m_threadHandle = AZStd::thread(td, AZStd::bind(&TargetManagementComponent::TickThread, this));
}
void TargetManagementComponent::Deactivate()
diff --git a/Code/Framework/AzFramework/AzFramework/Terrain/TerrainDataRequestBus.h b/Code/Framework/AzFramework/AzFramework/Terrain/TerrainDataRequestBus.h
index 92eb28a110..3f6a8f0960 100644
--- a/Code/Framework/AzFramework/AzFramework/Terrain/TerrainDataRequestBus.h
+++ b/Code/Framework/AzFramework/AzFramework/Terrain/TerrainDataRequestBus.h
@@ -8,6 +8,7 @@
#pragma once
#include
+#include
#include
#include
#include
@@ -17,16 +18,38 @@ namespace AzFramework
{
namespace SurfaceData
{
+ namespace Constants
+ {
+ static const char* s_unassignedTagName = "(unassigned)";
+ }
+
struct SurfaceTagWeight
{
AZ_TYPE_INFO(SurfaceTagWeight, "{EA14018E-E853-4BF5-8E13-D83BB99A54CC}");
- AZ::Crc32 m_surfaceType;
- float m_weight; //! A Value in the range [0.0f .. 1.0f]
+ AZ::Crc32 m_surfaceType = AZ::Crc32(Constants::s_unassignedTagName);
+ float m_weight = 0.0f; //! A Value in the range [0.0f .. 1.0f]
//! Don't call this directly. TerrainDataRequests::Reflect is doing it already.
static void Reflect(AZ::ReflectContext* context);
};
+
+ struct SurfaceTagWeightComparator
+ {
+ bool operator()(const SurfaceTagWeight& tagWeight1, const SurfaceTagWeight& tagWeight2) const
+ {
+ if (!AZ::IsClose(tagWeight1.m_weight, tagWeight2.m_weight))
+ {
+ return tagWeight1.m_weight > tagWeight2.m_weight;
+ }
+ else
+ {
+ return tagWeight1.m_surfaceType > tagWeight2.m_surfaceType;
+ }
+ }
+ };
+
+ using OrderedSurfaceTagWeightSet = AZStd::set;
} //namespace SurfaceData
namespace Terrain
@@ -75,8 +98,28 @@ namespace AzFramework
//! @terrainExists: Can be nullptr. If != nullptr then, if there's no terrain at location x,y or location x,y is inside a terrain HOLE then *terrainExistsPtr will be set to false,
//! otherwise *terrainExistsPtr will be set to true.
virtual SurfaceData::SurfaceTagWeight GetMaxSurfaceWeight(AZ::Vector3 position, Sampler sampleFilter = Sampler::BILINEAR, bool* terrainExistsPtr = nullptr) const = 0;
+ virtual SurfaceData::SurfaceTagWeight GetMaxSurfaceWeightFromVector2(const AZ::Vector2& inPosition, Sampler sampleFilter = Sampler::DEFAULT, bool* terrainExistsPtr = nullptr) const = 0;
virtual SurfaceData::SurfaceTagWeight GetMaxSurfaceWeightFromFloats(float x, float y, Sampler sampleFilter = Sampler::BILINEAR, bool* terrainExistsPtr = nullptr) const = 0;
+ //! Given an XY coordinate, return the set of surface types and weights. The Vector3 input position version is defined to ignore
+ //! the input Z value.
+ virtual void GetSurfaceWeights(
+ const AZ::Vector3& inPosition,
+ SurfaceData::OrderedSurfaceTagWeightSet& outSurfaceWeights,
+ Sampler sampleFilter = Sampler::DEFAULT,
+ bool* terrainExistsPtr = nullptr) const = 0;
+ virtual void GetSurfaceWeightsFromVector2(
+ const AZ::Vector2& inPosition,
+ SurfaceData::OrderedSurfaceTagWeightSet& outSurfaceWeights,
+ Sampler sampleFilter = Sampler::DEFAULT,
+ bool* terrainExistsPtr = nullptr) const = 0;
+ virtual void GetSurfaceWeightsFromFloats(
+ float x,
+ float y,
+ SurfaceData::OrderedSurfaceTagWeightSet& outSurfaceWeights,
+ Sampler sampleFilter = Sampler::DEFAULT,
+ bool* terrainExistsPtr = nullptr) const = 0;
+
//! Convenience function for low level systems that can't do a reverse lookup from Crc to string. Everyone else should use GetMaxSurfaceWeight or GetMaxSurfaceWeightFromFloats.
//! Not available in the behavior context.
//! Returns nullptr if the position is inside a hole or outside of the terrain boundaries.
diff --git a/Code/Framework/AzFramework/AzFramework/Visibility/EntityBoundsUnionBus.h b/Code/Framework/AzFramework/AzFramework/Visibility/EntityBoundsUnionBus.h
index b6c26e3e9e..862dea38cc 100644
--- a/Code/Framework/AzFramework/AzFramework/Visibility/EntityBoundsUnionBus.h
+++ b/Code/Framework/AzFramework/AzFramework/Visibility/EntityBoundsUnionBus.h
@@ -28,9 +28,12 @@ namespace AzFramework
//! @note This is used to drive event driven updates to the visibility system.
virtual void RefreshEntityLocalBoundsUnion(AZ::EntityId entityId) = 0;
- //! Returns the cached union of all component Aabbs.
+ //! Returns the cached union of all component Aabbs in local entity space.
virtual AZ::Aabb GetEntityLocalBoundsUnion(AZ::EntityId entityId) const = 0;
+ //! Returns the cached union of all component Aabbs in world space.
+ virtual AZ::Aabb GetEntityWorldBoundsUnion(AZ::EntityId entityId) const = 0;
+
//! Writes the current changes made to all entities (transforms and bounds) to the visibility system.
//! @note During normal operation this is called every frame in OnTick but can
//! also be called explicitly (e.g. For testing purposes).
diff --git a/Code/Framework/AzFramework/AzFramework/Visibility/EntityVisibilityBoundsUnionSystem.cpp b/Code/Framework/AzFramework/AzFramework/Visibility/EntityVisibilityBoundsUnionSystem.cpp
index 826570fee5..1963411147 100644
--- a/Code/Framework/AzFramework/AzFramework/Visibility/EntityVisibilityBoundsUnionSystem.cpp
+++ b/Code/Framework/AzFramework/AzFramework/Visibility/EntityVisibilityBoundsUnionSystem.cpp
@@ -128,6 +128,24 @@ namespace AzFramework
return AZ::Aabb::CreateNull();
}
+ AZ::Aabb EntityVisibilityBoundsUnionSystem::GetEntityWorldBoundsUnion(const AZ::EntityId entityId) const
+ {
+ AZ::Entity* entity = AZ::Interface::Get()->FindEntity(entityId);
+ if (entity != nullptr)
+ {
+ // if the entity is not found in the mapping then return a null Aabb, this is to mimic
+ // as closely as possible the behavior of an individual GetLocalBounds call to an Entity that
+ // had been deleted (there would be no response, leaving the default value assigned)
+ if (auto instance_it = m_entityVisibilityBoundsUnionInstanceMapping.find(entity);
+ instance_it != m_entityVisibilityBoundsUnionInstanceMapping.end())
+ {
+ return instance_it->second.m_localEntityBoundsUnion.GetTranslated(entity->GetTransform()->GetWorldTranslation());
+ }
+ }
+
+ return AZ::Aabb::CreateNull();
+ }
+
void EntityVisibilityBoundsUnionSystem::ProcessEntityBoundsUnionRequests()
{
AZ_PROFILE_FUNCTION(AzFramework);
diff --git a/Code/Framework/AzFramework/AzFramework/Visibility/EntityVisibilityBoundsUnionSystem.h b/Code/Framework/AzFramework/AzFramework/Visibility/EntityVisibilityBoundsUnionSystem.h
index 03109f0dd2..1a3531e506 100644
--- a/Code/Framework/AzFramework/AzFramework/Visibility/EntityVisibilityBoundsUnionSystem.h
+++ b/Code/Framework/AzFramework/AzFramework/Visibility/EntityVisibilityBoundsUnionSystem.h
@@ -31,6 +31,7 @@ namespace AzFramework
// EntityBoundsUnionRequestBus overrides ...
void RefreshEntityLocalBoundsUnion(AZ::EntityId entityId) override;
AZ::Aabb GetEntityLocalBoundsUnion(AZ::EntityId entityId) const override;
+ AZ::Aabb GetEntityWorldBoundsUnion(AZ::EntityId entityId) const override;
void ProcessEntityBoundsUnionRequests() override;
void OnTransformUpdated(AZ::Entity* entity) override;
diff --git a/Code/Framework/AzFramework/Platform/Android/AzFramework/IO/LocalFileIO_Android.cpp b/Code/Framework/AzFramework/Platform/Android/AzFramework/IO/LocalFileIO_Android.cpp
index b88c7cf25b..b454755cd4 100644
--- a/Code/Framework/AzFramework/Platform/Android/AzFramework/IO/LocalFileIO_Android.cpp
+++ b/Code/Framework/AzFramework/Platform/Android/AzFramework/IO/LocalFileIO_Android.cpp
@@ -40,26 +40,6 @@ namespace AZ
{
namespace IO
{
- bool LocalFileIO::IsDirectory(const char* filePath)
- {
- ANDROID_IO_PROFILE_SECTION_ARGS("IsDir:%s", filePath);
-
- char resolvedPath[AZ_MAX_PATH_LEN];
- ResolvePath(filePath, resolvedPath, AZ_MAX_PATH_LEN);
-
- if (AZ::Android::Utils::IsApkPath(resolvedPath))
- {
- return AZ::Android::APKFileHandler::IsDirectory(AZ::Android::Utils::StripApkPrefix(resolvedPath).c_str());
- }
-
- struct stat result;
- if (stat(resolvedPath, &result) == 0)
- {
- return S_ISDIR(result.st_mode);
- }
- return false;
- }
-
Result LocalFileIO::Copy(const char* sourceFilePath, const char* destinationFilePath)
{
char resolvedSourcePath[AZ_MAX_PATH_LEN];
diff --git a/Code/Framework/AzFramework/Platform/Common/UnixLike/AzFramework/IO/LocalFileIO_UnixLike.cpp b/Code/Framework/AzFramework/Platform/Common/UnixLike/AzFramework/IO/LocalFileIO_UnixLike.cpp
index c9cbdfbe7d..844464681a 100644
--- a/Code/Framework/AzFramework/Platform/Common/UnixLike/AzFramework/IO/LocalFileIO_UnixLike.cpp
+++ b/Code/Framework/AzFramework/Platform/Common/UnixLike/AzFramework/IO/LocalFileIO_UnixLike.cpp
@@ -17,19 +17,6 @@ namespace AZ
{
namespace IO
{
- bool LocalFileIO::IsDirectory(const char* filePath)
- {
- char resolvedPath[AZ_MAX_PATH_LEN] = {0};
- ResolvePath(filePath, resolvedPath, AZ_MAX_PATH_LEN);
-
- struct stat result;
- if (stat(resolvedPath, &result) == 0)
- {
- return S_ISDIR(result.st_mode);
- }
- return false;
- }
-
Result LocalFileIO::Copy(const char* sourceFilePath, const char* destinationFilePath)
{
char resolvedSourceFilePath[AZ_MAX_PATH_LEN] = {0};
diff --git a/Code/Framework/AzFramework/Platform/Common/WinAPI/AzFramework/IO/LocalFileIO_WinAPI.cpp b/Code/Framework/AzFramework/Platform/Common/WinAPI/AzFramework/IO/LocalFileIO_WinAPI.cpp
index 5a56a360a8..64787d4951 100644
--- a/Code/Framework/AzFramework/Platform/Common/WinAPI/AzFramework/IO/LocalFileIO_WinAPI.cpp
+++ b/Code/Framework/AzFramework/Platform/Common/WinAPI/AzFramework/IO/LocalFileIO_WinAPI.cpp
@@ -15,22 +15,6 @@ namespace AZ
{
namespace IO
{
- bool LocalFileIO::IsDirectory(const char* filePath)
- {
- char resolvedPath[AZ_MAX_PATH_LEN];
- ResolvePath(filePath, resolvedPath, AZ_MAX_PATH_LEN);
-
- wchar_t resolvedPathW[AZ_MAX_PATH_LEN];
- AZStd::to_wstring(resolvedPathW, AZ_MAX_PATH_LEN, resolvedPath);
- DWORD fileAttributes = GetFileAttributesW(resolvedPathW);
- if (fileAttributes == INVALID_FILE_ATTRIBUTES)
- {
- return false;
- }
-
- return (fileAttributes & FILE_ATTRIBUTE_DIRECTORY) != 0;
- }
-
Result LocalFileIO::FindFiles(const char* filePath, const char* filter, FindFilesCallbackType callback)
{
char resolvedPath[AZ_MAX_PATH_LEN];
diff --git a/Code/Framework/AzFramework/Platform/Windows/AzFramework/Windowing/NativeWindow_Windows.cpp b/Code/Framework/AzFramework/Platform/Windows/AzFramework/Windowing/NativeWindow_Windows.cpp
index 3f2b29a7bb..57b37037ae 100644
--- a/Code/Framework/AzFramework/Platform/Windows/AzFramework/Windowing/NativeWindow_Windows.cpp
+++ b/Code/Framework/AzFramework/Platform/Windows/AzFramework/Windowing/NativeWindow_Windows.cpp
@@ -239,6 +239,8 @@ namespace AzFramework
RAWINPUT* rawInput = (RAWINPUT*)rawInputBytes;
AzFramework::RawInputNotificationBusWindows::Broadcast(
&AzFramework::RawInputNotificationBusWindows::Events::OnRawInputEvent, *rawInput);
+
+ delete [] rawInputBytes;
break;
}
case WM_CHAR:
diff --git a/Code/Framework/AzFramework/Tests/FileIO.cpp b/Code/Framework/AzFramework/Tests/FileIO.cpp
index fb95512968..dbee109978 100644
--- a/Code/Framework/AzFramework/Tests/FileIO.cpp
+++ b/Code/Framework/AzFramework/Tests/FileIO.cpp
@@ -14,7 +14,6 @@
#include
#include
#include
-#include
#include
#include
#include
@@ -30,21 +29,6 @@ using namespace AZ;
using namespace AZ::IO;
using namespace AZ::Debug;
-namespace PathUtil
-{
- AZStd::string AddSlash(const AZStd::string& path)
- {
- if (path.empty() || path[path.length() - 1] == '/')
- {
- return path;
- }
- if (path[path.length() - 1] == '\\')
- {
- return path.substr(0, path.length() - 1) + "/";
- }
- return path + "/";
- }
-}
namespace UnitTest
{
@@ -161,15 +145,16 @@ namespace UnitTest
: public ScopedAllocatorSetupFixture
{
public:
- AZStd::string m_root;
- AZStd::string folderName;
- AZStd::string deepFolder;
- AZStd::string extraFolder;
-
- AZStd::string fileRoot;
- AZStd::string file01Name;
- AZStd::string file02Name;
- AZStd::string file03Name;
+ AZ::Test::ScopedAutoTempDirectory m_tempDir;
+ AZ::IO::Path m_root;
+ AZ::IO::Path m_folderName;
+ AZ::IO::Path m_deepFolder;
+ AZ::IO::Path m_extraFolder;
+
+ AZ::IO::Path m_fileRoot;
+ AZ::IO::Path m_file01Name;
+ AZ::IO::Path m_file02Name;
+ AZ::IO::Path m_file03Name;
int m_randomFolderKey = 0;
FolderFixture()
@@ -179,43 +164,13 @@ namespace UnitTest
void ChooseRandomFolder()
{
- char currentDir[AZ_MAX_PATH_LEN];
- AZ::Utils::GetExecutableDirectory(currentDir, AZ_MAX_PATH_LEN);
-
- folderName = currentDir;
- folderName.append("/temp");
- m_root = folderName;
- if (folderName.size() > 0)
- {
- folderName = PathUtil::AddSlash(folderName);
- }
-
- AZStd::string tempName = AZStd::string::format("tmp%08x", m_randomFolderKey);
- folderName.append(tempName.c_str());
- folderName = PathUtil::AddSlash(folderName);
- AZStd::replace(folderName.begin(), folderName.end(), '\\', '/');
-
- // Make sure the drive letter is capitalized
- if (folderName.size() > 2)
- {
- if (folderName[1] == ':')
- {
- folderName[0] = static_cast(toupper(folderName[0]));
- }
- }
-
- deepFolder = folderName;
- deepFolder.append("test");
-
- deepFolder = PathUtil::AddSlash(deepFolder);
- deepFolder.append("subdir");
-
- extraFolder = deepFolder;
- extraFolder = PathUtil::AddSlash(extraFolder);
- extraFolder.append("subdir2");
+ m_root = m_tempDir.GetDirectory();
+ m_folderName = m_root / AZStd::string::format("tmp%08x", m_randomFolderKey);
+ m_deepFolder = m_folderName / "test" / "subdir";
+ m_extraFolder = m_deepFolder / "subdir2";
// make a couple files there, and in the root:
- fileRoot = PathUtil::AddSlash(extraFolder);
+ m_fileRoot = m_extraFolder;
}
void SetUp() override
@@ -229,37 +184,33 @@ namespace UnitTest
{
ChooseRandomFolder();
++m_randomFolderKey;
- } while (local.IsDirectory(fileRoot.c_str()));
+ } while (local.IsDirectory(m_fileRoot.c_str()));
- file01Name = fileRoot + "file01.txt";
- file02Name = fileRoot + "file02.asdf";
- file03Name = fileRoot + "test123.wha";
+ m_file01Name = m_fileRoot / "file01.txt";
+ m_file02Name = m_fileRoot / "file02.asdf";
+ m_file03Name = m_fileRoot / "test123.wha";
}
void TearDown() override
{
- if ((!folderName.empty())&&(strstr(folderName.c_str(), "/temp") != nullptr))
- {
- // cleanup!
- LocalFileIO local;
- local.DestroyPath(folderName.c_str());
- }
}
void CreateTestFiles()
{
+ constexpr auto openMode = SystemFile::OpenMode::SF_OPEN_WRITE_ONLY
+ | SystemFile::OpenMode::SF_OPEN_CREATE
+ | SystemFile::OpenMode::SF_OPEN_CREATE_NEW;
+ constexpr AZStd::string_view testContent("this is just a test");
+
LocalFileIO local;
- AZ_TEST_ASSERT(local.CreatePath(fileRoot.c_str()));
- AZ_TEST_ASSERT(local.IsDirectory(fileRoot.c_str()));
- for (const AZStd::string& filename : { file01Name, file02Name, file03Name })
+ AZ_TEST_ASSERT(local.CreatePath(m_fileRoot.c_str()));
+ AZ_TEST_ASSERT(local.IsDirectory(m_fileRoot.c_str()));
+ for (const AZ::IO::Path& filename : { m_file01Name, m_file02Name, m_file03Name })
{
-#ifdef AZ_COMPILER_MSVC
- FILE* tempFile;
- fopen_s(&tempFile, filename.c_str(), "wb");
-#else
- FILE* tempFile = fopen(filename.c_str(), "wb");
-#endif
- fwrite("this is just a test", 1, 19, tempFile);
- fclose(tempFile);
+ SystemFile tempFile;
+ tempFile.Open(filename.c_str(), openMode);
+
+ tempFile.Write(testContent.data(), testContent.size());
+ tempFile.Close();
}
}
};
@@ -272,28 +223,23 @@ namespace UnitTest
{
LocalFileIO local;
- AZ_TEST_ASSERT(!local.Exists(folderName.c_str()));
+ AZ_TEST_ASSERT(!local.Exists(m_folderName.c_str()));
- AZStd::string longPathCreateTest = folderName;
- longPathCreateTest.append("one");
- longPathCreateTest = PathUtil::AddSlash(longPathCreateTest);
- longPathCreateTest.append("two");
- longPathCreateTest = PathUtil::AddSlash(longPathCreateTest);
- longPathCreateTest.append("three");
+ AZ::IO::Path longPathCreateTest = m_folderName / "one" / "two" / "three";
AZ_TEST_ASSERT(!local.Exists(longPathCreateTest.c_str()));
AZ_TEST_ASSERT(!local.IsDirectory(longPathCreateTest.c_str()));
AZ_TEST_ASSERT(local.CreatePath(longPathCreateTest.c_str()));
AZ_TEST_ASSERT(local.IsDirectory(longPathCreateTest.c_str()));
- AZ_TEST_ASSERT(!local.Exists(deepFolder.c_str()));
- AZ_TEST_ASSERT(!local.IsDirectory(deepFolder.c_str()));
- AZ_TEST_ASSERT(local.CreatePath(deepFolder.c_str()));
- AZ_TEST_ASSERT(local.IsDirectory(deepFolder.c_str()));
+ AZ_TEST_ASSERT(!local.Exists(m_deepFolder.c_str()));
+ AZ_TEST_ASSERT(!local.IsDirectory(m_deepFolder.c_str()));
+ AZ_TEST_ASSERT(local.CreatePath(m_deepFolder.c_str()));
+ AZ_TEST_ASSERT(local.IsDirectory(m_deepFolder.c_str()));
- AZ_TEST_ASSERT(local.Exists(deepFolder.c_str()));
- AZ_TEST_ASSERT(local.CreatePath(deepFolder.c_str()));
- AZ_TEST_ASSERT(local.Exists(deepFolder.c_str()));
+ AZ_TEST_ASSERT(local.Exists(m_deepFolder.c_str()));
+ AZ_TEST_ASSERT(local.CreatePath(m_deepFolder.c_str()));
+ AZ_TEST_ASSERT(local.Exists(m_deepFolder.c_str()));
}
};
@@ -310,16 +256,19 @@ namespace UnitTest
{
LocalFileIO local;
- AZ_TEST_ASSERT(!local.Exists(fileRoot.c_str()));
- AZ_TEST_ASSERT(!local.IsDirectory(fileRoot.c_str()));
- AZ_TEST_ASSERT(local.CreatePath(fileRoot.c_str()));
- AZ_TEST_ASSERT(local.IsDirectory(fileRoot.c_str()));
-
- FILE* tempFile = nullptr;
- azfopen(&tempFile, file01Name.c_str(), "wb");
+ AZ_TEST_ASSERT(!local.Exists(m_fileRoot.c_str()));
+ AZ_TEST_ASSERT(!local.IsDirectory(m_fileRoot.c_str()));
+ AZ_TEST_ASSERT(local.CreatePath(m_fileRoot.c_str()));
+ AZ_TEST_ASSERT(local.IsDirectory(m_fileRoot.c_str()));
- fwrite("this is just a test", 1, 19, tempFile);
- fclose(tempFile);
+ constexpr auto openMode = SystemFile::OpenMode::SF_OPEN_WRITE_ONLY
+ | SystemFile::OpenMode::SF_OPEN_CREATE
+ | SystemFile::OpenMode::SF_OPEN_CREATE_NEW;
+ SystemFile tempFile;
+ tempFile.Open(m_file01Name.c_str(), openMode);
+ constexpr AZStd::string_view testContent("this is just a test");
+ tempFile.Write(testContent.data(), testContent.size());
+ tempFile.Close();
AZ::IO::HandleType fileHandle = AZ::IO::InvalidHandle;
AZ_TEST_ASSERT(!local.Open("", AZ::IO::OpenMode::ModeWrite, fileHandle));
@@ -327,12 +276,12 @@ namespace UnitTest
// test size without opening:
AZ::u64 fs = 0;
- AZ_TEST_ASSERT(local.Size(file01Name.c_str(), fs));
+ AZ_TEST_ASSERT(local.Size(m_file01Name.c_str(), fs));
AZ_TEST_ASSERT(fs == 19);
fileHandle = AZ::IO::InvalidHandle;
- AZ::u64 modTimeA = local.ModificationTime(file01Name.c_str());
+ AZ::u64 modTimeA = local.ModificationTime(m_file01Name.c_str());
AZ_TEST_ASSERT(modTimeA != 0);
// test invalid handle ops:
@@ -344,14 +293,14 @@ namespace UnitTest
AZ_TEST_ASSERT(!local.Read(fileHandle, nullptr, 0, false));
AZ_TEST_ASSERT(!local.Tell(fileHandle, fs));
- AZ_TEST_ASSERT(!local.Exists((file01Name + "notexist").c_str()));
+ AZ_TEST_ASSERT(!local.Exists((m_file01Name.Native() + "notexist").c_str()));
- AZ_TEST_ASSERT(local.Exists(file01Name.c_str()));
- AZ_TEST_ASSERT(!local.IsReadOnly(file01Name.c_str()));
- AZ_TEST_ASSERT(!local.IsDirectory(file01Name.c_str()));
+ AZ_TEST_ASSERT(local.Exists(m_file01Name.c_str()));
+ AZ_TEST_ASSERT(!local.IsReadOnly(m_file01Name.c_str()));
+ AZ_TEST_ASSERT(!local.IsDirectory(m_file01Name.c_str()));
// test reads and seeks.
- AZ_TEST_ASSERT(local.Open(file01Name.c_str(), AZ::IO::OpenMode::ModeRead, fileHandle));
+ AZ_TEST_ASSERT(local.Open(m_file01Name.c_str(), AZ::IO::OpenMode::ModeRead, fileHandle));
AZ_TEST_ASSERT(fileHandle != AZ::IO::InvalidHandle);
// use this again later...
@@ -368,7 +317,7 @@ namespace UnitTest
// test size without opening, after its already open:
fs = 0;
- AZ_TEST_ASSERT(local.Size(file01Name.c_str(), fs));
+ AZ_TEST_ASSERT(local.Size(m_file01Name.c_str(), fs));
AZ_TEST_ASSERT(fs == 19);
AZ::u64 offs = 0;
@@ -442,22 +391,22 @@ namespace UnitTest
#if AZ_TRAIT_AZFRAMEWORKTEST_PERFORM_CHMOD_TEST
#if AZ_TRAIT_USE_WINDOWS_FILE_API
- _chmod(file01Name.c_str(), _S_IREAD);
+ _chmod(m_file01Name.c_str(), _S_IREAD);
#else
- chmod(file01Name.c_str(), S_IRUSR | S_IRGRP | S_IROTH);
+ chmod(m_file01Name.c_str(), S_IRUSR | S_IRGRP | S_IROTH);
#endif
- AZ_TEST_ASSERT(local.IsReadOnly(file01Name.c_str()));
+ AZ_TEST_ASSERT(local.IsReadOnly(m_file01Name.c_str()));
#if AZ_TRAIT_USE_WINDOWS_FILE_API
- _chmod(file01Name.c_str(), _S_IREAD | _S_IWRITE);
+ _chmod(m_file01Name.c_str(), _S_IREAD | _S_IWRITE);
#else
- chmod(file01Name.c_str(), S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP | S_IROTH | S_IWOTH);
+ chmod(m_file01Name.c_str(), S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP | S_IROTH | S_IWOTH);
#endif
#endif
- AZ_TEST_ASSERT(!local.IsReadOnly(file01Name.c_str()));
+ AZ_TEST_ASSERT(!local.IsReadOnly(m_file01Name.c_str()));
}
};
@@ -474,14 +423,14 @@ namespace UnitTest
{
LocalFileIO local;
- AZ_TEST_ASSERT(local.CreatePath(fileRoot.c_str()));
- AZ_TEST_ASSERT(local.IsDirectory(fileRoot.c_str()));
+ AZ_TEST_ASSERT(local.CreatePath(m_fileRoot.c_str()));
+ AZ_TEST_ASSERT(local.IsDirectory(m_fileRoot.c_str()));
{
#ifdef AZ_COMPILER_MSVC
FILE* tempFile;
- fopen_s(&tempFile, file01Name.c_str(), "wb");
+ fopen_s(&tempFile, m_file01Name.c_str(), "wb");
#else
- FILE* tempFile = fopen(file01Name.c_str(), "wb");
+ FILE* tempFile = fopen(m_file01Name.c_str(), "wb");
#endif
fwrite("this is just a test", 1, 19, tempFile);
fclose(tempFile);
@@ -489,47 +438,47 @@ namespace UnitTest
// make sure attributes are copied (such as modtime) even if they're copied:
AZStd::this_thread::sleep_for(AZStd::chrono::milliseconds(1500));
- AZ_TEST_ASSERT(local.Copy(file01Name.c_str(), file02Name.c_str()));
+ AZ_TEST_ASSERT(local.Copy(m_file01Name.c_str(), m_file02Name.c_str()));
AZStd::this_thread::sleep_for(AZStd::chrono::milliseconds(1500));
- AZ_TEST_ASSERT(local.Copy(file01Name.c_str(), file03Name.c_str()));
-
- AZ_TEST_ASSERT(local.Exists(file01Name.c_str()));
- AZ_TEST_ASSERT(local.Exists(file02Name.c_str()));
- AZ_TEST_ASSERT(local.Exists(file03Name.c_str()));
- AZ_TEST_ASSERT(!local.DestroyPath(file01Name.c_str())); // you may not destroy files.
- AZ_TEST_ASSERT(!local.DestroyPath(file02Name.c_str()));
- AZ_TEST_ASSERT(!local.DestroyPath(file03Name.c_str()));
- AZ_TEST_ASSERT(local.Exists(file01Name.c_str()));
- AZ_TEST_ASSERT(local.Exists(file02Name.c_str()));
- AZ_TEST_ASSERT(local.Exists(file03Name.c_str()));
+ AZ_TEST_ASSERT(local.Copy(m_file01Name.c_str(), m_file03Name.c_str()));
+
+ AZ_TEST_ASSERT(local.Exists(m_file01Name.c_str()));
+ AZ_TEST_ASSERT(local.Exists(m_file02Name.c_str()));
+ AZ_TEST_ASSERT(local.Exists(m_file03Name.c_str()));
+ AZ_TEST_ASSERT(!local.DestroyPath(m_file01Name.c_str())); // you may not destroy files.
+ AZ_TEST_ASSERT(!local.DestroyPath(m_file02Name.c_str()));
+ AZ_TEST_ASSERT(!local.DestroyPath(m_file03Name.c_str()));
+ AZ_TEST_ASSERT(local.Exists(m_file01Name.c_str()));
+ AZ_TEST_ASSERT(local.Exists(m_file02Name.c_str()));
+ AZ_TEST_ASSERT(local.Exists(m_file03Name.c_str()));
AZ::u64 f1s = 0;
AZ::u64 f2s = 0;
AZ::u64 f3s = 0;
- AZ_TEST_ASSERT(local.Size(file01Name.c_str(), f1s));
- AZ_TEST_ASSERT(local.Size(file02Name.c_str(), f2s));
- AZ_TEST_ASSERT(local.Size(file03Name.c_str(), f3s));
+ AZ_TEST_ASSERT(local.Size(m_file01Name.c_str(), f1s));
+ AZ_TEST_ASSERT(local.Size(m_file02Name.c_str(), f2s));
+ AZ_TEST_ASSERT(local.Size(m_file03Name.c_str(), f3s));
AZ_TEST_ASSERT(f1s == f2s);
AZ_TEST_ASSERT(f1s == f3s);
// Copying over top other files is allowed
SystemFile file;
- EXPECT_TRUE(file.Open(file01Name.c_str(), SystemFile::SF_OPEN_WRITE_ONLY));
+ EXPECT_TRUE(file.Open(m_file01Name.c_str(), SystemFile::SF_OPEN_WRITE_ONLY));
file.Write("this is just a test that is longer", 34);
file.Close();
// make sure attributes are copied (such as modtime) even if they're copied:
AZStd::this_thread::sleep_for(AZStd::chrono::milliseconds(1500));
- EXPECT_TRUE(local.Copy(file01Name.c_str(), file02Name.c_str()));
+ EXPECT_TRUE(local.Copy(m_file01Name.c_str(), m_file02Name.c_str()));
f1s = 0;
f2s = 0;
f3s = 0;
- EXPECT_TRUE(local.Size(file01Name.c_str(), f1s));
- EXPECT_TRUE(local.Size(file02Name.c_str(), f2s));
- EXPECT_TRUE(local.Size(file03Name.c_str(), f3s));
+ EXPECT_TRUE(local.Size(m_file01Name.c_str(), f1s));
+ EXPECT_TRUE(local.Size(m_file02Name.c_str(), f2s));
+ EXPECT_TRUE(local.Size(m_file03Name.c_str(), f3s));
EXPECT_EQ(f1s, f2s);
EXPECT_NE(f1s, f3s);
}
@@ -552,37 +501,37 @@ namespace UnitTest
AZ::u64 modTimeC = 0;
AZ::u64 modTimeD = 0;
- modTimeC = local.ModificationTime(file02Name.c_str());
- modTimeD = local.ModificationTime(file03Name.c_str());
+ modTimeC = local.ModificationTime(m_file02Name.c_str());
+ modTimeD = local.ModificationTime(m_file03Name.c_str());
// make sure modtimes are in ascending order (at least)
AZ_TEST_ASSERT(modTimeD >= modTimeC);
// now touch some of the files. This is also how we test append mode, and write mode.
AZ::IO::HandleType fileHandle = AZ::IO::InvalidHandle;
- AZ_TEST_ASSERT(local.Open(file02Name.c_str(), AZ::IO::OpenMode::ModeAppend | AZ::IO::OpenMode::ModeBinary, fileHandle));
+ AZ_TEST_ASSERT(local.Open(m_file02Name.c_str(), AZ::IO::OpenMode::ModeAppend | AZ::IO::OpenMode::ModeBinary, fileHandle));
AZ_TEST_ASSERT(fileHandle != AZ::IO::InvalidHandle);
AZ_TEST_ASSERT(local.Write(fileHandle, "more", 4));
AZ_TEST_ASSERT(local.Close(fileHandle));
AZStd::this_thread::sleep_for(AZStd::chrono::milliseconds(1500));
// No-append-mode
- AZ_TEST_ASSERT(local.Open(file03Name.c_str(), AZ::IO::OpenMode::ModeWrite | AZ::IO::OpenMode::ModeBinary, fileHandle));
+ AZ_TEST_ASSERT(local.Open(m_file03Name.c_str(), AZ::IO::OpenMode::ModeWrite | AZ::IO::OpenMode::ModeBinary, fileHandle));
AZ_TEST_ASSERT(fileHandle != AZ::IO::InvalidHandle);
AZ_TEST_ASSERT(local.Write(fileHandle, "more", 4));
AZ_TEST_ASSERT(local.Close(fileHandle));
- modTimeC = local.ModificationTime(file02Name.c_str());
- modTimeD = local.ModificationTime(file03Name.c_str());
+ modTimeC = local.ModificationTime(m_file02Name.c_str());
+ modTimeD = local.ModificationTime(m_file03Name.c_str());
AZ_TEST_ASSERT(modTimeD > modTimeC);
AZ::u64 f1s = 0;
AZ::u64 f2s = 0;
AZ::u64 f3s = 0;
- AZ_TEST_ASSERT(local.Size(file01Name.c_str(), f1s));
- AZ_TEST_ASSERT(local.Size(file02Name.c_str(), f2s));
- AZ_TEST_ASSERT(local.Size(file03Name.c_str(), f3s));
+ AZ_TEST_ASSERT(local.Size(m_file01Name.c_str(), f1s));
+ AZ_TEST_ASSERT(local.Size(m_file02Name.c_str(), f2s));
+ AZ_TEST_ASSERT(local.Size(m_file03Name.c_str(), f3s));
AZ_TEST_ASSERT(f2s == f1s + 4);
AZ_TEST_ASSERT(f3s == 4);
}
@@ -603,8 +552,8 @@ namespace UnitTest
CreateTestFiles();
- AZStd::vector resultFiles;
- bool foundOK = local.FindFiles(fileRoot.c_str(), "*",
+ AZStd::vector resultFiles;
+ bool foundOK = local.FindFiles(m_fileRoot.c_str(), "*",
[&](const char* filePath) -> bool
{
resultFiles.push_back(filePath);
@@ -616,7 +565,7 @@ namespace UnitTest
resultFiles.clear();
- foundOK = local.FindFiles(fileRoot.c_str(), "*",
+ foundOK = local.FindFiles(m_fileRoot.c_str(), "*",
[&](const char* filePath) -> bool
{
resultFiles.push_back(filePath);
@@ -627,7 +576,7 @@ namespace UnitTest
AZ_TEST_ASSERT(resultFiles.size() == 3);
// note: following tests accumulate more files without clearing resultfiles.
- foundOK = local.FindFiles(fileRoot.c_str(), "*.txt",
+ foundOK = local.FindFiles(m_fileRoot.c_str(), "*.txt",
[&](const char* filePath) -> bool
{
resultFiles.push_back(filePath);
@@ -637,7 +586,7 @@ namespace UnitTest
AZ_TEST_ASSERT(foundOK);
AZ_TEST_ASSERT(resultFiles.size() == 4);
- foundOK = local.FindFiles(fileRoot.c_str(), "file*.asdf",
+ foundOK = local.FindFiles(m_fileRoot.c_str(), "file*.asdf",
[&](const char* filePath) -> bool
{
resultFiles.push_back(filePath);
@@ -647,7 +596,7 @@ namespace UnitTest
AZ_TEST_ASSERT(foundOK);
AZ_TEST_ASSERT(resultFiles.size() == 5);
- foundOK = local.FindFiles(fileRoot.c_str(), "asaf.asdf",
+ foundOK = local.FindFiles(m_fileRoot.c_str(), "asaf.asdf",
[&](const char* filePath) -> bool
{
resultFiles.push_back(filePath);
@@ -660,7 +609,7 @@ namespace UnitTest
resultFiles.clear();
// test to make sure directories show up:
- foundOK = local.FindFiles(deepFolder.c_str(), "*",
+ foundOK = local.FindFiles(m_deepFolder.c_str(), "*",
[&](const char* filePath) -> bool
{
resultFiles.push_back(filePath);
@@ -668,11 +617,11 @@ namespace UnitTest
});
// canonicalize the name in the same way that find does.
- //AZStd::replace() extraFolder.replace('\\', '/'); FIXME PPATEL
+ //AZStd::replace() m_extraFolder.replace('\\', '/'); FIXME PPATEL
AZ_TEST_ASSERT(foundOK);
AZ_TEST_ASSERT(resultFiles.size() == 1);
- AZ_TEST_ASSERT(resultFiles[0] == extraFolder);
+ AZ_TEST_ASSERT(resultFiles[0] == m_extraFolder);
resultFiles.clear();
foundOK = local.FindFiles("o:137787621!@#$%^&&**())_+[])_", "asaf.asdf",
[&](const char* filePath) -> bool
@@ -684,13 +633,13 @@ namespace UnitTest
AZ_TEST_ASSERT(!foundOK);
AZ_TEST_ASSERT(resultFiles.size() == 0);
- AZStd::string file04Name = fileRoot + "test.wha";
+ AZ::IO::Path file04Name = m_fileRoot / "test.wha";
// test rename
- AZ_TEST_ASSERT(local.Rename(file03Name.c_str(), file04Name.c_str()));
- AZ_TEST_ASSERT(!local.Rename(file03Name.c_str(), file04Name.c_str()));
+ AZ_TEST_ASSERT(local.Rename(m_file03Name.c_str(), file04Name.c_str()));
+ AZ_TEST_ASSERT(!local.Rename(m_file03Name.c_str(), file04Name.c_str()));
AZ_TEST_ASSERT(local.Rename(file04Name.c_str(), file04Name.c_str())); // this is valid and ok
AZ_TEST_ASSERT(local.Exists(file04Name.c_str()));
- AZ_TEST_ASSERT(!local.Exists(file03Name.c_str()));
+ AZ_TEST_ASSERT(!local.Exists(m_file03Name.c_str()));
AZ_TEST_ASSERT(!local.IsDirectory(file04Name.c_str()));
AZ::u64 f3s = 0;
@@ -698,8 +647,8 @@ namespace UnitTest
AZ_TEST_ASSERT(f3s == 19);
// deep destroy directory:
- AZ_TEST_ASSERT(local.DestroyPath(folderName.c_str()));
- AZ_TEST_ASSERT(!local.Exists(folderName.c_str()));
+ AZ_TEST_ASSERT(local.DestroyPath(m_folderName.c_str()));
+ AZ_TEST_ASSERT(!local.Exists(m_folderName.c_str()));
}
};
@@ -715,7 +664,7 @@ namespace UnitTest
AZ::IO::LocalFileIO local;
// test aliases
- local.SetAlias("@test@", folderName.c_str());
+ local.SetAlias("@test@", m_folderName.c_str());
const char* testDest1 = local.GetAlias("@test@");
AZ_TEST_ASSERT(testDest1 != nullptr);
const char* testDest2 = local.GetAlias("@NOPE@");
@@ -725,18 +674,18 @@ namespace UnitTest
// test resolving
const char* aliasTestPath = "@test@\\some\\path\\somefile.txt";
- char aliasResolvedPath[AZ_MAX_PATH_LEN];
- bool resolveDidWork = local.ResolvePath(aliasTestPath, aliasResolvedPath, AZ_MAX_PATH_LEN);
+ char aliasResolvedPath[AZ::IO::MaxPathLength];
+ bool resolveDidWork = local.ResolvePath(aliasTestPath, aliasResolvedPath, AZ::IO::MaxPathLength);
AZ_TEST_ASSERT(resolveDidWork);
- AZStd::string expectedResolvedPath = folderName + "some/path/somefile.txt";
+ AZ::IO::Path expectedResolvedPath = m_folderName / "some/path/somefile.txt";
AZ_TEST_ASSERT(aliasResolvedPath == expectedResolvedPath);
// more resolve path tests with invalid inputs
const char* testPath = nullptr;
char* testResolvedPath = nullptr;
- resolveDidWork = local.ResolvePath(testPath, aliasResolvedPath, AZ_MAX_PATH_LEN);
+ resolveDidWork = local.ResolvePath(testPath, aliasResolvedPath, AZ::IO::MaxPathLength);
AZ_TEST_ASSERT(!resolveDidWork);
- resolveDidWork = local.ResolvePath(aliasTestPath, testResolvedPath, AZ_MAX_PATH_LEN);
+ resolveDidWork = local.ResolvePath(aliasTestPath, testResolvedPath, AZ::IO::MaxPathLength);
AZ_TEST_ASSERT(!resolveDidWork);
resolveDidWork = local.ResolvePath(aliasTestPath, aliasResolvedPath, 0);
AZ_TEST_ASSERT(!resolveDidWork);
@@ -751,7 +700,7 @@ namespace UnitTest
// Test that sending in a too small output path fails,
// if the output buffer is too small to hold the resolved path
- size_t SMALLER_THAN_FINAL_RESOLVED_PATH = expectedResolvedPath.length() - 1;
+ size_t SMALLER_THAN_FINAL_RESOLVED_PATH = expectedResolvedPath.Native().length() - 1;
AZ_TEST_START_TRACE_SUPPRESSION;
resolveDidWork = local.ResolvePath(aliasTestPath, aliasResolvedPath, SMALLER_THAN_FINAL_RESOLVED_PATH);
AZ_TEST_STOP_TRACE_SUPPRESSION(1);
@@ -766,22 +715,23 @@ namespace UnitTest
TEST_F(AliasTest, ResolvePath_PathViewOverload_Succeeds)
{
AZ::IO::LocalFileIO local;
- local.SetAlias("@test@", folderName.c_str());
+ local.SetAlias("@test@", m_folderName.c_str());
AZ::IO::PathView aliasTestPath = "@test@\\some\\path\\somefile.txt";
AZ::IO::FixedMaxPath aliasResolvedPath;
ASSERT_TRUE(local.ResolvePath(aliasResolvedPath, aliasTestPath));
- const auto expectedResolvedPath = AZ::IO::FixedMaxPathString::format("%ssome/path/somefile.txt", folderName.c_str());
- EXPECT_STREQ(expectedResolvedPath.c_str(), aliasResolvedPath.c_str());
+ AZ::IO::Path expectedResolvedPath = m_folderName / "some" / "path" / "somefile.txt";
+
+ EXPECT_EQ(expectedResolvedPath, aliasResolvedPath);
AZStd::optional optionalResolvedPath = local.ResolvePath(aliasTestPath);
ASSERT_TRUE(optionalResolvedPath);
- EXPECT_STREQ(expectedResolvedPath.c_str(), optionalResolvedPath->c_str());
+ EXPECT_EQ(expectedResolvedPath, optionalResolvedPath.value());
}
TEST_F(AliasTest, ResolvePath_PathViewOverloadWithEmptyPath_Fails)
{
AZ::IO::LocalFileIO local;
- local.SetAlias("@test@", folderName.c_str());
+ local.SetAlias("@test@", m_folderName.c_str());
AZ::IO::FixedMaxPath aliasResolvedPath;
EXPECT_FALSE(local.ResolvePath(aliasResolvedPath, {}));
}
@@ -860,24 +810,23 @@ namespace UnitTest
{
LocalFileIO localFileIO;
AZ::IO::FileIOBase::SetInstance(&localFileIO);
- AZStd::string path;
- AzFramework::StringFunc::Path::GetFullPath(file01Name.c_str(), path);
+ AZ::IO::Path path = m_file01Name.ParentPath();
AZ_TEST_ASSERT(localFileIO.CreatePath(path.c_str()));
- AzFramework::StringFunc::Path::GetFullPath(file02Name.c_str(), path);
+ path = m_file01Name.ParentPath();
AZ_TEST_ASSERT(localFileIO.CreatePath(path.c_str()));
AZ::IO::HandleType fileHandle = AZ::IO::InvalidHandle;
- localFileIO.Open(file01Name.c_str(), OpenMode::ModeWrite | OpenMode::ModeText, fileHandle);
+ localFileIO.Open(m_file01Name.c_str(), OpenMode::ModeWrite | OpenMode::ModeText, fileHandle);
localFileIO.Write(fileHandle, "DummyFile", 9);
localFileIO.Close(fileHandle);
AZ::IO::HandleType fileHandle1 = AZ::IO::InvalidHandle;
- localFileIO.Open(file02Name.c_str(), OpenMode::ModeWrite | OpenMode::ModeText, fileHandle1);
+ localFileIO.Open(m_file02Name.c_str(), OpenMode::ModeWrite | OpenMode::ModeText, fileHandle1);
localFileIO.Write(fileHandle1, "TestFile", 8);
localFileIO.Close(fileHandle1);
fileHandle1 = AZ::IO::InvalidHandle;
- localFileIO.Open(file02Name.c_str(), OpenMode::ModeRead | OpenMode::ModeText, fileHandle1);
+ localFileIO.Open(m_file02Name.c_str(), OpenMode::ModeRead | OpenMode::ModeText, fileHandle1);
static const size_t testStringLen = 256;
char testString[testStringLen] = { 0 };
localFileIO.Read(fileHandle1, testString, testStringLen);
@@ -885,50 +834,50 @@ namespace UnitTest
AZ_TEST_ASSERT(strncmp(testString, "TestFile", 8) == 0);
// try swapping files when none of the files are in use
- AZ_TEST_ASSERT(AZ::IO::SmartMove(file01Name.c_str(), file02Name.c_str()));
+ AZ_TEST_ASSERT(AZ::IO::SmartMove(m_file01Name.c_str(), m_file02Name.c_str()));
fileHandle1 = AZ::IO::InvalidHandle;
- localFileIO.Open(file02Name.c_str(), OpenMode::ModeRead | OpenMode::ModeText, fileHandle1);
+ localFileIO.Open(m_file02Name.c_str(), OpenMode::ModeRead | OpenMode::ModeText, fileHandle1);
testString[0] = '\0';
localFileIO.Read(fileHandle1, testString, testStringLen);
localFileIO.Close(fileHandle1);
AZ_TEST_ASSERT(strncmp(testString, "DummyFile", 9) == 0);
//try swapping files when source file is not present, this should fail
- AZ_TEST_ASSERT(!AZ::IO::SmartMove(file01Name.c_str(), file02Name.c_str()));
+ AZ_TEST_ASSERT(!AZ::IO::SmartMove(m_file01Name.c_str(), m_file02Name.c_str()));
fileHandle = AZ::IO::InvalidHandle;
- localFileIO.Open(file01Name.c_str(), OpenMode::ModeWrite | OpenMode::ModeText, fileHandle);
+ localFileIO.Open(m_file01Name.c_str(), OpenMode::ModeWrite | OpenMode::ModeText, fileHandle);
localFileIO.Write(fileHandle, "TestFile", 8);
localFileIO.Close(fileHandle);
#if AZ_TRAIT_AZFRAMEWORKTEST_MOVE_WHILE_OPEN
fileHandle1 = AZ::IO::InvalidHandle;
- localFileIO.Open(file02Name.c_str(), OpenMode::ModeRead | OpenMode::ModeText, fileHandle1);
+ localFileIO.Open(m_file02Name.c_str(), OpenMode::ModeRead | OpenMode::ModeText, fileHandle1);
testString[0] = '\0';
localFileIO.Read(fileHandle1, testString, testStringLen);
// try swapping files when the destination file is open for read only,
// since window is unable to move files that are open for read, this will fail.
- AZ_TEST_ASSERT(!AZ::IO::SmartMove(file01Name.c_str(), file02Name.c_str()));
+ AZ_TEST_ASSERT(!AZ::IO::SmartMove(m_file01Name.c_str(), m_file02Name.c_str()));
localFileIO.Close(fileHandle1);
#endif
fileHandle = AZ::IO::InvalidHandle;
- localFileIO.Open(file01Name.c_str(), OpenMode::ModeRead | OpenMode::ModeText, fileHandle);
+ localFileIO.Open(m_file01Name.c_str(), OpenMode::ModeRead | OpenMode::ModeText, fileHandle);
// try swapping files when the source file is open for read only
- AZ_TEST_ASSERT(AZ::IO::SmartMove(file01Name.c_str(), file02Name.c_str()));
+ AZ_TEST_ASSERT(AZ::IO::SmartMove(m_file01Name.c_str(), m_file02Name.c_str()));
localFileIO.Close(fileHandle);
fileHandle1 = AZ::IO::InvalidHandle;
- localFileIO.Open(file02Name.c_str(), OpenMode::ModeRead | OpenMode::ModeText, fileHandle1);
+ localFileIO.Open(m_file02Name.c_str(), OpenMode::ModeRead | OpenMode::ModeText, fileHandle1);
testString[0] = '\0';
localFileIO.Read(fileHandle1, testString, testStringLen);
AZ_TEST_ASSERT(strncmp(testString, "TestFile", 8) == 0);
localFileIO.Close(fileHandle1);
- localFileIO.Remove(file01Name.c_str());
- localFileIO.Remove(file02Name.c_str());
+ localFileIO.Remove(m_file01Name.c_str());
+ localFileIO.Remove(m_file02Name.c_str());
localFileIO.DestroyPath(m_root.c_str());
AZ::IO::FileIOBase::SetInstance(nullptr);
diff --git a/Code/Framework/AzGameFramework/AzGameFramework/Application/GameApplication.cpp b/Code/Framework/AzGameFramework/AzGameFramework/Application/GameApplication.cpp
index 475a7d5504..424132b624 100644
--- a/Code/Framework/AzGameFramework/AzGameFramework/Application/GameApplication.cpp
+++ b/Code/Framework/AzGameFramework/AzGameFramework/Application/GameApplication.cpp
@@ -28,20 +28,22 @@ namespace AzGameFramework
// can read from the FileIOBase instance if available
m_settingsRegistry->SetUseFileIO(true);
- // Attempt to mount the engine pak from the Executable Directory
- // at the Assets alias, otherwise to attempting to mount the engine pak
- // from the Cache folder
- AZ::IO::FixedMaxPath enginePakPath = AZ::Utils::GetExecutableDirectory();
- enginePakPath /= "engine.pak";
- if (!m_archive->OpenPack("@assets@", enginePakPath.Native()))
+ // Attempt to mount the engine pak to the project product asset alias
+ // Search Order:
+ // - Project Cache Root Directory
+ // - Executable Directory
+ bool enginePakOpened{};
+ AZ::IO::FixedMaxPath enginePakPath;
+ if (m_settingsRegistry->Get(enginePakPath.Native(), AZ::SettingsRegistryMergeUtils::FilePathKey_CacheRootFolder))
{
- enginePakPath.clear();
- if (m_settingsRegistry->Get(enginePakPath.Native(), AZ::SettingsRegistryMergeUtils::FilePathKey_CacheRootFolder))
- {
- // fall back to checking Project Cache Root.
- enginePakPath /= "engine.pak";
- m_archive->OpenPack("@assets@", enginePakPath.Native());
- }
+ // fall back to checking Project Cache Root.
+ enginePakPath /= "engine.pak";
+ enginePakOpened = m_archive->OpenPack("@projectproductassets@", enginePakPath.Native());
+ }
+ if (!enginePakOpened)
+ {
+ enginePakPath = AZ::IO::FixedMaxPath(AZ::Utils::GetExecutableDirectory()) / "engine.pak";
+ m_archive->OpenPack("@projectproductassets@", enginePakPath.Native());
}
}
diff --git a/Code/Framework/AzNetworking/AzNetworking/AutoGen/AutoPacketDispatcher_Inline.jinja b/Code/Framework/AzNetworking/AzNetworking/AutoGen/AutoPacketDispatcher_Inline.jinja
index c6f1a23402..145f15bb19 100644
--- a/Code/Framework/AzNetworking/AzNetworking/AutoGen/AutoPacketDispatcher_Inline.jinja
+++ b/Code/Framework/AzNetworking/AzNetworking/AutoGen/AutoPacketDispatcher_Inline.jinja
@@ -6,16 +6,25 @@ namespace {{ xml.attrib['Name'] }}
{
switch (aznumeric_cast(packetHeader.GetPacketType()))
{
+{% set packet_ns = namespace(handshake=false) %}
+{% for Packet in xml.iter('Packet') %}
+{% if ('HandshakePacket' in Packet.attrib) and (Packet.attrib['HandshakePacket']|booleanTrue == true) %}
+{% set packet_ns.handshake = True %}
+{% endif %}
+{% endfor %}
+
{% for Packet in xml.iter('Packet') %}
case aznumeric_cast({{ Packet.attrib['Name'] }}::Type):
{
AZLOG(Debug_DispatchPackets, "Received packet %s", "{{ Packet.attrib['Name'] }}");
-{% if ('HandshakePacket' not in Packet.attrib) or (Packet.attrib['HandshakePacket'] == 'false') %}
- if (!handler.IsHandshakeComplete())
+{% if packet_ns.handshake %}
+{% if ('HandshakePacket' not in Packet.attrib) or (Packet.attrib['HandshakePacket'] == 'false') %}
+ if (!handler.IsHandshakeComplete(connection))
{
return AzNetworking::PacketDispatchResult::Skipped;
}
-{% endif %}
+{% endif %}
+{% endif %}
{{ Packet.attrib['Name'] }} packet;
if (!serializer.Serialize(packet, "Packet"))
diff --git a/Code/Framework/AzNetworking/AzNetworking/DataStructures/TimeoutQueue.h b/Code/Framework/AzNetworking/AzNetworking/DataStructures/TimeoutQueue.h
index 76defd0b32..239af5be0e 100644
--- a/Code/Framework/AzNetworking/AzNetworking/DataStructures/TimeoutQueue.h
+++ b/Code/Framework/AzNetworking/AzNetworking/DataStructures/TimeoutQueue.h
@@ -94,6 +94,7 @@ namespace AzNetworking
class ITimeoutHandler
{
public:
+ virtual ~ITimeoutHandler() = default;
//! Handler callback for timed out items.
//! @param item containing registered timeout details
diff --git a/Code/Framework/AzNetworking/AzNetworking/Framework/INetworkInterface.h b/Code/Framework/AzNetworking/AzNetworking/Framework/INetworkInterface.h
index 09aa62f7d7..3a37a44a02 100644
--- a/Code/Framework/AzNetworking/AzNetworking/Framework/INetworkInterface.h
+++ b/Code/Framework/AzNetworking/AzNetworking/Framework/INetworkInterface.h
@@ -103,13 +103,13 @@ namespace AzNetworking
//! @return boolean true on success
virtual bool Disconnect(ConnectionId connectionId, DisconnectReason reason) = 0;
- //! Sets whether this connection interface can disconnect by virtue of a timeout
- //! @param timeoutEnabled If this connection interface will automatically disconnect due to a timeout
- virtual void SetTimeoutEnabled(bool timeoutEnabled) = 0;
+ //! Sets the timeout time in milliseconds, 0 ms means timeouts are disabled.
+ //! @param timeoutMs the number of milliseconds with no traffic before we timeout and close a connection
+ virtual void SetTimeoutMs(AZ::TimeMs timeoutMs) = 0;
- //! Whether this connection interface will disconnect by virtue of a time out (does not account for cvars affecting all connections)
- //! @return boolean true if this connection will not disconnect on timeout (does not account for cvars affecting all connections)
- virtual bool IsTimeoutEnabled() const = 0;
+ //! Retrieves the timeout time in milliseconds for this network interface, 0 ms means timeouts are disabled.
+ //! @return the timeout time in milliseconds for this network interface, 0 ms means timeouts are disabled
+ virtual AZ::TimeMs GetTimeoutMs() const = 0;
//! Const access to the metrics tracked by this network interface.
//! @return const reference to the metrics tracked by this network interface
diff --git a/Code/Framework/AzNetworking/AzNetworking/Serialization/AzContainerSerializers.h b/Code/Framework/AzNetworking/AzNetworking/Serialization/AzContainerSerializers.h
index 59e0cc8235..e99144acbf 100644
--- a/Code/Framework/AzNetworking/AzNetworking/Serialization/AzContainerSerializers.h
+++ b/Code/Framework/AzNetworking/AzNetworking/Serialization/AzContainerSerializers.h
@@ -321,4 +321,19 @@ namespace AzNetworking
return serializer.IsValid();
}
};
+
+ template <>
+ struct SerializeObjectHelper
+ {
+ static bool SerializeObject(ISerializer& serializer, AZ::Aabb& value)
+ {
+ AZ::Vector3 minValue = value.GetMin();
+ AZ::Vector3 maxValue = value.GetMax();
+ serializer.Serialize(minValue, "minValue");
+ serializer.Serialize(maxValue, "maxValue");
+ value.SetMin(minValue);
+ value.SetMax(maxValue);
+ return serializer.IsValid();
+ }
+ };
}
diff --git a/Code/Framework/AzNetworking/AzNetworking/TcpTransport/TcpNetworkInterface.cpp b/Code/Framework/AzNetworking/AzNetworking/TcpTransport/TcpNetworkInterface.cpp
index 62335a9b39..1ccff7be50 100644
--- a/Code/Framework/AzNetworking/AzNetworking/TcpTransport/TcpNetworkInterface.cpp
+++ b/Code/Framework/AzNetworking/AzNetworking/TcpTransport/TcpNetworkInterface.cpp
@@ -22,14 +22,15 @@ namespace AzNetworking
#endif
AZ_CVAR(bool, net_TcpTimeoutConnections, true, nullptr, AZ::ConsoleFunctorFlags::DontReplicate, "Boolean value on whether we should timeout Tcp connections");
- AZ_CVAR(AZ::TimeMs, net_TcpHearthbeatTimeMs, AZ::TimeMs{ 2 * 1000 }, nullptr, AZ::ConsoleFunctorFlags::Null, "Tcp connection heartbeat frequency");
- AZ_CVAR(AZ::TimeMs, net_TcpTimeoutTimeMs, AZ::TimeMs{ 10 * 1000 }, nullptr, AZ::ConsoleFunctorFlags::Null, "Time in milliseconds before we timeout an idle Tcp connection");
+ AZ_CVAR(AZ::TimeMs, net_TcpHeartbeatTimeMs, AZ::TimeMs{ 2 * 1000 }, nullptr, AZ::ConsoleFunctorFlags::Null, "Tcp connection heartbeat frequency");
+ AZ_CVAR(AZ::TimeMs, net_TcpDefaultTimeoutMs, AZ::TimeMs{ 10 * 1000 }, nullptr, AZ::ConsoleFunctorFlags::Null, "Time in milliseconds before we timeout an idle Tcp connection");
TcpNetworkInterface::TcpNetworkInterface(AZ::Name name, IConnectionListener& connectionListener, TrustZone trustZone, TcpListenThread& listenThread)
: m_name(name)
, m_trustZone(trustZone)
, m_connectionListener(connectionListener)
, m_listenThread(listenThread)
+ , m_timeoutMs(net_TcpDefaultTimeoutMs)
{
;
}
@@ -97,7 +98,7 @@ namespace AzNetworking
}
AZLOG_INFO("Adding new socket %d", static_cast(tcpSocket->GetSocketFd()));
- const TimeoutId newTimeoutId = m_connectionTimeoutQueue.RegisterItem(static_cast(tcpSocket->GetSocketFd()), net_TcpHearthbeatTimeMs);
+ const TimeoutId newTimeoutId = m_connectionTimeoutQueue.RegisterItem(static_cast(tcpSocket->GetSocketFd()), net_TcpHeartbeatTimeMs);
connection->SetTimeoutId(newTimeoutId);
connection->SendReliablePacket(CorePackets::InitiateConnectionPacket());
m_connectionListener.OnConnect(connection.get());
@@ -174,14 +175,14 @@ namespace AzNetworking
return connection->Disconnect(reason, TerminationEndpoint::Local);
}
- void TcpNetworkInterface::SetTimeoutEnabled(bool timeoutEnabled)
+ void TcpNetworkInterface::SetTimeoutMs(AZ::TimeMs timeoutMs)
{
- m_timeoutEnabled = timeoutEnabled;
+ m_timeoutMs = timeoutMs;
}
- bool TcpNetworkInterface::IsTimeoutEnabled() const
+ AZ::TimeMs TcpNetworkInterface::GetTimeoutMs() const
{
- return m_timeoutEnabled;
+ return m_timeoutMs;
}
void TcpNetworkInterface::QueueNewConnection(const PendingConnection& pendingConnection)
@@ -257,7 +258,7 @@ namespace AzNetworking
return;
}
AZLOG(NET_TcpTraffic, "Adding new socket %d", static_cast(tcpSocket.GetSocketFd()));
- const TimeoutId timeoutId = m_connectionTimeoutQueue.RegisterItem(static_cast(tcpSocket.GetSocketFd()), net_TcpTimeoutTimeMs);
+ const TimeoutId timeoutId = m_connectionTimeoutQueue.RegisterItem(static_cast(tcpSocket.GetSocketFd()), m_timeoutMs);
AZStd::unique_ptr connection = AZStd::make_unique(connectionId, remoteAddress, *this, tcpSocket, timeoutId);
AZ_Assert(connection->GetConnectionRole() == ConnectionRole::Acceptor, "Invalid role for connection");
GetConnectionListener().OnConnect(connection.get());
@@ -316,7 +317,7 @@ namespace AzNetworking
{
tcpConnection->SendReliablePacket(CorePackets::HeartbeatPacket());
}
- else if (net_TcpTimeoutConnections && m_networkInterface.IsTimeoutEnabled())
+ else if (net_TcpTimeoutConnections && (m_networkInterface.GetTimeoutMs() > AZ::TimeMs{ 0 }))
{
tcpConnection->Disconnect(DisconnectReason::Timeout, TerminationEndpoint::Local);
return TimeoutResult::Delete;
diff --git a/Code/Framework/AzNetworking/AzNetworking/TcpTransport/TcpNetworkInterface.h b/Code/Framework/AzNetworking/AzNetworking/TcpTransport/TcpNetworkInterface.h
index b9ea88974d..d8f5d1b62b 100644
--- a/Code/Framework/AzNetworking/AzNetworking/TcpTransport/TcpNetworkInterface.h
+++ b/Code/Framework/AzNetworking/AzNetworking/TcpTransport/TcpNetworkInterface.h
@@ -99,8 +99,8 @@ namespace AzNetworking
bool WasPacketAcked(ConnectionId connectionId, PacketId packetId) override;
bool StopListening() override;
bool Disconnect(ConnectionId connectionId, DisconnectReason reason) override;
- void SetTimeoutEnabled(bool timeoutEnabled) override;
- bool IsTimeoutEnabled() const override;
+ void SetTimeoutMs(AZ::TimeMs timeoutMs) override;
+ AZ::TimeMs GetTimeoutMs() const override;
//! @}
//! Queues a new incoming connection for this network interface.
@@ -156,7 +156,7 @@ namespace AzNetworking
AZ::Name m_name;
TrustZone m_trustZone;
uint16_t m_port = 0;
- bool m_timeoutEnabled = true;
+ AZ::TimeMs m_timeoutMs = AZ::TimeMs{ 0 };
IConnectionListener& m_connectionListener;
TcpConnectionSet m_connectionSet;
TcpSocketManager m_tcpSocketManager;
diff --git a/Code/Framework/AzNetworking/AzNetworking/TcpTransport/TcpSocket.cpp b/Code/Framework/AzNetworking/AzNetworking/TcpTransport/TcpSocket.cpp
index 272683febc..e469b70640 100644
--- a/Code/Framework/AzNetworking/AzNetworking/TcpTransport/TcpSocket.cpp
+++ b/Code/Framework/AzNetworking/AzNetworking/TcpTransport/TcpSocket.cpp
@@ -53,18 +53,11 @@ namespace AzNetworking
{
Close();
- if (!SocketCreateInternal())
- {
- return false;
- }
-
- if (!BindSocketForListenInternal(port))
- {
- return false;
- }
-
- if (!(SetSocketNonBlocking(m_socketFd) && SetSocketNoDelay(m_socketFd)))
+ if (!SocketCreateInternal()
+ || !BindSocketForListenInternal(port)
+ || !(SetSocketNonBlocking(m_socketFd) && SetSocketNoDelay(m_socketFd)))
{
+ Close();
return false;
}
@@ -75,18 +68,11 @@ namespace AzNetworking
{
Close();
- if (!SocketCreateInternal())
- {
- return false;
- }
-
- if (!BindSocketForConnectInternal(address))
- {
- return false;
- }
-
- if (!(SetSocketNonBlocking(m_socketFd) && SetSocketNoDelay(m_socketFd)))
+ if (!SocketCreateInternal()
+ || !BindSocketForConnectInternal(address)
+ || !(SetSocketNonBlocking(m_socketFd) && SetSocketNoDelay(m_socketFd)))
{
+ Close();
return false;
}
diff --git a/Code/Framework/AzNetworking/AzNetworking/UdpTransport/UdpNetworkInterface.cpp b/Code/Framework/AzNetworking/AzNetworking/UdpTransport/UdpNetworkInterface.cpp
index bf01ece458..b0e64f93e3 100644
--- a/Code/Framework/AzNetworking/AzNetworking/UdpTransport/UdpNetworkInterface.cpp
+++ b/Code/Framework/AzNetworking/AzNetworking/UdpTransport/UdpNetworkInterface.cpp
@@ -31,8 +31,8 @@ namespace AzNetworking
AZ_CVAR(bool, net_UdpTimeoutConnections, true, nullptr, AZ::ConsoleFunctorFlags::DontReplicate, "Boolean value on whether we should timeout Udp connections");
AZ_CVAR(AZ::TimeMs, net_UdpPacketTimeSliceMs, AZ::TimeMs{ 8 }, nullptr, AZ::ConsoleFunctorFlags::DontReplicate, "The number of milliseconds to allow for packet processing");
- AZ_CVAR(AZ::TimeMs, net_UdpHearthbeatTimeMs, AZ::TimeMs{ 2 * 1000 }, nullptr, AZ::ConsoleFunctorFlags::Null, "Udp connection heartbeat frequency");
- AZ_CVAR(AZ::TimeMs, net_UdpTimeoutTimeMs, AZ::TimeMs{ 10 * 1000 }, nullptr, AZ::ConsoleFunctorFlags::Null, "Time in milliseconds before we timeout an idle Udp connection");
+ AZ_CVAR(AZ::TimeMs, net_UdpHeartbeatTimeMs, AZ::TimeMs{ 2 * 1000 }, nullptr, AZ::ConsoleFunctorFlags::Null, "Udp connection heartbeat frequency");
+ AZ_CVAR(AZ::TimeMs, net_UdpDefaultTimeoutMs, AZ::TimeMs{ 10 * 1000 }, nullptr, AZ::ConsoleFunctorFlags::Null, "Time in milliseconds before we timeout an idle Udp connection");
AZ_CVAR(AZ::TimeMs, net_MinPacketTimeoutMs, AZ::TimeMs{ 200 }, nullptr, AZ::ConsoleFunctorFlags::DontReplicate, "Minimum time to wait before timing out an unacked packet");
AZ_CVAR(int32_t, net_MaxTimeoutsPerFrame, 1000, nullptr, AZ::ConsoleFunctorFlags::DontReplicate, "Maximum number of packet timeouts to allow to process in a single frame");
AZ_CVAR(float, net_RttFudgeScalar, 2.0f, nullptr, AZ::ConsoleFunctorFlags::DontReplicate, "Scalar value to multiply computed Rtt by to determine an optimal packet timeout threshold");
@@ -61,6 +61,7 @@ namespace AzNetworking
, m_connectionListener(connectionListener)
, m_socket(net_UdpUseEncryption ? new DtlsSocket() : new UdpSocket())
, m_readerThread(readerThread)
+ , m_timeoutMs(net_UdpDefaultTimeoutMs)
{
const AZ::CVarFixedString compressor = static_cast(net_UdpCompressor);
const AZ::Name compressorName = AZ::Name(compressor);
@@ -138,7 +139,7 @@ namespace AzNetworking
}
const ConnectionId connectionId = m_connectionSet.GetNextConnectionId();
- const TimeoutId timeoutId = m_connectionTimeoutQueue.RegisterItem(aznumeric_cast(connectionId), net_UdpHearthbeatTimeMs);
+ const TimeoutId timeoutId = m_connectionTimeoutQueue.RegisterItem(aznumeric_cast(connectionId), m_timeoutMs);
AZStd::unique_ptr connection = AZStd::make_unique(connectionId, remoteAddress, *this, ConnectionRole::Connector);
UdpPacketEncodingBuffer dtlsData;
@@ -403,14 +404,14 @@ namespace AzNetworking
return connection->Disconnect(reason, TerminationEndpoint::Local);
}
- void UdpNetworkInterface::SetTimeoutEnabled(bool timeoutEnabled)
+ void UdpNetworkInterface::SetTimeoutMs(AZ::TimeMs timeoutMs)
{
- m_timeoutEnabled = timeoutEnabled;
+ m_timeoutMs = timeoutMs;
}
- bool UdpNetworkInterface::IsTimeoutEnabled() const
+ AZ::TimeMs UdpNetworkInterface::GetTimeoutMs() const
{
- return m_timeoutEnabled;
+ return m_timeoutMs;
}
bool UdpNetworkInterface::IsEncrypted() const
@@ -681,7 +682,7 @@ namespace AzNetworking
// How long should we sit in the timeout queue before heartbeating or disconnecting
const ConnectionId connectionId = m_connectionSet.GetNextConnectionId();
- const TimeoutId timeoutId = m_connectionTimeoutQueue.RegisterItem(aznumeric_cast(connectionId), net_UdpTimeoutTimeMs);
+ const TimeoutId timeoutId = m_connectionTimeoutQueue.RegisterItem(aznumeric_cast(connectionId), m_timeoutMs);
AZLOG(Debug_UdpConnect, "Accepted new Udp Connection");
AZStd::unique_ptr connection = AZStd::make_unique(connectionId, connectPacket.m_address, *this, ConnectionRole::Acceptor);
@@ -745,7 +746,7 @@ namespace AzNetworking
{
udpConnection->SendUnreliablePacket(CorePackets::HeartbeatPacket());
}
- else if (net_UdpTimeoutConnections && m_networkInterface.IsTimeoutEnabled())
+ else if (net_UdpTimeoutConnections && (m_networkInterface.GetTimeoutMs() > AZ::TimeMs{ 0 }))
{
udpConnection->Disconnect(DisconnectReason::Timeout, TerminationEndpoint::Local);
return TimeoutResult::Delete;
diff --git a/Code/Framework/AzNetworking/AzNetworking/UdpTransport/UdpNetworkInterface.h b/Code/Framework/AzNetworking/AzNetworking/UdpTransport/UdpNetworkInterface.h
index 949914da91..8f827c74c4 100644
--- a/Code/Framework/AzNetworking/AzNetworking/UdpTransport/UdpNetworkInterface.h
+++ b/Code/Framework/AzNetworking/AzNetworking/UdpTransport/UdpNetworkInterface.h
@@ -104,8 +104,8 @@ namespace AzNetworking
bool WasPacketAcked(ConnectionId connectionId, PacketId packetId) override;
bool StopListening() override;
bool Disconnect(ConnectionId connectionId, DisconnectReason reason) override;
- void SetTimeoutEnabled(bool timeoutEnabled) override;
- bool IsTimeoutEnabled() const override;
+ void SetTimeoutMs(AZ::TimeMs timeoutMs) override;
+ AZ::TimeMs GetTimeoutMs() const override;
//! @}
//! Returns true if this is an encrypted socket, false if not.
@@ -181,7 +181,7 @@ namespace AzNetworking
TrustZone m_trustZone;
uint16_t m_port = 0;
bool m_allowIncomingConnections = false;
- bool m_timeoutEnabled = true;
+ AZ::TimeMs m_timeoutMs = AZ::TimeMs{ 0 };
IConnectionListener& m_connectionListener;
UdpConnectionSet m_connectionSet;
TimeoutQueue m_connectionTimeoutQueue;
diff --git a/Code/Framework/AzNetworking/AzNetworking/UdpTransport/UdpSocket.cpp b/Code/Framework/AzNetworking/AzNetworking/UdpTransport/UdpSocket.cpp
index 44f6562c84..300b3527fa 100644
--- a/Code/Framework/AzNetworking/AzNetworking/UdpTransport/UdpSocket.cpp
+++ b/Code/Framework/AzNetworking/AzNetworking/UdpTransport/UdpSocket.cpp
@@ -79,17 +79,15 @@ namespace AzNetworking
{
const int32_t error = GetLastNetworkError();
AZLOG_ERROR("Failed to bind UDP socket to port %u (%d:%s)", uint32_t(port), error, GetNetworkErrorDesc(error));
+ Close();
return false;
}
}
- if (!SetSocketBufferSizes(m_socketFd, net_UdpSendBufferSize, net_UdpRecvBufferSize))
- {
- return false;
- }
-
- if (!SetSocketNonBlocking(m_socketFd))
+ if (!SetSocketBufferSizes(m_socketFd, net_UdpSendBufferSize, net_UdpRecvBufferSize)
+ || !SetSocketNonBlocking(m_socketFd))
{
+ Close();
return false;
}
diff --git a/Code/Framework/AzNetworking/AzNetworking/Utilities/TimedThread.cpp b/Code/Framework/AzNetworking/AzNetworking/Utilities/TimedThread.cpp
index c85d15ae45..565b37202a 100644
--- a/Code/Framework/AzNetworking/AzNetworking/Utilities/TimedThread.cpp
+++ b/Code/Framework/AzNetworking/AzNetworking/Utilities/TimedThread.cpp
@@ -26,27 +26,29 @@ namespace AzNetworking
{
m_running = true;
m_joinable = true;
- m_thread = AZStd::thread([this]()
- {
- OnStart();
- while (m_running)
+ m_thread = AZStd::thread(
+ m_threadDesc,
+ [this]()
{
- const AZ::TimeMs startTimeMs = AZ::GetElapsedTimeMs();
- OnUpdate(m_updateRate);
- const AZ::TimeMs updateTimeMs = AZ::GetElapsedTimeMs() - startTimeMs;
-
- if (m_updateRate > updateTimeMs)
+ OnStart();
+ while (m_running)
{
- AZStd::chrono::milliseconds sleepTimeMs(static_cast(m_updateRate - updateTimeMs));
- AZStd::this_thread::sleep_for(sleepTimeMs);
- }
- else if (m_updateRate < updateTimeMs)
- {
- AZLOG(NET_TimedThread, "TimedThread bled %d ms", aznumeric_cast(updateTimeMs - m_updateRate));
+ const AZ::TimeMs startTimeMs = AZ::GetElapsedTimeMs();
+ OnUpdate(m_updateRate);
+ const AZ::TimeMs updateTimeMs = AZ::GetElapsedTimeMs() - startTimeMs;
+
+ if (m_updateRate > updateTimeMs)
+ {
+ AZStd::chrono::milliseconds sleepTimeMs(static_cast(m_updateRate - updateTimeMs));
+ AZStd::this_thread::sleep_for(sleepTimeMs);
+ }
+ else if (m_updateRate < updateTimeMs)
+ {
+ AZLOG(NET_TimedThread, "TimedThread bled %d ms", aznumeric_cast(updateTimeMs - m_updateRate));
+ }
}
- }
- OnStop();
- }, &m_threadDesc);
+ OnStop();
+ });
}
void TimedThread::Stop()
diff --git a/Code/Framework/AzNetworking/Tests/TcpTransport/TcpTransportTests.cpp b/Code/Framework/AzNetworking/Tests/TcpTransport/TcpTransportTests.cpp
index 3031f66774..77632da572 100644
--- a/Code/Framework/AzNetworking/Tests/TcpTransport/TcpTransportTests.cpp
+++ b/Code/Framework/AzNetworking/Tests/TcpTransport/TcpTransportTests.cpp
@@ -149,8 +149,9 @@ namespace UnitTest
EXPECT_EQ(testServer.m_serverNetworkInterface->GetConnectionSet().GetConnectionCount(), 1);
EXPECT_EQ(testClient.m_clientNetworkInterface->GetConnectionSet().GetConnectionCount(), 1);
- testClient.m_clientNetworkInterface->SetTimeoutEnabled(true);
- EXPECT_TRUE(testClient.m_clientNetworkInterface->IsTimeoutEnabled());
+ const AZ::TimeMs timeoutMs = AZ::TimeMs{ 100 };
+ testClient.m_clientNetworkInterface->SetTimeoutMs(timeoutMs);
+ EXPECT_EQ(testClient.m_clientNetworkInterface->GetTimeoutMs(), timeoutMs);
EXPECT_TRUE(testServer.m_serverNetworkInterface->StopListening());
}
diff --git a/Code/Framework/AzNetworking/Tests/UdpTransport/UdpTransportTests.cpp b/Code/Framework/AzNetworking/Tests/UdpTransport/UdpTransportTests.cpp
index 91db3b4549..65c2cfa2b5 100644
--- a/Code/Framework/AzNetworking/Tests/UdpTransport/UdpTransportTests.cpp
+++ b/Code/Framework/AzNetworking/Tests/UdpTransport/UdpTransportTests.cpp
@@ -279,8 +279,9 @@ namespace UnitTest
EXPECT_EQ(testServer.m_serverNetworkInterface->GetConnectionSet().GetConnectionCount(), 1);
EXPECT_EQ(testClient.m_clientNetworkInterface->GetConnectionSet().GetConnectionCount(), 1);
- testClient.m_clientNetworkInterface->SetTimeoutEnabled(true);
- EXPECT_TRUE(testClient.m_clientNetworkInterface->IsTimeoutEnabled());
+ const AZ::TimeMs timeoutMs = AZ::TimeMs{ 100 };
+ testClient.m_clientNetworkInterface->SetTimeoutMs(timeoutMs);
+ EXPECT_EQ(testClient.m_clientNetworkInterface->GetTimeoutMs(), timeoutMs);
EXPECT_FALSE(dynamic_cast(testClient.m_clientNetworkInterface)->IsEncrypted());
diff --git a/Code/Framework/AzTest/AzTest/Printers.cpp b/Code/Framework/AzTest/AzTest/Printers.cpp
new file mode 100644
index 0000000000..dc639d87d1
--- /dev/null
+++ b/Code/Framework/AzTest/AzTest/Printers.cpp
@@ -0,0 +1,27 @@
+/*
+ * 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 AZ::IO
+{
+ void PrintTo(const AZ::IO::PathView& path, ::std::ostream* os)
+ {
+ *os << "path: " << AZ::IO::Path(path.Native(), AZ::IO::PosixPathSeparator).MakePreferred().c_str();
+ }
+
+ void PrintTo(const AZ::IO::Path& path, ::std::ostream* os)
+ {
+ *os << "path: " << AZ::IO::Path(path.Native(), AZ::IO::PosixPathSeparator).MakePreferred().c_str();
+ }
+
+ void PrintTo(const AZ::IO::FixedMaxPath& path, ::std::ostream* os)
+ {
+ *os << "path: " << AZ::IO::FixedMaxPath(path.Native(), AZ::IO::PosixPathSeparator).MakePreferred().c_str();
+ }
+}
diff --git a/Code/Framework/AzTest/AzTest/Printers.h b/Code/Framework/AzTest/AzTest/Printers.h
new file mode 100644
index 0000000000..3615f7b576
--- /dev/null
+++ b/Code/Framework/AzTest/AzTest/Printers.h
@@ -0,0 +1,40 @@
+/*
+ * 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
+
+namespace AZStd
+{
+ template
+ class basic_string;
+
+ template
+ class basic_string_view;
+
+ template
+ class basic_fixed_string;
+
+ template